2 * Copyright (C) 2006 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 import static java.lang.Math.max;
21 import android.animation.AnimatorInflater;
22 import android.animation.StateListAnimator;
23 import android.annotation.CallSuper;
24 import android.annotation.ColorInt;
25 import android.annotation.DrawableRes;
26 import android.annotation.FloatRange;
27 import android.annotation.IdRes;
28 import android.annotation.IntDef;
29 import android.annotation.IntRange;
30 import android.annotation.LayoutRes;
31 import android.annotation.NonNull;
32 import android.annotation.Nullable;
33 import android.annotation.Size;
34 import android.annotation.TestApi;
35 import android.annotation.UiThread;
36 import android.content.ClipData;
37 import android.content.Context;
38 import android.content.ContextWrapper;
39 import android.content.Intent;
40 import android.content.res.ColorStateList;
41 import android.content.res.Configuration;
42 import android.content.res.Resources;
43 import android.content.res.TypedArray;
44 import android.graphics.Bitmap;
45 import android.graphics.Canvas;
46 import android.graphics.Color;
47 import android.graphics.Insets;
48 import android.graphics.Interpolator;
49 import android.graphics.LinearGradient;
50 import android.graphics.Matrix;
51 import android.graphics.Outline;
52 import android.graphics.Paint;
53 import android.graphics.PixelFormat;
54 import android.graphics.Point;
55 import android.graphics.PorterDuff;
56 import android.graphics.PorterDuffXfermode;
57 import android.graphics.Rect;
58 import android.graphics.RectF;
59 import android.graphics.Region;
60 import android.graphics.Shader;
61 import android.graphics.drawable.ColorDrawable;
62 import android.graphics.drawable.Drawable;
63 import android.hardware.display.DisplayManagerGlobal;
64 import android.net.Uri;
65 import android.os.Build;
66 import android.os.Bundle;
67 import android.os.Handler;
68 import android.os.IBinder;
69 import android.os.Message;
70 import android.os.Parcel;
71 import android.os.Parcelable;
72 import android.os.RemoteException;
73 import android.os.SystemClock;
74 import android.os.SystemProperties;
75 import android.os.Trace;
76 import android.text.TextUtils;
77 import android.util.AttributeSet;
78 import android.util.FloatProperty;
79 import android.util.LayoutDirection;
80 import android.util.Log;
81 import android.util.LongSparseLongArray;
82 import android.util.Pools.SynchronizedPool;
83 import android.util.Property;
84 import android.util.SparseArray;
85 import android.util.StateSet;
86 import android.util.SuperNotCalledException;
87 import android.util.TypedValue;
88 import android.view.AccessibilityIterators.CharacterTextSegmentIterator;
89 import android.view.AccessibilityIterators.ParagraphTextSegmentIterator;
90 import android.view.AccessibilityIterators.TextSegmentIterator;
91 import android.view.AccessibilityIterators.WordTextSegmentIterator;
92 import android.view.ContextMenu.ContextMenuInfo;
93 import android.view.accessibility.AccessibilityEvent;
94 import android.view.accessibility.AccessibilityEventSource;
95 import android.view.accessibility.AccessibilityManager;
96 import android.view.accessibility.AccessibilityNodeInfo;
97 import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
98 import android.view.accessibility.AccessibilityNodeProvider;
99 import android.view.accessibility.AccessibilityWindowInfo;
100 import android.view.animation.Animation;
101 import android.view.animation.AnimationUtils;
102 import android.view.animation.Transformation;
103 import android.view.autofill.AutofillId;
104 import android.view.autofill.AutofillManager;
105 import android.view.autofill.AutofillValue;
106 import android.view.inputmethod.EditorInfo;
107 import android.view.inputmethod.InputConnection;
108 import android.view.inputmethod.InputMethodManager;
109 import android.widget.Checkable;
110 import android.widget.FrameLayout;
111 import android.widget.ScrollBarDrawable;
113 import com.android.internal.R;
114 import com.android.internal.view.TooltipPopup;
115 import com.android.internal.view.menu.MenuBuilder;
116 import com.android.internal.widget.ScrollBarUtils;
118 import com.google.android.collect.Lists;
119 import com.google.android.collect.Maps;
121 import java.lang.annotation.Retention;
122 import java.lang.annotation.RetentionPolicy;
123 import java.lang.ref.WeakReference;
124 import java.lang.reflect.Field;
125 import java.lang.reflect.InvocationTargetException;
126 import java.lang.reflect.Method;
127 import java.lang.reflect.Modifier;
128 import java.util.ArrayList;
129 import java.util.Arrays;
130 import java.util.Collection;
131 import java.util.Collections;
132 import java.util.HashMap;
133 import java.util.List;
134 import java.util.Locale;
135 import java.util.Map;
136 import java.util.concurrent.CopyOnWriteArrayList;
137 import java.util.concurrent.atomic.AtomicInteger;
138 import java.util.function.Predicate;
142 * This class represents the basic building block for user interface components. A View
143 * occupies a rectangular area on the screen and is responsible for drawing and
144 * event handling. View is the base class for <em>widgets</em>, which are
145 * used to create interactive UI components (buttons, text fields, etc.). The
146 * {@link android.view.ViewGroup} subclass is the base class for <em>layouts</em>, which
147 * are invisible containers that hold other Views (or other ViewGroups) and define
148 * their layout properties.
151 * <div class="special reference">
152 * <h3>Developer Guides</h3>
153 * <p>For information about using this class to develop your application's user interface,
154 * read the <a href="{@docRoot}guide/topics/ui/index.html">User Interface</a> developer guide.
157 * <a name="Using"></a>
158 * <h3>Using Views</h3>
160 * All of the views in a window are arranged in a single tree. You can add views
161 * either from code or by specifying a tree of views in one or more XML layout
162 * files. There are many specialized subclasses of views that act as controls or
163 * are capable of displaying text, images, or other content.
166 * Once you have created a tree of views, there are typically a few types of
167 * common operations you may wish to perform:
169 * <li><strong>Set properties:</strong> for example setting the text of a
170 * {@link android.widget.TextView}. The available properties and the methods
171 * that set them will vary among the different subclasses of views. Note that
172 * properties that are known at build time can be set in the XML layout
174 * <li><strong>Set focus:</strong> The framework will handle moving focus in
175 * response to user input. To force focus to a specific view, call
176 * {@link #requestFocus}.</li>
177 * <li><strong>Set up listeners:</strong> Views allow clients to set listeners
178 * that will be notified when something interesting happens to the view. For
179 * example, all views will let you set a listener to be notified when the view
180 * gains or loses focus. You can register such a listener using
181 * {@link #setOnFocusChangeListener(android.view.View.OnFocusChangeListener)}.
182 * Other view subclasses offer more specialized listeners. For example, a Button
183 * exposes a listener to notify clients when the button is clicked.</li>
184 * <li><strong>Set visibility:</strong> You can hide or show views using
185 * {@link #setVisibility(int)}.</li>
189 * Note: The Android framework is responsible for measuring, laying out and
190 * drawing views. You should not call methods that perform these actions on
191 * views yourself unless you are actually implementing a
192 * {@link android.view.ViewGroup}.
195 * <a name="Lifecycle"></a>
196 * <h3>Implementing a Custom View</h3>
199 * To implement a custom view, you will usually begin by providing overrides for
200 * some of the standard methods that the framework calls on all views. You do
201 * not need to override all of these methods. In fact, you can start by just
202 * overriding {@link #onDraw(android.graphics.Canvas)}.
203 * <table border="2" width="85%" align="center" cellpadding="5">
205 * <tr><th>Category</th> <th>Methods</th> <th>Description</th></tr>
210 * <td rowspan="2">Creation</td>
211 * <td>Constructors</td>
212 * <td>There is a form of the constructor that are called when the view
213 * is created from code and a form that is called when the view is
214 * inflated from a layout file. The second form should parse and apply
215 * any attributes defined in the layout file.
219 * <td><code>{@link #onFinishInflate()}</code></td>
220 * <td>Called after a view and all of its children has been inflated
225 * <td rowspan="3">Layout</td>
226 * <td><code>{@link #onMeasure(int, int)}</code></td>
227 * <td>Called to determine the size requirements for this view and all
232 * <td><code>{@link #onLayout(boolean, int, int, int, int)}</code></td>
233 * <td>Called when this view should assign a size and position to all
238 * <td><code>{@link #onSizeChanged(int, int, int, int)}</code></td>
239 * <td>Called when the size of this view has changed.
245 * <td><code>{@link #onDraw(android.graphics.Canvas)}</code></td>
246 * <td>Called when the view should render its content.
251 * <td rowspan="4">Event processing</td>
252 * <td><code>{@link #onKeyDown(int, KeyEvent)}</code></td>
253 * <td>Called when a new hardware key event occurs.
257 * <td><code>{@link #onKeyUp(int, KeyEvent)}</code></td>
258 * <td>Called when a hardware key up event occurs.
262 * <td><code>{@link #onTrackballEvent(MotionEvent)}</code></td>
263 * <td>Called when a trackball motion event occurs.
267 * <td><code>{@link #onTouchEvent(MotionEvent)}</code></td>
268 * <td>Called when a touch screen motion event occurs.
273 * <td rowspan="2">Focus</td>
274 * <td><code>{@link #onFocusChanged(boolean, int, android.graphics.Rect)}</code></td>
275 * <td>Called when the view gains or loses focus.
280 * <td><code>{@link #onWindowFocusChanged(boolean)}</code></td>
281 * <td>Called when the window containing the view gains or loses focus.
286 * <td rowspan="3">Attaching</td>
287 * <td><code>{@link #onAttachedToWindow()}</code></td>
288 * <td>Called when the view is attached to a window.
293 * <td><code>{@link #onDetachedFromWindow}</code></td>
294 * <td>Called when the view is detached from its window.
299 * <td><code>{@link #onWindowVisibilityChanged(int)}</code></td>
300 * <td>Called when the visibility of the window containing the view
311 * Views may have an integer id associated with them. These ids are typically
312 * assigned in the layout XML files, and are used to find specific views within
313 * the view tree. A common pattern is to:
315 * <li>Define a Button in the layout file and assign it a unique ID.
318 * android:id="@+id/my_button"
319 * android:layout_width="wrap_content"
320 * android:layout_height="wrap_content"
321 * android:text="@string/my_button_text"/>
323 * <li>From the onCreate method of an Activity, find the Button
324 * <pre class="prettyprint">
325 * Button myButton = findViewById(R.id.my_button);
329 * View IDs need not be unique throughout the tree, but it is good practice to
330 * ensure that they are at least unique within the part of the tree you are
334 * <a name="Position"></a>
337 * The geometry of a view is that of a rectangle. A view has a location,
338 * expressed as a pair of <em>left</em> and <em>top</em> coordinates, and
339 * two dimensions, expressed as a width and a height. The unit for location
340 * and dimensions is the pixel.
344 * It is possible to retrieve the location of a view by invoking the methods
345 * {@link #getLeft()} and {@link #getTop()}. The former returns the left, or X,
346 * coordinate of the rectangle representing the view. The latter returns the
347 * top, or Y, coordinate of the rectangle representing the view. These methods
348 * both return the location of the view relative to its parent. For instance,
349 * when getLeft() returns 20, that means the view is located 20 pixels to the
350 * right of the left edge of its direct parent.
354 * In addition, several convenience methods are offered to avoid unnecessary
355 * computations, namely {@link #getRight()} and {@link #getBottom()}.
356 * These methods return the coordinates of the right and bottom edges of the
357 * rectangle representing the view. For instance, calling {@link #getRight()}
358 * is similar to the following computation: <code>getLeft() + getWidth()</code>
359 * (see <a href="#SizePaddingMargins">Size</a> for more information about the width.)
362 * <a name="SizePaddingMargins"></a>
363 * <h3>Size, padding and margins</h3>
365 * The size of a view is expressed with a width and a height. A view actually
366 * possess two pairs of width and height values.
370 * The first pair is known as <em>measured width</em> and
371 * <em>measured height</em>. These dimensions define how big a view wants to be
372 * within its parent (see <a href="#Layout">Layout</a> for more details.) The
373 * measured dimensions can be obtained by calling {@link #getMeasuredWidth()}
374 * and {@link #getMeasuredHeight()}.
378 * The second pair is simply known as <em>width</em> and <em>height</em>, or
379 * sometimes <em>drawing width</em> and <em>drawing height</em>. These
380 * dimensions define the actual size of the view on screen, at drawing time and
381 * after layout. These values may, but do not have to, be different from the
382 * measured width and height. The width and height can be obtained by calling
383 * {@link #getWidth()} and {@link #getHeight()}.
387 * To measure its dimensions, a view takes into account its padding. The padding
388 * is expressed in pixels for the left, top, right and bottom parts of the view.
389 * Padding can be used to offset the content of the view by a specific amount of
390 * pixels. For instance, a left padding of 2 will push the view's content by
391 * 2 pixels to the right of the left edge. Padding can be set using the
392 * {@link #setPadding(int, int, int, int)} or {@link #setPaddingRelative(int, int, int, int)}
393 * method and queried by calling {@link #getPaddingLeft()}, {@link #getPaddingTop()},
394 * {@link #getPaddingRight()}, {@link #getPaddingBottom()}, {@link #getPaddingStart()},
395 * {@link #getPaddingEnd()}.
399 * Even though a view can define a padding, it does not provide any support for
400 * margins. However, view groups provide such a support. Refer to
401 * {@link android.view.ViewGroup} and
402 * {@link android.view.ViewGroup.MarginLayoutParams} for further information.
405 * <a name="Layout"></a>
408 * Layout is a two pass process: a measure pass and a layout pass. The measuring
409 * pass is implemented in {@link #measure(int, int)} and is a top-down traversal
410 * of the view tree. Each view pushes dimension specifications down the tree
411 * during the recursion. At the end of the measure pass, every view has stored
412 * its measurements. The second pass happens in
413 * {@link #layout(int,int,int,int)} and is also top-down. During
414 * this pass each parent is responsible for positioning all of its children
415 * using the sizes computed in the measure pass.
419 * When a view's measure() method returns, its {@link #getMeasuredWidth()} and
420 * {@link #getMeasuredHeight()} values must be set, along with those for all of
421 * that view's descendants. A view's measured width and measured height values
422 * must respect the constraints imposed by the view's parents. This guarantees
423 * that at the end of the measure pass, all parents accept all of their
424 * children's measurements. A parent view may call measure() more than once on
425 * its children. For example, the parent may measure each child once with
426 * unspecified dimensions to find out how big they want to be, then call
427 * measure() on them again with actual numbers if the sum of all the children's
428 * unconstrained sizes is too big or too small.
432 * The measure pass uses two classes to communicate dimensions. The
433 * {@link MeasureSpec} class is used by views to tell their parents how they
434 * want to be measured and positioned. The base LayoutParams class just
435 * describes how big the view wants to be for both width and height. For each
436 * dimension, it can specify one of:
438 * <li> an exact number
439 * <li>MATCH_PARENT, which means the view wants to be as big as its parent
441 * <li> WRAP_CONTENT, which means that the view wants to be just big enough to
442 * enclose its content (plus padding).
444 * There are subclasses of LayoutParams for different subclasses of ViewGroup.
445 * For example, AbsoluteLayout has its own subclass of LayoutParams which adds
450 * MeasureSpecs are used to push requirements down the tree from parent to
451 * child. A MeasureSpec can be in one of three modes:
453 * <li>UNSPECIFIED: This is used by a parent to determine the desired dimension
454 * of a child view. For example, a LinearLayout may call measure() on its child
455 * with the height set to UNSPECIFIED and a width of EXACTLY 240 to find out how
456 * tall the child view wants to be given a width of 240 pixels.
457 * <li>EXACTLY: This is used by the parent to impose an exact size on the
458 * child. The child must use this size, and guarantee that all of its
459 * descendants will fit within this size.
460 * <li>AT_MOST: This is used by the parent to impose a maximum size on the
461 * child. The child must guarantee that it and all of its descendants will fit
467 * To initiate a layout, call {@link #requestLayout}. This method is typically
468 * called by a view on itself when it believes that is can no longer fit within
469 * its current bounds.
472 * <a name="Drawing"></a>
475 * Drawing is handled by walking the tree and recording the drawing commands of
476 * any View that needs to update. After this, the drawing commands of the
477 * entire tree are issued to screen, clipped to the newly damaged area.
481 * The tree is largely recorded and drawn in order, with parents drawn before
482 * (i.e., behind) their children, with siblings drawn in the order they appear
483 * in the tree. If you set a background drawable for a View, then the View will
484 * draw it before calling back to its <code>onDraw()</code> method. The child
485 * drawing order can be overridden with
486 * {@link ViewGroup#setChildrenDrawingOrderEnabled(boolean) custom child drawing order}
487 * in a ViewGroup, and with {@link #setZ(float)} custom Z values} set on Views.
491 * To force a view to draw, call {@link #invalidate()}.
494 * <a name="EventHandlingThreading"></a>
495 * <h3>Event Handling and Threading</h3>
497 * The basic cycle of a view is as follows:
499 * <li>An event comes in and is dispatched to the appropriate view. The view
500 * handles the event and notifies any listeners.</li>
501 * <li>If in the course of processing the event, the view's bounds may need
502 * to be changed, the view will call {@link #requestLayout()}.</li>
503 * <li>Similarly, if in the course of processing the event the view's appearance
504 * may need to be changed, the view will call {@link #invalidate()}.</li>
505 * <li>If either {@link #requestLayout()} or {@link #invalidate()} were called,
506 * the framework will take care of measuring, laying out, and drawing the tree
507 * as appropriate.</li>
511 * <p><em>Note: The entire view tree is single threaded. You must always be on
512 * the UI thread when calling any method on any view.</em>
513 * If you are doing work on other threads and want to update the state of a view
514 * from that thread, you should use a {@link Handler}.
517 * <a name="FocusHandling"></a>
518 * <h3>Focus Handling</h3>
520 * The framework will handle routine focus movement in response to user input.
521 * This includes changing the focus as views are removed or hidden, or as new
522 * views become available. Views indicate their willingness to take focus
523 * through the {@link #isFocusable} method. To change whether a view can take
524 * focus, call {@link #setFocusable(boolean)}. When in touch mode (see notes below)
525 * views indicate whether they still would like focus via {@link #isFocusableInTouchMode}
526 * and can change this via {@link #setFocusableInTouchMode(boolean)}.
529 * Focus movement is based on an algorithm which finds the nearest neighbor in a
530 * given direction. In rare cases, the default algorithm may not match the
531 * intended behavior of the developer. In these situations, you can provide
532 * explicit overrides by using these XML attributes in the layout file:
543 * To get a particular view to take focus, call {@link #requestFocus()}.
546 * <a name="TouchMode"></a>
547 * <h3>Touch Mode</h3>
549 * When a user is navigating a user interface via directional keys such as a D-pad, it is
550 * necessary to give focus to actionable items such as buttons so the user can see
551 * what will take input. If the device has touch capabilities, however, and the user
552 * begins interacting with the interface by touching it, it is no longer necessary to
553 * always highlight, or give focus to, a particular view. This motivates a mode
554 * for interaction named 'touch mode'.
557 * For a touch capable device, once the user touches the screen, the device
558 * will enter touch mode. From this point onward, only views for which
559 * {@link #isFocusableInTouchMode} is true will be focusable, such as text editing widgets.
560 * Other views that are touchable, like buttons, will not take focus when touched; they will
561 * only fire the on click listeners.
564 * Any time a user hits a directional key, such as a D-pad direction, the view device will
565 * exit touch mode, and find a view to take focus, so that the user may resume interacting
566 * with the user interface without touching the screen again.
569 * The touch mode state is maintained across {@link android.app.Activity}s. Call
570 * {@link #isInTouchMode} to see whether the device is currently in touch mode.
573 * <a name="Scrolling"></a>
576 * The framework provides basic support for views that wish to internally
577 * scroll their content. This includes keeping track of the X and Y scroll
578 * offset as well as mechanisms for drawing scrollbars. See
579 * {@link #scrollBy(int, int)}, {@link #scrollTo(int, int)}, and
580 * {@link #awakenScrollBars()} for more details.
583 * <a name="Tags"></a>
586 * Unlike IDs, tags are not used to identify views. Tags are essentially an
587 * extra piece of information that can be associated with a view. They are most
588 * often used as a convenience to store data related to views in the views
589 * themselves rather than by putting them in a separate structure.
592 * Tags may be specified with character sequence values in layout XML as either
593 * a single tag using the {@link android.R.styleable#View_tag android:tag}
594 * attribute or multiple tags using the {@code <tag>} child element:
597 * android:tag="@string/mytag_value" />
599 * <tag android:id="@+id/mytag"
600 * android:value="@string/mytag_value" />
605 * Tags may also be specified with arbitrary objects from code using
606 * {@link #setTag(Object)} or {@link #setTag(int, Object)}.
609 * <a name="Themes"></a>
612 * By default, Views are created using the theme of the Context object supplied
613 * to their constructor; however, a different theme may be specified by using
614 * the {@link android.R.styleable#View_theme android:theme} attribute in layout
615 * XML or by passing a {@link ContextThemeWrapper} to the constructor from
619 * When the {@link android.R.styleable#View_theme android:theme} attribute is
620 * used in XML, the specified theme is applied on top of the inflation
621 * context's theme (see {@link LayoutInflater}) and used for the view itself as
622 * well as any child elements.
625 * In the following example, both views will be created using the Material dark
626 * color scheme; however, because an overlay theme is used which only defines a
627 * subset of attributes, the value of
628 * {@link android.R.styleable#Theme_colorAccent android:colorAccent} defined on
629 * the inflation context's theme (e.g. the Activity theme) will be preserved.
633 * android:theme="@android:theme/ThemeOverlay.Material.Dark">
635 * </LinearLayout>
639 * <a name="Properties"></a>
640 * <h3>Properties</h3>
642 * The View class exposes an {@link #ALPHA} property, as well as several transform-related
643 * properties, such as {@link #TRANSLATION_X} and {@link #TRANSLATION_Y}. These properties are
644 * available both in the {@link Property} form as well as in similarly-named setter/getter
645 * methods (such as {@link #setAlpha(float)} for {@link #ALPHA}). These properties can
646 * be used to set persistent state associated with these rendering-related properties on the view.
647 * The properties and methods can also be used in conjunction with
648 * {@link android.animation.Animator Animator}-based animations, described more in the
649 * <a href="#Animation">Animation</a> section.
652 * <a name="Animation"></a>
655 * Starting with Android 3.0, the preferred way of animating views is to use the
656 * {@link android.animation} package APIs. These {@link android.animation.Animator Animator}-based
657 * classes change actual properties of the View object, such as {@link #setAlpha(float) alpha} and
658 * {@link #setTranslationX(float) translationX}. This behavior is contrasted to that of the pre-3.0
659 * {@link android.view.animation.Animation Animation}-based classes, which instead animate only
660 * how the view is drawn on the display. In particular, the {@link ViewPropertyAnimator} class
661 * makes animating these View properties particularly easy and efficient.
664 * Alternatively, you can use the pre-3.0 animation classes to animate how Views are rendered.
665 * You can attach an {@link Animation} object to a view using
666 * {@link #setAnimation(Animation)} or
667 * {@link #startAnimation(Animation)}. The animation can alter the scale,
668 * rotation, translation and alpha of a view over time. If the animation is
669 * attached to a view that has children, the animation will affect the entire
670 * subtree rooted by that node. When an animation is started, the framework will
671 * take care of redrawing the appropriate views until the animation completes.
674 * <a name="Security"></a>
677 * Sometimes it is essential that an application be able to verify that an action
678 * is being performed with the full knowledge and consent of the user, such as
679 * granting a permission request, making a purchase or clicking on an advertisement.
680 * Unfortunately, a malicious application could try to spoof the user into
681 * performing these actions, unaware, by concealing the intended purpose of the view.
682 * As a remedy, the framework offers a touch filtering mechanism that can be used to
683 * improve the security of views that provide access to sensitive functionality.
685 * To enable touch filtering, call {@link #setFilterTouchesWhenObscured(boolean)} or set the
686 * android:filterTouchesWhenObscured layout attribute to true. When enabled, the framework
687 * will discard touches that are received whenever the view's window is obscured by
688 * another visible window. As a result, the view will not receive touches whenever a
689 * toast, dialog or other window appears above the view's window.
691 * For more fine-grained control over security, consider overriding the
692 * {@link #onFilterTouchEventForSecurity(MotionEvent)} method to implement your own
693 * security policy. See also {@link MotionEvent#FLAG_WINDOW_IS_OBSCURED}.
696 * @attr ref android.R.styleable#View_alpha
697 * @attr ref android.R.styleable#View_background
698 * @attr ref android.R.styleable#View_clickable
699 * @attr ref android.R.styleable#View_contentDescription
700 * @attr ref android.R.styleable#View_drawingCacheQuality
701 * @attr ref android.R.styleable#View_duplicateParentState
702 * @attr ref android.R.styleable#View_id
703 * @attr ref android.R.styleable#View_requiresFadingEdge
704 * @attr ref android.R.styleable#View_fadeScrollbars
705 * @attr ref android.R.styleable#View_fadingEdgeLength
706 * @attr ref android.R.styleable#View_filterTouchesWhenObscured
707 * @attr ref android.R.styleable#View_fitsSystemWindows
708 * @attr ref android.R.styleable#View_isScrollContainer
709 * @attr ref android.R.styleable#View_focusable
710 * @attr ref android.R.styleable#View_focusableInTouchMode
711 * @attr ref android.R.styleable#View_focusedByDefault
712 * @attr ref android.R.styleable#View_hapticFeedbackEnabled
713 * @attr ref android.R.styleable#View_keepScreenOn
714 * @attr ref android.R.styleable#View_keyboardNavigationCluster
715 * @attr ref android.R.styleable#View_layerType
716 * @attr ref android.R.styleable#View_layoutDirection
717 * @attr ref android.R.styleable#View_longClickable
718 * @attr ref android.R.styleable#View_minHeight
719 * @attr ref android.R.styleable#View_minWidth
720 * @attr ref android.R.styleable#View_nextClusterForward
721 * @attr ref android.R.styleable#View_nextFocusDown
722 * @attr ref android.R.styleable#View_nextFocusLeft
723 * @attr ref android.R.styleable#View_nextFocusRight
724 * @attr ref android.R.styleable#View_nextFocusUp
725 * @attr ref android.R.styleable#View_onClick
726 * @attr ref android.R.styleable#View_padding
727 * @attr ref android.R.styleable#View_paddingBottom
728 * @attr ref android.R.styleable#View_paddingLeft
729 * @attr ref android.R.styleable#View_paddingRight
730 * @attr ref android.R.styleable#View_paddingTop
731 * @attr ref android.R.styleable#View_paddingStart
732 * @attr ref android.R.styleable#View_paddingEnd
733 * @attr ref android.R.styleable#View_saveEnabled
734 * @attr ref android.R.styleable#View_rotation
735 * @attr ref android.R.styleable#View_rotationX
736 * @attr ref android.R.styleable#View_rotationY
737 * @attr ref android.R.styleable#View_scaleX
738 * @attr ref android.R.styleable#View_scaleY
739 * @attr ref android.R.styleable#View_scrollX
740 * @attr ref android.R.styleable#View_scrollY
741 * @attr ref android.R.styleable#View_scrollbarSize
742 * @attr ref android.R.styleable#View_scrollbarStyle
743 * @attr ref android.R.styleable#View_scrollbars
744 * @attr ref android.R.styleable#View_scrollbarDefaultDelayBeforeFade
745 * @attr ref android.R.styleable#View_scrollbarFadeDuration
746 * @attr ref android.R.styleable#View_scrollbarTrackHorizontal
747 * @attr ref android.R.styleable#View_scrollbarThumbHorizontal
748 * @attr ref android.R.styleable#View_scrollbarThumbVertical
749 * @attr ref android.R.styleable#View_scrollbarTrackVertical
750 * @attr ref android.R.styleable#View_scrollbarAlwaysDrawHorizontalTrack
751 * @attr ref android.R.styleable#View_scrollbarAlwaysDrawVerticalTrack
752 * @attr ref android.R.styleable#View_stateListAnimator
753 * @attr ref android.R.styleable#View_transitionName
754 * @attr ref android.R.styleable#View_soundEffectsEnabled
755 * @attr ref android.R.styleable#View_tag
756 * @attr ref android.R.styleable#View_textAlignment
757 * @attr ref android.R.styleable#View_textDirection
758 * @attr ref android.R.styleable#View_transformPivotX
759 * @attr ref android.R.styleable#View_transformPivotY
760 * @attr ref android.R.styleable#View_translationX
761 * @attr ref android.R.styleable#View_translationY
762 * @attr ref android.R.styleable#View_translationZ
763 * @attr ref android.R.styleable#View_visibility
764 * @attr ref android.R.styleable#View_theme
766 * @see android.view.ViewGroup
769 public class View implements Drawable.Callback, KeyEvent.Callback,
770 AccessibilityEventSource {
771 private static final boolean DBG = false;
774 public static boolean DEBUG_DRAW = false;
777 * The logging tag used by this class with android.util.Log.
779 protected static final String VIEW_LOG_TAG = "View";
782 * When set to true, apps will draw debugging information about their layouts.
786 public static final String DEBUG_LAYOUT_PROPERTY = "debug.layout";
789 * When set to true, this view will save its attribute data.
793 public static boolean mDebugViewAttributes = false;
796 * Used to mark a View that has no ID.
798 public static final int NO_ID = -1;
801 * Last ID that is given to Views that are no part of activities.
805 public static final int LAST_APP_ACCESSIBILITY_ID = Integer.MAX_VALUE / 2;
808 * Attribute to find the autofilled highlight
810 * @see #getAutofilledDrawable()
812 private static final int[] AUTOFILL_HIGHLIGHT_ATTR =
813 new int[]{android.R.attr.autofilledHighlight};
816 * Signals that compatibility booleans have been initialized according to
817 * target SDK versions.
819 private static boolean sCompatibilityDone = false;
822 * Use the old (broken) way of building MeasureSpecs.
824 private static boolean sUseBrokenMakeMeasureSpec = false;
827 * Always return a size of 0 for MeasureSpec values with a mode of UNSPECIFIED
829 static boolean sUseZeroUnspecifiedMeasureSpec = false;
832 * Ignore any optimizations using the measure cache.
834 private static boolean sIgnoreMeasureCache = false;
837 * Ignore an optimization that skips unnecessary EXACTLY layout passes.
839 private static boolean sAlwaysRemeasureExactly = false;
842 * Relax constraints around whether setLayoutParams() must be called after
843 * modifying the layout params.
845 private static boolean sLayoutParamsAlwaysChanged = false;
848 * Allow setForeground/setBackground to be called (and ignored) on a textureview,
851 static boolean sTextureViewIgnoresDrawableSetters = false;
854 * Prior to N, some ViewGroups would not convert LayoutParams properly even though both extend
855 * MarginLayoutParams. For instance, converting LinearLayout.LayoutParams to
856 * RelativeLayout.LayoutParams would lose margin information. This is fixed on N but target API
857 * check is implemented for backwards compatibility.
861 protected static boolean sPreserveMarginParamsInLayoutParamConversion;
864 * Prior to N, when drag enters into child of a view that has already received an
865 * ACTION_DRAG_ENTERED event, the parent doesn't get a ACTION_DRAG_EXITED event.
866 * ACTION_DRAG_LOCATION and ACTION_DROP were delivered to the parent of a view that returned
867 * false from its event handler for these events.
868 * Starting from N, the parent will get ACTION_DRAG_EXITED event before the child gets its
869 * ACTION_DRAG_ENTERED. ACTION_DRAG_LOCATION and ACTION_DROP are never propagated to the parent.
870 * sCascadedDragDrop is true for pre-N apps for backwards compatibility implementation.
872 static boolean sCascadedDragDrop;
875 * Prior to O, auto-focusable didn't exist and widgets such as ListView use hasFocusable
876 * to determine things like whether or not to permit item click events. We can't break
877 * apps that do this just because more things (clickable things) are now auto-focusable
878 * and they would get different results, so give old behavior to old apps.
880 static boolean sHasFocusableExcludeAutoFocusable;
883 * Prior to O, auto-focusable didn't exist and views marked as clickable weren't implicitly
884 * made focusable by default. As a result, apps could (incorrectly) change the clickable
885 * setting of views off the UI thread. Now that clickable can effect the focusable state,
886 * changing the clickable attribute off the UI thread will cause an exception (since changing
887 * the focusable state checks). In order to prevent apps from crashing, we will handle this
888 * specific case and just not notify parents on new focusables resulting from marking views
889 * clickable from outside the UI thread.
891 private static boolean sAutoFocusableOffUIThreadWontNotifyParents;
894 @IntDef({NOT_FOCUSABLE, FOCUSABLE, FOCUSABLE_AUTO})
895 @Retention(RetentionPolicy.SOURCE)
896 public @interface Focusable {}
899 * This view does not want keystrokes.
901 * Use with {@link #setFocusable(int)} and <a href="#attr_android:focusable">{@code
902 * android:focusable}.
904 public static final int NOT_FOCUSABLE = 0x00000000;
907 * This view wants keystrokes.
909 * Use with {@link #setFocusable(int)} and <a href="#attr_android:focusable">{@code
910 * android:focusable}.
912 public static final int FOCUSABLE = 0x00000001;
915 * This view determines focusability automatically. This is the default.
917 * Use with {@link #setFocusable(int)} and <a href="#attr_android:focusable">{@code
918 * android:focusable}.
920 public static final int FOCUSABLE_AUTO = 0x00000010;
923 * Mask for use with setFlags indicating bits used for focus.
925 private static final int FOCUSABLE_MASK = 0x00000011;
928 * This view will adjust its padding to fit sytem windows (e.g. status bar)
930 private static final int FITS_SYSTEM_WINDOWS = 0x00000002;
933 @IntDef({VISIBLE, INVISIBLE, GONE})
934 @Retention(RetentionPolicy.SOURCE)
935 public @interface Visibility {}
938 * This view is visible.
939 * Use with {@link #setVisibility} and <a href="#attr_android:visibility">{@code
940 * android:visibility}.
942 public static final int VISIBLE = 0x00000000;
945 * This view is invisible, but it still takes up space for layout purposes.
946 * Use with {@link #setVisibility} and <a href="#attr_android:visibility">{@code
947 * android:visibility}.
949 public static final int INVISIBLE = 0x00000004;
952 * This view is invisible, and it doesn't take any space for layout
953 * purposes. Use with {@link #setVisibility} and <a href="#attr_android:visibility">{@code
954 * android:visibility}.
956 public static final int GONE = 0x00000008;
959 * Mask for use with setFlags indicating bits used for visibility.
962 static final int VISIBILITY_MASK = 0x0000000C;
964 private static final int[] VISIBILITY_FLAGS = {VISIBLE, INVISIBLE, GONE};
967 * Hint indicating that this view can be autofilled with an email address.
969 * <p>Can be used with either {@link #setAutofillHints(String[])} or
970 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the
971 * value should be <code>{@value #AUTOFILL_HINT_EMAIL_ADDRESS}</code>).
973 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints.
975 public static final String AUTOFILL_HINT_EMAIL_ADDRESS = "emailAddress";
978 * Hint indicating that this view can be autofilled with a user's real name.
980 * <p>Can be used with either {@link #setAutofillHints(String[])} or
981 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the
982 * value should be <code>{@value #AUTOFILL_HINT_NAME}</code>).
984 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints.
986 public static final String AUTOFILL_HINT_NAME = "name";
989 * Hint indicating that this view can be autofilled with a username.
991 * <p>Can be used with either {@link #setAutofillHints(String[])} or
992 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the
993 * value should be <code>{@value #AUTOFILL_HINT_USERNAME}</code>).
995 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints.
997 public static final String AUTOFILL_HINT_USERNAME = "username";
1000 * Hint indicating that this view can be autofilled with a password.
1002 * <p>Can be used with either {@link #setAutofillHints(String[])} or
1003 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the
1004 * value should be <code>{@value #AUTOFILL_HINT_PASSWORD}</code>).
1006 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints.
1008 public static final String AUTOFILL_HINT_PASSWORD = "password";
1011 * Hint indicating that this view can be autofilled with a phone number.
1013 * <p>Can be used with either {@link #setAutofillHints(String[])} or
1014 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the
1015 * value should be <code>{@value #AUTOFILL_HINT_PHONE}</code>).
1017 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints.
1019 public static final String AUTOFILL_HINT_PHONE = "phone";
1022 * Hint indicating that this view can be autofilled with a postal address.
1024 * <p>Can be used with either {@link #setAutofillHints(String[])} or
1025 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the
1026 * value should be <code>{@value #AUTOFILL_HINT_POSTAL_ADDRESS}</code>).
1028 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints.
1030 public static final String AUTOFILL_HINT_POSTAL_ADDRESS = "postalAddress";
1033 * Hint indicating that this view can be autofilled with a postal code.
1035 * <p>Can be used with either {@link #setAutofillHints(String[])} or
1036 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the
1037 * value should be <code>{@value #AUTOFILL_HINT_POSTAL_CODE}</code>).
1039 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints.
1041 public static final String AUTOFILL_HINT_POSTAL_CODE = "postalCode";
1044 * Hint indicating that this view can be autofilled with a credit card number.
1046 * <p>Can be used with either {@link #setAutofillHints(String[])} or
1047 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the
1048 * value should be <code>{@value #AUTOFILL_HINT_CREDIT_CARD_NUMBER}</code>).
1050 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints.
1052 public static final String AUTOFILL_HINT_CREDIT_CARD_NUMBER = "creditCardNumber";
1055 * Hint indicating that this view can be autofilled with a credit card security code.
1057 * <p>Can be used with either {@link #setAutofillHints(String[])} or
1058 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the
1059 * value should be <code>{@value #AUTOFILL_HINT_CREDIT_CARD_SECURITY_CODE}</code>).
1061 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints.
1063 public static final String AUTOFILL_HINT_CREDIT_CARD_SECURITY_CODE = "creditCardSecurityCode";
1066 * Hint indicating that this view can be autofilled with a credit card expiration date.
1068 * <p>It should be used when the credit card expiration date is represented by just one view;
1069 * if it is represented by more than one (for example, one view for the month and another view
1070 * for the year), then each of these views should use the hint specific for the unit
1071 * ({@link #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DAY},
1072 * {@link #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_MONTH},
1073 * or {@link #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_YEAR}).
1075 * <p>Can be used with either {@link #setAutofillHints(String[])} or
1076 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the
1077 * value should be <code>{@value #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DATE}</code>).
1079 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints.
1081 public static final String AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DATE =
1082 "creditCardExpirationDate";
1085 * Hint indicating that this view can be autofilled with a credit card expiration month.
1087 * <p>Can be used with either {@link #setAutofillHints(String[])} or
1088 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the
1089 * value should be <code>{@value #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_MONTH}</code>).
1091 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints.
1093 public static final String AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_MONTH =
1094 "creditCardExpirationMonth";
1097 * Hint indicating that this view can be autofilled with a credit card expiration year.
1099 * <p>Can be used with either {@link #setAutofillHints(String[])} or
1100 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the
1101 * value should be <code>{@value #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_YEAR}</code>).
1103 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints.
1105 public static final String AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_YEAR =
1106 "creditCardExpirationYear";
1109 * Hint indicating that this view can be autofilled with a credit card expiration day.
1111 * <p>Can be used with either {@link #setAutofillHints(String[])} or
1112 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the
1113 * value should be <code>{@value #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DAY}</code>).
1115 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints.
1117 public static final String AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DAY = "creditCardExpirationDay";
1120 * Hints for the autofill services that describes the content of the view.
1122 private @Nullable String[] mAutofillHints;
1125 * Autofill id, lazily created on calls to {@link #getAutofillId()}.
1127 private AutofillId mAutofillId;
1133 AUTOFILL_TYPE_TOGGLE,
1137 @Retention(RetentionPolicy.SOURCE)
1138 public @interface AutofillType {}
1141 * Autofill type for views that cannot be autofilled.
1143 public static final int AUTOFILL_TYPE_NONE = 0;
1146 * Autofill type for a text field, which is filled by a {@link CharSequence}.
1148 * <p>{@link AutofillValue} instances for autofilling a {@link View} can be obtained through
1149 * {@link AutofillValue#forText(CharSequence)}, and the value passed to autofill a
1150 * {@link View} can be fetched through {@link AutofillValue#getTextValue()}.
1152 public static final int AUTOFILL_TYPE_TEXT = 1;
1155 * Autofill type for a togglable field, which is filled by a {@code boolean}.
1157 * <p>{@link AutofillValue} instances for autofilling a {@link View} can be obtained through
1158 * {@link AutofillValue#forToggle(boolean)}, and the value passed to autofill a
1159 * {@link View} can be fetched through {@link AutofillValue#getToggleValue()}.
1161 public static final int AUTOFILL_TYPE_TOGGLE = 2;
1164 * Autofill type for a selection list field, which is filled by an {@code int}
1165 * representing the element index inside the list (starting at {@code 0}).
1167 * <p>{@link AutofillValue} instances for autofilling a {@link View} can be obtained through
1168 * {@link AutofillValue#forList(int)}, and the value passed to autofill a
1169 * {@link View} can be fetched through {@link AutofillValue#getListValue()}.
1171 * <p>The available options in the selection list are typically provided by
1172 * {@link android.app.assist.AssistStructure.ViewNode#getAutofillOptions()}.
1174 public static final int AUTOFILL_TYPE_LIST = 3;
1178 * Autofill type for a field that contains a date, which is represented by a long representing
1179 * the number of milliseconds since the standard base time known as "the epoch", namely
1180 * January 1, 1970, 00:00:00 GMT (see {@link java.util.Date#getTime()}.
1182 * <p>{@link AutofillValue} instances for autofilling a {@link View} can be obtained through
1183 * {@link AutofillValue#forDate(long)}, and the values passed to
1184 * autofill a {@link View} can be fetched through {@link AutofillValue#getDateValue()}.
1186 public static final int AUTOFILL_TYPE_DATE = 4;
1190 IMPORTANT_FOR_AUTOFILL_AUTO,
1191 IMPORTANT_FOR_AUTOFILL_YES,
1192 IMPORTANT_FOR_AUTOFILL_NO,
1193 IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS,
1194 IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS
1196 @Retention(RetentionPolicy.SOURCE)
1197 public @interface AutofillImportance {}
1200 * Automatically determine whether a view is important for autofill.
1202 public static final int IMPORTANT_FOR_AUTOFILL_AUTO = 0x0;
1205 * The view is important for autofill, and its children (if any) will be traversed.
1207 public static final int IMPORTANT_FOR_AUTOFILL_YES = 0x1;
1210 * The view is not important for autofill, but its children (if any) will be traversed.
1212 public static final int IMPORTANT_FOR_AUTOFILL_NO = 0x2;
1215 * The view is important for autofill, but its children (if any) will not be traversed.
1217 public static final int IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS = 0x4;
1220 * The view is not important for autofill, and its children (if any) will not be traversed.
1222 public static final int IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS = 0x8;
1227 value = {AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS})
1228 @Retention(RetentionPolicy.SOURCE)
1229 public @interface AutofillFlags {}
1232 * Flag requesting you to add views that are marked as not important for autofill
1233 * (see {@link #setImportantForAutofill(int)}) to a {@link ViewStructure}.
1235 public static final int AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS = 0x1;
1238 * This view is enabled. Interpretation varies by subclass.
1239 * Use with ENABLED_MASK when calling setFlags.
1242 static final int ENABLED = 0x00000000;
1245 * This view is disabled. Interpretation varies by subclass.
1246 * Use with ENABLED_MASK when calling setFlags.
1249 static final int DISABLED = 0x00000020;
1252 * Mask for use with setFlags indicating bits used for indicating whether
1253 * this view is enabled
1256 static final int ENABLED_MASK = 0x00000020;
1259 * This view won't draw. {@link #onDraw(android.graphics.Canvas)} won't be
1260 * called and further optimizations will be performed. It is okay to have
1261 * this flag set and a background. Use with DRAW_MASK when calling setFlags.
1264 static final int WILL_NOT_DRAW = 0x00000080;
1267 * Mask for use with setFlags indicating bits used for indicating whether
1268 * this view is will draw
1271 static final int DRAW_MASK = 0x00000080;
1274 * <p>This view doesn't show scrollbars.</p>
1277 static final int SCROLLBARS_NONE = 0x00000000;
1280 * <p>This view shows horizontal scrollbars.</p>
1283 static final int SCROLLBARS_HORIZONTAL = 0x00000100;
1286 * <p>This view shows vertical scrollbars.</p>
1289 static final int SCROLLBARS_VERTICAL = 0x00000200;
1292 * <p>Mask for use with setFlags indicating bits used for indicating which
1293 * scrollbars are enabled.</p>
1296 static final int SCROLLBARS_MASK = 0x00000300;
1299 * Indicates that the view should filter touches when its window is obscured.
1300 * Refer to the class comments for more information about this security feature.
1303 static final int FILTER_TOUCHES_WHEN_OBSCURED = 0x00000400;
1306 * Set for framework elements that use FITS_SYSTEM_WINDOWS, to indicate
1307 * that they are optional and should be skipped if the window has
1308 * requested system UI flags that ignore those insets for layout.
1310 static final int OPTIONAL_FITS_SYSTEM_WINDOWS = 0x00000800;
1313 * <p>This view doesn't show fading edges.</p>
1316 static final int FADING_EDGE_NONE = 0x00000000;
1319 * <p>This view shows horizontal fading edges.</p>
1322 static final int FADING_EDGE_HORIZONTAL = 0x00001000;
1325 * <p>This view shows vertical fading edges.</p>
1328 static final int FADING_EDGE_VERTICAL = 0x00002000;
1331 * <p>Mask for use with setFlags indicating bits used for indicating which
1332 * fading edges are enabled.</p>
1335 static final int FADING_EDGE_MASK = 0x00003000;
1338 * <p>Indicates this view can be clicked. When clickable, a View reacts
1339 * to clicks by notifying the OnClickListener.<p>
1342 static final int CLICKABLE = 0x00004000;
1345 * <p>Indicates this view is caching its drawing into a bitmap.</p>
1348 static final int DRAWING_CACHE_ENABLED = 0x00008000;
1351 * <p>Indicates that no icicle should be saved for this view.<p>
1354 static final int SAVE_DISABLED = 0x000010000;
1357 * <p>Mask for use with setFlags indicating bits used for the saveEnabled
1361 static final int SAVE_DISABLED_MASK = 0x000010000;
1364 * <p>Indicates that no drawing cache should ever be created for this view.<p>
1367 static final int WILL_NOT_CACHE_DRAWING = 0x000020000;
1370 * <p>Indicates this view can take / keep focus when int touch mode.</p>
1373 static final int FOCUSABLE_IN_TOUCH_MODE = 0x00040000;
1376 @Retention(RetentionPolicy.SOURCE)
1377 @IntDef({DRAWING_CACHE_QUALITY_LOW, DRAWING_CACHE_QUALITY_HIGH, DRAWING_CACHE_QUALITY_AUTO})
1378 public @interface DrawingCacheQuality {}
1381 * <p>Enables low quality mode for the drawing cache.</p>
1383 public static final int DRAWING_CACHE_QUALITY_LOW = 0x00080000;
1386 * <p>Enables high quality mode for the drawing cache.</p>
1388 public static final int DRAWING_CACHE_QUALITY_HIGH = 0x00100000;
1391 * <p>Enables automatic quality mode for the drawing cache.</p>
1393 public static final int DRAWING_CACHE_QUALITY_AUTO = 0x00000000;
1395 private static final int[] DRAWING_CACHE_QUALITY_FLAGS = {
1396 DRAWING_CACHE_QUALITY_AUTO, DRAWING_CACHE_QUALITY_LOW, DRAWING_CACHE_QUALITY_HIGH
1400 * <p>Mask for use with setFlags indicating bits used for the cache
1401 * quality property.</p>
1404 static final int DRAWING_CACHE_QUALITY_MASK = 0x00180000;
1408 * Indicates this view can be long clicked. When long clickable, a View
1409 * reacts to long clicks by notifying the OnLongClickListener or showing a
1414 static final int LONG_CLICKABLE = 0x00200000;
1417 * <p>Indicates that this view gets its drawable states from its direct parent
1418 * and ignores its original internal states.</p>
1422 static final int DUPLICATE_PARENT_STATE = 0x00400000;
1426 * Indicates this view can be context clicked. When context clickable, a View reacts to a
1427 * context click (e.g. a primary stylus button press or right mouse click) by notifying the
1428 * OnContextClickListener.
1432 static final int CONTEXT_CLICKABLE = 0x00800000;
1437 SCROLLBARS_INSIDE_OVERLAY,
1438 SCROLLBARS_INSIDE_INSET,
1439 SCROLLBARS_OUTSIDE_OVERLAY,
1440 SCROLLBARS_OUTSIDE_INSET
1442 @Retention(RetentionPolicy.SOURCE)
1443 public @interface ScrollBarStyle {}
1446 * The scrollbar style to display the scrollbars inside the content area,
1447 * without increasing the padding. The scrollbars will be overlaid with
1448 * translucency on the view's content.
1450 public static final int SCROLLBARS_INSIDE_OVERLAY = 0;
1453 * The scrollbar style to display the scrollbars inside the padded area,
1454 * increasing the padding of the view. The scrollbars will not overlap the
1455 * content area of the view.
1457 public static final int SCROLLBARS_INSIDE_INSET = 0x01000000;
1460 * The scrollbar style to display the scrollbars at the edge of the view,
1461 * without increasing the padding. The scrollbars will be overlaid with
1464 public static final int SCROLLBARS_OUTSIDE_OVERLAY = 0x02000000;
1467 * The scrollbar style to display the scrollbars at the edge of the view,
1468 * increasing the padding of the view. The scrollbars will only overlap the
1469 * background, if any.
1471 public static final int SCROLLBARS_OUTSIDE_INSET = 0x03000000;
1474 * Mask to check if the scrollbar style is overlay or inset.
1477 static final int SCROLLBARS_INSET_MASK = 0x01000000;
1480 * Mask to check if the scrollbar style is inside or outside.
1483 static final int SCROLLBARS_OUTSIDE_MASK = 0x02000000;
1486 * Mask for scrollbar style.
1489 static final int SCROLLBARS_STYLE_MASK = 0x03000000;
1492 * View flag indicating that the screen should remain on while the
1493 * window containing this view is visible to the user. This effectively
1494 * takes care of automatically setting the WindowManager's
1495 * {@link WindowManager.LayoutParams#FLAG_KEEP_SCREEN_ON}.
1497 public static final int KEEP_SCREEN_ON = 0x04000000;
1500 * View flag indicating whether this view should have sound effects enabled
1501 * for events such as clicking and touching.
1503 public static final int SOUND_EFFECTS_ENABLED = 0x08000000;
1506 * View flag indicating whether this view should have haptic feedback
1507 * enabled for events such as long presses.
1509 public static final int HAPTIC_FEEDBACK_ENABLED = 0x10000000;
1512 * <p>Indicates that the view hierarchy should stop saving state when
1513 * it reaches this view. If state saving is initiated immediately at
1514 * the view, it will be allowed.
1517 static final int PARENT_SAVE_DISABLED = 0x20000000;
1520 * <p>Mask for use with setFlags indicating bits used for PARENT_SAVE_DISABLED.</p>
1523 static final int PARENT_SAVE_DISABLED_MASK = 0x20000000;
1525 private static Paint sDebugPaint;
1528 * <p>Indicates this view can display a tooltip on hover or long press.</p>
1531 static final int TOOLTIP = 0x40000000;
1534 @IntDef(flag = true,
1537 FOCUSABLES_TOUCH_MODE
1539 @Retention(RetentionPolicy.SOURCE)
1540 public @interface FocusableMode {}
1543 * View flag indicating whether {@link #addFocusables(ArrayList, int, int)}
1544 * should add all focusable Views regardless if they are focusable in touch mode.
1546 public static final int FOCUSABLES_ALL = 0x00000000;
1549 * View flag indicating whether {@link #addFocusables(ArrayList, int, int)}
1550 * should add only Views focusable in touch mode.
1552 public static final int FOCUSABLES_TOUCH_MODE = 0x00000001;
1563 @Retention(RetentionPolicy.SOURCE)
1564 public @interface FocusDirection {}
1573 @Retention(RetentionPolicy.SOURCE)
1574 public @interface FocusRealDirection {} // Like @FocusDirection, but without forward/backward
1577 * Use with {@link #focusSearch(int)}. Move focus to the previous selectable
1580 public static final int FOCUS_BACKWARD = 0x00000001;
1583 * Use with {@link #focusSearch(int)}. Move focus to the next selectable
1586 public static final int FOCUS_FORWARD = 0x00000002;
1589 * Use with {@link #focusSearch(int)}. Move focus to the left.
1591 public static final int FOCUS_LEFT = 0x00000011;
1594 * Use with {@link #focusSearch(int)}. Move focus up.
1596 public static final int FOCUS_UP = 0x00000021;
1599 * Use with {@link #focusSearch(int)}. Move focus to the right.
1601 public static final int FOCUS_RIGHT = 0x00000042;
1604 * Use with {@link #focusSearch(int)}. Move focus down.
1606 public static final int FOCUS_DOWN = 0x00000082;
1609 * Bits of {@link #getMeasuredWidthAndState()} and
1610 * {@link #getMeasuredWidthAndState()} that provide the actual measured size.
1612 public static final int MEASURED_SIZE_MASK = 0x00ffffff;
1615 * Bits of {@link #getMeasuredWidthAndState()} and
1616 * {@link #getMeasuredWidthAndState()} that provide the additional state bits.
1618 public static final int MEASURED_STATE_MASK = 0xff000000;
1621 * Bit shift of {@link #MEASURED_STATE_MASK} to get to the height bits
1622 * for functions that combine both width and height into a single int,
1623 * such as {@link #getMeasuredState()} and the childState argument of
1624 * {@link #resolveSizeAndState(int, int, int)}.
1626 public static final int MEASURED_HEIGHT_STATE_SHIFT = 16;
1629 * Bit of {@link #getMeasuredWidthAndState()} and
1630 * {@link #getMeasuredWidthAndState()} that indicates the measured size
1631 * is smaller that the space the view would like to have.
1633 public static final int MEASURED_STATE_TOO_SMALL = 0x01000000;
1636 * Base View state sets
1640 * Indicates the view has no states set. States are used with
1641 * {@link android.graphics.drawable.Drawable} to change the drawing of the
1642 * view depending on its state.
1644 * @see android.graphics.drawable.Drawable
1645 * @see #getDrawableState()
1647 protected static final int[] EMPTY_STATE_SET;
1649 * Indicates the view is enabled. States are used with
1650 * {@link android.graphics.drawable.Drawable} to change the drawing of the
1651 * view depending on its state.
1653 * @see android.graphics.drawable.Drawable
1654 * @see #getDrawableState()
1656 protected static final int[] ENABLED_STATE_SET;
1658 * Indicates the view is focused. States are used with
1659 * {@link android.graphics.drawable.Drawable} to change the drawing of the
1660 * view depending on its state.
1662 * @see android.graphics.drawable.Drawable
1663 * @see #getDrawableState()
1665 protected static final int[] FOCUSED_STATE_SET;
1667 * Indicates the view is selected. States are used with
1668 * {@link android.graphics.drawable.Drawable} to change the drawing of the
1669 * view depending on its state.
1671 * @see android.graphics.drawable.Drawable
1672 * @see #getDrawableState()
1674 protected static final int[] SELECTED_STATE_SET;
1676 * Indicates the view is pressed. States are used with
1677 * {@link android.graphics.drawable.Drawable} to change the drawing of the
1678 * view depending on its state.
1680 * @see android.graphics.drawable.Drawable
1681 * @see #getDrawableState()
1683 protected static final int[] PRESSED_STATE_SET;
1685 * Indicates the view's window has focus. States are used with
1686 * {@link android.graphics.drawable.Drawable} to change the drawing of the
1687 * view depending on its state.
1689 * @see android.graphics.drawable.Drawable
1690 * @see #getDrawableState()
1692 protected static final int[] WINDOW_FOCUSED_STATE_SET;
1695 * Indicates the view is enabled and has the focus.
1697 * @see #ENABLED_STATE_SET
1698 * @see #FOCUSED_STATE_SET
1700 protected static final int[] ENABLED_FOCUSED_STATE_SET;
1702 * Indicates the view is enabled and selected.
1704 * @see #ENABLED_STATE_SET
1705 * @see #SELECTED_STATE_SET
1707 protected static final int[] ENABLED_SELECTED_STATE_SET;
1709 * Indicates the view is enabled and that its window has focus.
1711 * @see #ENABLED_STATE_SET
1712 * @see #WINDOW_FOCUSED_STATE_SET
1714 protected static final int[] ENABLED_WINDOW_FOCUSED_STATE_SET;
1716 * Indicates the view is focused and selected.
1718 * @see #FOCUSED_STATE_SET
1719 * @see #SELECTED_STATE_SET
1721 protected static final int[] FOCUSED_SELECTED_STATE_SET;
1723 * Indicates the view has the focus and that its window has the focus.
1725 * @see #FOCUSED_STATE_SET
1726 * @see #WINDOW_FOCUSED_STATE_SET
1728 protected static final int[] FOCUSED_WINDOW_FOCUSED_STATE_SET;
1730 * Indicates the view is selected and that its window has the focus.
1732 * @see #SELECTED_STATE_SET
1733 * @see #WINDOW_FOCUSED_STATE_SET
1735 protected static final int[] SELECTED_WINDOW_FOCUSED_STATE_SET;
1738 * Indicates the view is enabled, focused and selected.
1740 * @see #ENABLED_STATE_SET
1741 * @see #FOCUSED_STATE_SET
1742 * @see #SELECTED_STATE_SET
1744 protected static final int[] ENABLED_FOCUSED_SELECTED_STATE_SET;
1746 * Indicates the view is enabled, focused and its window has the focus.
1748 * @see #ENABLED_STATE_SET
1749 * @see #FOCUSED_STATE_SET
1750 * @see #WINDOW_FOCUSED_STATE_SET
1752 protected static final int[] ENABLED_FOCUSED_WINDOW_FOCUSED_STATE_SET;
1754 * Indicates the view is enabled, selected and its window has the focus.
1756 * @see #ENABLED_STATE_SET
1757 * @see #SELECTED_STATE_SET
1758 * @see #WINDOW_FOCUSED_STATE_SET
1760 protected static final int[] ENABLED_SELECTED_WINDOW_FOCUSED_STATE_SET;
1762 * Indicates the view is focused, selected and its window has the focus.
1764 * @see #FOCUSED_STATE_SET
1765 * @see #SELECTED_STATE_SET
1766 * @see #WINDOW_FOCUSED_STATE_SET
1768 protected static final int[] FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET;
1770 * Indicates the view is enabled, focused, selected and its window
1773 * @see #ENABLED_STATE_SET
1774 * @see #FOCUSED_STATE_SET
1775 * @see #SELECTED_STATE_SET
1776 * @see #WINDOW_FOCUSED_STATE_SET
1778 protected static final int[] ENABLED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET;
1780 * Indicates the view is pressed and its window has the focus.
1782 * @see #PRESSED_STATE_SET
1783 * @see #WINDOW_FOCUSED_STATE_SET
1785 protected static final int[] PRESSED_WINDOW_FOCUSED_STATE_SET;
1787 * Indicates the view is pressed and selected.
1789 * @see #PRESSED_STATE_SET
1790 * @see #SELECTED_STATE_SET
1792 protected static final int[] PRESSED_SELECTED_STATE_SET;
1794 * Indicates the view is pressed, selected and its window has the focus.
1796 * @see #PRESSED_STATE_SET
1797 * @see #SELECTED_STATE_SET
1798 * @see #WINDOW_FOCUSED_STATE_SET
1800 protected static final int[] PRESSED_SELECTED_WINDOW_FOCUSED_STATE_SET;
1802 * Indicates the view is pressed and focused.
1804 * @see #PRESSED_STATE_SET
1805 * @see #FOCUSED_STATE_SET
1807 protected static final int[] PRESSED_FOCUSED_STATE_SET;
1809 * Indicates the view is pressed, focused and its window has the focus.
1811 * @see #PRESSED_STATE_SET
1812 * @see #FOCUSED_STATE_SET
1813 * @see #WINDOW_FOCUSED_STATE_SET
1815 protected static final int[] PRESSED_FOCUSED_WINDOW_FOCUSED_STATE_SET;
1817 * Indicates the view is pressed, focused and selected.
1819 * @see #PRESSED_STATE_SET
1820 * @see #SELECTED_STATE_SET
1821 * @see #FOCUSED_STATE_SET
1823 protected static final int[] PRESSED_FOCUSED_SELECTED_STATE_SET;
1825 * Indicates the view is pressed, focused, selected and its window has the focus.
1827 * @see #PRESSED_STATE_SET
1828 * @see #FOCUSED_STATE_SET
1829 * @see #SELECTED_STATE_SET
1830 * @see #WINDOW_FOCUSED_STATE_SET
1832 protected static final int[] PRESSED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET;
1834 * Indicates the view is pressed and enabled.
1836 * @see #PRESSED_STATE_SET
1837 * @see #ENABLED_STATE_SET
1839 protected static final int[] PRESSED_ENABLED_STATE_SET;
1841 * Indicates the view is pressed, enabled and its window has the focus.
1843 * @see #PRESSED_STATE_SET
1844 * @see #ENABLED_STATE_SET
1845 * @see #WINDOW_FOCUSED_STATE_SET
1847 protected static final int[] PRESSED_ENABLED_WINDOW_FOCUSED_STATE_SET;
1849 * Indicates the view is pressed, enabled and selected.
1851 * @see #PRESSED_STATE_SET
1852 * @see #ENABLED_STATE_SET
1853 * @see #SELECTED_STATE_SET
1855 protected static final int[] PRESSED_ENABLED_SELECTED_STATE_SET;
1857 * Indicates the view is pressed, enabled, selected and its window has the
1860 * @see #PRESSED_STATE_SET
1861 * @see #ENABLED_STATE_SET
1862 * @see #SELECTED_STATE_SET
1863 * @see #WINDOW_FOCUSED_STATE_SET
1865 protected static final int[] PRESSED_ENABLED_SELECTED_WINDOW_FOCUSED_STATE_SET;
1867 * Indicates the view is pressed, enabled and focused.
1869 * @see #PRESSED_STATE_SET
1870 * @see #ENABLED_STATE_SET
1871 * @see #FOCUSED_STATE_SET
1873 protected static final int[] PRESSED_ENABLED_FOCUSED_STATE_SET;
1875 * Indicates the view is pressed, enabled, focused and its window has the
1878 * @see #PRESSED_STATE_SET
1879 * @see #ENABLED_STATE_SET
1880 * @see #FOCUSED_STATE_SET
1881 * @see #WINDOW_FOCUSED_STATE_SET
1883 protected static final int[] PRESSED_ENABLED_FOCUSED_WINDOW_FOCUSED_STATE_SET;
1885 * Indicates the view is pressed, enabled, focused and selected.
1887 * @see #PRESSED_STATE_SET
1888 * @see #ENABLED_STATE_SET
1889 * @see #SELECTED_STATE_SET
1890 * @see #FOCUSED_STATE_SET
1892 protected static final int[] PRESSED_ENABLED_FOCUSED_SELECTED_STATE_SET;
1894 * Indicates the view is pressed, enabled, focused, selected and its window
1897 * @see #PRESSED_STATE_SET
1898 * @see #ENABLED_STATE_SET
1899 * @see #SELECTED_STATE_SET
1900 * @see #FOCUSED_STATE_SET
1901 * @see #WINDOW_FOCUSED_STATE_SET
1903 protected static final int[] PRESSED_ENABLED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET;
1906 EMPTY_STATE_SET = StateSet.get(0);
1908 WINDOW_FOCUSED_STATE_SET = StateSet.get(StateSet.VIEW_STATE_WINDOW_FOCUSED);
1910 SELECTED_STATE_SET = StateSet.get(StateSet.VIEW_STATE_SELECTED);
1911 SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get(
1912 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED);
1914 FOCUSED_STATE_SET = StateSet.get(StateSet.VIEW_STATE_FOCUSED);
1915 FOCUSED_WINDOW_FOCUSED_STATE_SET = StateSet.get(
1916 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_FOCUSED);
1917 FOCUSED_SELECTED_STATE_SET = StateSet.get(
1918 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_FOCUSED);
1919 FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get(
1920 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED
1921 | StateSet.VIEW_STATE_FOCUSED);
1923 ENABLED_STATE_SET = StateSet.get(StateSet.VIEW_STATE_ENABLED);
1924 ENABLED_WINDOW_FOCUSED_STATE_SET = StateSet.get(
1925 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_ENABLED);
1926 ENABLED_SELECTED_STATE_SET = StateSet.get(
1927 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_ENABLED);
1928 ENABLED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get(
1929 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED
1930 | StateSet.VIEW_STATE_ENABLED);
1931 ENABLED_FOCUSED_STATE_SET = StateSet.get(
1932 StateSet.VIEW_STATE_FOCUSED | StateSet.VIEW_STATE_ENABLED);
1933 ENABLED_FOCUSED_WINDOW_FOCUSED_STATE_SET = StateSet.get(
1934 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_FOCUSED
1935 | StateSet.VIEW_STATE_ENABLED);
1936 ENABLED_FOCUSED_SELECTED_STATE_SET = StateSet.get(
1937 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_FOCUSED
1938 | StateSet.VIEW_STATE_ENABLED);
1939 ENABLED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get(
1940 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED
1941 | StateSet.VIEW_STATE_FOCUSED| StateSet.VIEW_STATE_ENABLED);
1943 PRESSED_STATE_SET = StateSet.get(StateSet.VIEW_STATE_PRESSED);
1944 PRESSED_WINDOW_FOCUSED_STATE_SET = StateSet.get(
1945 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_PRESSED);
1946 PRESSED_SELECTED_STATE_SET = StateSet.get(
1947 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_PRESSED);
1948 PRESSED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get(
1949 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED
1950 | StateSet.VIEW_STATE_PRESSED);
1951 PRESSED_FOCUSED_STATE_SET = StateSet.get(
1952 StateSet.VIEW_STATE_FOCUSED | StateSet.VIEW_STATE_PRESSED);
1953 PRESSED_FOCUSED_WINDOW_FOCUSED_STATE_SET = StateSet.get(
1954 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_FOCUSED
1955 | StateSet.VIEW_STATE_PRESSED);
1956 PRESSED_FOCUSED_SELECTED_STATE_SET = StateSet.get(
1957 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_FOCUSED
1958 | StateSet.VIEW_STATE_PRESSED);
1959 PRESSED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get(
1960 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED
1961 | StateSet.VIEW_STATE_FOCUSED | StateSet.VIEW_STATE_PRESSED);
1962 PRESSED_ENABLED_STATE_SET = StateSet.get(
1963 StateSet.VIEW_STATE_ENABLED | StateSet.VIEW_STATE_PRESSED);
1964 PRESSED_ENABLED_WINDOW_FOCUSED_STATE_SET = StateSet.get(
1965 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_ENABLED
1966 | StateSet.VIEW_STATE_PRESSED);
1967 PRESSED_ENABLED_SELECTED_STATE_SET = StateSet.get(
1968 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_ENABLED
1969 | StateSet.VIEW_STATE_PRESSED);
1970 PRESSED_ENABLED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get(
1971 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED
1972 | StateSet.VIEW_STATE_ENABLED | StateSet.VIEW_STATE_PRESSED);
1973 PRESSED_ENABLED_FOCUSED_STATE_SET = StateSet.get(
1974 StateSet.VIEW_STATE_FOCUSED | StateSet.VIEW_STATE_ENABLED
1975 | StateSet.VIEW_STATE_PRESSED);
1976 PRESSED_ENABLED_FOCUSED_WINDOW_FOCUSED_STATE_SET = StateSet.get(
1977 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_FOCUSED
1978 | StateSet.VIEW_STATE_ENABLED | StateSet.VIEW_STATE_PRESSED);
1979 PRESSED_ENABLED_FOCUSED_SELECTED_STATE_SET = StateSet.get(
1980 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_FOCUSED
1981 | StateSet.VIEW_STATE_ENABLED | StateSet.VIEW_STATE_PRESSED);
1982 PRESSED_ENABLED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get(
1983 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED
1984 | StateSet.VIEW_STATE_FOCUSED| StateSet.VIEW_STATE_ENABLED
1985 | StateSet.VIEW_STATE_PRESSED);
1989 * Accessibility event types that are dispatched for text population.
1991 private static final int POPULATING_ACCESSIBILITY_EVENT_TYPES =
1992 AccessibilityEvent.TYPE_VIEW_CLICKED
1993 | AccessibilityEvent.TYPE_VIEW_LONG_CLICKED
1994 | AccessibilityEvent.TYPE_VIEW_SELECTED
1995 | AccessibilityEvent.TYPE_VIEW_FOCUSED
1996 | AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED
1997 | AccessibilityEvent.TYPE_VIEW_HOVER_ENTER
1998 | AccessibilityEvent.TYPE_VIEW_HOVER_EXIT
1999 | AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED
2000 | AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED
2001 | AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED
2002 | AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY;
2004 static final int DEBUG_CORNERS_COLOR = Color.rgb(63, 127, 255);
2006 static final int DEBUG_CORNERS_SIZE_DIP = 8;
2009 * Temporary Rect currently for use in setBackground(). This will probably
2010 * be extended in the future to hold our own class with more than just
2013 static final ThreadLocal<Rect> sThreadLocal = new ThreadLocal<Rect>();
2016 * Map used to store views' tags.
2018 private SparseArray<Object> mKeyedTags;
2021 * The animation currently associated with this view.
2024 protected Animation mCurrentAnimation = null;
2027 * Width as measured during measure pass.
2030 @ViewDebug.ExportedProperty(category = "measurement")
2034 * Height as measured during measure pass.
2037 @ViewDebug.ExportedProperty(category = "measurement")
2038 int mMeasuredHeight;
2041 * Flag to indicate that this view was marked INVALIDATED, or had its display list
2042 * invalidated, prior to the current drawing iteration. If true, the view must re-draw
2043 * its display list. This flag, used only when hw accelerated, allows us to clear the
2044 * flag while retaining this information until it's needed (at getDisplayList() time and
2045 * in drawChild(), when we decide to draw a view's children's display lists into our own).
2049 boolean mRecreateDisplayList = false;
2052 * The view's identifier.
2059 @ViewDebug.ExportedProperty(resolveId = true)
2062 /** The ID of this view for accessibility and autofill purposes.
2064 * <li>== {@link #NO_ID}: ID has not been assigned yet
2065 * <li>≤ {@link #LAST_APP_ACCESSIBILITY_ID}: View is not part of a activity. The ID is
2066 * unique in the process. This might change
2067 * over activity lifecycle events.
2068 * <li>> {@link #LAST_APP_ACCESSIBILITY_ID}: View is part of a activity. The ID is
2069 * unique in the activity. This stays the same
2070 * over activity lifecycle events.
2072 private int mAccessibilityViewId = NO_ID;
2074 private int mAccessibilityCursorPosition = ACCESSIBILITY_CURSOR_POSITION_UNDEFINED;
2076 SendViewStateChangedAccessibilityEvent mSendViewStateChangedAccessibilityEvent;
2082 * @see #setTag(Object)
2085 protected Object mTag = null;
2087 // for mPrivateFlags:
2089 static final int PFLAG_WANTS_FOCUS = 0x00000001;
2091 static final int PFLAG_FOCUSED = 0x00000002;
2093 static final int PFLAG_SELECTED = 0x00000004;
2095 static final int PFLAG_IS_ROOT_NAMESPACE = 0x00000008;
2097 static final int PFLAG_HAS_BOUNDS = 0x00000010;
2099 static final int PFLAG_DRAWN = 0x00000020;
2101 * When this flag is set, this view is running an animation on behalf of its
2102 * children and should therefore not cancel invalidate requests, even if they
2103 * lie outside of this view's bounds.
2107 static final int PFLAG_DRAW_ANIMATION = 0x00000040;
2109 static final int PFLAG_SKIP_DRAW = 0x00000080;
2111 static final int PFLAG_REQUEST_TRANSPARENT_REGIONS = 0x00000200;
2113 static final int PFLAG_DRAWABLE_STATE_DIRTY = 0x00000400;
2115 static final int PFLAG_MEASURED_DIMENSION_SET = 0x00000800;
2117 static final int PFLAG_FORCE_LAYOUT = 0x00001000;
2119 static final int PFLAG_LAYOUT_REQUIRED = 0x00002000;
2121 private static final int PFLAG_PRESSED = 0x00004000;
2124 static final int PFLAG_DRAWING_CACHE_VALID = 0x00008000;
2126 * Flag used to indicate that this view should be drawn once more (and only once
2127 * more) after its animation has completed.
2130 static final int PFLAG_ANIMATION_STARTED = 0x00010000;
2132 private static final int PFLAG_SAVE_STATE_CALLED = 0x00020000;
2135 * Indicates that the View returned true when onSetAlpha() was called and that
2136 * the alpha must be restored.
2139 static final int PFLAG_ALPHA_SET = 0x00040000;
2142 * Set by {@link #setScrollContainer(boolean)}.
2144 static final int PFLAG_SCROLL_CONTAINER = 0x00080000;
2147 * Set by {@link #setScrollContainer(boolean)}.
2149 static final int PFLAG_SCROLL_CONTAINER_ADDED = 0x00100000;
2152 * View flag indicating whether this view was invalidated (fully or partially.)
2156 static final int PFLAG_DIRTY = 0x00200000;
2159 * View flag indicating whether this view was invalidated by an opaque
2160 * invalidate request.
2164 static final int PFLAG_DIRTY_OPAQUE = 0x00400000;
2167 * Mask for {@link #PFLAG_DIRTY} and {@link #PFLAG_DIRTY_OPAQUE}.
2171 static final int PFLAG_DIRTY_MASK = 0x00600000;
2174 * Indicates whether the background is opaque.
2178 static final int PFLAG_OPAQUE_BACKGROUND = 0x00800000;
2181 * Indicates whether the scrollbars are opaque.
2185 static final int PFLAG_OPAQUE_SCROLLBARS = 0x01000000;
2188 * Indicates whether the view is opaque.
2192 static final int PFLAG_OPAQUE_MASK = 0x01800000;
2195 * Indicates a prepressed state;
2196 * the short time between ACTION_DOWN and recognizing
2197 * a 'real' press. Prepressed is used to recognize quick taps
2198 * even when they are shorter than ViewConfiguration.getTapTimeout().
2202 private static final int PFLAG_PREPRESSED = 0x02000000;
2205 * Indicates whether the view is temporarily detached.
2209 static final int PFLAG_CANCEL_NEXT_UP_EVENT = 0x04000000;
2212 * Indicates that we should awaken scroll bars once attached
2214 * PLEASE NOTE: This flag is now unused as we now send onVisibilityChanged
2215 * during window attachment and it is no longer needed. Feel free to repurpose it.
2219 private static final int PFLAG_AWAKEN_SCROLL_BARS_ON_ATTACH = 0x08000000;
2222 * Indicates that the view has received HOVER_ENTER. Cleared on HOVER_EXIT.
2225 private static final int PFLAG_HOVERED = 0x10000000;
2228 * no longer needed, should be reused
2230 private static final int PFLAG_DOES_NOTHING_REUSE_PLEASE = 0x20000000;
2233 static final int PFLAG_ACTIVATED = 0x40000000;
2236 * Indicates that this view was specifically invalidated, not just dirtied because some
2237 * child view was invalidated. The flag is used to determine when we need to recreate
2238 * a view's display list (as opposed to just returning a reference to its existing
2243 static final int PFLAG_INVALIDATED = 0x80000000;
2246 * Masks for mPrivateFlags2, as generated by dumpFlags():
2248 * |-------|-------|-------|-------|
2249 * 1 PFLAG2_DRAG_CAN_ACCEPT
2250 * 1 PFLAG2_DRAG_HOVERED
2251 * 11 PFLAG2_LAYOUT_DIRECTION_MASK
2252 * 1 PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL
2253 * 1 PFLAG2_LAYOUT_DIRECTION_RESOLVED
2254 * 11 PFLAG2_LAYOUT_DIRECTION_RESOLVED_MASK
2255 * 1 PFLAG2_TEXT_DIRECTION_FLAGS[1]
2256 * 1 PFLAG2_TEXT_DIRECTION_FLAGS[2]
2257 * 11 PFLAG2_TEXT_DIRECTION_FLAGS[3]
2258 * 1 PFLAG2_TEXT_DIRECTION_FLAGS[4]
2259 * 1 1 PFLAG2_TEXT_DIRECTION_FLAGS[5]
2260 * 11 PFLAG2_TEXT_DIRECTION_FLAGS[6]
2261 * 111 PFLAG2_TEXT_DIRECTION_FLAGS[7]
2262 * 111 PFLAG2_TEXT_DIRECTION_MASK
2263 * 1 PFLAG2_TEXT_DIRECTION_RESOLVED
2264 * 1 PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT
2265 * 111 PFLAG2_TEXT_DIRECTION_RESOLVED_MASK
2266 * 1 PFLAG2_TEXT_ALIGNMENT_FLAGS[1]
2267 * 1 PFLAG2_TEXT_ALIGNMENT_FLAGS[2]
2268 * 11 PFLAG2_TEXT_ALIGNMENT_FLAGS[3]
2269 * 1 PFLAG2_TEXT_ALIGNMENT_FLAGS[4]
2270 * 1 1 PFLAG2_TEXT_ALIGNMENT_FLAGS[5]
2271 * 11 PFLAG2_TEXT_ALIGNMENT_FLAGS[6]
2272 * 111 PFLAG2_TEXT_ALIGNMENT_MASK
2273 * 1 PFLAG2_TEXT_ALIGNMENT_RESOLVED
2274 * 1 PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT
2275 * 111 PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK
2276 * 111 PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK
2277 * 11 PFLAG2_ACCESSIBILITY_LIVE_REGION_MASK
2278 * 1 PFLAG2_ACCESSIBILITY_FOCUSED
2279 * 1 PFLAG2_SUBTREE_ACCESSIBILITY_STATE_CHANGED
2280 * 1 PFLAG2_VIEW_QUICK_REJECTED
2281 * 1 PFLAG2_PADDING_RESOLVED
2282 * 1 PFLAG2_DRAWABLE_RESOLVED
2283 * 1 PFLAG2_HAS_TRANSIENT_STATE
2284 * |-------|-------|-------|-------|
2288 * Indicates that this view has reported that it can accept the current drag's content.
2289 * Cleared when the drag operation concludes.
2292 static final int PFLAG2_DRAG_CAN_ACCEPT = 0x00000001;
2295 * Indicates that this view is currently directly under the drag location in a
2296 * drag-and-drop operation involving content that it can accept. Cleared when
2297 * the drag exits the view, or when the drag operation concludes.
2300 static final int PFLAG2_DRAG_HOVERED = 0x00000002;
2304 LAYOUT_DIRECTION_LTR,
2305 LAYOUT_DIRECTION_RTL,
2306 LAYOUT_DIRECTION_INHERIT,
2307 LAYOUT_DIRECTION_LOCALE
2309 @Retention(RetentionPolicy.SOURCE)
2310 // Not called LayoutDirection to avoid conflict with android.util.LayoutDirection
2311 public @interface LayoutDir {}
2315 LAYOUT_DIRECTION_LTR,
2316 LAYOUT_DIRECTION_RTL
2318 @Retention(RetentionPolicy.SOURCE)
2319 public @interface ResolvedLayoutDir {}
2322 * A flag to indicate that the layout direction of this view has not been defined yet.
2325 public static final int LAYOUT_DIRECTION_UNDEFINED = LayoutDirection.UNDEFINED;
2328 * Horizontal layout direction of this view is from Left to Right.
2329 * Use with {@link #setLayoutDirection}.
2331 public static final int LAYOUT_DIRECTION_LTR = LayoutDirection.LTR;
2334 * Horizontal layout direction of this view is from Right to Left.
2335 * Use with {@link #setLayoutDirection}.
2337 public static final int LAYOUT_DIRECTION_RTL = LayoutDirection.RTL;
2340 * Horizontal layout direction of this view is inherited from its parent.
2341 * Use with {@link #setLayoutDirection}.
2343 public static final int LAYOUT_DIRECTION_INHERIT = LayoutDirection.INHERIT;
2346 * Horizontal layout direction of this view is from deduced from the default language
2347 * script for the locale. Use with {@link #setLayoutDirection}.
2349 public static final int LAYOUT_DIRECTION_LOCALE = LayoutDirection.LOCALE;
2352 * Bit shift to get the horizontal layout direction. (bits after DRAG_HOVERED)
2355 static final int PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT = 2;
2358 * Mask for use with private flags indicating bits used for horizontal layout direction.
2361 static final int PFLAG2_LAYOUT_DIRECTION_MASK = 0x00000003 << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT;
2364 * Indicates whether the view horizontal layout direction has been resolved and drawn to the
2365 * right-to-left direction.
2368 static final int PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL = 4 << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT;
2371 * Indicates whether the view horizontal layout direction has been resolved.
2374 static final int PFLAG2_LAYOUT_DIRECTION_RESOLVED = 8 << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT;
2377 * Mask for use with private flags indicating bits used for resolved horizontal layout direction.
2380 static final int PFLAG2_LAYOUT_DIRECTION_RESOLVED_MASK = 0x0000000C
2381 << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT;
2384 * Array of horizontal layout direction flags for mapping attribute "layoutDirection" to correct
2388 private static final int[] LAYOUT_DIRECTION_FLAGS = {
2389 LAYOUT_DIRECTION_LTR,
2390 LAYOUT_DIRECTION_RTL,
2391 LAYOUT_DIRECTION_INHERIT,
2392 LAYOUT_DIRECTION_LOCALE
2396 * Default horizontal layout direction.
2398 private static final int LAYOUT_DIRECTION_DEFAULT = LAYOUT_DIRECTION_INHERIT;
2401 * Default horizontal layout direction.
2404 static final int LAYOUT_DIRECTION_RESOLVED_DEFAULT = LAYOUT_DIRECTION_LTR;
2407 * Text direction is inherited through {@link ViewGroup}
2409 public static final int TEXT_DIRECTION_INHERIT = 0;
2412 * Text direction is using "first strong algorithm". The first strong directional character
2413 * determines the paragraph direction. If there is no strong directional character, the
2414 * paragraph direction is the view's resolved layout direction.
2416 public static final int TEXT_DIRECTION_FIRST_STRONG = 1;
2419 * Text direction is using "any-RTL" algorithm. The paragraph direction is RTL if it contains
2420 * any strong RTL character, otherwise it is LTR if it contains any strong LTR characters.
2421 * If there are neither, the paragraph direction is the view's resolved layout direction.
2423 public static final int TEXT_DIRECTION_ANY_RTL = 2;
2426 * Text direction is forced to LTR.
2428 public static final int TEXT_DIRECTION_LTR = 3;
2431 * Text direction is forced to RTL.
2433 public static final int TEXT_DIRECTION_RTL = 4;
2436 * Text direction is coming from the system Locale.
2438 public static final int TEXT_DIRECTION_LOCALE = 5;
2441 * Text direction is using "first strong algorithm". The first strong directional character
2442 * determines the paragraph direction. If there is no strong directional character, the
2443 * paragraph direction is LTR.
2445 public static final int TEXT_DIRECTION_FIRST_STRONG_LTR = 6;
2448 * Text direction is using "first strong algorithm". The first strong directional character
2449 * determines the paragraph direction. If there is no strong directional character, the
2450 * paragraph direction is RTL.
2452 public static final int TEXT_DIRECTION_FIRST_STRONG_RTL = 7;
2455 * Default text direction is inherited
2457 private static final int TEXT_DIRECTION_DEFAULT = TEXT_DIRECTION_INHERIT;
2460 * Default resolved text direction
2463 static final int TEXT_DIRECTION_RESOLVED_DEFAULT = TEXT_DIRECTION_FIRST_STRONG;
2466 * Bit shift to get the horizontal layout direction. (bits after LAYOUT_DIRECTION_RESOLVED)
2469 static final int PFLAG2_TEXT_DIRECTION_MASK_SHIFT = 6;
2472 * Mask for use with private flags indicating bits used for text direction.
2475 static final int PFLAG2_TEXT_DIRECTION_MASK = 0x00000007
2476 << PFLAG2_TEXT_DIRECTION_MASK_SHIFT;
2479 * Array of text direction flags for mapping attribute "textDirection" to correct
2483 private static final int[] PFLAG2_TEXT_DIRECTION_FLAGS = {
2484 TEXT_DIRECTION_INHERIT << PFLAG2_TEXT_DIRECTION_MASK_SHIFT,
2485 TEXT_DIRECTION_FIRST_STRONG << PFLAG2_TEXT_DIRECTION_MASK_SHIFT,
2486 TEXT_DIRECTION_ANY_RTL << PFLAG2_TEXT_DIRECTION_MASK_SHIFT,
2487 TEXT_DIRECTION_LTR << PFLAG2_TEXT_DIRECTION_MASK_SHIFT,
2488 TEXT_DIRECTION_RTL << PFLAG2_TEXT_DIRECTION_MASK_SHIFT,
2489 TEXT_DIRECTION_LOCALE << PFLAG2_TEXT_DIRECTION_MASK_SHIFT,
2490 TEXT_DIRECTION_FIRST_STRONG_LTR << PFLAG2_TEXT_DIRECTION_MASK_SHIFT,
2491 TEXT_DIRECTION_FIRST_STRONG_RTL << PFLAG2_TEXT_DIRECTION_MASK_SHIFT
2495 * Indicates whether the view text direction has been resolved.
2498 static final int PFLAG2_TEXT_DIRECTION_RESOLVED = 0x00000008
2499 << PFLAG2_TEXT_DIRECTION_MASK_SHIFT;
2502 * Bit shift to get the horizontal layout direction. (bits after DRAG_HOVERED)
2505 static final int PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT = 10;
2508 * Mask for use with private flags indicating bits used for resolved text direction.
2511 static final int PFLAG2_TEXT_DIRECTION_RESOLVED_MASK = 0x00000007
2512 << PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT;
2515 * Indicates whether the view text direction has been resolved to the "first strong" heuristic.
2518 static final int PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT =
2519 TEXT_DIRECTION_RESOLVED_DEFAULT << PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT;
2523 TEXT_ALIGNMENT_INHERIT,
2524 TEXT_ALIGNMENT_GRAVITY,
2525 TEXT_ALIGNMENT_CENTER,
2526 TEXT_ALIGNMENT_TEXT_START,
2527 TEXT_ALIGNMENT_TEXT_END,
2528 TEXT_ALIGNMENT_VIEW_START,
2529 TEXT_ALIGNMENT_VIEW_END
2531 @Retention(RetentionPolicy.SOURCE)
2532 public @interface TextAlignment {}
2535 * Default text alignment. The text alignment of this View is inherited from its parent.
2536 * Use with {@link #setTextAlignment(int)}
2538 public static final int TEXT_ALIGNMENT_INHERIT = 0;
2541 * Default for the root view. The gravity determines the text alignment, ALIGN_NORMAL,
2542 * ALIGN_CENTER, or ALIGN_OPPOSITE, which are relative to each paragraph’s text direction.
2544 * Use with {@link #setTextAlignment(int)}
2546 public static final int TEXT_ALIGNMENT_GRAVITY = 1;
2549 * Align to the start of the paragraph, e.g. ALIGN_NORMAL.
2551 * Use with {@link #setTextAlignment(int)}
2553 public static final int TEXT_ALIGNMENT_TEXT_START = 2;
2556 * Align to the end of the paragraph, e.g. ALIGN_OPPOSITE.
2558 * Use with {@link #setTextAlignment(int)}
2560 public static final int TEXT_ALIGNMENT_TEXT_END = 3;
2563 * Center the paragraph, e.g. ALIGN_CENTER.
2565 * Use with {@link #setTextAlignment(int)}
2567 public static final int TEXT_ALIGNMENT_CENTER = 4;
2570 * Align to the start of the view, which is ALIGN_LEFT if the view’s resolved
2571 * layoutDirection is LTR, and ALIGN_RIGHT otherwise.
2573 * Use with {@link #setTextAlignment(int)}
2575 public static final int TEXT_ALIGNMENT_VIEW_START = 5;
2578 * Align to the end of the view, which is ALIGN_RIGHT if the view’s resolved
2579 * layoutDirection is LTR, and ALIGN_LEFT otherwise.
2581 * Use with {@link #setTextAlignment(int)}
2583 public static final int TEXT_ALIGNMENT_VIEW_END = 6;
2586 * Default text alignment is inherited
2588 private static final int TEXT_ALIGNMENT_DEFAULT = TEXT_ALIGNMENT_GRAVITY;
2591 * Default resolved text alignment
2594 static final int TEXT_ALIGNMENT_RESOLVED_DEFAULT = TEXT_ALIGNMENT_GRAVITY;
2597 * Bit shift to get the horizontal layout direction. (bits after DRAG_HOVERED)
2600 static final int PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT = 13;
2603 * Mask for use with private flags indicating bits used for text alignment.
2606 static final int PFLAG2_TEXT_ALIGNMENT_MASK = 0x00000007 << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT;
2609 * Array of text direction flags for mapping attribute "textAlignment" to correct
2613 private static final int[] PFLAG2_TEXT_ALIGNMENT_FLAGS = {
2614 TEXT_ALIGNMENT_INHERIT << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT,
2615 TEXT_ALIGNMENT_GRAVITY << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT,
2616 TEXT_ALIGNMENT_TEXT_START << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT,
2617 TEXT_ALIGNMENT_TEXT_END << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT,
2618 TEXT_ALIGNMENT_CENTER << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT,
2619 TEXT_ALIGNMENT_VIEW_START << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT,
2620 TEXT_ALIGNMENT_VIEW_END << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT
2624 * Indicates whether the view text alignment has been resolved.
2627 static final int PFLAG2_TEXT_ALIGNMENT_RESOLVED = 0x00000008 << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT;
2630 * Bit shift to get the resolved text alignment.
2633 static final int PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT = 17;
2636 * Mask for use with private flags indicating bits used for text alignment.
2639 static final int PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK = 0x00000007
2640 << PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT;
2643 * Indicates whether if the view text alignment has been resolved to gravity
2645 private static final int PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT =
2646 TEXT_ALIGNMENT_RESOLVED_DEFAULT << PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT;
2648 // Accessiblity constants for mPrivateFlags2
2651 * Shift for the bits in {@link #mPrivateFlags2} related to the
2652 * "importantForAccessibility" attribute.
2654 static final int PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT = 20;
2657 * Automatically determine whether a view is important for accessibility.
2659 public static final int IMPORTANT_FOR_ACCESSIBILITY_AUTO = 0x00000000;
2662 * The view is important for accessibility.
2664 public static final int IMPORTANT_FOR_ACCESSIBILITY_YES = 0x00000001;
2667 * The view is not important for accessibility.
2669 public static final int IMPORTANT_FOR_ACCESSIBILITY_NO = 0x00000002;
2672 * The view is not important for accessibility, nor are any of its
2675 public static final int IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS = 0x00000004;
2678 * The default whether the view is important for accessibility.
2680 static final int IMPORTANT_FOR_ACCESSIBILITY_DEFAULT = IMPORTANT_FOR_ACCESSIBILITY_AUTO;
2683 * Mask for obtaining the bits which specify how to determine
2684 * whether a view is important for accessibility.
2686 static final int PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK = (IMPORTANT_FOR_ACCESSIBILITY_AUTO
2687 | IMPORTANT_FOR_ACCESSIBILITY_YES | IMPORTANT_FOR_ACCESSIBILITY_NO
2688 | IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS)
2689 << PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT;
2692 * Shift for the bits in {@link #mPrivateFlags2} related to the
2693 * "accessibilityLiveRegion" attribute.
2695 static final int PFLAG2_ACCESSIBILITY_LIVE_REGION_SHIFT = 23;
2698 * Live region mode specifying that accessibility services should not
2699 * automatically announce changes to this view. This is the default live
2700 * region mode for most views.
2702 * Use with {@link #setAccessibilityLiveRegion(int)}.
2704 public static final int ACCESSIBILITY_LIVE_REGION_NONE = 0x00000000;
2707 * Live region mode specifying that accessibility services should announce
2708 * changes to this view.
2710 * Use with {@link #setAccessibilityLiveRegion(int)}.
2712 public static final int ACCESSIBILITY_LIVE_REGION_POLITE = 0x00000001;
2715 * Live region mode specifying that accessibility services should interrupt
2716 * ongoing speech to immediately announce changes to this view.
2718 * Use with {@link #setAccessibilityLiveRegion(int)}.
2720 public static final int ACCESSIBILITY_LIVE_REGION_ASSERTIVE = 0x00000002;
2723 * The default whether the view is important for accessibility.
2725 static final int ACCESSIBILITY_LIVE_REGION_DEFAULT = ACCESSIBILITY_LIVE_REGION_NONE;
2728 * Mask for obtaining the bits which specify a view's accessibility live
2731 static final int PFLAG2_ACCESSIBILITY_LIVE_REGION_MASK = (ACCESSIBILITY_LIVE_REGION_NONE
2732 | ACCESSIBILITY_LIVE_REGION_POLITE | ACCESSIBILITY_LIVE_REGION_ASSERTIVE)
2733 << PFLAG2_ACCESSIBILITY_LIVE_REGION_SHIFT;
2736 * Flag indicating whether a view has accessibility focus.
2738 static final int PFLAG2_ACCESSIBILITY_FOCUSED = 0x04000000;
2741 * Flag whether the accessibility state of the subtree rooted at this view changed.
2743 static final int PFLAG2_SUBTREE_ACCESSIBILITY_STATE_CHANGED = 0x08000000;
2746 * Flag indicating whether a view failed the quickReject() check in draw(). This condition
2747 * is used to check whether later changes to the view's transform should invalidate the
2748 * view to force the quickReject test to run again.
2750 static final int PFLAG2_VIEW_QUICK_REJECTED = 0x10000000;
2753 * Flag indicating that start/end padding has been resolved into left/right padding
2754 * for use in measurement, layout, drawing, etc. This is set by {@link #resolvePadding()}
2755 * and checked by {@link #measure(int, int)} to determine if padding needs to be resolved
2756 * during measurement. In some special cases this is required such as when an adapter-based
2757 * view measures prospective children without attaching them to a window.
2759 static final int PFLAG2_PADDING_RESOLVED = 0x20000000;
2762 * Flag indicating that the start/end drawables has been resolved into left/right ones.
2764 static final int PFLAG2_DRAWABLE_RESOLVED = 0x40000000;
2767 * Indicates that the view is tracking some sort of transient state
2768 * that the app should not need to be aware of, but that the framework
2769 * should take special care to preserve.
2771 static final int PFLAG2_HAS_TRANSIENT_STATE = 0x80000000;
2774 * Group of bits indicating that RTL properties resolution is done.
2776 static final int ALL_RTL_PROPERTIES_RESOLVED = PFLAG2_LAYOUT_DIRECTION_RESOLVED |
2777 PFLAG2_TEXT_DIRECTION_RESOLVED |
2778 PFLAG2_TEXT_ALIGNMENT_RESOLVED |
2779 PFLAG2_PADDING_RESOLVED |
2780 PFLAG2_DRAWABLE_RESOLVED;
2782 // There are a couple of flags left in mPrivateFlags2
2784 /* End of masks for mPrivateFlags2 */
2787 * Masks for mPrivateFlags3, as generated by dumpFlags():
2789 * |-------|-------|-------|-------|
2790 * 1 PFLAG3_VIEW_IS_ANIMATING_TRANSFORM
2791 * 1 PFLAG3_VIEW_IS_ANIMATING_ALPHA
2792 * 1 PFLAG3_IS_LAID_OUT
2793 * 1 PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT
2794 * 1 PFLAG3_CALLED_SUPER
2795 * 1 PFLAG3_APPLYING_INSETS
2796 * 1 PFLAG3_FITTING_SYSTEM_WINDOWS
2797 * 1 PFLAG3_NESTED_SCROLLING_ENABLED
2798 * 1 PFLAG3_SCROLL_INDICATOR_TOP
2799 * 1 PFLAG3_SCROLL_INDICATOR_BOTTOM
2800 * 1 PFLAG3_SCROLL_INDICATOR_LEFT
2801 * 1 PFLAG3_SCROLL_INDICATOR_RIGHT
2802 * 1 PFLAG3_SCROLL_INDICATOR_START
2803 * 1 PFLAG3_SCROLL_INDICATOR_END
2804 * 1 PFLAG3_ASSIST_BLOCKED
2806 * 1 PFLAG3_IS_AUTOFILLED
2807 * 1 PFLAG3_FINGER_DOWN
2808 * 1 PFLAG3_FOCUSED_BY_DEFAULT
2809 * 1111 PFLAG3_IMPORTANT_FOR_AUTOFILL
2810 * 1 PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE
2811 * 1 PFLAG3_HAS_OVERLAPPING_RENDERING_FORCED
2812 * 1 PFLAG3_TEMPORARY_DETACH
2813 * 1 PFLAG3_NO_REVEAL_ON_FOCUS
2814 * 1 PFLAG3_NOTIFY_AUTOFILL_ENTER_ON_LAYOUT
2815 * |-------|-------|-------|-------|
2819 * Flag indicating that view has a transform animation set on it. This is used to track whether
2820 * an animation is cleared between successive frames, in order to tell the associated
2821 * DisplayList to clear its animation matrix.
2823 static final int PFLAG3_VIEW_IS_ANIMATING_TRANSFORM = 0x1;
2826 * Flag indicating that view has an alpha animation set on it. This is used to track whether an
2827 * animation is cleared between successive frames, in order to tell the associated
2828 * DisplayList to restore its alpha value.
2830 static final int PFLAG3_VIEW_IS_ANIMATING_ALPHA = 0x2;
2833 * Flag indicating that the view has been through at least one layout since it
2834 * was last attached to a window.
2836 static final int PFLAG3_IS_LAID_OUT = 0x4;
2839 * Flag indicating that a call to measure() was skipped and should be done
2840 * instead when layout() is invoked.
2842 static final int PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT = 0x8;
2845 * Flag indicating that an overridden method correctly called down to
2846 * the superclass implementation as required by the API spec.
2848 static final int PFLAG3_CALLED_SUPER = 0x10;
2851 * Flag indicating that we're in the process of applying window insets.
2853 static final int PFLAG3_APPLYING_INSETS = 0x20;
2856 * Flag indicating that we're in the process of fitting system windows using the old method.
2858 static final int PFLAG3_FITTING_SYSTEM_WINDOWS = 0x40;
2861 * Flag indicating that nested scrolling is enabled for this view.
2862 * The view will optionally cooperate with views up its parent chain to allow for
2863 * integrated nested scrolling along the same axis.
2865 static final int PFLAG3_NESTED_SCROLLING_ENABLED = 0x80;
2868 * Flag indicating that the bottom scroll indicator should be displayed
2869 * when this view can scroll up.
2871 static final int PFLAG3_SCROLL_INDICATOR_TOP = 0x0100;
2874 * Flag indicating that the bottom scroll indicator should be displayed
2875 * when this view can scroll down.
2877 static final int PFLAG3_SCROLL_INDICATOR_BOTTOM = 0x0200;
2880 * Flag indicating that the left scroll indicator should be displayed
2881 * when this view can scroll left.
2883 static final int PFLAG3_SCROLL_INDICATOR_LEFT = 0x0400;
2886 * Flag indicating that the right scroll indicator should be displayed
2887 * when this view can scroll right.
2889 static final int PFLAG3_SCROLL_INDICATOR_RIGHT = 0x0800;
2892 * Flag indicating that the start scroll indicator should be displayed
2893 * when this view can scroll in the start direction.
2895 static final int PFLAG3_SCROLL_INDICATOR_START = 0x1000;
2898 * Flag indicating that the end scroll indicator should be displayed
2899 * when this view can scroll in the end direction.
2901 static final int PFLAG3_SCROLL_INDICATOR_END = 0x2000;
2903 static final int DRAG_MASK = PFLAG2_DRAG_CAN_ACCEPT | PFLAG2_DRAG_HOVERED;
2905 static final int SCROLL_INDICATORS_NONE = 0x0000;
2908 * Mask for use with setFlags indicating bits used for indicating which
2909 * scroll indicators are enabled.
2911 static final int SCROLL_INDICATORS_PFLAG3_MASK = PFLAG3_SCROLL_INDICATOR_TOP
2912 | PFLAG3_SCROLL_INDICATOR_BOTTOM | PFLAG3_SCROLL_INDICATOR_LEFT
2913 | PFLAG3_SCROLL_INDICATOR_RIGHT | PFLAG3_SCROLL_INDICATOR_START
2914 | PFLAG3_SCROLL_INDICATOR_END;
2917 * Left-shift required to translate between public scroll indicator flags
2918 * and internal PFLAGS3 flags. When used as a right-shift, translates
2919 * PFLAGS3 flags to public flags.
2921 static final int SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT = 8;
2924 @Retention(RetentionPolicy.SOURCE)
2925 @IntDef(flag = true,
2927 SCROLL_INDICATOR_TOP,
2928 SCROLL_INDICATOR_BOTTOM,
2929 SCROLL_INDICATOR_LEFT,
2930 SCROLL_INDICATOR_RIGHT,
2931 SCROLL_INDICATOR_START,
2932 SCROLL_INDICATOR_END,
2934 public @interface ScrollIndicators {}
2937 * Scroll indicator direction for the top edge of the view.
2939 * @see #setScrollIndicators(int)
2940 * @see #setScrollIndicators(int, int)
2941 * @see #getScrollIndicators()
2943 public static final int SCROLL_INDICATOR_TOP =
2944 PFLAG3_SCROLL_INDICATOR_TOP >> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT;
2947 * Scroll indicator direction for the bottom edge of the view.
2949 * @see #setScrollIndicators(int)
2950 * @see #setScrollIndicators(int, int)
2951 * @see #getScrollIndicators()
2953 public static final int SCROLL_INDICATOR_BOTTOM =
2954 PFLAG3_SCROLL_INDICATOR_BOTTOM >> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT;
2957 * Scroll indicator direction for the left edge of the view.
2959 * @see #setScrollIndicators(int)
2960 * @see #setScrollIndicators(int, int)
2961 * @see #getScrollIndicators()
2963 public static final int SCROLL_INDICATOR_LEFT =
2964 PFLAG3_SCROLL_INDICATOR_LEFT >> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT;
2967 * Scroll indicator direction for the right edge of the view.
2969 * @see #setScrollIndicators(int)
2970 * @see #setScrollIndicators(int, int)
2971 * @see #getScrollIndicators()
2973 public static final int SCROLL_INDICATOR_RIGHT =
2974 PFLAG3_SCROLL_INDICATOR_RIGHT >> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT;
2977 * Scroll indicator direction for the starting edge of the view.
2979 * Resolved according to the view's layout direction, see
2980 * {@link #getLayoutDirection()} for more information.
2982 * @see #setScrollIndicators(int)
2983 * @see #setScrollIndicators(int, int)
2984 * @see #getScrollIndicators()
2986 public static final int SCROLL_INDICATOR_START =
2987 PFLAG3_SCROLL_INDICATOR_START >> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT;
2990 * Scroll indicator direction for the ending edge of the view.
2992 * Resolved according to the view's layout direction, see
2993 * {@link #getLayoutDirection()} for more information.
2995 * @see #setScrollIndicators(int)
2996 * @see #setScrollIndicators(int, int)
2997 * @see #getScrollIndicators()
2999 public static final int SCROLL_INDICATOR_END =
3000 PFLAG3_SCROLL_INDICATOR_END >> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT;
3003 * <p>Indicates that we are allowing {@link ViewStructure} to traverse
3004 * into this view.<p>
3006 static final int PFLAG3_ASSIST_BLOCKED = 0x4000;
3009 * Flag indicating that the view is a root of a keyboard navigation cluster.
3011 * @see #isKeyboardNavigationCluster()
3012 * @see #setKeyboardNavigationCluster(boolean)
3014 private static final int PFLAG3_CLUSTER = 0x8000;
3017 * Flag indicating that the view is autofilled
3019 * @see #isAutofilled()
3020 * @see #setAutofilled(boolean)
3022 private static final int PFLAG3_IS_AUTOFILLED = 0x10000;
3025 * Indicates that the user is currently touching the screen.
3026 * Currently used for the tooltip positioning only.
3028 private static final int PFLAG3_FINGER_DOWN = 0x20000;
3031 * Flag indicating that this view is the default-focus view.
3033 * @see #isFocusedByDefault()
3034 * @see #setFocusedByDefault(boolean)
3036 private static final int PFLAG3_FOCUSED_BY_DEFAULT = 0x40000;
3039 * Shift for the bits in {@link #mPrivateFlags3} related to the
3040 * "importantForAutofill" attribute.
3042 static final int PFLAG3_IMPORTANT_FOR_AUTOFILL_SHIFT = 19;
3045 * Mask for obtaining the bits which specify how to determine
3046 * whether a view is important for autofill.
3048 static final int PFLAG3_IMPORTANT_FOR_AUTOFILL_MASK = (IMPORTANT_FOR_AUTOFILL_AUTO
3049 | IMPORTANT_FOR_AUTOFILL_YES | IMPORTANT_FOR_AUTOFILL_NO
3050 | IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS
3051 | IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS)
3052 << PFLAG3_IMPORTANT_FOR_AUTOFILL_SHIFT;
3055 * Whether this view has rendered elements that overlap (see {@link
3056 * #hasOverlappingRendering()}, {@link #forceHasOverlappingRendering(boolean)}, and
3057 * {@link #getHasOverlappingRendering()} ). The value in this bit is only valid when
3058 * PFLAG3_HAS_OVERLAPPING_RENDERING_FORCED has been set. Otherwise, the value is
3059 * determined by whatever {@link #hasOverlappingRendering()} returns.
3061 private static final int PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE = 0x800000;
3064 * Whether {@link #forceHasOverlappingRendering(boolean)} has been called. When true, value
3065 * in PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE is valid.
3067 private static final int PFLAG3_HAS_OVERLAPPING_RENDERING_FORCED = 0x1000000;
3070 * Flag indicating that the view is temporarily detached from the parent view.
3072 * @see #onStartTemporaryDetach()
3073 * @see #onFinishTemporaryDetach()
3075 static final int PFLAG3_TEMPORARY_DETACH = 0x2000000;
3078 * Flag indicating that the view does not wish to be revealed within its parent
3079 * hierarchy when it gains focus. Expressed in the negative since the historical
3080 * default behavior is to reveal on focus; this flag suppresses that behavior.
3082 * @see #setRevealOnFocusHint(boolean)
3083 * @see #getRevealOnFocusHint()
3085 private static final int PFLAG3_NO_REVEAL_ON_FOCUS = 0x4000000;
3088 * Flag indicating that when layout is completed we should notify
3089 * that the view was entered for autofill purposes. To minimize
3090 * showing autofill for views not visible to the user we evaluate
3091 * user visibility which cannot be done until the view is laid out.
3093 static final int PFLAG3_NOTIFY_AUTOFILL_ENTER_ON_LAYOUT = 0x8000000;
3095 /* End of masks for mPrivateFlags3 */
3098 * Always allow a user to over-scroll this view, provided it is a
3099 * view that can scroll.
3101 * @see #getOverScrollMode()
3102 * @see #setOverScrollMode(int)
3104 public static final int OVER_SCROLL_ALWAYS = 0;
3107 * Allow a user to over-scroll this view only if the content is large
3108 * enough to meaningfully scroll, provided it is a view that can scroll.
3110 * @see #getOverScrollMode()
3111 * @see #setOverScrollMode(int)
3113 public static final int OVER_SCROLL_IF_CONTENT_SCROLLS = 1;
3116 * Never allow a user to over-scroll this view.
3118 * @see #getOverScrollMode()
3119 * @see #setOverScrollMode(int)
3121 public static final int OVER_SCROLL_NEVER = 2;
3124 * Special constant for {@link #setSystemUiVisibility(int)}: View has
3125 * requested the system UI (status bar) to be visible (the default).
3127 * @see #setSystemUiVisibility(int)
3129 public static final int SYSTEM_UI_FLAG_VISIBLE = 0;
3132 * Flag for {@link #setSystemUiVisibility(int)}: View has requested the
3133 * system UI to enter an unobtrusive "low profile" mode.
3135 * <p>This is for use in games, book readers, video players, or any other
3136 * "immersive" application where the usual system chrome is deemed too distracting.
3138 * <p>In low profile mode, the status bar and/or navigation icons may dim.
3140 * @see #setSystemUiVisibility(int)
3142 public static final int SYSTEM_UI_FLAG_LOW_PROFILE = 0x00000001;
3145 * Flag for {@link #setSystemUiVisibility(int)}: View has requested that the
3146 * system navigation be temporarily hidden.
3148 * <p>This is an even less obtrusive state than that called for by
3149 * {@link #SYSTEM_UI_FLAG_LOW_PROFILE}; on devices that draw essential navigation controls
3150 * (Home, Back, and the like) on screen, <code>SYSTEM_UI_FLAG_HIDE_NAVIGATION</code> will cause
3151 * those to disappear. This is useful (in conjunction with the
3152 * {@link android.view.WindowManager.LayoutParams#FLAG_FULLSCREEN FLAG_FULLSCREEN} and
3153 * {@link android.view.WindowManager.LayoutParams#FLAG_LAYOUT_IN_SCREEN FLAG_LAYOUT_IN_SCREEN}
3154 * window flags) for displaying content using every last pixel on the display.
3156 * <p>There is a limitation: because navigation controls are so important, the least user
3157 * interaction will cause them to reappear immediately. When this happens, both
3158 * this flag and {@link #SYSTEM_UI_FLAG_FULLSCREEN} will be cleared automatically,
3159 * so that both elements reappear at the same time.
3161 * @see #setSystemUiVisibility(int)
3163 public static final int SYSTEM_UI_FLAG_HIDE_NAVIGATION = 0x00000002;
3166 * Flag for {@link #setSystemUiVisibility(int)}: View has requested to go
3167 * into the normal fullscreen mode so that its content can take over the screen
3168 * while still allowing the user to interact with the application.
3170 * <p>This has the same visual effect as
3171 * {@link android.view.WindowManager.LayoutParams#FLAG_FULLSCREEN
3172 * WindowManager.LayoutParams.FLAG_FULLSCREEN},
3173 * meaning that non-critical screen decorations (such as the status bar) will be
3174 * hidden while the user is in the View's window, focusing the experience on
3175 * that content. Unlike the window flag, if you are using ActionBar in
3176 * overlay mode with {@link Window#FEATURE_ACTION_BAR_OVERLAY
3177 * Window.FEATURE_ACTION_BAR_OVERLAY}, then enabling this flag will also
3178 * hide the action bar.
3180 * <p>This approach to going fullscreen is best used over the window flag when
3181 * it is a transient state -- that is, the application does this at certain
3182 * points in its user interaction where it wants to allow the user to focus
3183 * on content, but not as a continuous state. For situations where the application
3184 * would like to simply stay full screen the entire time (such as a game that
3185 * wants to take over the screen), the
3186 * {@link android.view.WindowManager.LayoutParams#FLAG_FULLSCREEN window flag}
3187 * is usually a better approach. The state set here will be removed by the system
3188 * in various situations (such as the user moving to another application) like
3189 * the other system UI states.
3191 * <p>When using this flag, the application should provide some easy facility
3192 * for the user to go out of it. A common example would be in an e-book
3193 * reader, where tapping on the screen brings back whatever screen and UI
3194 * decorations that had been hidden while the user was immersed in reading
3197 * @see #setSystemUiVisibility(int)
3199 public static final int SYSTEM_UI_FLAG_FULLSCREEN = 0x00000004;
3202 * Flag for {@link #setSystemUiVisibility(int)}: When using other layout
3203 * flags, we would like a stable view of the content insets given to
3204 * {@link #fitSystemWindows(Rect)}. This means that the insets seen there
3205 * will always represent the worst case that the application can expect
3206 * as a continuous state. In the stock Android UI this is the space for
3207 * the system bar, nav bar, and status bar, but not more transient elements
3208 * such as an input method.
3210 * The stable layout your UI sees is based on the system UI modes you can
3211 * switch to. That is, if you specify {@link #SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN}
3212 * then you will get a stable layout for changes of the
3213 * {@link #SYSTEM_UI_FLAG_FULLSCREEN} mode; if you specify
3214 * {@link #SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN} and
3215 * {@link #SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION}, then you can transition
3216 * to {@link #SYSTEM_UI_FLAG_FULLSCREEN} and {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}
3217 * with a stable layout. (Note that you should avoid using
3218 * {@link #SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION} by itself.)
3220 * If you have set the window flag {@link WindowManager.LayoutParams#FLAG_FULLSCREEN}
3221 * to hide the status bar (instead of using {@link #SYSTEM_UI_FLAG_FULLSCREEN}),
3222 * then a hidden status bar will be considered a "stable" state for purposes
3223 * here. This allows your UI to continually hide the status bar, while still
3224 * using the system UI flags to hide the action bar while still retaining
3225 * a stable layout. Note that changing the window fullscreen flag will never
3226 * provide a stable layout for a clean transition.
3228 * <p>If you are using ActionBar in
3229 * overlay mode with {@link Window#FEATURE_ACTION_BAR_OVERLAY
3230 * Window.FEATURE_ACTION_BAR_OVERLAY}, this flag will also impact the
3231 * insets it adds to those given to the application.
3233 public static final int SYSTEM_UI_FLAG_LAYOUT_STABLE = 0x00000100;
3236 * Flag for {@link #setSystemUiVisibility(int)}: View would like its window
3237 * to be laid out as if it has requested
3238 * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, even if it currently hasn't. This
3239 * allows it to avoid artifacts when switching in and out of that mode, at
3240 * the expense that some of its user interface may be covered by screen
3241 * decorations when they are shown. You can perform layout of your inner
3242 * UI elements to account for the navigation system UI through the
3243 * {@link #fitSystemWindows(Rect)} method.
3245 public static final int SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION = 0x00000200;
3248 * Flag for {@link #setSystemUiVisibility(int)}: View would like its window
3249 * to be laid out as if it has requested
3250 * {@link #SYSTEM_UI_FLAG_FULLSCREEN}, even if it currently hasn't. This
3251 * allows it to avoid artifacts when switching in and out of that mode, at
3252 * the expense that some of its user interface may be covered by screen
3253 * decorations when they are shown. You can perform layout of your inner
3254 * UI elements to account for non-fullscreen system UI through the
3255 * {@link #fitSystemWindows(Rect)} method.
3257 public static final int SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN = 0x00000400;
3260 * Flag for {@link #setSystemUiVisibility(int)}: View would like to remain interactive when
3261 * hiding the navigation bar with {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}. If this flag is
3262 * not set, {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION} will be force cleared by the system on any
3264 * <p>Since this flag is a modifier for {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, it only
3265 * has an effect when used in combination with that flag.</p>
3267 public static final int SYSTEM_UI_FLAG_IMMERSIVE = 0x00000800;
3270 * Flag for {@link #setSystemUiVisibility(int)}: View would like to remain interactive when
3271 * hiding the status bar with {@link #SYSTEM_UI_FLAG_FULLSCREEN} and/or hiding the navigation
3272 * bar with {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}. Use this flag to create an immersive
3273 * experience while also hiding the system bars. If this flag is not set,
3274 * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION} will be force cleared by the system on any user
3275 * interaction, and {@link #SYSTEM_UI_FLAG_FULLSCREEN} will be force-cleared by the system
3276 * if the user swipes from the top of the screen.
3277 * <p>When system bars are hidden in immersive mode, they can be revealed temporarily with
3278 * system gestures, such as swiping from the top of the screen. These transient system bars
3279 * will overlay app’s content, may have some degree of transparency, and will automatically
3280 * hide after a short timeout.
3281 * </p><p>Since this flag is a modifier for {@link #SYSTEM_UI_FLAG_FULLSCREEN} and
3282 * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, it only has an effect when used in combination
3283 * with one or both of those flags.</p>
3285 public static final int SYSTEM_UI_FLAG_IMMERSIVE_STICKY = 0x00001000;
3288 * Flag for {@link #setSystemUiVisibility(int)}: Requests the status bar to draw in a mode that
3289 * is compatible with light status bar backgrounds.
3291 * <p>For this to take effect, the window must request
3292 * {@link android.view.WindowManager.LayoutParams#FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS
3293 * FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS} but not
3294 * {@link android.view.WindowManager.LayoutParams#FLAG_TRANSLUCENT_STATUS
3295 * FLAG_TRANSLUCENT_STATUS}.
3297 * @see android.R.attr#windowLightStatusBar
3299 public static final int SYSTEM_UI_FLAG_LIGHT_STATUS_BAR = 0x00002000;
3302 * This flag was previously used for a private API. DO NOT reuse it for a public API as it might
3303 * trigger undefined behavior on older platforms with apps compiled against a new SDK.
3305 private static final int SYSTEM_UI_RESERVED_LEGACY1 = 0x00004000;
3308 * This flag was previously used for a private API. DO NOT reuse it for a public API as it might
3309 * trigger undefined behavior on older platforms with apps compiled against a new SDK.
3311 private static final int SYSTEM_UI_RESERVED_LEGACY2 = 0x00010000;
3314 * Flag for {@link #setSystemUiVisibility(int)}: Requests the navigation bar to draw in a mode
3315 * that is compatible with light navigation bar backgrounds.
3317 * <p>For this to take effect, the window must request
3318 * {@link android.view.WindowManager.LayoutParams#FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS
3319 * FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS} but not
3320 * {@link android.view.WindowManager.LayoutParams#FLAG_TRANSLUCENT_NAVIGATION
3321 * FLAG_TRANSLUCENT_NAVIGATION}.
3323 public static final int SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR = 0x00000010;
3326 * @deprecated Use {@link #SYSTEM_UI_FLAG_LOW_PROFILE} instead.
3329 public static final int STATUS_BAR_HIDDEN = SYSTEM_UI_FLAG_LOW_PROFILE;
3332 * @deprecated Use {@link #SYSTEM_UI_FLAG_VISIBLE} instead.
3335 public static final int STATUS_BAR_VISIBLE = SYSTEM_UI_FLAG_VISIBLE;
3340 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked
3341 * out of the public fields to keep the undefined bits out of the developer's way.
3343 * Flag to make the status bar not expandable. Unless you also
3344 * set {@link #STATUS_BAR_DISABLE_NOTIFICATION_ICONS}, new notifications will continue to show.
3346 public static final int STATUS_BAR_DISABLE_EXPAND = 0x00010000;
3351 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked
3352 * out of the public fields to keep the undefined bits out of the developer's way.
3354 * Flag to hide notification icons and scrolling ticker text.
3356 public static final int STATUS_BAR_DISABLE_NOTIFICATION_ICONS = 0x00020000;
3361 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked
3362 * out of the public fields to keep the undefined bits out of the developer's way.
3364 * Flag to disable incoming notification alerts. This will not block
3365 * icons, but it will block sound, vibrating and other visual or aural notifications.
3367 public static final int STATUS_BAR_DISABLE_NOTIFICATION_ALERTS = 0x00040000;
3372 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked
3373 * out of the public fields to keep the undefined bits out of the developer's way.
3375 * Flag to hide only the scrolling ticker. Note that
3376 * {@link #STATUS_BAR_DISABLE_NOTIFICATION_ICONS} implies
3377 * {@link #STATUS_BAR_DISABLE_NOTIFICATION_TICKER}.
3379 public static final int STATUS_BAR_DISABLE_NOTIFICATION_TICKER = 0x00080000;
3384 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked
3385 * out of the public fields to keep the undefined bits out of the developer's way.
3387 * Flag to hide the center system info area.
3389 public static final int STATUS_BAR_DISABLE_SYSTEM_INFO = 0x00100000;
3394 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked
3395 * out of the public fields to keep the undefined bits out of the developer's way.
3397 * Flag to hide only the home button. Don't use this
3398 * unless you're a special part of the system UI (i.e., setup wizard, keyguard).
3400 public static final int STATUS_BAR_DISABLE_HOME = 0x00200000;
3405 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked
3406 * out of the public fields to keep the undefined bits out of the developer's way.
3408 * Flag to hide only the back button. Don't use this
3409 * unless you're a special part of the system UI (i.e., setup wizard, keyguard).
3411 public static final int STATUS_BAR_DISABLE_BACK = 0x00400000;
3416 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked
3417 * out of the public fields to keep the undefined bits out of the developer's way.
3419 * Flag to hide only the clock. You might use this if your activity has
3420 * its own clock making the status bar's clock redundant.
3422 public static final int STATUS_BAR_DISABLE_CLOCK = 0x00800000;
3427 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked
3428 * out of the public fields to keep the undefined bits out of the developer's way.
3430 * Flag to hide only the recent apps button. Don't use this
3431 * unless you're a special part of the system UI (i.e., setup wizard, keyguard).
3433 public static final int STATUS_BAR_DISABLE_RECENT = 0x01000000;
3438 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked
3439 * out of the public fields to keep the undefined bits out of the developer's way.
3441 * Flag to disable the global search gesture. Don't use this
3442 * unless you're a special part of the system UI (i.e., setup wizard, keyguard).
3444 public static final int STATUS_BAR_DISABLE_SEARCH = 0x02000000;
3449 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked
3450 * out of the public fields to keep the undefined bits out of the developer's way.
3452 * Flag to specify that the status bar is displayed in transient mode.
3454 public static final int STATUS_BAR_TRANSIENT = 0x04000000;
3459 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked
3460 * out of the public fields to keep the undefined bits out of the developer's way.
3462 * Flag to specify that the navigation bar is displayed in transient mode.
3464 public static final int NAVIGATION_BAR_TRANSIENT = 0x08000000;
3469 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked
3470 * out of the public fields to keep the undefined bits out of the developer's way.
3472 * Flag to specify that the hidden status bar would like to be shown.
3474 public static final int STATUS_BAR_UNHIDE = 0x10000000;
3479 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked
3480 * out of the public fields to keep the undefined bits out of the developer's way.
3482 * Flag to specify that the hidden navigation bar would like to be shown.
3484 public static final int NAVIGATION_BAR_UNHIDE = 0x20000000;
3489 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked
3490 * out of the public fields to keep the undefined bits out of the developer's way.
3492 * Flag to specify that the status bar is displayed in translucent mode.
3494 public static final int STATUS_BAR_TRANSLUCENT = 0x40000000;
3499 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked
3500 * out of the public fields to keep the undefined bits out of the developer's way.
3502 * Flag to specify that the navigation bar is displayed in translucent mode.
3504 public static final int NAVIGATION_BAR_TRANSLUCENT = 0x80000000;
3509 * Makes navigation bar transparent (but not the status bar).
3511 public static final int NAVIGATION_BAR_TRANSPARENT = 0x00008000;
3516 * Makes status bar transparent (but not the navigation bar).
3518 public static final int STATUS_BAR_TRANSPARENT = 0x00000008;
3523 * Makes both status bar and navigation bar transparent.
3525 public static final int SYSTEM_UI_TRANSPARENT = NAVIGATION_BAR_TRANSPARENT
3526 | STATUS_BAR_TRANSPARENT;
3531 public static final int PUBLIC_STATUS_BAR_VISIBILITY_MASK = 0x00003FF7;
3534 * These are the system UI flags that can be cleared by events outside
3535 * of an application. Currently this is just the ability to tap on the
3536 * screen while hiding the navigation bar to have it return.
3539 public static final int SYSTEM_UI_CLEARABLE_FLAGS =
3540 SYSTEM_UI_FLAG_LOW_PROFILE | SYSTEM_UI_FLAG_HIDE_NAVIGATION
3541 | SYSTEM_UI_FLAG_FULLSCREEN;
3544 * Flags that can impact the layout in relation to system UI.
3546 public static final int SYSTEM_UI_LAYOUT_FLAGS =
3547 SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
3548 | SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
3551 @IntDef(flag = true,
3552 value = { FIND_VIEWS_WITH_TEXT, FIND_VIEWS_WITH_CONTENT_DESCRIPTION })
3553 @Retention(RetentionPolicy.SOURCE)
3554 public @interface FindViewFlags {}
3557 * Find views that render the specified text.
3559 * @see #findViewsWithText(ArrayList, CharSequence, int)
3561 public static final int FIND_VIEWS_WITH_TEXT = 0x00000001;
3564 * Find find views that contain the specified content description.
3566 * @see #findViewsWithText(ArrayList, CharSequence, int)
3568 public static final int FIND_VIEWS_WITH_CONTENT_DESCRIPTION = 0x00000002;
3571 * Find views that contain {@link AccessibilityNodeProvider}. Such
3572 * a View is a root of virtual view hierarchy and may contain the searched
3573 * text. If this flag is set Views with providers are automatically
3574 * added and it is a responsibility of the client to call the APIs of
3575 * the provider to determine whether the virtual tree rooted at this View
3576 * contains the text, i.e. getting the list of {@link AccessibilityNodeInfo}s
3577 * representing the virtual views with this text.
3579 * @see #findViewsWithText(ArrayList, CharSequence, int)
3583 public static final int FIND_VIEWS_WITH_ACCESSIBILITY_NODE_PROVIDERS = 0x00000004;
3586 * The undefined cursor position.
3590 public static final int ACCESSIBILITY_CURSOR_POSITION_UNDEFINED = -1;
3593 * Indicates that the screen has changed state and is now off.
3595 * @see #onScreenStateChanged(int)
3597 public static final int SCREEN_STATE_OFF = 0x0;
3600 * Indicates that the screen has changed state and is now on.
3602 * @see #onScreenStateChanged(int)
3604 public static final int SCREEN_STATE_ON = 0x1;
3607 * Indicates no axis of view scrolling.
3609 public static final int SCROLL_AXIS_NONE = 0;
3612 * Indicates scrolling along the horizontal axis.
3614 public static final int SCROLL_AXIS_HORIZONTAL = 1 << 0;
3617 * Indicates scrolling along the vertical axis.
3619 public static final int SCROLL_AXIS_VERTICAL = 1 << 1;
3622 * Controls the over-scroll mode for this view.
3623 * See {@link #overScrollBy(int, int, int, int, int, int, int, int, boolean)},
3624 * {@link #OVER_SCROLL_ALWAYS}, {@link #OVER_SCROLL_IF_CONTENT_SCROLLS},
3625 * and {@link #OVER_SCROLL_NEVER}.
3627 private int mOverScrollMode;
3630 * The parent this view is attached to.
3635 protected ViewParent mParent;
3640 AttachInfo mAttachInfo;
3645 @ViewDebug.ExportedProperty(flagMapping = {
3646 @ViewDebug.FlagToString(mask = PFLAG_FORCE_LAYOUT, equals = PFLAG_FORCE_LAYOUT,
3647 name = "FORCE_LAYOUT"),
3648 @ViewDebug.FlagToString(mask = PFLAG_LAYOUT_REQUIRED, equals = PFLAG_LAYOUT_REQUIRED,
3649 name = "LAYOUT_REQUIRED"),
3650 @ViewDebug.FlagToString(mask = PFLAG_DRAWING_CACHE_VALID, equals = PFLAG_DRAWING_CACHE_VALID,
3651 name = "DRAWING_CACHE_INVALID", outputIf = false),
3652 @ViewDebug.FlagToString(mask = PFLAG_DRAWN, equals = PFLAG_DRAWN, name = "DRAWN", outputIf = true),
3653 @ViewDebug.FlagToString(mask = PFLAG_DRAWN, equals = PFLAG_DRAWN, name = "NOT_DRAWN", outputIf = false),
3654 @ViewDebug.FlagToString(mask = PFLAG_DIRTY_MASK, equals = PFLAG_DIRTY_OPAQUE, name = "DIRTY_OPAQUE"),
3655 @ViewDebug.FlagToString(mask = PFLAG_DIRTY_MASK, equals = PFLAG_DIRTY, name = "DIRTY")
3656 }, formatToHexString = true)
3659 public int mPrivateFlags;
3664 * This view's request for the visibility of the status bar.
3667 @ViewDebug.ExportedProperty(flagMapping = {
3668 @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_LOW_PROFILE,
3669 equals = SYSTEM_UI_FLAG_LOW_PROFILE,
3670 name = "SYSTEM_UI_FLAG_LOW_PROFILE", outputIf = true),
3671 @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_HIDE_NAVIGATION,
3672 equals = SYSTEM_UI_FLAG_HIDE_NAVIGATION,
3673 name = "SYSTEM_UI_FLAG_HIDE_NAVIGATION", outputIf = true),
3674 @ViewDebug.FlagToString(mask = PUBLIC_STATUS_BAR_VISIBILITY_MASK,
3675 equals = SYSTEM_UI_FLAG_VISIBLE,
3676 name = "SYSTEM_UI_FLAG_VISIBLE", outputIf = true)
3677 }, formatToHexString = true)
3678 int mSystemUiVisibility;
3681 * Reference count for transient state.
3682 * @see #setHasTransientState(boolean)
3684 int mTransientStateCount = 0;
3687 * Count of how many windows this view has been attached to.
3689 int mWindowAttachCount;
3692 * The layout parameters associated with this view and used by the parent
3693 * {@link android.view.ViewGroup} to determine how this view should be
3697 protected ViewGroup.LayoutParams mLayoutParams;
3700 * The view flags hold various views states.
3703 @ViewDebug.ExportedProperty(formatToHexString = true)
3706 static class TransformationInfo {
3708 * The transform matrix for the View. This transform is calculated internally
3709 * based on the translation, rotation, and scale properties.
3711 * Do *not* use this variable directly; instead call getMatrix(), which will
3712 * load the value from the View's RenderNode.
3714 private final Matrix mMatrix = new Matrix();
3717 * The inverse transform matrix for the View. This transform is calculated
3718 * internally based on the translation, rotation, and scale properties.
3720 * Do *not* use this variable directly; instead call getInverseMatrix(),
3721 * which will load the value from the View's RenderNode.
3723 private Matrix mInverseMatrix;
3726 * The opacity of the View. This is a value from 0 to 1, where 0 means
3727 * completely transparent and 1 means completely opaque.
3729 @ViewDebug.ExportedProperty
3733 * The opacity of the view as manipulated by the Fade transition. This is a hidden
3734 * property only used by transitions, which is composited with the other alpha
3735 * values to calculate the final visual alpha value.
3737 float mTransitionAlpha = 1f;
3741 public TransformationInfo mTransformationInfo;
3744 * Current clip bounds. to which all drawing of this view are constrained.
3746 Rect mClipBounds = null;
3748 private boolean mLastIsOpaque;
3751 * The distance in pixels from the left edge of this view's parent
3752 * to the left edge of this view.
3755 @ViewDebug.ExportedProperty(category = "layout")
3756 protected int mLeft;
3758 * The distance in pixels from the left edge of this view's parent
3759 * to the right edge of this view.
3762 @ViewDebug.ExportedProperty(category = "layout")
3763 protected int mRight;
3765 * The distance in pixels from the top edge of this view's parent
3766 * to the top edge of this view.
3769 @ViewDebug.ExportedProperty(category = "layout")
3772 * The distance in pixels from the top edge of this view's parent
3773 * to the bottom edge of this view.
3776 @ViewDebug.ExportedProperty(category = "layout")
3777 protected int mBottom;
3780 * The offset, in pixels, by which the content of this view is scrolled
3784 @ViewDebug.ExportedProperty(category = "scrolling")
3785 protected int mScrollX;
3787 * The offset, in pixels, by which the content of this view is scrolled
3791 @ViewDebug.ExportedProperty(category = "scrolling")
3792 protected int mScrollY;
3795 * The left padding in pixels, that is the distance in pixels between the
3796 * left edge of this view and the left edge of its content.
3799 @ViewDebug.ExportedProperty(category = "padding")
3800 protected int mPaddingLeft = 0;
3802 * The right padding in pixels, that is the distance in pixels between the
3803 * right edge of this view and the right edge of its content.
3806 @ViewDebug.ExportedProperty(category = "padding")
3807 protected int mPaddingRight = 0;
3809 * The top padding in pixels, that is the distance in pixels between the
3810 * top edge of this view and the top edge of its content.
3813 @ViewDebug.ExportedProperty(category = "padding")
3814 protected int mPaddingTop;
3816 * The bottom padding in pixels, that is the distance in pixels between the
3817 * bottom edge of this view and the bottom edge of its content.
3820 @ViewDebug.ExportedProperty(category = "padding")
3821 protected int mPaddingBottom;
3824 * The layout insets in pixels, that is the distance in pixels between the
3825 * visible edges of this view its bounds.
3827 private Insets mLayoutInsets;
3830 * Briefly describes the view and is primarily used for accessibility support.
3832 private CharSequence mContentDescription;
3835 * Specifies the id of a view for which this view serves as a label for
3836 * accessibility purposes.
3838 private int mLabelForId = View.NO_ID;
3841 * Predicate for matching labeled view id with its label for
3842 * accessibility purposes.
3844 private MatchLabelForPredicate mMatchLabelForPredicate;
3847 * Specifies a view before which this one is visited in accessibility traversal.
3849 private int mAccessibilityTraversalBeforeId = NO_ID;
3852 * Specifies a view after which this one is visited in accessibility traversal.
3854 private int mAccessibilityTraversalAfterId = NO_ID;
3857 * Predicate for matching a view by its id.
3859 private MatchIdPredicate mMatchIdPredicate;
3862 * Cache the paddingRight set by the user to append to the scrollbar's size.
3866 @ViewDebug.ExportedProperty(category = "padding")
3867 protected int mUserPaddingRight;
3870 * Cache the paddingBottom set by the user to append to the scrollbar's size.
3874 @ViewDebug.ExportedProperty(category = "padding")
3875 protected int mUserPaddingBottom;
3878 * Cache the paddingLeft set by the user to append to the scrollbar's size.
3882 @ViewDebug.ExportedProperty(category = "padding")
3883 protected int mUserPaddingLeft;
3886 * Cache the paddingStart set by the user to append to the scrollbar's size.
3889 @ViewDebug.ExportedProperty(category = "padding")
3890 int mUserPaddingStart;
3893 * Cache the paddingEnd set by the user to append to the scrollbar's size.
3896 @ViewDebug.ExportedProperty(category = "padding")
3897 int mUserPaddingEnd;
3900 * Cache initial left padding.
3904 int mUserPaddingLeftInitial;
3907 * Cache initial right padding.
3911 int mUserPaddingRightInitial;
3914 * Default undefined padding
3916 private static final int UNDEFINED_PADDING = Integer.MIN_VALUE;
3919 * Cache if a left padding has been defined
3921 private boolean mLeftPaddingDefined = false;
3924 * Cache if a right padding has been defined
3926 private boolean mRightPaddingDefined = false;
3931 int mOldWidthMeasureSpec = Integer.MIN_VALUE;
3935 int mOldHeightMeasureSpec = Integer.MIN_VALUE;
3937 private LongSparseLongArray mMeasureCache;
3939 @ViewDebug.ExportedProperty(deepExport = true, prefix = "bg_")
3940 private Drawable mBackground;
3941 private TintInfo mBackgroundTint;
3943 @ViewDebug.ExportedProperty(deepExport = true, prefix = "fg_")
3944 private ForegroundInfo mForegroundInfo;
3946 private Drawable mScrollIndicatorDrawable;
3949 * RenderNode used for backgrounds.
3951 * When non-null and valid, this is expected to contain an up-to-date copy
3952 * of the background drawable. It is cleared on temporary detach, and reset
3955 private RenderNode mBackgroundRenderNode;
3957 private int mBackgroundResource;
3958 private boolean mBackgroundSizeChanged;
3960 /** The default focus highlight.
3961 * @see #mDefaultFocusHighlightEnabled
3962 * @see Drawable#hasFocusStateSpecified()
3964 private Drawable mDefaultFocusHighlight;
3965 private Drawable mDefaultFocusHighlightCache;
3966 private boolean mDefaultFocusHighlightSizeChanged;
3968 * True if the default focus highlight is needed on the target device.
3970 private static boolean sUseDefaultFocusHighlight;
3972 private String mTransitionName;
3974 static class TintInfo {
3975 ColorStateList mTintList;
3976 PorterDuff.Mode mTintMode;
3977 boolean mHasTintMode;
3978 boolean mHasTintList;
3981 private static class ForegroundInfo {
3982 private Drawable mDrawable;
3983 private TintInfo mTintInfo;
3984 private int mGravity = Gravity.FILL;
3985 private boolean mInsidePadding = true;
3986 private boolean mBoundsChanged = true;
3987 private final Rect mSelfBounds = new Rect();
3988 private final Rect mOverlayBounds = new Rect();
3991 static class ListenerInfo {
3993 * Listener used to dispatch focus change events.
3994 * This field should be made private, so it is hidden from the SDK.
3997 protected OnFocusChangeListener mOnFocusChangeListener;
4000 * Listeners for layout change events.
4002 private ArrayList<OnLayoutChangeListener> mOnLayoutChangeListeners;
4004 protected OnScrollChangeListener mOnScrollChangeListener;
4007 * Listeners for attach events.
4009 private CopyOnWriteArrayList<OnAttachStateChangeListener> mOnAttachStateChangeListeners;
4012 * Listener used to dispatch click events.
4013 * This field should be made private, so it is hidden from the SDK.
4016 public OnClickListener mOnClickListener;
4019 * Listener used to dispatch long click events.
4020 * This field should be made private, so it is hidden from the SDK.
4023 protected OnLongClickListener mOnLongClickListener;
4026 * Listener used to dispatch context click events. This field should be made private, so it
4027 * is hidden from the SDK.
4030 protected OnContextClickListener mOnContextClickListener;
4033 * Listener used to build the context menu.
4034 * This field should be made private, so it is hidden from the SDK.
4037 protected OnCreateContextMenuListener mOnCreateContextMenuListener;
4039 private OnKeyListener mOnKeyListener;
4041 private OnTouchListener mOnTouchListener;
4043 private OnHoverListener mOnHoverListener;
4045 private OnGenericMotionListener mOnGenericMotionListener;
4047 private OnDragListener mOnDragListener;
4049 private OnSystemUiVisibilityChangeListener mOnSystemUiVisibilityChangeListener;
4051 OnApplyWindowInsetsListener mOnApplyWindowInsetsListener;
4053 OnCapturedPointerListener mOnCapturedPointerListener;
4056 ListenerInfo mListenerInfo;
4058 private static class TooltipInfo {
4060 * Text to be displayed in a tooltip popup.
4063 CharSequence mTooltipText;
4066 * View-relative position of the tooltip anchor point.
4072 * The tooltip popup.
4075 TooltipPopup mTooltipPopup;
4078 * Set to true if the tooltip was shown as a result of a long click.
4080 boolean mTooltipFromLongClick;
4083 * Keep these Runnables so that they can be used to reschedule.
4085 Runnable mShowTooltipRunnable;
4086 Runnable mHideTooltipRunnable;
4089 TooltipInfo mTooltipInfo;
4091 // Temporary values used to hold (x,y) coordinates when delegating from the
4092 // two-arg performLongClick() method to the legacy no-arg version.
4093 private float mLongClickX = Float.NaN;
4094 private float mLongClickY = Float.NaN;
4097 * The application environment this view lives in.
4098 * This field should be made private, so it is hidden from the SDK.
4101 @ViewDebug.ExportedProperty(deepExport = true)
4102 protected Context mContext;
4104 private final Resources mResources;
4106 private ScrollabilityCache mScrollCache;
4108 private int[] mDrawableState = null;
4110 ViewOutlineProvider mOutlineProvider = ViewOutlineProvider.BACKGROUND;
4113 * Animator that automatically runs based on state changes.
4115 private StateListAnimator mStateListAnimator;
4118 * When this view has focus and the next focus is {@link #FOCUS_LEFT},
4119 * the user may specify which view to go to next.
4121 private int mNextFocusLeftId = View.NO_ID;
4124 * When this view has focus and the next focus is {@link #FOCUS_RIGHT},
4125 * the user may specify which view to go to next.
4127 private int mNextFocusRightId = View.NO_ID;
4130 * When this view has focus and the next focus is {@link #FOCUS_UP},
4131 * the user may specify which view to go to next.
4133 private int mNextFocusUpId = View.NO_ID;
4136 * When this view has focus and the next focus is {@link #FOCUS_DOWN},
4137 * the user may specify which view to go to next.
4139 private int mNextFocusDownId = View.NO_ID;
4142 * When this view has focus and the next focus is {@link #FOCUS_FORWARD},
4143 * the user may specify which view to go to next.
4145 int mNextFocusForwardId = View.NO_ID;
4148 * User-specified next keyboard navigation cluster in the {@link #FOCUS_FORWARD} direction.
4150 * @see #findUserSetNextKeyboardNavigationCluster(View, int)
4152 int mNextClusterForwardId = View.NO_ID;
4155 * Whether this View should use a default focus highlight when it gets focused but doesn't
4156 * have {@link android.R.attr#state_focused} defined in its background.
4158 boolean mDefaultFocusHighlightEnabled = true;
4160 private CheckForLongPress mPendingCheckForLongPress;
4161 private CheckForTap mPendingCheckForTap = null;
4162 private PerformClick mPerformClick;
4163 private SendViewScrolledAccessibilityEvent mSendViewScrolledAccessibilityEvent;
4165 private UnsetPressedState mUnsetPressedState;
4168 * Whether the long press's action has been invoked. The tap's action is invoked on the
4169 * up event while a long press is invoked as soon as the long press duration is reached, so
4170 * a long press could be performed before the tap is checked, in which case the tap's action
4171 * should not be invoked.
4173 private boolean mHasPerformedLongPress;
4176 * Whether a context click button is currently pressed down. This is true when the stylus is
4177 * touching the screen and the primary button has been pressed, or if a mouse's right button is
4178 * pressed. This is false once the button is released or if the stylus has been lifted.
4180 private boolean mInContextButtonPress;
4183 * Whether the next up event should be ignored for the purposes of gesture recognition. This is
4184 * true after a stylus button press has occured, when the next up event should not be recognized
4187 private boolean mIgnoreNextUpEvent;
4190 * The minimum height of the view. We'll try our best to have the height
4191 * of this view to at least this amount.
4193 @ViewDebug.ExportedProperty(category = "measurement")
4194 private int mMinHeight;
4197 * The minimum width of the view. We'll try our best to have the width
4198 * of this view to at least this amount.
4200 @ViewDebug.ExportedProperty(category = "measurement")
4201 private int mMinWidth;
4204 * The delegate to handle touch events that are physically in this view
4205 * but should be handled by another view.
4207 private TouchDelegate mTouchDelegate = null;
4210 * Solid color to use as a background when creating the drawing cache. Enables
4211 * the cache to use 16 bit bitmaps instead of 32 bit.
4213 private int mDrawingCacheBackgroundColor = 0;
4216 * Special tree observer used when mAttachInfo is null.
4218 private ViewTreeObserver mFloatingTreeObserver;
4221 * Cache the touch slop from the context that created the view.
4223 private int mTouchSlop;
4226 * Object that handles automatic animation of view properties.
4228 private ViewPropertyAnimator mAnimator = null;
4231 * List of registered FrameMetricsObservers.
4233 private ArrayList<FrameMetricsObserver> mFrameMetricsObservers;
4236 * Flag indicating that a drag can cross window boundaries. When
4237 * {@link #startDragAndDrop(ClipData, DragShadowBuilder, Object, int)} is called
4238 * with this flag set, all visible applications with targetSdkVersion >=
4239 * {@link android.os.Build.VERSION_CODES#N API 24} will be able to participate
4240 * in the drag operation and receive the dragged content.
4242 * <p>If this is the only flag set, then the drag recipient will only have access to text data
4243 * and intents contained in the {@link ClipData} object. Access to URIs contained in the
4244 * {@link ClipData} is determined by other DRAG_FLAG_GLOBAL_* flags</p>
4246 public static final int DRAG_FLAG_GLOBAL = 1 << 8; // 256
4249 * When this flag is used with {@link #DRAG_FLAG_GLOBAL}, the drag recipient will be able to
4250 * request read access to the content URI(s) contained in the {@link ClipData} object.
4251 * @see android.content.Intent#FLAG_GRANT_READ_URI_PERMISSION
4253 public static final int DRAG_FLAG_GLOBAL_URI_READ = Intent.FLAG_GRANT_READ_URI_PERMISSION;
4256 * When this flag is used with {@link #DRAG_FLAG_GLOBAL}, the drag recipient will be able to
4257 * request write access to the content URI(s) contained in the {@link ClipData} object.
4258 * @see android.content.Intent#FLAG_GRANT_WRITE_URI_PERMISSION
4260 public static final int DRAG_FLAG_GLOBAL_URI_WRITE = Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
4263 * When this flag is used with {@link #DRAG_FLAG_GLOBAL_URI_READ} and/or {@link
4264 * #DRAG_FLAG_GLOBAL_URI_WRITE}, the URI permission grant can be persisted across device
4265 * reboots until explicitly revoked with
4266 * {@link android.content.Context#revokeUriPermission(Uri, int)} Context.revokeUriPermission}.
4267 * @see android.content.Intent#FLAG_GRANT_PERSISTABLE_URI_PERMISSION
4269 public static final int DRAG_FLAG_GLOBAL_PERSISTABLE_URI_PERMISSION =
4270 Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION;
4273 * When this flag is used with {@link #DRAG_FLAG_GLOBAL_URI_READ} and/or {@link
4274 * #DRAG_FLAG_GLOBAL_URI_WRITE}, the URI permission grant applies to any URI that is a prefix
4275 * match against the original granted URI.
4276 * @see android.content.Intent#FLAG_GRANT_PREFIX_URI_PERMISSION
4278 public static final int DRAG_FLAG_GLOBAL_PREFIX_URI_PERMISSION =
4279 Intent.FLAG_GRANT_PREFIX_URI_PERMISSION;
4282 * Flag indicating that the drag shadow will be opaque. When
4283 * {@link #startDragAndDrop(ClipData, DragShadowBuilder, Object, int)} is called
4284 * with this flag set, the drag shadow will be opaque, otherwise, it will be semitransparent.
4286 public static final int DRAG_FLAG_OPAQUE = 1 << 9;
4289 * Vertical scroll factor cached by {@link #getVerticalScrollFactor}.
4291 private float mVerticalScrollFactor;
4294 * Position of the vertical scroll bar.
4296 private int mVerticalScrollbarPosition;
4299 * Position the scroll bar at the default position as determined by the system.
4301 public static final int SCROLLBAR_POSITION_DEFAULT = 0;
4304 * Position the scroll bar along the left edge.
4306 public static final int SCROLLBAR_POSITION_LEFT = 1;
4309 * Position the scroll bar along the right edge.
4311 public static final int SCROLLBAR_POSITION_RIGHT = 2;
4314 * Indicates that the view does not have a layer.
4316 * @see #getLayerType()
4317 * @see #setLayerType(int, android.graphics.Paint)
4318 * @see #LAYER_TYPE_SOFTWARE
4319 * @see #LAYER_TYPE_HARDWARE
4321 public static final int LAYER_TYPE_NONE = 0;
4324 * <p>Indicates that the view has a software layer. A software layer is backed
4325 * by a bitmap and causes the view to be rendered using Android's software
4326 * rendering pipeline, even if hardware acceleration is enabled.</p>
4328 * <p>Software layers have various usages:</p>
4329 * <p>When the application is not using hardware acceleration, a software layer
4330 * is useful to apply a specific color filter and/or blending mode and/or
4331 * translucency to a view and all its children.</p>
4332 * <p>When the application is using hardware acceleration, a software layer
4333 * is useful to render drawing primitives not supported by the hardware
4334 * accelerated pipeline. It can also be used to cache a complex view tree
4335 * into a texture and reduce the complexity of drawing operations. For instance,
4336 * when animating a complex view tree with a translation, a software layer can
4337 * be used to render the view tree only once.</p>
4338 * <p>Software layers should be avoided when the affected view tree updates
4339 * often. Every update will require to re-render the software layer, which can
4340 * potentially be slow (particularly when hardware acceleration is turned on
4341 * since the layer will have to be uploaded into a hardware texture after every
4344 * @see #getLayerType()
4345 * @see #setLayerType(int, android.graphics.Paint)
4346 * @see #LAYER_TYPE_NONE
4347 * @see #LAYER_TYPE_HARDWARE
4349 public static final int LAYER_TYPE_SOFTWARE = 1;
4352 * <p>Indicates that the view has a hardware layer. A hardware layer is backed
4353 * by a hardware specific texture (generally Frame Buffer Objects or FBO on
4354 * OpenGL hardware) and causes the view to be rendered using Android's hardware
4355 * rendering pipeline, but only if hardware acceleration is turned on for the
4356 * view hierarchy. When hardware acceleration is turned off, hardware layers
4357 * behave exactly as {@link #LAYER_TYPE_SOFTWARE software layers}.</p>
4359 * <p>A hardware layer is useful to apply a specific color filter and/or
4360 * blending mode and/or translucency to a view and all its children.</p>
4361 * <p>A hardware layer can be used to cache a complex view tree into a
4362 * texture and reduce the complexity of drawing operations. For instance,
4363 * when animating a complex view tree with a translation, a hardware layer can
4364 * be used to render the view tree only once.</p>
4365 * <p>A hardware layer can also be used to increase the rendering quality when
4366 * rotation transformations are applied on a view. It can also be used to
4367 * prevent potential clipping issues when applying 3D transforms on a view.</p>
4369 * @see #getLayerType()
4370 * @see #setLayerType(int, android.graphics.Paint)
4371 * @see #LAYER_TYPE_NONE
4372 * @see #LAYER_TYPE_SOFTWARE
4374 public static final int LAYER_TYPE_HARDWARE = 2;
4376 @ViewDebug.ExportedProperty(category = "drawing", mapping = {
4377 @ViewDebug.IntToString(from = LAYER_TYPE_NONE, to = "NONE"),
4378 @ViewDebug.IntToString(from = LAYER_TYPE_SOFTWARE, to = "SOFTWARE"),
4379 @ViewDebug.IntToString(from = LAYER_TYPE_HARDWARE, to = "HARDWARE")
4381 int mLayerType = LAYER_TYPE_NONE;
4385 * Set to true when drawing cache is enabled and cannot be created.
4389 public boolean mCachingFailed;
4390 private Bitmap mDrawingCache;
4391 private Bitmap mUnscaledDrawingCache;
4394 * RenderNode holding View properties, potentially holding a DisplayList of View content.
4396 * When non-null and valid, this is expected to contain an up-to-date copy
4397 * of the View content. Its DisplayList content is cleared on temporary detach and reset on
4400 final RenderNode mRenderNode;
4403 * Set to true when the view is sending hover accessibility events because it
4404 * is the innermost hovered view.
4406 private boolean mSendingHoverAccessibilityEvents;
4409 * Delegate for injecting accessibility functionality.
4411 AccessibilityDelegate mAccessibilityDelegate;
4414 * The view's overlay layer. Developers get a reference to the overlay via getOverlay()
4415 * and add/remove objects to/from the overlay directly through the Overlay methods.
4417 ViewOverlay mOverlay;
4420 * The currently active parent view for receiving delegated nested scrolling events.
4421 * This is set by {@link #startNestedScroll(int)} during a touch interaction and cleared
4422 * by {@link #stopNestedScroll()} at the same point where we clear
4423 * requestDisallowInterceptTouchEvent.
4425 private ViewParent mNestedScrollingParent;
4428 * Consistency verifier for debugging purposes.
4431 protected final InputEventConsistencyVerifier mInputEventConsistencyVerifier =
4432 InputEventConsistencyVerifier.isInstrumentationEnabled() ?
4433 new InputEventConsistencyVerifier(this, 0) : null;
4435 private static final AtomicInteger sNextGeneratedId = new AtomicInteger(1);
4437 private int[] mTempNestedScrollConsumed;
4440 * An overlay is going to draw this View instead of being drawn as part of this
4441 * View's parent. mGhostView is the View in the Overlay that must be invalidated
4442 * when this view is invalidated.
4444 GhostView mGhostView;
4447 * Holds pairs of adjacent attribute data: attribute name followed by its value.
4450 @ViewDebug.ExportedProperty(category = "attributes", hasAdjacentMapping = true)
4451 public String[] mAttributes;
4454 * Maps a Resource id to its name.
4456 private static SparseArray<String> mAttributeMap;
4459 * Queue of pending runnables. Used to postpone calls to post() until this
4460 * view is attached and has a handler.
4462 private HandlerActionQueue mRunQueue;
4465 * The pointer icon when the mouse hovers on this view. The default is null.
4467 private PointerIcon mPointerIcon;
4472 String mStartActivityRequestWho;
4475 private RoundScrollbarRenderer mRoundScrollbarRenderer;
4477 /** Used to delay visibility updates sent to the autofill manager */
4478 private Handler mVisibilityChangeForAutofillHandler;
4481 * Simple constructor to use when creating a view from code.
4483 * @param context The Context the view is running in, through which it can
4484 * access the current theme, resources, etc.
4486 public View(Context context) {
4488 mResources = context != null ? context.getResources() : null;
4489 mViewFlags = SOUND_EFFECTS_ENABLED | HAPTIC_FEEDBACK_ENABLED | FOCUSABLE_AUTO;
4490 // Set some flags defaults
4492 (LAYOUT_DIRECTION_DEFAULT << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT) |
4493 (TEXT_DIRECTION_DEFAULT << PFLAG2_TEXT_DIRECTION_MASK_SHIFT) |
4494 (PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT) |
4495 (TEXT_ALIGNMENT_DEFAULT << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT) |
4496 (PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT) |
4497 (IMPORTANT_FOR_ACCESSIBILITY_DEFAULT << PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT);
4498 mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
4499 setOverScrollMode(OVER_SCROLL_IF_CONTENT_SCROLLS);
4500 mUserPaddingStart = UNDEFINED_PADDING;
4501 mUserPaddingEnd = UNDEFINED_PADDING;
4502 mRenderNode = RenderNode.create(getClass().getName(), this);
4504 if (!sCompatibilityDone && context != null) {
4505 final int targetSdkVersion = context.getApplicationInfo().targetSdkVersion;
4507 // Older apps may need this compatibility hack for measurement.
4508 sUseBrokenMakeMeasureSpec = targetSdkVersion <= Build.VERSION_CODES.JELLY_BEAN_MR1;
4510 // Older apps expect onMeasure() to always be called on a layout pass, regardless
4511 // of whether a layout was requested on that View.
4512 sIgnoreMeasureCache = targetSdkVersion < Build.VERSION_CODES.KITKAT;
4514 Canvas.sCompatibilityRestore = targetSdkVersion < Build.VERSION_CODES.M;
4515 Canvas.sCompatibilitySetBitmap = targetSdkVersion < Build.VERSION_CODES.O;
4517 // In M and newer, our widgets can pass a "hint" value in the size
4518 // for UNSPECIFIED MeasureSpecs. This lets child views of scrolling containers
4519 // know what the expected parent size is going to be, so e.g. list items can size
4520 // themselves at 1/3 the size of their container. It breaks older apps though,
4521 // specifically apps that use some popular open source libraries.
4522 sUseZeroUnspecifiedMeasureSpec = targetSdkVersion < Build.VERSION_CODES.M;
4524 // Old versions of the platform would give different results from
4525 // LinearLayout measurement passes using EXACTLY and non-EXACTLY
4526 // modes, so we always need to run an additional EXACTLY pass.
4527 sAlwaysRemeasureExactly = targetSdkVersion <= Build.VERSION_CODES.M;
4529 // Prior to N, layout params could change without requiring a
4530 // subsequent call to setLayoutParams() and they would usually
4531 // work. Partial layout breaks this assumption.
4532 sLayoutParamsAlwaysChanged = targetSdkVersion <= Build.VERSION_CODES.M;
4534 // Prior to N, TextureView would silently ignore calls to setBackground/setForeground.
4535 // On N+, we throw, but that breaks compatibility with apps that use these methods.
4536 sTextureViewIgnoresDrawableSetters = targetSdkVersion <= Build.VERSION_CODES.M;
4538 // Prior to N, we would drop margins in LayoutParam conversions. The fix triggers bugs
4539 // in apps so we target check it to avoid breaking existing apps.
4540 sPreserveMarginParamsInLayoutParamConversion =
4541 targetSdkVersion >= Build.VERSION_CODES.N;
4543 sCascadedDragDrop = targetSdkVersion < Build.VERSION_CODES.N;
4545 sHasFocusableExcludeAutoFocusable = targetSdkVersion < Build.VERSION_CODES.O;
4547 sAutoFocusableOffUIThreadWontNotifyParents = targetSdkVersion < Build.VERSION_CODES.O;
4549 sUseDefaultFocusHighlight = context.getResources().getBoolean(
4550 com.android.internal.R.bool.config_useDefaultFocusHighlight);
4552 sCompatibilityDone = true;
4557 * Constructor that is called when inflating a view from XML. This is called
4558 * when a view is being constructed from an XML file, supplying attributes
4559 * that were specified in the XML file. This version uses a default style of
4560 * 0, so the only attribute values applied are those in the Context's Theme
4561 * and the given AttributeSet.
4564 * The method onFinishInflate() will be called after all children have been
4567 * @param context The Context the view is running in, through which it can
4568 * access the current theme, resources, etc.
4569 * @param attrs The attributes of the XML tag that is inflating the view.
4570 * @see #View(Context, AttributeSet, int)
4572 public View(Context context, @Nullable AttributeSet attrs) {
4573 this(context, attrs, 0);
4577 * Perform inflation from XML and apply a class-specific base style from a
4578 * theme attribute. This constructor of View allows subclasses to use their
4579 * own base style when they are inflating. For example, a Button class's
4580 * constructor would call this version of the super class constructor and
4581 * supply <code>R.attr.buttonStyle</code> for <var>defStyleAttr</var>; this
4582 * allows the theme's button style to modify all of the base view attributes
4583 * (in particular its background) as well as the Button class's attributes.
4585 * @param context The Context the view is running in, through which it can
4586 * access the current theme, resources, etc.
4587 * @param attrs The attributes of the XML tag that is inflating the view.
4588 * @param defStyleAttr An attribute in the current theme that contains a
4589 * reference to a style resource that supplies default values for
4590 * the view. Can be 0 to not look for defaults.
4591 * @see #View(Context, AttributeSet)
4593 public View(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
4594 this(context, attrs, defStyleAttr, 0);
4598 * Perform inflation from XML and apply a class-specific base style from a
4599 * theme attribute or style resource. This constructor of View allows
4600 * subclasses to use their own base style when they are inflating.
4602 * When determining the final value of a particular attribute, there are
4603 * four inputs that come into play:
4605 * <li>Any attribute values in the given AttributeSet.
4606 * <li>The style resource specified in the AttributeSet (named "style").
4607 * <li>The default style specified by <var>defStyleAttr</var>.
4608 * <li>The default style specified by <var>defStyleRes</var>.
4609 * <li>The base values in this theme.
4612 * Each of these inputs is considered in-order, with the first listed taking
4613 * precedence over the following ones. In other words, if in the
4614 * AttributeSet you have supplied <code><Button * textColor="#ff000000"></code>
4615 * , then the button's text will <em>always</em> be black, regardless of
4616 * what is specified in any of the styles.
4618 * @param context The Context the view is running in, through which it can
4619 * access the current theme, resources, etc.
4620 * @param attrs The attributes of the XML tag that is inflating the view.
4621 * @param defStyleAttr An attribute in the current theme that contains a
4622 * reference to a style resource that supplies default values for
4623 * the view. Can be 0 to not look for defaults.
4624 * @param defStyleRes A resource identifier of a style resource that
4625 * supplies default values for the view, used only if
4626 * defStyleAttr is 0 or can not be found in the theme. Can be 0
4627 * to not look for defaults.
4628 * @see #View(Context, AttributeSet, int)
4630 public View(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
4633 final TypedArray a = context.obtainStyledAttributes(
4634 attrs, com.android.internal.R.styleable.View, defStyleAttr, defStyleRes);
4636 if (mDebugViewAttributes) {
4637 saveAttributeData(attrs, a);
4640 Drawable background = null;
4642 int leftPadding = -1;
4643 int topPadding = -1;
4644 int rightPadding = -1;
4645 int bottomPadding = -1;
4646 int startPadding = UNDEFINED_PADDING;
4647 int endPadding = UNDEFINED_PADDING;
4650 int paddingHorizontal = -1;
4651 int paddingVertical = -1;
4653 int viewFlagValues = 0;
4654 int viewFlagMasks = 0;
4656 boolean setScrollContainer = false;
4664 float elevation = 0;
4666 float rotationX = 0;
4667 float rotationY = 0;
4670 boolean transformSet = false;
4672 int scrollbarStyle = SCROLLBARS_INSIDE_OVERLAY;
4673 int overScrollMode = mOverScrollMode;
4674 boolean initializeScrollbars = false;
4675 boolean initializeScrollIndicators = false;
4677 boolean startPaddingDefined = false;
4678 boolean endPaddingDefined = false;
4679 boolean leftPaddingDefined = false;
4680 boolean rightPaddingDefined = false;
4682 final int targetSdkVersion = context.getApplicationInfo().targetSdkVersion;
4684 // Set default values.
4685 viewFlagValues |= FOCUSABLE_AUTO;
4686 viewFlagMasks |= FOCUSABLE_AUTO;
4688 final int N = a.getIndexCount();
4689 for (int i = 0; i < N; i++) {
4690 int attr = a.getIndex(i);
4692 case com.android.internal.R.styleable.View_background:
4693 background = a.getDrawable(attr);
4695 case com.android.internal.R.styleable.View_padding:
4696 padding = a.getDimensionPixelSize(attr, -1);
4697 mUserPaddingLeftInitial = padding;
4698 mUserPaddingRightInitial = padding;
4699 leftPaddingDefined = true;
4700 rightPaddingDefined = true;
4702 case com.android.internal.R.styleable.View_paddingHorizontal:
4703 paddingHorizontal = a.getDimensionPixelSize(attr, -1);
4704 mUserPaddingLeftInitial = paddingHorizontal;
4705 mUserPaddingRightInitial = paddingHorizontal;
4706 leftPaddingDefined = true;
4707 rightPaddingDefined = true;
4709 case com.android.internal.R.styleable.View_paddingVertical:
4710 paddingVertical = a.getDimensionPixelSize(attr, -1);
4712 case com.android.internal.R.styleable.View_paddingLeft:
4713 leftPadding = a.getDimensionPixelSize(attr, -1);
4714 mUserPaddingLeftInitial = leftPadding;
4715 leftPaddingDefined = true;
4717 case com.android.internal.R.styleable.View_paddingTop:
4718 topPadding = a.getDimensionPixelSize(attr, -1);
4720 case com.android.internal.R.styleable.View_paddingRight:
4721 rightPadding = a.getDimensionPixelSize(attr, -1);
4722 mUserPaddingRightInitial = rightPadding;
4723 rightPaddingDefined = true;
4725 case com.android.internal.R.styleable.View_paddingBottom:
4726 bottomPadding = a.getDimensionPixelSize(attr, -1);
4728 case com.android.internal.R.styleable.View_paddingStart:
4729 startPadding = a.getDimensionPixelSize(attr, UNDEFINED_PADDING);
4730 startPaddingDefined = (startPadding != UNDEFINED_PADDING);
4732 case com.android.internal.R.styleable.View_paddingEnd:
4733 endPadding = a.getDimensionPixelSize(attr, UNDEFINED_PADDING);
4734 endPaddingDefined = (endPadding != UNDEFINED_PADDING);
4736 case com.android.internal.R.styleable.View_scrollX:
4737 x = a.getDimensionPixelOffset(attr, 0);
4739 case com.android.internal.R.styleable.View_scrollY:
4740 y = a.getDimensionPixelOffset(attr, 0);
4742 case com.android.internal.R.styleable.View_alpha:
4743 setAlpha(a.getFloat(attr, 1f));
4745 case com.android.internal.R.styleable.View_transformPivotX:
4746 setPivotX(a.getDimension(attr, 0));
4748 case com.android.internal.R.styleable.View_transformPivotY:
4749 setPivotY(a.getDimension(attr, 0));
4751 case com.android.internal.R.styleable.View_translationX:
4752 tx = a.getDimension(attr, 0);
4753 transformSet = true;
4755 case com.android.internal.R.styleable.View_translationY:
4756 ty = a.getDimension(attr, 0);
4757 transformSet = true;
4759 case com.android.internal.R.styleable.View_translationZ:
4760 tz = a.getDimension(attr, 0);
4761 transformSet = true;
4763 case com.android.internal.R.styleable.View_elevation:
4764 elevation = a.getDimension(attr, 0);
4765 transformSet = true;
4767 case com.android.internal.R.styleable.View_rotation:
4768 rotation = a.getFloat(attr, 0);
4769 transformSet = true;
4771 case com.android.internal.R.styleable.View_rotationX:
4772 rotationX = a.getFloat(attr, 0);
4773 transformSet = true;
4775 case com.android.internal.R.styleable.View_rotationY:
4776 rotationY = a.getFloat(attr, 0);
4777 transformSet = true;
4779 case com.android.internal.R.styleable.View_scaleX:
4780 sx = a.getFloat(attr, 1f);
4781 transformSet = true;
4783 case com.android.internal.R.styleable.View_scaleY:
4784 sy = a.getFloat(attr, 1f);
4785 transformSet = true;
4787 case com.android.internal.R.styleable.View_id:
4788 mID = a.getResourceId(attr, NO_ID);
4790 case com.android.internal.R.styleable.View_tag:
4791 mTag = a.getText(attr);
4793 case com.android.internal.R.styleable.View_fitsSystemWindows:
4794 if (a.getBoolean(attr, false)) {
4795 viewFlagValues |= FITS_SYSTEM_WINDOWS;
4796 viewFlagMasks |= FITS_SYSTEM_WINDOWS;
4799 case com.android.internal.R.styleable.View_focusable:
4800 viewFlagValues = (viewFlagValues & ~FOCUSABLE_MASK) | getFocusableAttribute(a);
4801 if ((viewFlagValues & FOCUSABLE_AUTO) == 0) {
4802 viewFlagMasks |= FOCUSABLE_MASK;
4805 case com.android.internal.R.styleable.View_focusableInTouchMode:
4806 if (a.getBoolean(attr, false)) {
4807 // unset auto focus since focusableInTouchMode implies explicit focusable
4808 viewFlagValues &= ~FOCUSABLE_AUTO;
4809 viewFlagValues |= FOCUSABLE_IN_TOUCH_MODE | FOCUSABLE;
4810 viewFlagMasks |= FOCUSABLE_IN_TOUCH_MODE | FOCUSABLE_MASK;
4813 case com.android.internal.R.styleable.View_clickable:
4814 if (a.getBoolean(attr, false)) {
4815 viewFlagValues |= CLICKABLE;
4816 viewFlagMasks |= CLICKABLE;
4819 case com.android.internal.R.styleable.View_longClickable:
4820 if (a.getBoolean(attr, false)) {
4821 viewFlagValues |= LONG_CLICKABLE;
4822 viewFlagMasks |= LONG_CLICKABLE;
4825 case com.android.internal.R.styleable.View_contextClickable:
4826 if (a.getBoolean(attr, false)) {
4827 viewFlagValues |= CONTEXT_CLICKABLE;
4828 viewFlagMasks |= CONTEXT_CLICKABLE;
4831 case com.android.internal.R.styleable.View_saveEnabled:
4832 if (!a.getBoolean(attr, true)) {
4833 viewFlagValues |= SAVE_DISABLED;
4834 viewFlagMasks |= SAVE_DISABLED_MASK;
4837 case com.android.internal.R.styleable.View_duplicateParentState:
4838 if (a.getBoolean(attr, false)) {
4839 viewFlagValues |= DUPLICATE_PARENT_STATE;
4840 viewFlagMasks |= DUPLICATE_PARENT_STATE;
4843 case com.android.internal.R.styleable.View_visibility:
4844 final int visibility = a.getInt(attr, 0);
4845 if (visibility != 0) {
4846 viewFlagValues |= VISIBILITY_FLAGS[visibility];
4847 viewFlagMasks |= VISIBILITY_MASK;
4850 case com.android.internal.R.styleable.View_layoutDirection:
4851 // Clear any layout direction flags (included resolved bits) already set
4853 ~(PFLAG2_LAYOUT_DIRECTION_MASK | PFLAG2_LAYOUT_DIRECTION_RESOLVED_MASK);
4854 // Set the layout direction flags depending on the value of the attribute
4855 final int layoutDirection = a.getInt(attr, -1);
4856 final int value = (layoutDirection != -1) ?
4857 LAYOUT_DIRECTION_FLAGS[layoutDirection] : LAYOUT_DIRECTION_DEFAULT;
4858 mPrivateFlags2 |= (value << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT);
4860 case com.android.internal.R.styleable.View_drawingCacheQuality:
4861 final int cacheQuality = a.getInt(attr, 0);
4862 if (cacheQuality != 0) {
4863 viewFlagValues |= DRAWING_CACHE_QUALITY_FLAGS[cacheQuality];
4864 viewFlagMasks |= DRAWING_CACHE_QUALITY_MASK;
4867 case com.android.internal.R.styleable.View_contentDescription:
4868 setContentDescription(a.getString(attr));
4870 case com.android.internal.R.styleable.View_accessibilityTraversalBefore:
4871 setAccessibilityTraversalBefore(a.getResourceId(attr, NO_ID));
4873 case com.android.internal.R.styleable.View_accessibilityTraversalAfter:
4874 setAccessibilityTraversalAfter(a.getResourceId(attr, NO_ID));
4876 case com.android.internal.R.styleable.View_labelFor:
4877 setLabelFor(a.getResourceId(attr, NO_ID));
4879 case com.android.internal.R.styleable.View_soundEffectsEnabled:
4880 if (!a.getBoolean(attr, true)) {
4881 viewFlagValues &= ~SOUND_EFFECTS_ENABLED;
4882 viewFlagMasks |= SOUND_EFFECTS_ENABLED;
4885 case com.android.internal.R.styleable.View_hapticFeedbackEnabled:
4886 if (!a.getBoolean(attr, true)) {
4887 viewFlagValues &= ~HAPTIC_FEEDBACK_ENABLED;
4888 viewFlagMasks |= HAPTIC_FEEDBACK_ENABLED;
4891 case R.styleable.View_scrollbars:
4892 final int scrollbars = a.getInt(attr, SCROLLBARS_NONE);
4893 if (scrollbars != SCROLLBARS_NONE) {
4894 viewFlagValues |= scrollbars;
4895 viewFlagMasks |= SCROLLBARS_MASK;
4896 initializeScrollbars = true;
4899 //noinspection deprecation
4900 case R.styleable.View_fadingEdge:
4901 if (targetSdkVersion >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
4902 // Ignore the attribute starting with ICS
4905 // With builds < ICS, fall through and apply fading edges
4906 case R.styleable.View_requiresFadingEdge:
4907 final int fadingEdge = a.getInt(attr, FADING_EDGE_NONE);
4908 if (fadingEdge != FADING_EDGE_NONE) {
4909 viewFlagValues |= fadingEdge;
4910 viewFlagMasks |= FADING_EDGE_MASK;
4911 initializeFadingEdgeInternal(a);
4914 case R.styleable.View_scrollbarStyle:
4915 scrollbarStyle = a.getInt(attr, SCROLLBARS_INSIDE_OVERLAY);
4916 if (scrollbarStyle != SCROLLBARS_INSIDE_OVERLAY) {
4917 viewFlagValues |= scrollbarStyle & SCROLLBARS_STYLE_MASK;
4918 viewFlagMasks |= SCROLLBARS_STYLE_MASK;
4921 case R.styleable.View_isScrollContainer:
4922 setScrollContainer = true;
4923 if (a.getBoolean(attr, false)) {
4924 setScrollContainer(true);
4927 case com.android.internal.R.styleable.View_keepScreenOn:
4928 if (a.getBoolean(attr, false)) {
4929 viewFlagValues |= KEEP_SCREEN_ON;
4930 viewFlagMasks |= KEEP_SCREEN_ON;
4933 case R.styleable.View_filterTouchesWhenObscured:
4934 if (a.getBoolean(attr, false)) {
4935 viewFlagValues |= FILTER_TOUCHES_WHEN_OBSCURED;
4936 viewFlagMasks |= FILTER_TOUCHES_WHEN_OBSCURED;
4939 case R.styleable.View_nextFocusLeft:
4940 mNextFocusLeftId = a.getResourceId(attr, View.NO_ID);
4942 case R.styleable.View_nextFocusRight:
4943 mNextFocusRightId = a.getResourceId(attr, View.NO_ID);
4945 case R.styleable.View_nextFocusUp:
4946 mNextFocusUpId = a.getResourceId(attr, View.NO_ID);
4948 case R.styleable.View_nextFocusDown:
4949 mNextFocusDownId = a.getResourceId(attr, View.NO_ID);
4951 case R.styleable.View_nextFocusForward:
4952 mNextFocusForwardId = a.getResourceId(attr, View.NO_ID);
4954 case R.styleable.View_nextClusterForward:
4955 mNextClusterForwardId = a.getResourceId(attr, View.NO_ID);
4957 case R.styleable.View_minWidth:
4958 mMinWidth = a.getDimensionPixelSize(attr, 0);
4960 case R.styleable.View_minHeight:
4961 mMinHeight = a.getDimensionPixelSize(attr, 0);
4963 case R.styleable.View_onClick:
4964 if (context.isRestricted()) {
4965 throw new IllegalStateException("The android:onClick attribute cannot "
4966 + "be used within a restricted context");
4969 final String handlerName = a.getString(attr);
4970 if (handlerName != null) {
4971 setOnClickListener(new DeclaredOnClickListener(this, handlerName));
4974 case R.styleable.View_overScrollMode:
4975 overScrollMode = a.getInt(attr, OVER_SCROLL_IF_CONTENT_SCROLLS);
4977 case R.styleable.View_verticalScrollbarPosition:
4978 mVerticalScrollbarPosition = a.getInt(attr, SCROLLBAR_POSITION_DEFAULT);
4980 case R.styleable.View_layerType:
4981 setLayerType(a.getInt(attr, LAYER_TYPE_NONE), null);
4983 case R.styleable.View_textDirection:
4984 // Clear any text direction flag already set
4985 mPrivateFlags2 &= ~PFLAG2_TEXT_DIRECTION_MASK;
4986 // Set the text direction flags depending on the value of the attribute
4987 final int textDirection = a.getInt(attr, -1);
4988 if (textDirection != -1) {
4989 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_FLAGS[textDirection];
4992 case R.styleable.View_textAlignment:
4993 // Clear any text alignment flag already set
4994 mPrivateFlags2 &= ~PFLAG2_TEXT_ALIGNMENT_MASK;
4995 // Set the text alignment flag depending on the value of the attribute
4996 final int textAlignment = a.getInt(attr, TEXT_ALIGNMENT_DEFAULT);
4997 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_FLAGS[textAlignment];
4999 case R.styleable.View_importantForAccessibility:
5000 setImportantForAccessibility(a.getInt(attr,
5001 IMPORTANT_FOR_ACCESSIBILITY_DEFAULT));
5003 case R.styleable.View_accessibilityLiveRegion:
5004 setAccessibilityLiveRegion(a.getInt(attr, ACCESSIBILITY_LIVE_REGION_DEFAULT));
5006 case R.styleable.View_transitionName:
5007 setTransitionName(a.getString(attr));
5009 case R.styleable.View_nestedScrollingEnabled:
5010 setNestedScrollingEnabled(a.getBoolean(attr, false));
5012 case R.styleable.View_stateListAnimator:
5013 setStateListAnimator(AnimatorInflater.loadStateListAnimator(context,
5014 a.getResourceId(attr, 0)));
5016 case R.styleable.View_backgroundTint:
5017 // This will get applied later during setBackground().
5018 if (mBackgroundTint == null) {
5019 mBackgroundTint = new TintInfo();
5021 mBackgroundTint.mTintList = a.getColorStateList(
5022 R.styleable.View_backgroundTint);
5023 mBackgroundTint.mHasTintList = true;
5025 case R.styleable.View_backgroundTintMode:
5026 // This will get applied later during setBackground().
5027 if (mBackgroundTint == null) {
5028 mBackgroundTint = new TintInfo();
5030 mBackgroundTint.mTintMode = Drawable.parseTintMode(a.getInt(
5031 R.styleable.View_backgroundTintMode, -1), null);
5032 mBackgroundTint.mHasTintMode = true;
5034 case R.styleable.View_outlineProvider:
5035 setOutlineProviderFromAttribute(a.getInt(R.styleable.View_outlineProvider,
5036 PROVIDER_BACKGROUND));
5038 case R.styleable.View_foreground:
5039 if (targetSdkVersion >= Build.VERSION_CODES.M || this instanceof FrameLayout) {
5040 setForeground(a.getDrawable(attr));
5043 case R.styleable.View_foregroundGravity:
5044 if (targetSdkVersion >= Build.VERSION_CODES.M || this instanceof FrameLayout) {
5045 setForegroundGravity(a.getInt(attr, Gravity.NO_GRAVITY));
5048 case R.styleable.View_foregroundTintMode:
5049 if (targetSdkVersion >= Build.VERSION_CODES.M || this instanceof FrameLayout) {
5050 setForegroundTintMode(Drawable.parseTintMode(a.getInt(attr, -1), null));
5053 case R.styleable.View_foregroundTint:
5054 if (targetSdkVersion >= Build.VERSION_CODES.M || this instanceof FrameLayout) {
5055 setForegroundTintList(a.getColorStateList(attr));
5058 case R.styleable.View_foregroundInsidePadding:
5059 if (targetSdkVersion >= Build.VERSION_CODES.M || this instanceof FrameLayout) {
5060 if (mForegroundInfo == null) {
5061 mForegroundInfo = new ForegroundInfo();
5063 mForegroundInfo.mInsidePadding = a.getBoolean(attr,
5064 mForegroundInfo.mInsidePadding);
5067 case R.styleable.View_scrollIndicators:
5068 final int scrollIndicators =
5069 (a.getInt(attr, 0) << SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT)
5070 & SCROLL_INDICATORS_PFLAG3_MASK;
5071 if (scrollIndicators != 0) {
5072 mPrivateFlags3 |= scrollIndicators;
5073 initializeScrollIndicators = true;
5076 case R.styleable.View_pointerIcon:
5077 final int resourceId = a.getResourceId(attr, 0);
5078 if (resourceId != 0) {
5079 setPointerIcon(PointerIcon.load(
5080 context.getResources(), resourceId));
5082 final int pointerType = a.getInt(attr, PointerIcon.TYPE_NOT_SPECIFIED);
5083 if (pointerType != PointerIcon.TYPE_NOT_SPECIFIED) {
5084 setPointerIcon(PointerIcon.getSystemIcon(context, pointerType));
5088 case R.styleable.View_forceHasOverlappingRendering:
5089 if (a.peekValue(attr) != null) {
5090 forceHasOverlappingRendering(a.getBoolean(attr, true));
5093 case R.styleable.View_tooltipText:
5094 setTooltipText(a.getText(attr));
5096 case R.styleable.View_keyboardNavigationCluster:
5097 if (a.peekValue(attr) != null) {
5098 setKeyboardNavigationCluster(a.getBoolean(attr, true));
5101 case R.styleable.View_focusedByDefault:
5102 if (a.peekValue(attr) != null) {
5103 setFocusedByDefault(a.getBoolean(attr, true));
5106 case R.styleable.View_autofillHints:
5107 if (a.peekValue(attr) != null) {
5108 CharSequence[] rawHints = null;
5109 String rawString = null;
5111 if (a.getType(attr) == TypedValue.TYPE_REFERENCE) {
5112 int resId = a.getResourceId(attr, 0);
5115 rawHints = a.getTextArray(attr);
5116 } catch (Resources.NotFoundException e) {
5117 rawString = getResources().getString(resId);
5120 rawString = a.getString(attr);
5123 if (rawHints == null) {
5124 if (rawString == null) {
5125 throw new IllegalArgumentException(
5126 "Could not resolve autofillHints");
5128 rawHints = rawString.split(",");
5132 String[] hints = new String[rawHints.length];
5134 int numHints = rawHints.length;
5135 for (int rawHintNum = 0; rawHintNum < numHints; rawHintNum++) {
5136 hints[rawHintNum] = rawHints[rawHintNum].toString().trim();
5138 setAutofillHints(hints);
5141 case R.styleable.View_importantForAutofill:
5142 if (a.peekValue(attr) != null) {
5143 setImportantForAutofill(a.getInt(attr, IMPORTANT_FOR_AUTOFILL_AUTO));
5146 case R.styleable.View_defaultFocusHighlightEnabled:
5147 if (a.peekValue(attr) != null) {
5148 setDefaultFocusHighlightEnabled(a.getBoolean(attr, true));
5154 setOverScrollMode(overScrollMode);
5156 // Cache start/end user padding as we cannot fully resolve padding here (we dont have yet
5157 // the resolved layout direction). Those cached values will be used later during padding
5159 mUserPaddingStart = startPadding;
5160 mUserPaddingEnd = endPadding;
5162 if (background != null) {
5163 setBackground(background);
5166 // setBackground above will record that padding is currently provided by the background.
5167 // If we have padding specified via xml, record that here instead and use it.
5168 mLeftPaddingDefined = leftPaddingDefined;
5169 mRightPaddingDefined = rightPaddingDefined;
5172 leftPadding = padding;
5173 topPadding = padding;
5174 rightPadding = padding;
5175 bottomPadding = padding;
5176 mUserPaddingLeftInitial = padding;
5177 mUserPaddingRightInitial = padding;
5179 if (paddingHorizontal >= 0) {
5180 leftPadding = paddingHorizontal;
5181 rightPadding = paddingHorizontal;
5182 mUserPaddingLeftInitial = paddingHorizontal;
5183 mUserPaddingRightInitial = paddingHorizontal;
5185 if (paddingVertical >= 0) {
5186 topPadding = paddingVertical;
5187 bottomPadding = paddingVertical;
5191 if (isRtlCompatibilityMode()) {
5192 // RTL compatibility mode: pre Jelly Bean MR1 case OR no RTL support case.
5193 // left / right padding are used if defined (meaning here nothing to do). If they are not
5194 // defined and start / end padding are defined (e.g. in Frameworks resources), then we use
5195 // start / end and resolve them as left / right (layout direction is not taken into account).
5196 // Padding from the background drawable is stored at this point in mUserPaddingLeftInitial
5197 // and mUserPaddingRightInitial) so drawable padding will be used as ultimate default if
5199 if (!mLeftPaddingDefined && startPaddingDefined) {
5200 leftPadding = startPadding;
5202 mUserPaddingLeftInitial = (leftPadding >= 0) ? leftPadding : mUserPaddingLeftInitial;
5203 if (!mRightPaddingDefined && endPaddingDefined) {
5204 rightPadding = endPadding;
5206 mUserPaddingRightInitial = (rightPadding >= 0) ? rightPadding : mUserPaddingRightInitial;
5208 // Jelly Bean MR1 and after case: if start/end defined, they will override any left/right
5209 // values defined. Otherwise, left /right values are used.
5210 // Padding from the background drawable is stored at this point in mUserPaddingLeftInitial
5211 // and mUserPaddingRightInitial) so drawable padding will be used as ultimate default if
5213 final boolean hasRelativePadding = startPaddingDefined || endPaddingDefined;
5215 if (mLeftPaddingDefined && !hasRelativePadding) {
5216 mUserPaddingLeftInitial = leftPadding;
5218 if (mRightPaddingDefined && !hasRelativePadding) {
5219 mUserPaddingRightInitial = rightPadding;
5224 mUserPaddingLeftInitial,
5225 topPadding >= 0 ? topPadding : mPaddingTop,
5226 mUserPaddingRightInitial,
5227 bottomPadding >= 0 ? bottomPadding : mPaddingBottom);
5229 if (viewFlagMasks != 0) {
5230 setFlags(viewFlagValues, viewFlagMasks);
5233 if (initializeScrollbars) {
5234 initializeScrollbarsInternal(a);
5237 if (initializeScrollIndicators) {
5238 initializeScrollIndicatorsInternal();
5243 // Needs to be called after mViewFlags is set
5244 if (scrollbarStyle != SCROLLBARS_INSIDE_OVERLAY) {
5248 if (x != 0 || y != 0) {
5253 setTranslationX(tx);
5254 setTranslationY(ty);
5255 setTranslationZ(tz);
5256 setElevation(elevation);
5257 setRotation(rotation);
5258 setRotationX(rotationX);
5259 setRotationY(rotationY);
5264 if (!setScrollContainer && (viewFlagValues&SCROLLBARS_VERTICAL) != 0) {
5265 setScrollContainer(true);
5268 computeOpaqueFlags();
5272 * An implementation of OnClickListener that attempts to lazily load a
5273 * named click handling method from a parent or ancestor context.
5275 private static class DeclaredOnClickListener implements OnClickListener {
5276 private final View mHostView;
5277 private final String mMethodName;
5279 private Method mResolvedMethod;
5280 private Context mResolvedContext;
5282 public DeclaredOnClickListener(@NonNull View hostView, @NonNull String methodName) {
5283 mHostView = hostView;
5284 mMethodName = methodName;
5288 public void onClick(@NonNull View v) {
5289 if (mResolvedMethod == null) {
5290 resolveMethod(mHostView.getContext(), mMethodName);
5294 mResolvedMethod.invoke(mResolvedContext, v);
5295 } catch (IllegalAccessException e) {
5296 throw new IllegalStateException(
5297 "Could not execute non-public method for android:onClick", e);
5298 } catch (InvocationTargetException e) {
5299 throw new IllegalStateException(
5300 "Could not execute method for android:onClick", e);
5305 private void resolveMethod(@Nullable Context context, @NonNull String name) {
5306 while (context != null) {
5308 if (!context.isRestricted()) {
5309 final Method method = context.getClass().getMethod(mMethodName, View.class);
5310 if (method != null) {
5311 mResolvedMethod = method;
5312 mResolvedContext = context;
5316 } catch (NoSuchMethodException e) {
5317 // Failed to find method, keep searching up the hierarchy.
5320 if (context instanceof ContextWrapper) {
5321 context = ((ContextWrapper) context).getBaseContext();
5323 // Can't search up the hierarchy, null out and fail.
5328 final int id = mHostView.getId();
5329 final String idText = id == NO_ID ? "" : " with id '"
5330 + mHostView.getContext().getResources().getResourceEntryName(id) + "'";
5331 throw new IllegalStateException("Could not find method " + mMethodName
5332 + "(View) in a parent or ancestor Context for android:onClick "
5333 + "attribute defined on view " + mHostView.getClass() + idText);
5338 * Non-public constructor for use in testing
5342 mRenderNode = RenderNode.create(getClass().getName(), this);
5345 final boolean debugDraw() {
5346 return DEBUG_DRAW || mAttachInfo != null && mAttachInfo.mDebugLayout;
5349 private static SparseArray<String> getAttributeMap() {
5350 if (mAttributeMap == null) {
5351 mAttributeMap = new SparseArray<>();
5353 return mAttributeMap;
5356 private void saveAttributeData(@Nullable AttributeSet attrs, @NonNull TypedArray t) {
5357 final int attrsCount = attrs == null ? 0 : attrs.getAttributeCount();
5358 final int indexCount = t.getIndexCount();
5359 final String[] attributes = new String[(attrsCount + indexCount) * 2];
5363 // Store raw XML attributes.
5364 for (int j = 0; j < attrsCount; ++j) {
5365 attributes[i] = attrs.getAttributeName(j);
5366 attributes[i + 1] = attrs.getAttributeValue(j);
5370 // Store resolved styleable attributes.
5371 final Resources res = t.getResources();
5372 final SparseArray<String> attributeMap = getAttributeMap();
5373 for (int j = 0; j < indexCount; ++j) {
5374 final int index = t.getIndex(j);
5375 if (!t.hasValueOrEmpty(index)) {
5376 // Value is undefined. Skip it.
5380 final int resourceId = t.getResourceId(index, 0);
5381 if (resourceId == 0) {
5382 // Value is not a reference. Skip it.
5386 String resourceName = attributeMap.get(resourceId);
5387 if (resourceName == null) {
5389 resourceName = res.getResourceName(resourceId);
5390 } catch (Resources.NotFoundException e) {
5391 resourceName = "0x" + Integer.toHexString(resourceId);
5393 attributeMap.put(resourceId, resourceName);
5396 attributes[i] = resourceName;
5397 attributes[i + 1] = t.getString(index);
5401 // Trim to fit contents.
5402 final String[] trimmed = new String[i];
5403 System.arraycopy(attributes, 0, trimmed, 0, i);
5404 mAttributes = trimmed;
5407 public String toString() {
5408 StringBuilder out = new StringBuilder(128);
5409 out.append(getClass().getName());
5411 out.append(Integer.toHexString(System.identityHashCode(this)));
5413 switch (mViewFlags&VISIBILITY_MASK) {
5414 case VISIBLE: out.append('V'); break;
5415 case INVISIBLE: out.append('I'); break;
5416 case GONE: out.append('G'); break;
5417 default: out.append('.'); break;
5419 out.append((mViewFlags & FOCUSABLE) == FOCUSABLE ? 'F' : '.');
5420 out.append((mViewFlags&ENABLED_MASK) == ENABLED ? 'E' : '.');
5421 out.append((mViewFlags&DRAW_MASK) == WILL_NOT_DRAW ? '.' : 'D');
5422 out.append((mViewFlags&SCROLLBARS_HORIZONTAL) != 0 ? 'H' : '.');
5423 out.append((mViewFlags&SCROLLBARS_VERTICAL) != 0 ? 'V' : '.');
5424 out.append((mViewFlags&CLICKABLE) != 0 ? 'C' : '.');
5425 out.append((mViewFlags&LONG_CLICKABLE) != 0 ? 'L' : '.');
5426 out.append((mViewFlags&CONTEXT_CLICKABLE) != 0 ? 'X' : '.');
5428 out.append((mPrivateFlags&PFLAG_IS_ROOT_NAMESPACE) != 0 ? 'R' : '.');
5429 out.append((mPrivateFlags&PFLAG_FOCUSED) != 0 ? 'F' : '.');
5430 out.append((mPrivateFlags&PFLAG_SELECTED) != 0 ? 'S' : '.');
5431 if ((mPrivateFlags&PFLAG_PREPRESSED) != 0) {
5434 out.append((mPrivateFlags&PFLAG_PRESSED) != 0 ? 'P' : '.');
5436 out.append((mPrivateFlags&PFLAG_HOVERED) != 0 ? 'H' : '.');
5437 out.append((mPrivateFlags&PFLAG_ACTIVATED) != 0 ? 'A' : '.');
5438 out.append((mPrivateFlags&PFLAG_INVALIDATED) != 0 ? 'I' : '.');
5439 out.append((mPrivateFlags&PFLAG_DIRTY_MASK) != 0 ? 'D' : '.');
5447 out.append(mBottom);
5448 final int id = getId();
5451 out.append(Integer.toHexString(id));
5452 final Resources r = mResources;
5453 if (id > 0 && Resources.resourceHasPackage(id) && r != null) {
5456 switch (id&0xff000000) {
5464 pkgname = r.getResourcePackageName(id);
5467 String typename = r.getResourceTypeName(id);
5468 String entryname = r.getResourceEntryName(id);
5470 out.append(pkgname);
5472 out.append(typename);
5474 out.append(entryname);
5475 } catch (Resources.NotFoundException e) {
5480 return out.toString();
5485 * Initializes the fading edges from a given set of styled attributes. This
5486 * method should be called by subclasses that need fading edges and when an
5487 * instance of these subclasses is created programmatically rather than
5488 * being inflated from XML. This method is automatically called when the XML
5492 * @param a the styled attributes set to initialize the fading edges from
5496 protected void initializeFadingEdge(TypedArray a) {
5497 // This method probably shouldn't have been included in the SDK to begin with.
5498 // It relies on 'a' having been initialized using an attribute filter array that is
5499 // not publicly available to the SDK. The old method has been renamed
5500 // to initializeFadingEdgeInternal and hidden for framework use only;
5501 // this one initializes using defaults to make it safe to call for apps.
5503 TypedArray arr = mContext.obtainStyledAttributes(com.android.internal.R.styleable.View);
5505 initializeFadingEdgeInternal(arr);
5512 * Initializes the fading edges from a given set of styled attributes. This
5513 * method should be called by subclasses that need fading edges and when an
5514 * instance of these subclasses is created programmatically rather than
5515 * being inflated from XML. This method is automatically called when the XML
5519 * @param a the styled attributes set to initialize the fading edges from
5520 * @hide This is the real method; the public one is shimmed to be safe to call from apps.
5522 protected void initializeFadingEdgeInternal(TypedArray a) {
5525 mScrollCache.fadingEdgeLength = a.getDimensionPixelSize(
5526 R.styleable.View_fadingEdgeLength,
5527 ViewConfiguration.get(mContext).getScaledFadingEdgeLength());
5531 * Returns the size of the vertical faded edges used to indicate that more
5532 * content in this view is visible.
5534 * @return The size in pixels of the vertical faded edge or 0 if vertical
5535 * faded edges are not enabled for this view.
5536 * @attr ref android.R.styleable#View_fadingEdgeLength
5538 public int getVerticalFadingEdgeLength() {
5539 if (isVerticalFadingEdgeEnabled()) {
5540 ScrollabilityCache cache = mScrollCache;
5541 if (cache != null) {
5542 return cache.fadingEdgeLength;
5549 * Set the size of the faded edge used to indicate that more content in this
5550 * view is available. Will not change whether the fading edge is enabled; use
5551 * {@link #setVerticalFadingEdgeEnabled(boolean)} or
5552 * {@link #setHorizontalFadingEdgeEnabled(boolean)} to enable the fading edge
5553 * for the vertical or horizontal fading edges.
5555 * @param length The size in pixels of the faded edge used to indicate that more
5556 * content in this view is visible.
5558 public void setFadingEdgeLength(int length) {
5560 mScrollCache.fadingEdgeLength = length;
5564 * Returns the size of the horizontal faded edges used to indicate that more
5565 * content in this view is visible.
5567 * @return The size in pixels of the horizontal faded edge or 0 if horizontal
5568 * faded edges are not enabled for this view.
5569 * @attr ref android.R.styleable#View_fadingEdgeLength
5571 public int getHorizontalFadingEdgeLength() {
5572 if (isHorizontalFadingEdgeEnabled()) {
5573 ScrollabilityCache cache = mScrollCache;
5574 if (cache != null) {
5575 return cache.fadingEdgeLength;
5582 * Returns the width of the vertical scrollbar.
5584 * @return The width in pixels of the vertical scrollbar or 0 if there
5585 * is no vertical scrollbar.
5587 public int getVerticalScrollbarWidth() {
5588 ScrollabilityCache cache = mScrollCache;
5589 if (cache != null) {
5590 ScrollBarDrawable scrollBar = cache.scrollBar;
5591 if (scrollBar != null) {
5592 int size = scrollBar.getSize(true);
5594 size = cache.scrollBarSize;
5604 * Returns the height of the horizontal scrollbar.
5606 * @return The height in pixels of the horizontal scrollbar or 0 if
5607 * there is no horizontal scrollbar.
5609 protected int getHorizontalScrollbarHeight() {
5610 ScrollabilityCache cache = mScrollCache;
5611 if (cache != null) {
5612 ScrollBarDrawable scrollBar = cache.scrollBar;
5613 if (scrollBar != null) {
5614 int size = scrollBar.getSize(false);
5616 size = cache.scrollBarSize;
5627 * Initializes the scrollbars from a given set of styled attributes. This
5628 * method should be called by subclasses that need scrollbars and when an
5629 * instance of these subclasses is created programmatically rather than
5630 * being inflated from XML. This method is automatically called when the XML
5634 * @param a the styled attributes set to initialize the scrollbars from
5638 protected void initializeScrollbars(TypedArray a) {
5639 // It's not safe to use this method from apps. The parameter 'a' must have been obtained
5640 // using the View filter array which is not available to the SDK. As such, internal
5641 // framework usage now uses initializeScrollbarsInternal and we grab a default
5642 // TypedArray with the right filter instead here.
5643 TypedArray arr = mContext.obtainStyledAttributes(com.android.internal.R.styleable.View);
5645 initializeScrollbarsInternal(arr);
5647 // We ignored the method parameter. Recycle the one we actually did use.
5653 * Initializes the scrollbars from a given set of styled attributes. This
5654 * method should be called by subclasses that need scrollbars and when an
5655 * instance of these subclasses is created programmatically rather than
5656 * being inflated from XML. This method is automatically called when the XML
5660 * @param a the styled attributes set to initialize the scrollbars from
5663 protected void initializeScrollbarsInternal(TypedArray a) {
5666 final ScrollabilityCache scrollabilityCache = mScrollCache;
5668 if (scrollabilityCache.scrollBar == null) {
5669 scrollabilityCache.scrollBar = new ScrollBarDrawable();
5670 scrollabilityCache.scrollBar.setState(getDrawableState());
5671 scrollabilityCache.scrollBar.setCallback(this);
5674 final boolean fadeScrollbars = a.getBoolean(R.styleable.View_fadeScrollbars, true);
5676 if (!fadeScrollbars) {
5677 scrollabilityCache.state = ScrollabilityCache.ON;
5679 scrollabilityCache.fadeScrollBars = fadeScrollbars;
5682 scrollabilityCache.scrollBarFadeDuration = a.getInt(
5683 R.styleable.View_scrollbarFadeDuration, ViewConfiguration
5684 .getScrollBarFadeDuration());
5685 scrollabilityCache.scrollBarDefaultDelayBeforeFade = a.getInt(
5686 R.styleable.View_scrollbarDefaultDelayBeforeFade,
5687 ViewConfiguration.getScrollDefaultDelay());
5690 scrollabilityCache.scrollBarSize = a.getDimensionPixelSize(
5691 com.android.internal.R.styleable.View_scrollbarSize,
5692 ViewConfiguration.get(mContext).getScaledScrollBarSize());
5694 Drawable track = a.getDrawable(R.styleable.View_scrollbarTrackHorizontal);
5695 scrollabilityCache.scrollBar.setHorizontalTrackDrawable(track);
5697 Drawable thumb = a.getDrawable(R.styleable.View_scrollbarThumbHorizontal);
5698 if (thumb != null) {
5699 scrollabilityCache.scrollBar.setHorizontalThumbDrawable(thumb);
5702 boolean alwaysDraw = a.getBoolean(R.styleable.View_scrollbarAlwaysDrawHorizontalTrack,
5705 scrollabilityCache.scrollBar.setAlwaysDrawHorizontalTrack(true);
5708 track = a.getDrawable(R.styleable.View_scrollbarTrackVertical);
5709 scrollabilityCache.scrollBar.setVerticalTrackDrawable(track);
5711 thumb = a.getDrawable(R.styleable.View_scrollbarThumbVertical);
5712 if (thumb != null) {
5713 scrollabilityCache.scrollBar.setVerticalThumbDrawable(thumb);
5716 alwaysDraw = a.getBoolean(R.styleable.View_scrollbarAlwaysDrawVerticalTrack,
5719 scrollabilityCache.scrollBar.setAlwaysDrawVerticalTrack(true);
5722 // Apply layout direction to the new Drawables if needed
5723 final int layoutDirection = getLayoutDirection();
5724 if (track != null) {
5725 track.setLayoutDirection(layoutDirection);
5727 if (thumb != null) {
5728 thumb.setLayoutDirection(layoutDirection);
5731 // Re-apply user/background padding so that scrollbar(s) get added
5735 private void initializeScrollIndicatorsInternal() {
5736 // Some day maybe we'll break this into top/left/start/etc. and let the
5737 // client control it. Until then, you can have any scroll indicator you
5738 // want as long as it's a 1dp foreground-colored rectangle.
5739 if (mScrollIndicatorDrawable == null) {
5740 mScrollIndicatorDrawable = mContext.getDrawable(R.drawable.scroll_indicator_material);
5746 * Initalizes the scrollability cache if necessary.
5749 private void initScrollCache() {
5750 if (mScrollCache == null) {
5751 mScrollCache = new ScrollabilityCache(ViewConfiguration.get(mContext), this);
5755 private ScrollabilityCache getScrollCache() {
5757 return mScrollCache;
5761 * Set the position of the vertical scroll bar. Should be one of
5762 * {@link #SCROLLBAR_POSITION_DEFAULT}, {@link #SCROLLBAR_POSITION_LEFT} or
5763 * {@link #SCROLLBAR_POSITION_RIGHT}.
5765 * @param position Where the vertical scroll bar should be positioned.
5767 public void setVerticalScrollbarPosition(int position) {
5768 if (mVerticalScrollbarPosition != position) {
5769 mVerticalScrollbarPosition = position;
5770 computeOpaqueFlags();
5776 * @return The position where the vertical scroll bar will show, if applicable.
5777 * @see #setVerticalScrollbarPosition(int)
5779 public int getVerticalScrollbarPosition() {
5780 return mVerticalScrollbarPosition;
5783 boolean isOnScrollbar(float x, float y) {
5784 if (mScrollCache == null) {
5789 if (isVerticalScrollBarEnabled() && !isVerticalScrollBarHidden()) {
5790 final Rect touchBounds = mScrollCache.mScrollBarTouchBounds;
5791 getVerticalScrollBarBounds(null, touchBounds);
5792 if (touchBounds.contains((int) x, (int) y)) {
5796 if (isHorizontalScrollBarEnabled()) {
5797 final Rect touchBounds = mScrollCache.mScrollBarTouchBounds;
5798 getHorizontalScrollBarBounds(null, touchBounds);
5799 if (touchBounds.contains((int) x, (int) y)) {
5806 boolean isOnScrollbarThumb(float x, float y) {
5807 return isOnVerticalScrollbarThumb(x, y) || isOnHorizontalScrollbarThumb(x, y);
5810 private boolean isOnVerticalScrollbarThumb(float x, float y) {
5811 if (mScrollCache == null) {
5814 if (isVerticalScrollBarEnabled() && !isVerticalScrollBarHidden()) {
5817 final Rect bounds = mScrollCache.mScrollBarBounds;
5818 final Rect touchBounds = mScrollCache.mScrollBarTouchBounds;
5819 getVerticalScrollBarBounds(bounds, touchBounds);
5820 final int range = computeVerticalScrollRange();
5821 final int offset = computeVerticalScrollOffset();
5822 final int extent = computeVerticalScrollExtent();
5823 final int thumbLength = ScrollBarUtils.getThumbLength(bounds.height(), bounds.width(),
5825 final int thumbOffset = ScrollBarUtils.getThumbOffset(bounds.height(), thumbLength,
5826 extent, range, offset);
5827 final int thumbTop = bounds.top + thumbOffset;
5828 final int adjust = Math.max(mScrollCache.scrollBarMinTouchTarget - thumbLength, 0) / 2;
5829 if (x >= touchBounds.left && x <= touchBounds.right
5830 && y >= thumbTop - adjust && y <= thumbTop + thumbLength + adjust) {
5837 private boolean isOnHorizontalScrollbarThumb(float x, float y) {
5838 if (mScrollCache == null) {
5841 if (isHorizontalScrollBarEnabled()) {
5844 final Rect bounds = mScrollCache.mScrollBarBounds;
5845 final Rect touchBounds = mScrollCache.mScrollBarTouchBounds;
5846 getHorizontalScrollBarBounds(bounds, touchBounds);
5847 final int range = computeHorizontalScrollRange();
5848 final int offset = computeHorizontalScrollOffset();
5849 final int extent = computeHorizontalScrollExtent();
5850 final int thumbLength = ScrollBarUtils.getThumbLength(bounds.width(), bounds.height(),
5852 final int thumbOffset = ScrollBarUtils.getThumbOffset(bounds.width(), thumbLength,
5853 extent, range, offset);
5854 final int thumbLeft = bounds.left + thumbOffset;
5855 final int adjust = Math.max(mScrollCache.scrollBarMinTouchTarget - thumbLength, 0) / 2;
5856 if (x >= thumbLeft - adjust && x <= thumbLeft + thumbLength + adjust
5857 && y >= touchBounds.top && y <= touchBounds.bottom) {
5864 boolean isDraggingScrollBar() {
5865 return mScrollCache != null
5866 && mScrollCache.mScrollBarDraggingState != ScrollabilityCache.NOT_DRAGGING;
5870 * Sets the state of all scroll indicators.
5872 * See {@link #setScrollIndicators(int, int)} for usage information.
5874 * @param indicators a bitmask of indicators that should be enabled, or
5875 * {@code 0} to disable all indicators
5876 * @see #setScrollIndicators(int, int)
5877 * @see #getScrollIndicators()
5878 * @attr ref android.R.styleable#View_scrollIndicators
5880 public void setScrollIndicators(@ScrollIndicators int indicators) {
5881 setScrollIndicators(indicators,
5882 SCROLL_INDICATORS_PFLAG3_MASK >>> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT);
5886 * Sets the state of the scroll indicators specified by the mask. To change
5887 * all scroll indicators at once, see {@link #setScrollIndicators(int)}.
5889 * When a scroll indicator is enabled, it will be displayed if the view
5890 * can scroll in the direction of the indicator.
5892 * Multiple indicator types may be enabled or disabled by passing the
5893 * logical OR of the desired types. If multiple types are specified, they
5894 * will all be set to the same enabled state.
5896 * For example, to enable the top scroll indicatorExample: {@code setScrollIndicators
5898 * @param indicators the indicator direction, or the logical OR of multiple
5899 * indicator directions. One or more of:
5901 * <li>{@link #SCROLL_INDICATOR_TOP}</li>
5902 * <li>{@link #SCROLL_INDICATOR_BOTTOM}</li>
5903 * <li>{@link #SCROLL_INDICATOR_LEFT}</li>
5904 * <li>{@link #SCROLL_INDICATOR_RIGHT}</li>
5905 * <li>{@link #SCROLL_INDICATOR_START}</li>
5906 * <li>{@link #SCROLL_INDICATOR_END}</li>
5908 * @see #setScrollIndicators(int)
5909 * @see #getScrollIndicators()
5910 * @attr ref android.R.styleable#View_scrollIndicators
5912 public void setScrollIndicators(@ScrollIndicators int indicators, @ScrollIndicators int mask) {
5913 // Shift and sanitize mask.
5914 mask <<= SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT;
5915 mask &= SCROLL_INDICATORS_PFLAG3_MASK;
5917 // Shift and mask indicators.
5918 indicators <<= SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT;
5921 // Merge with non-masked flags.
5922 final int updatedFlags = indicators | (mPrivateFlags3 & ~mask);
5924 if (mPrivateFlags3 != updatedFlags) {
5925 mPrivateFlags3 = updatedFlags;
5927 if (indicators != 0) {
5928 initializeScrollIndicatorsInternal();
5935 * Returns a bitmask representing the enabled scroll indicators.
5937 * For example, if the top and left scroll indicators are enabled and all
5938 * other indicators are disabled, the return value will be
5939 * {@code View.SCROLL_INDICATOR_TOP | View.SCROLL_INDICATOR_LEFT}.
5941 * To check whether the bottom scroll indicator is enabled, use the value
5942 * of {@code (getScrollIndicators() & View.SCROLL_INDICATOR_BOTTOM) != 0}.
5944 * @return a bitmask representing the enabled scroll indicators
5947 public int getScrollIndicators() {
5948 return (mPrivateFlags3 & SCROLL_INDICATORS_PFLAG3_MASK)
5949 >>> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT;
5952 ListenerInfo getListenerInfo() {
5953 if (mListenerInfo != null) {
5954 return mListenerInfo;
5956 mListenerInfo = new ListenerInfo();
5957 return mListenerInfo;
5961 * Register a callback to be invoked when the scroll X or Y positions of
5964 * <b>Note:</b> Some views handle scrolling independently from View and may
5965 * have their own separate listeners for scroll-type events. For example,
5966 * {@link android.widget.ListView ListView} allows clients to register an
5967 * {@link android.widget.ListView#setOnScrollListener(android.widget.AbsListView.OnScrollListener) AbsListView.OnScrollListener}
5968 * to listen for changes in list scroll position.
5970 * @param l The listener to notify when the scroll X or Y position changes.
5971 * @see android.view.View#getScrollX()
5972 * @see android.view.View#getScrollY()
5974 public void setOnScrollChangeListener(OnScrollChangeListener l) {
5975 getListenerInfo().mOnScrollChangeListener = l;
5979 * Register a callback to be invoked when focus of this view changed.
5981 * @param l The callback that will run.
5983 public void setOnFocusChangeListener(OnFocusChangeListener l) {
5984 getListenerInfo().mOnFocusChangeListener = l;
5988 * Add a listener that will be called when the bounds of the view change due to
5989 * layout processing.
5991 * @param listener The listener that will be called when layout bounds change.
5993 public void addOnLayoutChangeListener(OnLayoutChangeListener listener) {
5994 ListenerInfo li = getListenerInfo();
5995 if (li.mOnLayoutChangeListeners == null) {
5996 li.mOnLayoutChangeListeners = new ArrayList<OnLayoutChangeListener>();
5998 if (!li.mOnLayoutChangeListeners.contains(listener)) {
5999 li.mOnLayoutChangeListeners.add(listener);
6004 * Remove a listener for layout changes.
6006 * @param listener The listener for layout bounds change.
6008 public void removeOnLayoutChangeListener(OnLayoutChangeListener listener) {
6009 ListenerInfo li = mListenerInfo;
6010 if (li == null || li.mOnLayoutChangeListeners == null) {
6013 li.mOnLayoutChangeListeners.remove(listener);
6017 * Add a listener for attach state changes.
6019 * This listener will be called whenever this view is attached or detached
6020 * from a window. Remove the listener using
6021 * {@link #removeOnAttachStateChangeListener(OnAttachStateChangeListener)}.
6023 * @param listener Listener to attach
6024 * @see #removeOnAttachStateChangeListener(OnAttachStateChangeListener)
6026 public void addOnAttachStateChangeListener(OnAttachStateChangeListener listener) {
6027 ListenerInfo li = getListenerInfo();
6028 if (li.mOnAttachStateChangeListeners == null) {
6029 li.mOnAttachStateChangeListeners
6030 = new CopyOnWriteArrayList<OnAttachStateChangeListener>();
6032 li.mOnAttachStateChangeListeners.add(listener);
6036 * Remove a listener for attach state changes. The listener will receive no further
6037 * notification of window attach/detach events.
6039 * @param listener Listener to remove
6040 * @see #addOnAttachStateChangeListener(OnAttachStateChangeListener)
6042 public void removeOnAttachStateChangeListener(OnAttachStateChangeListener listener) {
6043 ListenerInfo li = mListenerInfo;
6044 if (li == null || li.mOnAttachStateChangeListeners == null) {
6047 li.mOnAttachStateChangeListeners.remove(listener);
6051 * Returns the focus-change callback registered for this view.
6053 * @return The callback, or null if one is not registered.
6055 public OnFocusChangeListener getOnFocusChangeListener() {
6056 ListenerInfo li = mListenerInfo;
6057 return li != null ? li.mOnFocusChangeListener : null;
6061 * Register a callback to be invoked when this view is clicked. If this view is not
6062 * clickable, it becomes clickable.
6064 * @param l The callback that will run
6066 * @see #setClickable(boolean)
6068 public void setOnClickListener(@Nullable OnClickListener l) {
6069 if (!isClickable()) {
6072 getListenerInfo().mOnClickListener = l;
6076 * Return whether this view has an attached OnClickListener. Returns
6077 * true if there is a listener, false if there is none.
6079 public boolean hasOnClickListeners() {
6080 ListenerInfo li = mListenerInfo;
6081 return (li != null && li.mOnClickListener != null);
6085 * Register a callback to be invoked when this view is clicked and held. If this view is not
6086 * long clickable, it becomes long clickable.
6088 * @param l The callback that will run
6090 * @see #setLongClickable(boolean)
6092 public void setOnLongClickListener(@Nullable OnLongClickListener l) {
6093 if (!isLongClickable()) {
6094 setLongClickable(true);
6096 getListenerInfo().mOnLongClickListener = l;
6100 * Register a callback to be invoked when this view is context clicked. If the view is not
6101 * context clickable, it becomes context clickable.
6103 * @param l The callback that will run
6104 * @see #setContextClickable(boolean)
6106 public void setOnContextClickListener(@Nullable OnContextClickListener l) {
6107 if (!isContextClickable()) {
6108 setContextClickable(true);
6110 getListenerInfo().mOnContextClickListener = l;
6114 * Register a callback to be invoked when the context menu for this view is
6115 * being built. If this view is not long clickable, it becomes long clickable.
6117 * @param l The callback that will run
6120 public void setOnCreateContextMenuListener(OnCreateContextMenuListener l) {
6121 if (!isLongClickable()) {
6122 setLongClickable(true);
6124 getListenerInfo().mOnCreateContextMenuListener = l;
6128 * Set an observer to collect stats for each frame rendered for this view.
6132 public void addFrameMetricsListener(Window window,
6133 Window.OnFrameMetricsAvailableListener listener,
6135 if (mAttachInfo != null) {
6136 if (mAttachInfo.mThreadedRenderer != null) {
6137 if (mFrameMetricsObservers == null) {
6138 mFrameMetricsObservers = new ArrayList<>();
6141 FrameMetricsObserver fmo = new FrameMetricsObserver(window,
6142 handler.getLooper(), listener);
6143 mFrameMetricsObservers.add(fmo);
6144 mAttachInfo.mThreadedRenderer.addFrameMetricsObserver(fmo);
6146 Log.w(VIEW_LOG_TAG, "View not hardware-accelerated. Unable to observe frame stats");
6149 if (mFrameMetricsObservers == null) {
6150 mFrameMetricsObservers = new ArrayList<>();
6153 FrameMetricsObserver fmo = new FrameMetricsObserver(window,
6154 handler.getLooper(), listener);
6155 mFrameMetricsObservers.add(fmo);
6160 * Remove observer configured to collect frame stats for this view.
6164 public void removeFrameMetricsListener(
6165 Window.OnFrameMetricsAvailableListener listener) {
6166 ThreadedRenderer renderer = getThreadedRenderer();
6167 FrameMetricsObserver fmo = findFrameMetricsObserver(listener);
6169 throw new IllegalArgumentException(
6170 "attempt to remove OnFrameMetricsAvailableListener that was never added");
6173 if (mFrameMetricsObservers != null) {
6174 mFrameMetricsObservers.remove(fmo);
6175 if (renderer != null) {
6176 renderer.removeFrameMetricsObserver(fmo);
6181 private void registerPendingFrameMetricsObservers() {
6182 if (mFrameMetricsObservers != null) {
6183 ThreadedRenderer renderer = getThreadedRenderer();
6184 if (renderer != null) {
6185 for (FrameMetricsObserver fmo : mFrameMetricsObservers) {
6186 renderer.addFrameMetricsObserver(fmo);
6189 Log.w(VIEW_LOG_TAG, "View not hardware-accelerated. Unable to observe frame stats");
6194 private FrameMetricsObserver findFrameMetricsObserver(
6195 Window.OnFrameMetricsAvailableListener listener) {
6196 for (int i = 0; i < mFrameMetricsObservers.size(); i++) {
6197 FrameMetricsObserver observer = mFrameMetricsObservers.get(i);
6198 if (observer.mListener == listener) {
6207 * Call this view's OnClickListener, if it is defined. Performs all normal
6208 * actions associated with clicking: reporting accessibility event, playing
6211 * @return True there was an assigned OnClickListener that was called, false
6212 * otherwise is returned.
6214 public boolean performClick() {
6215 final boolean result;
6216 final ListenerInfo li = mListenerInfo;
6217 if (li != null && li.mOnClickListener != null) {
6218 playSoundEffect(SoundEffectConstants.CLICK);
6219 li.mOnClickListener.onClick(this);
6225 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);
6227 notifyEnterOrExitForAutoFillIfNeeded(true);
6233 * Directly call any attached OnClickListener. Unlike {@link #performClick()},
6234 * this only calls the listener, and does not do any associated clicking
6235 * actions like reporting an accessibility event.
6237 * @return True there was an assigned OnClickListener that was called, false
6238 * otherwise is returned.
6240 public boolean callOnClick() {
6241 ListenerInfo li = mListenerInfo;
6242 if (li != null && li.mOnClickListener != null) {
6243 li.mOnClickListener.onClick(this);
6250 * Calls this view's OnLongClickListener, if it is defined. Invokes the
6251 * context menu if the OnLongClickListener did not consume the event.
6253 * @return {@code true} if one of the above receivers consumed the event,
6254 * {@code false} otherwise
6256 public boolean performLongClick() {
6257 return performLongClickInternal(mLongClickX, mLongClickY);
6261 * Calls this view's OnLongClickListener, if it is defined. Invokes the
6262 * context menu if the OnLongClickListener did not consume the event,
6263 * anchoring it to an (x,y) coordinate.
6265 * @param x x coordinate of the anchoring touch event, or {@link Float#NaN}
6266 * to disable anchoring
6267 * @param y y coordinate of the anchoring touch event, or {@link Float#NaN}
6268 * to disable anchoring
6269 * @return {@code true} if one of the above receivers consumed the event,
6270 * {@code false} otherwise
6272 public boolean performLongClick(float x, float y) {
6275 final boolean handled = performLongClick();
6276 mLongClickX = Float.NaN;
6277 mLongClickY = Float.NaN;
6282 * Calls this view's OnLongClickListener, if it is defined. Invokes the
6283 * context menu if the OnLongClickListener did not consume the event,
6284 * optionally anchoring it to an (x,y) coordinate.
6286 * @param x x coordinate of the anchoring touch event, or {@link Float#NaN}
6287 * to disable anchoring
6288 * @param y y coordinate of the anchoring touch event, or {@link Float#NaN}
6289 * to disable anchoring
6290 * @return {@code true} if one of the above receivers consumed the event,
6291 * {@code false} otherwise
6293 private boolean performLongClickInternal(float x, float y) {
6294 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_LONG_CLICKED);
6296 boolean handled = false;
6297 final ListenerInfo li = mListenerInfo;
6298 if (li != null && li.mOnLongClickListener != null) {
6299 handled = li.mOnLongClickListener.onLongClick(View.this);
6302 final boolean isAnchored = !Float.isNaN(x) && !Float.isNaN(y);
6303 handled = isAnchored ? showContextMenu(x, y) : showContextMenu();
6305 if ((mViewFlags & TOOLTIP) == TOOLTIP) {
6307 handled = showLongClickTooltip((int) x, (int) y);
6311 performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
6317 * Call this view's OnContextClickListener, if it is defined.
6319 * @param x the x coordinate of the context click
6320 * @param y the y coordinate of the context click
6321 * @return True if there was an assigned OnContextClickListener that consumed the event, false
6324 public boolean performContextClick(float x, float y) {
6325 return performContextClick();
6329 * Call this view's OnContextClickListener, if it is defined.
6331 * @return True if there was an assigned OnContextClickListener that consumed the event, false
6334 public boolean performContextClick() {
6335 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CONTEXT_CLICKED);
6337 boolean handled = false;
6338 ListenerInfo li = mListenerInfo;
6339 if (li != null && li.mOnContextClickListener != null) {
6340 handled = li.mOnContextClickListener.onContextClick(View.this);
6343 performHapticFeedback(HapticFeedbackConstants.CONTEXT_CLICK);
6349 * Performs button-related actions during a touch down event.
6351 * @param event The event.
6352 * @return True if the down was consumed.
6356 protected boolean performButtonActionOnTouchDown(MotionEvent event) {
6357 if (event.isFromSource(InputDevice.SOURCE_MOUSE) &&
6358 (event.getButtonState() & MotionEvent.BUTTON_SECONDARY) != 0) {
6359 showContextMenu(event.getX(), event.getY());
6360 mPrivateFlags |= PFLAG_CANCEL_NEXT_UP_EVENT;
6367 * Shows the context menu for this view.
6369 * @return {@code true} if the context menu was shown, {@code false}
6371 * @see #showContextMenu(float, float)
6373 public boolean showContextMenu() {
6374 return getParent().showContextMenuForChild(this);
6378 * Shows the context menu for this view anchored to the specified
6379 * view-relative coordinate.
6381 * @param x the X coordinate in pixels relative to the view to which the
6382 * menu should be anchored, or {@link Float#NaN} to disable anchoring
6383 * @param y the Y coordinate in pixels relative to the view to which the
6384 * menu should be anchored, or {@link Float#NaN} to disable anchoring
6385 * @return {@code true} if the context menu was shown, {@code false}
6388 public boolean showContextMenu(float x, float y) {
6389 return getParent().showContextMenuForChild(this, x, y);
6393 * Start an action mode with the default type {@link ActionMode#TYPE_PRIMARY}.
6395 * @param callback Callback that will control the lifecycle of the action mode
6396 * @return The new action mode if it is started, null otherwise
6399 * @see #startActionMode(android.view.ActionMode.Callback, int)
6401 public ActionMode startActionMode(ActionMode.Callback callback) {
6402 return startActionMode(callback, ActionMode.TYPE_PRIMARY);
6406 * Start an action mode with the given type.
6408 * @param callback Callback that will control the lifecycle of the action mode
6409 * @param type One of {@link ActionMode#TYPE_PRIMARY} or {@link ActionMode#TYPE_FLOATING}.
6410 * @return The new action mode if it is started, null otherwise
6414 public ActionMode startActionMode(ActionMode.Callback callback, int type) {
6415 ViewParent parent = getParent();
6416 if (parent == null) return null;
6418 return parent.startActionModeForChild(this, callback, type);
6419 } catch (AbstractMethodError ame) {
6420 // Older implementations of custom views might not implement this.
6421 return parent.startActionModeForChild(this, callback);
6426 * Call {@link Context#startActivityForResult(String, Intent, int, Bundle)} for the View's
6427 * Context, creating a unique View identifier to retrieve the result.
6429 * @param intent The Intent to be started.
6430 * @param requestCode The request code to use.
6433 public void startActivityForResult(Intent intent, int requestCode) {
6434 mStartActivityRequestWho = "@android:view:" + System.identityHashCode(this);
6435 getContext().startActivityForResult(mStartActivityRequestWho, intent, requestCode, null);
6439 * If this View corresponds to the calling who, dispatches the activity result.
6440 * @param who The identifier for the targeted View to receive the result.
6441 * @param requestCode The integer request code originally supplied to
6442 * startActivityForResult(), allowing you to identify who this
6444 * @param resultCode The integer result code returned by the child activity
6445 * through its setResult().
6446 * @param data An Intent, which can return result data to the caller
6447 * (various data can be attached to Intent "extras").
6448 * @return {@code true} if the activity result was dispatched.
6451 public boolean dispatchActivityResult(
6452 String who, int requestCode, int resultCode, Intent data) {
6453 if (mStartActivityRequestWho != null && mStartActivityRequestWho.equals(who)) {
6454 onActivityResult(requestCode, resultCode, data);
6455 mStartActivityRequestWho = null;
6462 * Receive the result from a previous call to {@link #startActivityForResult(Intent, int)}.
6464 * @param requestCode The integer request code originally supplied to
6465 * startActivityForResult(), allowing you to identify who this
6467 * @param resultCode The integer result code returned by the child activity
6468 * through its setResult().
6469 * @param data An Intent, which can return result data to the caller
6470 * (various data can be attached to Intent "extras").
6473 public void onActivityResult(int requestCode, int resultCode, Intent data) {
6478 * Register a callback to be invoked when a hardware key is pressed in this view.
6479 * Key presses in software input methods will generally not trigger the methods of
6481 * @param l the key listener to attach to this view
6483 public void setOnKeyListener(OnKeyListener l) {
6484 getListenerInfo().mOnKeyListener = l;
6488 * Register a callback to be invoked when a touch event is sent to this view.
6489 * @param l the touch listener to attach to this view
6491 public void setOnTouchListener(OnTouchListener l) {
6492 getListenerInfo().mOnTouchListener = l;
6496 * Register a callback to be invoked when a generic motion event is sent to this view.
6497 * @param l the generic motion listener to attach to this view
6499 public void setOnGenericMotionListener(OnGenericMotionListener l) {
6500 getListenerInfo().mOnGenericMotionListener = l;
6504 * Register a callback to be invoked when a hover event is sent to this view.
6505 * @param l the hover listener to attach to this view
6507 public void setOnHoverListener(OnHoverListener l) {
6508 getListenerInfo().mOnHoverListener = l;
6512 * Register a drag event listener callback object for this View. The parameter is
6513 * an implementation of {@link android.view.View.OnDragListener}. To send a drag event to a
6514 * View, the system calls the
6515 * {@link android.view.View.OnDragListener#onDrag(View,DragEvent)} method.
6516 * @param l An implementation of {@link android.view.View.OnDragListener}.
6518 public void setOnDragListener(OnDragListener l) {
6519 getListenerInfo().mOnDragListener = l;
6523 * Give this view focus. This will cause
6524 * {@link #onFocusChanged(boolean, int, android.graphics.Rect)} to be called.
6526 * Note: this does not check whether this {@link View} should get focus, it just
6527 * gives it focus no matter what. It should only be called internally by framework
6528 * code that knows what it is doing, namely {@link #requestFocus(int, Rect)}.
6530 * @param direction values are {@link View#FOCUS_UP}, {@link View#FOCUS_DOWN},
6531 * {@link View#FOCUS_LEFT} or {@link View#FOCUS_RIGHT}. This is the direction which
6532 * focus moved when requestFocus() is called. It may not always
6533 * apply, in which case use the default View.FOCUS_DOWN.
6534 * @param previouslyFocusedRect The rectangle of the view that had focus
6535 * prior in this View's coordinate system.
6537 void handleFocusGainInternal(@FocusRealDirection int direction, Rect previouslyFocusedRect) {
6539 System.out.println(this + " requestFocus()");
6542 if ((mPrivateFlags & PFLAG_FOCUSED) == 0) {
6543 mPrivateFlags |= PFLAG_FOCUSED;
6545 View oldFocus = (mAttachInfo != null) ? getRootView().findFocus() : null;
6547 if (mParent != null) {
6548 mParent.requestChildFocus(this, this);
6549 updateFocusedInCluster(oldFocus, direction);
6552 if (mAttachInfo != null) {
6553 mAttachInfo.mTreeObserver.dispatchOnGlobalFocusChange(oldFocus, this);
6556 onFocusChanged(true, direction, previouslyFocusedRect);
6557 refreshDrawableState();
6562 * Sets this view's preference for reveal behavior when it gains focus.
6564 * <p>When set to true, this is a signal to ancestor views in the hierarchy that
6565 * this view would prefer to be brought fully into view when it gains focus.
6566 * For example, a text field that a user is meant to type into. Other views such
6567 * as scrolling containers may prefer to opt-out of this behavior.</p>
6569 * <p>The default value for views is true, though subclasses may change this
6570 * based on their preferred behavior.</p>
6572 * @param revealOnFocus true to request reveal on focus in ancestors, false otherwise
6574 * @see #getRevealOnFocusHint()
6576 public final void setRevealOnFocusHint(boolean revealOnFocus) {
6577 if (revealOnFocus) {
6578 mPrivateFlags3 &= ~PFLAG3_NO_REVEAL_ON_FOCUS;
6580 mPrivateFlags3 |= PFLAG3_NO_REVEAL_ON_FOCUS;
6585 * Returns this view's preference for reveal behavior when it gains focus.
6587 * <p>When this method returns true for a child view requesting focus, ancestor
6588 * views responding to a focus change in {@link ViewParent#requestChildFocus(View, View)}
6589 * should make a best effort to make the newly focused child fully visible to the user.
6590 * When it returns false, ancestor views should preferably not disrupt scroll positioning or
6591 * other properties affecting visibility to the user as part of the focus change.</p>
6593 * @return true if this view would prefer to become fully visible when it gains focus,
6594 * false if it would prefer not to disrupt scroll positioning
6596 * @see #setRevealOnFocusHint(boolean)
6598 public final boolean getRevealOnFocusHint() {
6599 return (mPrivateFlags3 & PFLAG3_NO_REVEAL_ON_FOCUS) == 0;
6603 * Populates <code>outRect</code> with the hotspot bounds. By default,
6604 * the hotspot bounds are identical to the screen bounds.
6606 * @param outRect rect to populate with hotspot bounds
6607 * @hide Only for internal use by views and widgets.
6609 public void getHotspotBounds(Rect outRect) {
6610 final Drawable background = getBackground();
6611 if (background != null) {
6612 background.getHotspotBounds(outRect);
6614 getBoundsOnScreen(outRect);
6619 * Request that a rectangle of this view be visible on the screen,
6620 * scrolling if necessary just enough.
6622 * <p>A View should call this if it maintains some notion of which part
6623 * of its content is interesting. For example, a text editing view
6624 * should call this when its cursor moves.
6625 * <p>The Rectangle passed into this method should be in the View's content coordinate space.
6626 * It should not be affected by which part of the View is currently visible or its scroll
6629 * @param rectangle The rectangle in the View's content coordinate space
6630 * @return Whether any parent scrolled.
6632 public boolean requestRectangleOnScreen(Rect rectangle) {
6633 return requestRectangleOnScreen(rectangle, false);
6637 * Request that a rectangle of this view be visible on the screen,
6638 * scrolling if necessary just enough.
6640 * <p>A View should call this if it maintains some notion of which part
6641 * of its content is interesting. For example, a text editing view
6642 * should call this when its cursor moves.
6643 * <p>The Rectangle passed into this method should be in the View's content coordinate space.
6644 * It should not be affected by which part of the View is currently visible or its scroll
6646 * <p>When <code>immediate</code> is set to true, scrolling will not be
6649 * @param rectangle The rectangle in the View's content coordinate space
6650 * @param immediate True to forbid animated scrolling, false otherwise
6651 * @return Whether any parent scrolled.
6653 public boolean requestRectangleOnScreen(Rect rectangle, boolean immediate) {
6654 if (mParent == null) {
6660 RectF position = (mAttachInfo != null) ? mAttachInfo.mTmpTransformRect : new RectF();
6661 position.set(rectangle);
6663 ViewParent parent = mParent;
6664 boolean scrolled = false;
6665 while (parent != null) {
6666 rectangle.set((int) position.left, (int) position.top,
6667 (int) position.right, (int) position.bottom);
6669 scrolled |= parent.requestChildRectangleOnScreen(child, rectangle, immediate);
6671 if (!(parent instanceof View)) {
6675 // move it from child's content coordinate space to parent's content coordinate space
6676 position.offset(child.mLeft - child.getScrollX(), child.mTop -child.getScrollY());
6678 child = (View) parent;
6679 parent = child.getParent();
6686 * Called when this view wants to give up focus. If focus is cleared
6687 * {@link #onFocusChanged(boolean, int, android.graphics.Rect)} is called.
6689 * <strong>Note:</strong> When a View clears focus the framework is trying
6690 * to give focus to the first focusable View from the top. Hence, if this
6691 * View is the first from the top that can take focus, then all callbacks
6692 * related to clearing focus will be invoked after which the framework will
6693 * give focus to this view.
6696 public void clearFocus() {
6698 System.out.println(this + " clearFocus()");
6701 clearFocusInternal(null, true, true);
6705 * Clears focus from the view, optionally propagating the change up through
6706 * the parent hierarchy and requesting that the root view place new focus.
6708 * @param propagate whether to propagate the change up through the parent
6710 * @param refocus when propagate is true, specifies whether to request the
6711 * root view place new focus
6713 void clearFocusInternal(View focused, boolean propagate, boolean refocus) {
6714 if ((mPrivateFlags & PFLAG_FOCUSED) != 0) {
6715 mPrivateFlags &= ~PFLAG_FOCUSED;
6717 if (propagate && mParent != null) {
6718 mParent.clearChildFocus(this);
6721 onFocusChanged(false, 0, null);
6722 refreshDrawableState();
6724 if (propagate && (!refocus || !rootViewRequestFocus())) {
6725 notifyGlobalFocusCleared(this);
6730 void notifyGlobalFocusCleared(View oldFocus) {
6731 if (oldFocus != null && mAttachInfo != null) {
6732 mAttachInfo.mTreeObserver.dispatchOnGlobalFocusChange(oldFocus, null);
6736 boolean rootViewRequestFocus() {
6737 final View root = getRootView();
6738 return root != null && root.requestFocus();
6742 * Called internally by the view system when a new view is getting focus.
6743 * This is what clears the old focus.
6745 * <b>NOTE:</b> The parent view's focused child must be updated manually
6746 * after calling this method. Otherwise, the view hierarchy may be left in
6747 * an inconstent state.
6749 void unFocus(View focused) {
6751 System.out.println(this + " unFocus()");
6754 clearFocusInternal(focused, false, false);
6758 * Returns true if this view has focus itself, or is the ancestor of the
6759 * view that has focus.
6761 * @return True if this view has or contains focus, false otherwise.
6763 @ViewDebug.ExportedProperty(category = "focus")
6764 public boolean hasFocus() {
6765 return (mPrivateFlags & PFLAG_FOCUSED) != 0;
6769 * Returns true if this view is focusable or if it contains a reachable View
6770 * for which {@link #hasFocusable()} returns {@code true}. A "reachable hasFocusable()"
6771 * is a view whose parents do not block descendants focus.
6772 * Only {@link #VISIBLE} views are considered focusable.
6774 * <p>As of {@link Build.VERSION_CODES#O} views that are determined to be focusable
6775 * through {@link #FOCUSABLE_AUTO} will also cause this method to return {@code true}.
6776 * Apps that declare a {@link android.content.pm.ApplicationInfo#targetSdkVersion} of
6777 * earlier than {@link Build.VERSION_CODES#O} will continue to see this method return
6778 * {@code false} for views not explicitly marked as focusable.
6779 * Use {@link #hasExplicitFocusable()} if you require the pre-{@link Build.VERSION_CODES#O}
6782 * @return {@code true} if the view is focusable or if the view contains a focusable
6783 * view, {@code false} otherwise
6785 * @see ViewGroup#FOCUS_BLOCK_DESCENDANTS
6786 * @see ViewGroup#getTouchscreenBlocksFocus()
6787 * @see #hasExplicitFocusable()
6789 public boolean hasFocusable() {
6790 return hasFocusable(!sHasFocusableExcludeAutoFocusable, false);
6794 * Returns true if this view is focusable or if it contains a reachable View
6795 * for which {@link #hasExplicitFocusable()} returns {@code true}.
6796 * A "reachable hasExplicitFocusable()" is a view whose parents do not block descendants focus.
6797 * Only {@link #VISIBLE} views for which {@link #getFocusable()} would return
6798 * {@link #FOCUSABLE} are considered focusable.
6800 * <p>This method preserves the pre-{@link Build.VERSION_CODES#O} behavior of
6801 * {@link #hasFocusable()} in that only views explicitly set focusable will cause
6802 * this method to return true. A view set to {@link #FOCUSABLE_AUTO} that resolves
6803 * to focusable will not.</p>
6805 * @return {@code true} if the view is focusable or if the view contains a focusable
6806 * view, {@code false} otherwise
6808 * @see #hasFocusable()
6810 public boolean hasExplicitFocusable() {
6811 return hasFocusable(false, true);
6814 boolean hasFocusable(boolean allowAutoFocus, boolean dispatchExplicit) {
6815 if (!isFocusableInTouchMode()) {
6816 for (ViewParent p = mParent; p instanceof ViewGroup; p = p.getParent()) {
6817 final ViewGroup g = (ViewGroup) p;
6818 if (g.shouldBlockFocusForTouchscreen()) {
6824 // Invisible and gone views are never focusable.
6825 if ((mViewFlags & VISIBILITY_MASK) != VISIBLE) {
6829 // Only use effective focusable value when allowed.
6830 if ((allowAutoFocus || getFocusable() != FOCUSABLE_AUTO) && isFocusable()) {
6838 * Called by the view system when the focus state of this view changes.
6839 * When the focus change event is caused by directional navigation, direction
6840 * and previouslyFocusedRect provide insight into where the focus is coming from.
6841 * When overriding, be sure to call up through to the super class so that
6842 * the standard focus handling will occur.
6844 * @param gainFocus True if the View has focus; false otherwise.
6845 * @param direction The direction focus has moved when requestFocus()
6846 * is called to give this view focus. Values are
6847 * {@link #FOCUS_UP}, {@link #FOCUS_DOWN}, {@link #FOCUS_LEFT},
6848 * {@link #FOCUS_RIGHT}, {@link #FOCUS_FORWARD}, or {@link #FOCUS_BACKWARD}.
6849 * It may not always apply, in which case use the default.
6850 * @param previouslyFocusedRect The rectangle, in this view's coordinate
6851 * system, of the previously focused view. If applicable, this will be
6852 * passed in as finer grained information about where the focus is coming
6853 * from (in addition to direction). Will be <code>null</code> otherwise.
6856 protected void onFocusChanged(boolean gainFocus, @FocusDirection int direction,
6857 @Nullable Rect previouslyFocusedRect) {
6859 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED);
6861 notifyViewAccessibilityStateChangedIfNeeded(
6862 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED);
6865 // Here we check whether we still need the default focus highlight, and switch it on/off.
6866 switchDefaultFocusHighlight();
6868 InputMethodManager imm = InputMethodManager.peekInstance();
6873 if (imm != null && mAttachInfo != null && mAttachInfo.mHasWindowFocus) {
6877 } else if (imm != null && mAttachInfo != null && mAttachInfo.mHasWindowFocus) {
6882 ListenerInfo li = mListenerInfo;
6883 if (li != null && li.mOnFocusChangeListener != null) {
6884 li.mOnFocusChangeListener.onFocusChange(this, gainFocus);
6887 if (mAttachInfo != null) {
6888 mAttachInfo.mKeyDispatchState.reset(this);
6891 notifyEnterOrExitForAutoFillIfNeeded(gainFocus);
6894 private void notifyEnterOrExitForAutoFillIfNeeded(boolean enter) {
6895 if (isAutofillable() && isAttachedToWindow()) {
6896 AutofillManager afm = getAutofillManager();
6898 if (enter && hasWindowFocus() && isFocused()) {
6899 // We have not been laid out yet, hence cannot evaluate
6900 // whether this view is visible to the user, we will do
6901 // the evaluation once layout is complete.
6903 mPrivateFlags3 |= PFLAG3_NOTIFY_AUTOFILL_ENTER_ON_LAYOUT;
6904 } else if (isVisibleToUser()) {
6905 afm.notifyViewEntered(this);
6907 } else if (!hasWindowFocus() || !isFocused()) {
6908 afm.notifyViewExited(this);
6915 * Sends an accessibility event of the given type. If accessibility is
6916 * not enabled this method has no effect. The default implementation calls
6917 * {@link #onInitializeAccessibilityEvent(AccessibilityEvent)} first
6918 * to populate information about the event source (this View), then calls
6919 * {@link #dispatchPopulateAccessibilityEvent(AccessibilityEvent)} to
6920 * populate the text content of the event source including its descendants,
6922 * {@link ViewParent#requestSendAccessibilityEvent(View, AccessibilityEvent)}
6923 * on its parent to request sending of the event to interested parties.
6925 * If an {@link AccessibilityDelegate} has been specified via calling
6926 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its
6927 * {@link AccessibilityDelegate#sendAccessibilityEvent(View, int)} is
6928 * responsible for handling this call.
6931 * @param eventType The type of the event to send, as defined by several types from
6932 * {@link android.view.accessibility.AccessibilityEvent}, such as
6933 * {@link android.view.accessibility.AccessibilityEvent#TYPE_VIEW_CLICKED} or
6934 * {@link android.view.accessibility.AccessibilityEvent#TYPE_VIEW_HOVER_ENTER}.
6936 * @see #onInitializeAccessibilityEvent(AccessibilityEvent)
6937 * @see #dispatchPopulateAccessibilityEvent(AccessibilityEvent)
6938 * @see ViewParent#requestSendAccessibilityEvent(View, AccessibilityEvent)
6939 * @see AccessibilityDelegate
6941 public void sendAccessibilityEvent(int eventType) {
6942 if (mAccessibilityDelegate != null) {
6943 mAccessibilityDelegate.sendAccessibilityEvent(this, eventType);
6945 sendAccessibilityEventInternal(eventType);
6950 * Convenience method for sending a {@link AccessibilityEvent#TYPE_ANNOUNCEMENT}
6951 * {@link AccessibilityEvent} to make an announcement which is related to some
6952 * sort of a context change for which none of the events representing UI transitions
6953 * is a good fit. For example, announcing a new page in a book. If accessibility
6954 * is not enabled this method does nothing.
6956 * @param text The announcement text.
6958 public void announceForAccessibility(CharSequence text) {
6959 if (AccessibilityManager.getInstance(mContext).isEnabled() && mParent != null) {
6960 AccessibilityEvent event = AccessibilityEvent.obtain(
6961 AccessibilityEvent.TYPE_ANNOUNCEMENT);
6962 onInitializeAccessibilityEvent(event);
6963 event.getText().add(text);
6964 event.setContentDescription(null);
6965 mParent.requestSendAccessibilityEvent(this, event);
6970 * @see #sendAccessibilityEvent(int)
6972 * Note: Called from the default {@link AccessibilityDelegate}.
6976 public void sendAccessibilityEventInternal(int eventType) {
6977 if (AccessibilityManager.getInstance(mContext).isEnabled()) {
6978 sendAccessibilityEventUnchecked(AccessibilityEvent.obtain(eventType));
6983 * This method behaves exactly as {@link #sendAccessibilityEvent(int)} but
6984 * takes as an argument an empty {@link AccessibilityEvent} and does not
6985 * perform a check whether accessibility is enabled.
6987 * If an {@link AccessibilityDelegate} has been specified via calling
6988 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its
6989 * {@link AccessibilityDelegate#sendAccessibilityEventUnchecked(View, AccessibilityEvent)}
6990 * is responsible for handling this call.
6993 * @param event The event to send.
6995 * @see #sendAccessibilityEvent(int)
6997 public void sendAccessibilityEventUnchecked(AccessibilityEvent event) {
6998 if (mAccessibilityDelegate != null) {
6999 mAccessibilityDelegate.sendAccessibilityEventUnchecked(this, event);
7001 sendAccessibilityEventUncheckedInternal(event);
7006 * @see #sendAccessibilityEventUnchecked(AccessibilityEvent)
7008 * Note: Called from the default {@link AccessibilityDelegate}.
7012 public void sendAccessibilityEventUncheckedInternal(AccessibilityEvent event) {
7016 onInitializeAccessibilityEvent(event);
7017 // Only a subset of accessibility events populates text content.
7018 if ((event.getEventType() & POPULATING_ACCESSIBILITY_EVENT_TYPES) != 0) {
7019 dispatchPopulateAccessibilityEvent(event);
7021 // In the beginning we called #isShown(), so we know that getParent() is not null.
7022 ViewParent parent = getParent();
7023 if (parent != null) {
7024 getParent().requestSendAccessibilityEvent(this, event);
7029 * Dispatches an {@link AccessibilityEvent} to the {@link View} first and then
7030 * to its children for adding their text content to the event. Note that the
7031 * event text is populated in a separate dispatch path since we add to the
7032 * event not only the text of the source but also the text of all its descendants.
7033 * A typical implementation will call
7034 * {@link #onPopulateAccessibilityEvent(AccessibilityEvent)} on the this view
7035 * and then call the {@link #dispatchPopulateAccessibilityEvent(AccessibilityEvent)}
7036 * on each child. Override this method if custom population of the event text
7037 * content is required.
7039 * If an {@link AccessibilityDelegate} has been specified via calling
7040 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its
7041 * {@link AccessibilityDelegate#dispatchPopulateAccessibilityEvent(View, AccessibilityEvent)}
7042 * is responsible for handling this call.
7045 * <em>Note:</em> Accessibility events of certain types are not dispatched for
7046 * populating the event text via this method. For details refer to {@link AccessibilityEvent}.
7049 * @param event The event.
7051 * @return True if the event population was completed.
7053 public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
7054 if (mAccessibilityDelegate != null) {
7055 return mAccessibilityDelegate.dispatchPopulateAccessibilityEvent(this, event);
7057 return dispatchPopulateAccessibilityEventInternal(event);
7062 * @see #dispatchPopulateAccessibilityEvent(AccessibilityEvent)
7064 * Note: Called from the default {@link AccessibilityDelegate}.
7068 public boolean dispatchPopulateAccessibilityEventInternal(AccessibilityEvent event) {
7069 onPopulateAccessibilityEvent(event);
7074 * Called from {@link #dispatchPopulateAccessibilityEvent(AccessibilityEvent)}
7075 * giving a chance to this View to populate the accessibility event with its
7076 * text content. While this method is free to modify event
7077 * attributes other than text content, doing so should normally be performed in
7078 * {@link #onInitializeAccessibilityEvent(AccessibilityEvent)}.
7080 * Example: Adding formatted date string to an accessibility event in addition
7081 * to the text added by the super implementation:
7082 * <pre> public void onPopulateAccessibilityEvent(AccessibilityEvent event) {
7083 * super.onPopulateAccessibilityEvent(event);
7084 * final int flags = DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_SHOW_WEEKDAY;
7085 * String selectedDateUtterance = DateUtils.formatDateTime(mContext,
7086 * mCurrentDate.getTimeInMillis(), flags);
7087 * event.getText().add(selectedDateUtterance);
7090 * If an {@link AccessibilityDelegate} has been specified via calling
7091 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its
7092 * {@link AccessibilityDelegate#onPopulateAccessibilityEvent(View, AccessibilityEvent)}
7093 * is responsible for handling this call.
7095 * <p class="note"><strong>Note:</strong> Always call the super implementation before adding
7096 * information to the event, in case the default implementation has basic information to add.
7099 * @param event The accessibility event which to populate.
7101 * @see #sendAccessibilityEvent(int)
7102 * @see #dispatchPopulateAccessibilityEvent(AccessibilityEvent)
7105 public void onPopulateAccessibilityEvent(AccessibilityEvent event) {
7106 if (mAccessibilityDelegate != null) {
7107 mAccessibilityDelegate.onPopulateAccessibilityEvent(this, event);
7109 onPopulateAccessibilityEventInternal(event);
7114 * @see #onPopulateAccessibilityEvent(AccessibilityEvent)
7116 * Note: Called from the default {@link AccessibilityDelegate}.
7120 public void onPopulateAccessibilityEventInternal(AccessibilityEvent event) {
7124 * Initializes an {@link AccessibilityEvent} with information about
7125 * this View which is the event source. In other words, the source of
7126 * an accessibility event is the view whose state change triggered firing
7129 * Example: Setting the password property of an event in addition
7130 * to properties set by the super implementation:
7131 * <pre> public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
7132 * super.onInitializeAccessibilityEvent(event);
7133 * event.setPassword(true);
7136 * If an {@link AccessibilityDelegate} has been specified via calling
7137 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its
7138 * {@link AccessibilityDelegate#onInitializeAccessibilityEvent(View, AccessibilityEvent)}
7139 * is responsible for handling this call.
7141 * <p class="note"><strong>Note:</strong> Always call the super implementation before adding
7142 * information to the event, in case the default implementation has basic information to add.
7144 * @param event The event to initialize.
7146 * @see #sendAccessibilityEvent(int)
7147 * @see #dispatchPopulateAccessibilityEvent(AccessibilityEvent)
7150 public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
7151 if (mAccessibilityDelegate != null) {
7152 mAccessibilityDelegate.onInitializeAccessibilityEvent(this, event);
7154 onInitializeAccessibilityEventInternal(event);
7159 * @see #onInitializeAccessibilityEvent(AccessibilityEvent)
7161 * Note: Called from the default {@link AccessibilityDelegate}.
7165 public void onInitializeAccessibilityEventInternal(AccessibilityEvent event) {
7166 event.setSource(this);
7167 event.setClassName(getAccessibilityClassName());
7168 event.setPackageName(getContext().getPackageName());
7169 event.setEnabled(isEnabled());
7170 event.setContentDescription(mContentDescription);
7172 switch (event.getEventType()) {
7173 case AccessibilityEvent.TYPE_VIEW_FOCUSED: {
7174 ArrayList<View> focusablesTempList = (mAttachInfo != null)
7175 ? mAttachInfo.mTempArrayList : new ArrayList<View>();
7176 getRootView().addFocusables(focusablesTempList, View.FOCUS_FORWARD, FOCUSABLES_ALL);
7177 event.setItemCount(focusablesTempList.size());
7178 event.setCurrentItemIndex(focusablesTempList.indexOf(this));
7179 if (mAttachInfo != null) {
7180 focusablesTempList.clear();
7183 case AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED: {
7184 CharSequence text = getIterableTextForAccessibility();
7185 if (text != null && text.length() > 0) {
7186 event.setFromIndex(getAccessibilitySelectionStart());
7187 event.setToIndex(getAccessibilitySelectionEnd());
7188 event.setItemCount(text.length());
7195 * Returns an {@link AccessibilityNodeInfo} representing this view from the
7196 * point of view of an {@link android.accessibilityservice.AccessibilityService}.
7197 * This method is responsible for obtaining an accessibility node info from a
7198 * pool of reusable instances and calling
7199 * {@link #onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)} on this view to
7200 * initialize the former.
7202 * Note: The client is responsible for recycling the obtained instance by calling
7203 * {@link AccessibilityNodeInfo#recycle()} to minimize object creation.
7206 * @return A populated {@link AccessibilityNodeInfo}.
7208 * @see AccessibilityNodeInfo
7210 public AccessibilityNodeInfo createAccessibilityNodeInfo() {
7211 if (mAccessibilityDelegate != null) {
7212 return mAccessibilityDelegate.createAccessibilityNodeInfo(this);
7214 return createAccessibilityNodeInfoInternal();
7219 * @see #createAccessibilityNodeInfo()
7223 public AccessibilityNodeInfo createAccessibilityNodeInfoInternal() {
7224 AccessibilityNodeProvider provider = getAccessibilityNodeProvider();
7225 if (provider != null) {
7226 return provider.createAccessibilityNodeInfo(AccessibilityNodeProvider.HOST_VIEW_ID);
7228 AccessibilityNodeInfo info = AccessibilityNodeInfo.obtain(this);
7229 onInitializeAccessibilityNodeInfo(info);
7235 * Initializes an {@link AccessibilityNodeInfo} with information about this view.
7236 * The base implementation sets:
7238 * <li>{@link AccessibilityNodeInfo#setParent(View)},</li>
7239 * <li>{@link AccessibilityNodeInfo#setBoundsInParent(Rect)},</li>
7240 * <li>{@link AccessibilityNodeInfo#setBoundsInScreen(Rect)},</li>
7241 * <li>{@link AccessibilityNodeInfo#setPackageName(CharSequence)},</li>
7242 * <li>{@link AccessibilityNodeInfo#setClassName(CharSequence)},</li>
7243 * <li>{@link AccessibilityNodeInfo#setContentDescription(CharSequence)},</li>
7244 * <li>{@link AccessibilityNodeInfo#setEnabled(boolean)},</li>
7245 * <li>{@link AccessibilityNodeInfo#setClickable(boolean)},</li>
7246 * <li>{@link AccessibilityNodeInfo#setFocusable(boolean)},</li>
7247 * <li>{@link AccessibilityNodeInfo#setFocused(boolean)},</li>
7248 * <li>{@link AccessibilityNodeInfo#setLongClickable(boolean)},</li>
7249 * <li>{@link AccessibilityNodeInfo#setSelected(boolean)},</li>
7250 * <li>{@link AccessibilityNodeInfo#setContextClickable(boolean)}</li>
7253 * Subclasses should override this method, call the super implementation,
7254 * and set additional attributes.
7257 * If an {@link AccessibilityDelegate} has been specified via calling
7258 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its
7259 * {@link AccessibilityDelegate#onInitializeAccessibilityNodeInfo(View, AccessibilityNodeInfo)}
7260 * is responsible for handling this call.
7263 * @param info The instance to initialize.
7266 public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
7267 if (mAccessibilityDelegate != null) {
7268 mAccessibilityDelegate.onInitializeAccessibilityNodeInfo(this, info);
7270 onInitializeAccessibilityNodeInfoInternal(info);
7275 * Gets the location of this view in screen coordinates.
7277 * @param outRect The output location
7280 public void getBoundsOnScreen(Rect outRect) {
7281 getBoundsOnScreen(outRect, false);
7285 * Gets the location of this view in screen coordinates.
7287 * @param outRect The output location
7288 * @param clipToParent Whether to clip child bounds to the parent ones.
7291 public void getBoundsOnScreen(Rect outRect, boolean clipToParent) {
7292 if (mAttachInfo == null) {
7296 RectF position = mAttachInfo.mTmpTransformRect;
7297 position.set(0, 0, mRight - mLeft, mBottom - mTop);
7298 mapRectFromViewToScreenCoords(position, clipToParent);
7299 outRect.set(Math.round(position.left), Math.round(position.top),
7300 Math.round(position.right), Math.round(position.bottom));
7304 * Map a rectangle from view-relative coordinates to screen-relative coordinates
7306 * @param rect The rectangle to be mapped
7307 * @param clipToParent Whether to clip child bounds to the parent ones.
7310 public void mapRectFromViewToScreenCoords(RectF rect, boolean clipToParent) {
7311 if (!hasIdentityMatrix()) {
7312 getMatrix().mapRect(rect);
7315 rect.offset(mLeft, mTop);
7317 ViewParent parent = mParent;
7318 while (parent instanceof View) {
7319 View parentView = (View) parent;
7321 rect.offset(-parentView.mScrollX, -parentView.mScrollY);
7324 rect.left = Math.max(rect.left, 0);
7325 rect.top = Math.max(rect.top, 0);
7326 rect.right = Math.min(rect.right, parentView.getWidth());
7327 rect.bottom = Math.min(rect.bottom, parentView.getHeight());
7330 if (!parentView.hasIdentityMatrix()) {
7331 parentView.getMatrix().mapRect(rect);
7334 rect.offset(parentView.mLeft, parentView.mTop);
7336 parent = parentView.mParent;
7339 if (parent instanceof ViewRootImpl) {
7340 ViewRootImpl viewRootImpl = (ViewRootImpl) parent;
7341 rect.offset(0, -viewRootImpl.mCurScrollY);
7344 rect.offset(mAttachInfo.mWindowLeft, mAttachInfo.mWindowTop);
7348 * Return the class name of this object to be used for accessibility purposes.
7349 * Subclasses should only override this if they are implementing something that
7350 * should be seen as a completely new class of view when used by accessibility,
7351 * unrelated to the class it is deriving from. This is used to fill in
7352 * {@link AccessibilityNodeInfo#setClassName AccessibilityNodeInfo.setClassName}.
7354 public CharSequence getAccessibilityClassName() {
7355 return View.class.getName();
7359 * Called when assist structure is being retrieved from a view as part of
7360 * {@link android.app.Activity#onProvideAssistData Activity.onProvideAssistData}.
7361 * @param structure Fill in with structured view data. The default implementation
7362 * fills in all data that can be inferred from the view itself.
7364 public void onProvideStructure(ViewStructure structure) {
7365 onProvideStructureForAssistOrAutofill(structure, false, 0);
7369 * Called when assist structure is being retrieved from a view as part of an autofill request.
7371 * <p>This method already provides most of what's needed for autofill, but should be overridden
7374 * <li>The view contents does not include PII (Personally Identifiable Information), so it
7375 * can call {@link ViewStructure#setDataIsSensitive(boolean)} passing {@code false}.
7376 * <li>It must set fields such {@link ViewStructure#setText(CharSequence)},
7377 * {@link ViewStructure#setAutofillOptions(CharSequence[])},
7378 * or {@link ViewStructure#setWebDomain(String)}.
7379 * <li> The {@code left} and {@code top} values set in
7380 * {@link ViewStructure#setDimens(int, int, int, int, int, int)} need to be relative to the next
7381 * {@link ViewGroup#isImportantForAutofill() included} parent in the structure.
7384 * @param structure Fill in with structured view data. The default implementation
7385 * fills in all data that can be inferred from the view itself.
7386 * @param flags optional flags.
7388 * @see #AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS
7390 public void onProvideAutofillStructure(ViewStructure structure, @AutofillFlags int flags) {
7391 onProvideStructureForAssistOrAutofill(structure, true, flags);
7394 private void onProvideStructureForAssistOrAutofill(ViewStructure structure,
7395 boolean forAutofill, @AutofillFlags int flags) {
7397 if (id != NO_ID && !isViewIdGenerated(id)) {
7398 String pkg, type, entry;
7400 final Resources res = getResources();
7401 entry = res.getResourceEntryName(id);
7402 type = res.getResourceTypeName(id);
7403 pkg = res.getResourcePackageName(id);
7404 } catch (Resources.NotFoundException e) {
7405 entry = type = pkg = null;
7407 structure.setId(id, pkg, type, entry);
7409 structure.setId(id, null, null, null);
7413 final @AutofillType int autofillType = getAutofillType();
7414 // Don't need to fill autofill info if view does not support it.
7415 // For example, only TextViews that are editable support autofill
7416 if (autofillType != AUTOFILL_TYPE_NONE) {
7417 structure.setAutofillType(autofillType);
7418 structure.setAutofillHints(getAutofillHints());
7419 structure.setAutofillValue(getAutofillValue());
7423 int ignoredParentLeft = 0;
7424 int ignoredParentTop = 0;
7425 if (forAutofill && (flags & AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS) == 0) {
7426 View parentGroup = null;
7428 ViewParent viewParent = getParent();
7429 if (viewParent instanceof View) {
7430 parentGroup = (View) viewParent;
7433 while (parentGroup != null && !parentGroup.isImportantForAutofill()) {
7434 ignoredParentLeft += parentGroup.mLeft;
7435 ignoredParentTop += parentGroup.mTop;
7437 viewParent = parentGroup.getParent();
7438 if (viewParent instanceof View) {
7439 parentGroup = (View) viewParent;
7446 structure.setDimens(ignoredParentLeft + mLeft, ignoredParentTop + mTop, mScrollX, mScrollY,
7447 mRight - mLeft, mBottom - mTop);
7449 if (!hasIdentityMatrix()) {
7450 structure.setTransformation(getMatrix());
7452 structure.setElevation(getZ());
7454 structure.setVisibility(getVisibility());
7455 structure.setEnabled(isEnabled());
7456 if (isClickable()) {
7457 structure.setClickable(true);
7459 if (isFocusable()) {
7460 structure.setFocusable(true);
7463 structure.setFocused(true);
7465 if (isAccessibilityFocused()) {
7466 structure.setAccessibilityFocused(true);
7469 structure.setSelected(true);
7471 if (isActivated()) {
7472 structure.setActivated(true);
7474 if (isLongClickable()) {
7475 structure.setLongClickable(true);
7477 if (this instanceof Checkable) {
7478 structure.setCheckable(true);
7479 if (((Checkable)this).isChecked()) {
7480 structure.setChecked(true);
7484 structure.setOpaque(true);
7486 if (isContextClickable()) {
7487 structure.setContextClickable(true);
7489 structure.setClassName(getAccessibilityClassName().toString());
7490 structure.setContentDescription(getContentDescription());
7494 * Called when assist structure is being retrieved from a view as part of
7495 * {@link android.app.Activity#onProvideAssistData Activity.onProvideAssistData} to
7496 * generate additional virtual structure under this view. The defaullt implementation
7497 * uses {@link #getAccessibilityNodeProvider()} to try to generate this from the
7498 * view's virtual accessibility nodes, if any. You can override this for a more
7499 * optimal implementation providing this data.
7501 public void onProvideVirtualStructure(ViewStructure structure) {
7502 AccessibilityNodeProvider provider = getAccessibilityNodeProvider();
7503 if (provider != null) {
7504 AccessibilityNodeInfo info = createAccessibilityNodeInfo();
7505 structure.setChildCount(1);
7506 ViewStructure root = structure.newChild(0);
7507 populateVirtualStructure(root, provider, info);
7513 * Called when assist structure is being retrieved from a view as part of an autofill request
7514 * to generate additional virtual structure under this view.
7516 * <p>When implementing this method, subclasses must follow the rules below:
7519 * <li>Also implement {@link #autofill(SparseArray)} to autofill the virtual
7522 * {@link android.view.autofill.AutofillManager#notifyViewEntered} and
7523 * {@link android.view.autofill.AutofillManager#notifyViewExited(View, int)}
7524 * when the focus inside the view changed.
7525 * <li>Call {@link android.view.autofill.AutofillManager#notifyValueChanged(View, int,
7526 * AutofillValue)} when the value of a child changed.
7527 * <li>Call {@link AutofillManager#commit()} when the autofill context
7528 * of the view structure changed and you want the current autofill interaction if such
7530 * <li>Call {@link AutofillManager#cancel()} when the autofill context
7531 * of the view structure changed and you want the current autofill interaction if such
7533 * <li> The {@code left} and {@code top} values set in
7534 * {@link ViewStructure#setDimens(int, int, int, int, int, int)} need to be relative to the next
7535 * {@link ViewGroup#isImportantForAutofill() included} parent in the structure.
7538 * @param structure Fill in with structured view data.
7539 * @param flags optional flags.
7541 * @see #AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS
7543 public void onProvideAutofillVirtualStructure(ViewStructure structure, int flags) {
7547 * Automatically fills the content of this view with the {@code value}.
7549 * <p>By default does nothing, but views should override it (and {@link #getAutofillType()},
7550 * {@link #getAutofillValue()}, and {@link #onProvideAutofillStructure(ViewStructure, int)}
7551 * to support the Autofill Framework.
7553 * <p>Typically, it is implemented by:
7556 * <li>Calling the proper getter method on {@link AutofillValue} to fetch the actual value.
7557 * <li>Passing the actual value to the equivalent setter in the view.
7560 * <p>For example, a text-field view could implement the method this way:
7562 * <pre class="prettyprint">
7564 * public void autofill(AutofillValue value) {
7565 * if (!value.isText() || !this.isEditable()) {
7568 * CharSequence text = value.getTextValue();
7569 * if (text != null) {
7570 * this.setText(text);
7575 * <p>If the value is updated asynchronously the next call to
7576 * {@link AutofillManager#notifyValueChanged(View)} must happen <u>after</u> the value was
7577 * changed to the autofilled value. If not, the view will not be considered autofilled.
7579 * @param value value to be autofilled.
7581 public void autofill(@SuppressWarnings("unused") AutofillValue value) {
7585 * Automatically fills the content of a virtual views.
7587 * <p>See {@link #autofill(AutofillValue)} and
7588 * {@link #onProvideAutofillVirtualStructure(ViewStructure, int)} for more info.
7589 * <p>To indicate that a virtual view was autofilled
7590 * <code>?android:attr/autofilledHighlight</code> should be drawn over it until the data
7593 * @param values map of values to be autofilled, keyed by virtual child id.
7595 * @attr ref android.R.styleable#Theme_autofilledHighlight
7597 public void autofill(@NonNull @SuppressWarnings("unused") SparseArray<AutofillValue> values) {
7601 * Gets the unique identifier of this view on the screen for Autofill purposes.
7603 * @return The View's Autofill id.
7605 public final AutofillId getAutofillId() {
7606 if (mAutofillId == null) {
7607 // The autofill id needs to be unique, but its value doesn't matter,
7608 // so it's better to reuse the accessibility id to save space.
7609 mAutofillId = new AutofillId(getAccessibilityViewId());
7615 * Describes the autofill type that should be used on calls to
7616 * {@link #autofill(AutofillValue)} and {@link #autofill(SparseArray)}.
7618 * <p>By default returns {@link #AUTOFILL_TYPE_NONE}, but views should override it (and
7619 * {@link #autofill(AutofillValue)} to support the Autofill Framework.
7621 public @AutofillType int getAutofillType() {
7622 return AUTOFILL_TYPE_NONE;
7626 * Gets the hints that help an {@link android.service.autofill.AutofillService} determine how
7627 * to autofill the view with the user's data.
7629 * <p>See {@link #setAutofillHints(String...)} for more info about these hints.
7631 * @return The hints set via the attribute or {@link #setAutofillHints(String...)}, or
7632 * {@code null} if no hints were set.
7634 * @attr ref android.R.styleable#View_autofillHints
7636 @ViewDebug.ExportedProperty()
7637 @Nullable public String[] getAutofillHints() {
7638 return mAutofillHints;
7644 public boolean isAutofilled() {
7645 return (mPrivateFlags3 & PFLAG3_IS_AUTOFILLED) != 0;
7649 * Gets the {@link View}'s current autofill value.
7651 * <p>By default returns {@code null}, but views should override it (and
7652 * {@link #autofill(AutofillValue)}, and {@link #getAutofillType()} to support the Autofill
7656 public AutofillValue getAutofillValue() {
7661 * Gets the mode for determining whether this View is important for autofill.
7663 * <p>See {@link #setImportantForAutofill(int)} for more info about this mode.
7665 * @return {@link #IMPORTANT_FOR_AUTOFILL_AUTO} by default, or value passed to
7666 * {@link #setImportantForAutofill(int)}.
7668 * @attr ref android.R.styleable#View_importantForAutofill
7670 @ViewDebug.ExportedProperty(mapping = {
7671 @ViewDebug.IntToString(from = IMPORTANT_FOR_AUTOFILL_AUTO, to = "auto"),
7672 @ViewDebug.IntToString(from = IMPORTANT_FOR_AUTOFILL_YES, to = "yes"),
7673 @ViewDebug.IntToString(from = IMPORTANT_FOR_AUTOFILL_NO, to = "no"),
7674 @ViewDebug.IntToString(from = IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS,
7675 to = "yesExcludeDescendants"),
7676 @ViewDebug.IntToString(from = IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS,
7677 to = "noExcludeDescendants")})
7678 public @AutofillImportance int getImportantForAutofill() {
7679 return (mPrivateFlags3
7680 & PFLAG3_IMPORTANT_FOR_AUTOFILL_MASK) >> PFLAG3_IMPORTANT_FOR_AUTOFILL_SHIFT;
7684 * Sets the mode for determining whether this View is important for autofill.
7686 * <p>This property controls how this view is presented to the autofill components
7687 * which help users to fill credentials, addresses, etc. For example, views
7688 * that contain labels and input fields are useful for autofill components to
7689 * determine the user context and provide values for the inputs. Note that the
7690 * user can always override this by manually triggering autotill which would
7691 * expose the view to the autofill provider.
7693 * <p>The platform determines the importance for autofill automatically but you
7694 * can use this method to customize the behavior. See the autofill modes below
7697 * <p>See {@link #setImportantForAutofill(int)} for more info about this mode.
7699 * @param mode {@link #IMPORTANT_FOR_AUTOFILL_AUTO}, {@link #IMPORTANT_FOR_AUTOFILL_YES},
7700 * {@link #IMPORTANT_FOR_AUTOFILL_NO}, {@link #IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS},
7701 * or {@link #IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS}.
7703 * @attr ref android.R.styleable#View_importantForAutofill
7705 public void setImportantForAutofill(@AutofillImportance int mode) {
7706 mPrivateFlags3 &= ~PFLAG3_IMPORTANT_FOR_AUTOFILL_MASK;
7707 mPrivateFlags3 |= (mode << PFLAG3_IMPORTANT_FOR_AUTOFILL_SHIFT)
7708 & PFLAG3_IMPORTANT_FOR_AUTOFILL_MASK;
7712 * Hints the Android System whether the {@link android.app.assist.AssistStructure.ViewNode}
7713 * associated with this View should be included in a {@link ViewStructure} used for
7714 * autofill purposes.
7716 * <p>Generally speaking, a view is important for autofill if:
7718 * <li>The view can-be autofilled by an {@link android.service.autofill.AutofillService}.
7719 * <li>The view contents can help an {@link android.service.autofill.AutofillService} to
7720 * autofill other views.
7723 * <p>For example, view containers should typically return {@code false} for performance reasons
7724 * (since the important info is provided by their children), but if the container is actually
7725 * whose children are part of a compound view, it should return {@code true} (and then override
7726 * {@link #dispatchProvideAutofillStructure(ViewStructure, int)} to simply call
7727 * {@link #onProvideAutofillStructure(ViewStructure, int)} so its children are not included in
7728 * the structure). On the other hand, views representing labels or editable fields should
7729 * typically return {@code true}, but in some cases they could return {@code false} (for
7730 * example, if they're part of a "Captcha" mechanism).
7732 * <p>By default, this method returns {@code true} if {@link #getImportantForAutofill()} returns
7733 * {@link #IMPORTANT_FOR_AUTOFILL_YES}, {@code false } if it returns
7734 * {@link #IMPORTANT_FOR_AUTOFILL_NO}, and use some heuristics to define the importance when it
7735 * returns {@link #IMPORTANT_FOR_AUTOFILL_AUTO}. Hence, it should rarely be overridden - Views
7736 * should use {@link #setImportantForAutofill(int)} instead.
7738 * <p><strong>Note:</strong> returning {@code false} does not guarantee the view will be
7739 * excluded from the structure; for example, if the user explicitly requested autofill, the
7740 * View might be always included.
7742 * <p>This decision applies just for the view, not its children - if the view children are not
7743 * important for autofill, the view should override
7744 * {@link #dispatchProvideAutofillStructure(ViewStructure, int)} to simply call
7745 * {@link #onProvideAutofillStructure(ViewStructure, int)} (instead of calling
7746 * {@link #dispatchProvideAutofillStructure(ViewStructure, int)} for each child).
7748 * @return whether the view is considered important for autofill.
7750 * @see #setImportantForAutofill(int)
7751 * @see #IMPORTANT_FOR_AUTOFILL_AUTO
7752 * @see #IMPORTANT_FOR_AUTOFILL_YES
7753 * @see #IMPORTANT_FOR_AUTOFILL_NO
7754 * @see #IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS
7755 * @see #IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS
7757 public final boolean isImportantForAutofill() {
7758 // Check parent mode to ensure we're not hidden.
7759 ViewParent parent = mParent;
7760 while (parent instanceof View) {
7761 final int parentImportance = ((View) parent).getImportantForAutofill();
7762 if (parentImportance == IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS
7763 || parentImportance == IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS) {
7766 parent = parent.getParent();
7769 final int importance = getImportantForAutofill();
7771 // First, check the explicit states.
7772 if (importance == IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS
7773 || importance == IMPORTANT_FOR_AUTOFILL_YES) {
7776 if (importance == IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS
7777 || importance == IMPORTANT_FOR_AUTOFILL_NO) {
7781 // Then use some heuristics to handle AUTO.
7783 // Always include views that have an explicit resource id.
7785 if (id != NO_ID && !isViewIdGenerated(id)) {
7786 final Resources res = getResources();
7787 String entry = null;
7790 entry = res.getResourceEntryName(id);
7791 pkg = res.getResourcePackageName(id);
7792 } catch (Resources.NotFoundException e) {
7795 if (entry != null && pkg != null && pkg.equals(mContext.getPackageName())) {
7800 // Otherwise, assume it's not important...
7805 private AutofillManager getAutofillManager() {
7806 return mContext.getSystemService(AutofillManager.class);
7809 private boolean isAutofillable() {
7810 return getAutofillType() != AUTOFILL_TYPE_NONE && isImportantForAutofill()
7811 && getAccessibilityViewId() > LAST_APP_ACCESSIBILITY_ID;
7814 private void populateVirtualStructure(ViewStructure structure,
7815 AccessibilityNodeProvider provider, AccessibilityNodeInfo info) {
7816 structure.setId(AccessibilityNodeInfo.getVirtualDescendantId(info.getSourceNodeId()),
7818 Rect rect = structure.getTempRect();
7819 info.getBoundsInParent(rect);
7820 structure.setDimens(rect.left, rect.top, 0, 0, rect.width(), rect.height());
7821 structure.setVisibility(VISIBLE);
7822 structure.setEnabled(info.isEnabled());
7823 if (info.isClickable()) {
7824 structure.setClickable(true);
7826 if (info.isFocusable()) {
7827 structure.setFocusable(true);
7829 if (info.isFocused()) {
7830 structure.setFocused(true);
7832 if (info.isAccessibilityFocused()) {
7833 structure.setAccessibilityFocused(true);
7835 if (info.isSelected()) {
7836 structure.setSelected(true);
7838 if (info.isLongClickable()) {
7839 structure.setLongClickable(true);
7841 if (info.isCheckable()) {
7842 structure.setCheckable(true);
7843 if (info.isChecked()) {
7844 structure.setChecked(true);
7847 if (info.isContextClickable()) {
7848 structure.setContextClickable(true);
7850 CharSequence cname = info.getClassName();
7851 structure.setClassName(cname != null ? cname.toString() : null);
7852 structure.setContentDescription(info.getContentDescription());
7853 if ((info.getText() != null || info.getError() != null)) {
7854 structure.setText(info.getText(), info.getTextSelectionStart(),
7855 info.getTextSelectionEnd());
7857 final int NCHILDREN = info.getChildCount();
7858 if (NCHILDREN > 0) {
7859 structure.setChildCount(NCHILDREN);
7860 for (int i=0; i<NCHILDREN; i++) {
7861 AccessibilityNodeInfo cinfo = provider.createAccessibilityNodeInfo(
7862 AccessibilityNodeInfo.getVirtualDescendantId(info.getChildId(i)));
7863 ViewStructure child = structure.newChild(i);
7864 populateVirtualStructure(child, provider, cinfo);
7871 * Dispatch creation of {@link ViewStructure} down the hierarchy. The default
7872 * implementation calls {@link #onProvideStructure} and
7873 * {@link #onProvideVirtualStructure}.
7875 public void dispatchProvideStructure(ViewStructure structure) {
7876 dispatchProvideStructureForAssistOrAutofill(structure, false, 0);
7880 * Dispatch creation of {@link ViewStructure} down the hierarchy.
7882 * <p>The default implementation does the following:
7885 * <li>Sets the {@link AutofillId} in the structure.
7886 * <li>Calls {@link #onProvideAutofillStructure(ViewStructure, int)}.
7887 * <li>Calls {@link #onProvideAutofillVirtualStructure(ViewStructure, int)}.
7890 * <p>When overridden, it must either call
7891 * {@code super.dispatchProvideAutofillStructure(structure, flags)} or explicitly
7892 * set the {@link AutofillId} in the structure (for example, by calling
7893 * {@code structure.setAutofillId(getAutofillId())}).
7895 * <p>When providing your implementation you need to decide how to handle
7896 * the {@link #AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS} flag which instructs you
7897 * to report all views to the structure regardless if {@link #isImportantForAutofill()}
7898 * returns true. We encourage you respect the importance property for a better
7899 * user experience in your app. If the flag is not set then you should filter out
7900 * not important views to optimize autofill performance in your app.
7902 * @param structure Fill in with structured view data.
7903 * @param flags optional flags.
7905 * @see #AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS
7907 public void dispatchProvideAutofillStructure(@NonNull ViewStructure structure,
7908 @AutofillFlags int flags) {
7909 dispatchProvideStructureForAssistOrAutofill(structure, true, flags);
7912 private void dispatchProvideStructureForAssistOrAutofill(ViewStructure structure,
7913 boolean forAutofill, @AutofillFlags int flags) {
7915 structure.setAutofillId(getAutofillId());
7916 onProvideAutofillStructure(structure, flags);
7917 onProvideAutofillVirtualStructure(structure, flags);
7918 } else if (!isAssistBlocked()) {
7919 onProvideStructure(structure);
7920 onProvideVirtualStructure(structure);
7922 structure.setClassName(getAccessibilityClassName().toString());
7923 structure.setAssistBlocked(true);
7928 * @see #onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)
7930 * Note: Called from the default {@link AccessibilityDelegate}.
7934 public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
7935 if (mAttachInfo == null) {
7939 Rect bounds = mAttachInfo.mTmpInvalRect;
7941 getDrawingRect(bounds);
7942 info.setBoundsInParent(bounds);
7944 getBoundsOnScreen(bounds, true);
7945 info.setBoundsInScreen(bounds);
7947 ViewParent parent = getParentForAccessibility();
7948 if (parent instanceof View) {
7949 info.setParent((View) parent);
7952 if (mID != View.NO_ID) {
7953 View rootView = getRootView();
7954 if (rootView == null) {
7958 View label = rootView.findLabelForView(this, mID);
7959 if (label != null) {
7960 info.setLabeledBy(label);
7963 if ((mAttachInfo.mAccessibilityFetchFlags
7964 & AccessibilityNodeInfo.FLAG_REPORT_VIEW_IDS) != 0
7965 && Resources.resourceHasPackage(mID)) {
7967 String viewId = getResources().getResourceName(mID);
7968 info.setViewIdResourceName(viewId);
7969 } catch (Resources.NotFoundException nfe) {
7975 if (mLabelForId != View.NO_ID) {
7976 View rootView = getRootView();
7977 if (rootView == null) {
7980 View labeled = rootView.findViewInsideOutShouldExist(this, mLabelForId);
7981 if (labeled != null) {
7982 info.setLabelFor(labeled);
7986 if (mAccessibilityTraversalBeforeId != View.NO_ID) {
7987 View rootView = getRootView();
7988 if (rootView == null) {
7991 View next = rootView.findViewInsideOutShouldExist(this,
7992 mAccessibilityTraversalBeforeId);
7993 if (next != null && next.includeForAccessibility()) {
7994 info.setTraversalBefore(next);
7998 if (mAccessibilityTraversalAfterId != View.NO_ID) {
7999 View rootView = getRootView();
8000 if (rootView == null) {
8003 View next = rootView.findViewInsideOutShouldExist(this,
8004 mAccessibilityTraversalAfterId);
8005 if (next != null && next.includeForAccessibility()) {
8006 info.setTraversalAfter(next);
8010 info.setVisibleToUser(isVisibleToUser());
8012 info.setImportantForAccessibility(isImportantForAccessibility());
8013 info.setPackageName(mContext.getPackageName());
8014 info.setClassName(getAccessibilityClassName());
8015 info.setContentDescription(getContentDescription());
8017 info.setEnabled(isEnabled());
8018 info.setClickable(isClickable());
8019 info.setFocusable(isFocusable());
8020 info.setFocused(isFocused());
8021 info.setAccessibilityFocused(isAccessibilityFocused());
8022 info.setSelected(isSelected());
8023 info.setLongClickable(isLongClickable());
8024 info.setContextClickable(isContextClickable());
8025 info.setLiveRegion(getAccessibilityLiveRegion());
8027 // TODO: These make sense only if we are in an AdapterView but all
8028 // views can be selected. Maybe from accessibility perspective
8029 // we should report as selectable view in an AdapterView.
8030 info.addAction(AccessibilityNodeInfo.ACTION_SELECT);
8031 info.addAction(AccessibilityNodeInfo.ACTION_CLEAR_SELECTION);
8033 if (isFocusable()) {
8035 info.addAction(AccessibilityNodeInfo.ACTION_CLEAR_FOCUS);
8037 info.addAction(AccessibilityNodeInfo.ACTION_FOCUS);
8041 if (!isAccessibilityFocused()) {
8042 info.addAction(AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS);
8044 info.addAction(AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS);
8047 if (isClickable() && isEnabled()) {
8048 info.addAction(AccessibilityNodeInfo.ACTION_CLICK);
8051 if (isLongClickable() && isEnabled()) {
8052 info.addAction(AccessibilityNodeInfo.ACTION_LONG_CLICK);
8055 if (isContextClickable() && isEnabled()) {
8056 info.addAction(AccessibilityAction.ACTION_CONTEXT_CLICK);
8059 CharSequence text = getIterableTextForAccessibility();
8060 if (text != null && text.length() > 0) {
8061 info.setTextSelection(getAccessibilitySelectionStart(), getAccessibilitySelectionEnd());
8063 info.addAction(AccessibilityNodeInfo.ACTION_SET_SELECTION);
8064 info.addAction(AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY);
8065 info.addAction(AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY);
8066 info.setMovementGranularities(AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER
8067 | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD
8068 | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH);
8071 info.addAction(AccessibilityAction.ACTION_SHOW_ON_SCREEN);
8072 populateAccessibilityNodeInfoDrawingOrderInParent(info);
8076 * Adds extra data to an {@link AccessibilityNodeInfo} based on an explicit request for the
8079 * This method only needs overloading if the node is marked as having extra data available.
8082 * @param info The info to which to add the extra data. Never {@code null}.
8083 * @param extraDataKey A key specifying the type of extra data to add to the info. The
8084 * extra data should be added to the {@link Bundle} returned by
8085 * the info's {@link AccessibilityNodeInfo#getExtras} method. Never
8087 * @param arguments A {@link Bundle} holding any arguments relevant for this request. May be
8088 * {@code null} if the service provided no arguments.
8090 * @see AccessibilityNodeInfo#setAvailableExtraData(List)
8092 public void addExtraDataToAccessibilityNodeInfo(
8093 @NonNull AccessibilityNodeInfo info, @NonNull String extraDataKey,
8094 @Nullable Bundle arguments) {
8098 * Determine the order in which this view will be drawn relative to its siblings for a11y
8100 * @param info The info whose drawing order should be populated
8102 private void populateAccessibilityNodeInfoDrawingOrderInParent(AccessibilityNodeInfo info) {
8104 * If the view's bounds haven't been set yet, layout has not completed. In that situation,
8105 * drawing order may not be well-defined, and some Views with custom drawing order may
8106 * not be initialized sufficiently to respond properly getChildDrawingOrder.
8108 if ((mPrivateFlags & PFLAG_HAS_BOUNDS) == 0) {
8109 info.setDrawingOrder(0);
8112 int drawingOrderInParent = 1;
8113 // Iterate up the hierarchy if parents are not important for a11y
8114 View viewAtDrawingLevel = this;
8115 final ViewParent parent = getParentForAccessibility();
8116 while (viewAtDrawingLevel != parent) {
8117 final ViewParent currentParent = viewAtDrawingLevel.getParent();
8118 if (!(currentParent instanceof ViewGroup)) {
8119 // Should only happen for the Decor
8120 drawingOrderInParent = 0;
8123 final ViewGroup parentGroup = (ViewGroup) currentParent;
8124 final int childCount = parentGroup.getChildCount();
8125 if (childCount > 1) {
8126 List<View> preorderedList = parentGroup.buildOrderedChildList();
8127 if (preorderedList != null) {
8128 final int childDrawIndex = preorderedList.indexOf(viewAtDrawingLevel);
8129 for (int i = 0; i < childDrawIndex; i++) {
8130 drawingOrderInParent += numViewsForAccessibility(preorderedList.get(i));
8133 final int childIndex = parentGroup.indexOfChild(viewAtDrawingLevel);
8134 final boolean customOrder = parentGroup.isChildrenDrawingOrderEnabled();
8135 final int childDrawIndex = ((childIndex >= 0) && customOrder) ? parentGroup
8136 .getChildDrawingOrder(childCount, childIndex) : childIndex;
8137 final int numChildrenToIterate = customOrder ? childCount : childDrawIndex;
8138 if (childDrawIndex != 0) {
8139 for (int i = 0; i < numChildrenToIterate; i++) {
8140 final int otherDrawIndex = (customOrder ?
8141 parentGroup.getChildDrawingOrder(childCount, i) : i);
8142 if (otherDrawIndex < childDrawIndex) {
8143 drawingOrderInParent +=
8144 numViewsForAccessibility(parentGroup.getChildAt(i));
8151 viewAtDrawingLevel = (View) currentParent;
8153 info.setDrawingOrder(drawingOrderInParent);
8156 private static int numViewsForAccessibility(View view) {
8158 if (view.includeForAccessibility()) {
8160 } else if (view instanceof ViewGroup) {
8161 return ((ViewGroup) view).getNumChildrenForAccessibility();
8167 private View findLabelForView(View view, int labeledId) {
8168 if (mMatchLabelForPredicate == null) {
8169 mMatchLabelForPredicate = new MatchLabelForPredicate();
8171 mMatchLabelForPredicate.mLabeledId = labeledId;
8172 return findViewByPredicateInsideOut(view, mMatchLabelForPredicate);
8176 * Computes whether this view is visible to the user. Such a view is
8177 * attached, visible, all its predecessors are visible, it is not clipped
8178 * entirely by its predecessors, and has an alpha greater than zero.
8180 * @return Whether the view is visible on the screen.
8184 protected boolean isVisibleToUser() {
8185 return isVisibleToUser(null);
8189 * Computes whether the given portion of this view is visible to the user.
8190 * Such a view is attached, visible, all its predecessors are visible,
8191 * has an alpha greater than zero, and the specified portion is not
8192 * clipped entirely by its predecessors.
8194 * @param boundInView the portion of the view to test; coordinates should be relative; may be
8195 * <code>null</code>, and the entire view will be tested in this case.
8196 * When <code>true</code> is returned by the function, the actual visible
8197 * region will be stored in this parameter; that is, if boundInView is fully
8198 * contained within the view, no modification will be made, otherwise regions
8199 * outside of the visible area of the view will be clipped.
8201 * @return Whether the specified portion of the view is visible on the screen.
8205 protected boolean isVisibleToUser(Rect boundInView) {
8206 if (mAttachInfo != null) {
8207 // Attached to invisible window means this view is not visible.
8208 if (mAttachInfo.mWindowVisibility != View.VISIBLE) {
8211 // An invisible predecessor or one with alpha zero means
8212 // that this view is not visible to the user.
8213 Object current = this;
8214 while (current instanceof View) {
8215 View view = (View) current;
8216 // We have attach info so this view is attached and there is no
8217 // need to check whether we reach to ViewRootImpl on the way up.
8218 if (view.getAlpha() <= 0 || view.getTransitionAlpha() <= 0 ||
8219 view.getVisibility() != VISIBLE) {
8222 current = view.mParent;
8224 // Check if the view is entirely covered by its predecessors.
8225 Rect visibleRect = mAttachInfo.mTmpInvalRect;
8226 Point offset = mAttachInfo.mPoint;
8227 if (!getGlobalVisibleRect(visibleRect, offset)) {
8230 // Check if the visible portion intersects the rectangle of interest.
8231 if (boundInView != null) {
8232 visibleRect.offset(-offset.x, -offset.y);
8233 return boundInView.intersect(visibleRect);
8241 * Returns the delegate for implementing accessibility support via
8242 * composition. For more details see {@link AccessibilityDelegate}.
8244 * @return The delegate, or null if none set.
8248 public AccessibilityDelegate getAccessibilityDelegate() {
8249 return mAccessibilityDelegate;
8253 * Sets a delegate for implementing accessibility support via composition
8254 * (as opposed to inheritance). For more details, see
8255 * {@link AccessibilityDelegate}.
8257 * <strong>Note:</strong> On platform versions prior to
8258 * {@link android.os.Build.VERSION_CODES#M API 23}, delegate methods on
8259 * views in the {@code android.widget.*} package are called <i>before</i>
8260 * host methods. This prevents certain properties such as class name from
8261 * being modified by overriding
8262 * {@link AccessibilityDelegate#onInitializeAccessibilityNodeInfo(View, AccessibilityNodeInfo)},
8263 * as any changes will be overwritten by the host class.
8265 * Starting in {@link android.os.Build.VERSION_CODES#M API 23}, delegate
8266 * methods are called <i>after</i> host methods, which all properties to be
8267 * modified without being overwritten by the host class.
8269 * @param delegate the object to which accessibility method calls should be
8271 * @see AccessibilityDelegate
8273 public void setAccessibilityDelegate(@Nullable AccessibilityDelegate delegate) {
8274 mAccessibilityDelegate = delegate;
8278 * Gets the provider for managing a virtual view hierarchy rooted at this View
8279 * and reported to {@link android.accessibilityservice.AccessibilityService}s
8280 * that explore the window content.
8282 * If this method returns an instance, this instance is responsible for managing
8283 * {@link AccessibilityNodeInfo}s describing the virtual sub-tree rooted at this
8284 * View including the one representing the View itself. Similarly the returned
8285 * instance is responsible for performing accessibility actions on any virtual
8286 * view or the root view itself.
8289 * If an {@link AccessibilityDelegate} has been specified via calling
8290 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its
8291 * {@link AccessibilityDelegate#getAccessibilityNodeProvider(View)}
8292 * is responsible for handling this call.
8295 * @return The provider.
8297 * @see AccessibilityNodeProvider
8299 public AccessibilityNodeProvider getAccessibilityNodeProvider() {
8300 if (mAccessibilityDelegate != null) {
8301 return mAccessibilityDelegate.getAccessibilityNodeProvider(this);
8308 * Gets the unique identifier of this view on the screen for accessibility purposes.
8310 * @return The view accessibility id.
8314 public int getAccessibilityViewId() {
8315 if (mAccessibilityViewId == NO_ID) {
8316 mAccessibilityViewId = mContext.getNextAccessibilityId();
8318 return mAccessibilityViewId;
8322 * Gets the unique identifier of the window in which this View reseides.
8324 * @return The window accessibility id.
8328 public int getAccessibilityWindowId() {
8329 return mAttachInfo != null ? mAttachInfo.mAccessibilityWindowId
8330 : AccessibilityWindowInfo.UNDEFINED_WINDOW_ID;
8334 * Returns the {@link View}'s content description.
8336 * <strong>Note:</strong> Do not override this method, as it will have no
8337 * effect on the content description presented to accessibility services.
8338 * You must call {@link #setContentDescription(CharSequence)} to modify the
8339 * content description.
8341 * @return the content description
8342 * @see #setContentDescription(CharSequence)
8343 * @attr ref android.R.styleable#View_contentDescription
8345 @ViewDebug.ExportedProperty(category = "accessibility")
8346 public CharSequence getContentDescription() {
8347 return mContentDescription;
8351 * Sets the {@link View}'s content description.
8353 * A content description briefly describes the view and is primarily used
8354 * for accessibility support to determine how a view should be presented to
8355 * the user. In the case of a view with no textual representation, such as
8356 * {@link android.widget.ImageButton}, a useful content description
8357 * explains what the view does. For example, an image button with a phone
8358 * icon that is used to place a call may use "Call" as its content
8359 * description. An image of a floppy disk that is used to save a file may
8362 * @param contentDescription The content description.
8363 * @see #getContentDescription()
8364 * @attr ref android.R.styleable#View_contentDescription
8366 @RemotableViewMethod
8367 public void setContentDescription(CharSequence contentDescription) {
8368 if (mContentDescription == null) {
8369 if (contentDescription == null) {
8372 } else if (mContentDescription.equals(contentDescription)) {
8375 mContentDescription = contentDescription;
8376 final boolean nonEmptyDesc = contentDescription != null && contentDescription.length() > 0;
8377 if (nonEmptyDesc && getImportantForAccessibility() == IMPORTANT_FOR_ACCESSIBILITY_AUTO) {
8378 setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES);
8379 notifySubtreeAccessibilityStateChangedIfNeeded();
8381 notifyViewAccessibilityStateChangedIfNeeded(
8382 AccessibilityEvent.CONTENT_CHANGE_TYPE_CONTENT_DESCRIPTION);
8387 * Sets the id of a view before which this one is visited in accessibility traversal.
8388 * A screen-reader must visit the content of this view before the content of the one
8389 * it precedes. For example, if view B is set to be before view A, then a screen-reader
8390 * will traverse the entire content of B before traversing the entire content of A,
8391 * regardles of what traversal strategy it is using.
8393 * Views that do not have specified before/after relationships are traversed in order
8394 * determined by the screen-reader.
8397 * Setting that this view is before a view that is not important for accessibility
8398 * or if this view is not important for accessibility will have no effect as the
8399 * screen-reader is not aware of unimportant views.
8402 * @param beforeId The id of a view this one precedes in accessibility traversal.
8404 * @attr ref android.R.styleable#View_accessibilityTraversalBefore
8406 * @see #setImportantForAccessibility(int)
8408 @RemotableViewMethod
8409 public void setAccessibilityTraversalBefore(int beforeId) {
8410 if (mAccessibilityTraversalBeforeId == beforeId) {
8413 mAccessibilityTraversalBeforeId = beforeId;
8414 notifyViewAccessibilityStateChangedIfNeeded(
8415 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED);
8419 * Gets the id of a view before which this one is visited in accessibility traversal.
8421 * @return The id of a view this one precedes in accessibility traversal if
8422 * specified, otherwise {@link #NO_ID}.
8424 * @see #setAccessibilityTraversalBefore(int)
8426 public int getAccessibilityTraversalBefore() {
8427 return mAccessibilityTraversalBeforeId;
8431 * Sets the id of a view after which this one is visited in accessibility traversal.
8432 * A screen-reader must visit the content of the other view before the content of this
8433 * one. For example, if view B is set to be after view A, then a screen-reader
8434 * will traverse the entire content of A before traversing the entire content of B,
8435 * regardles of what traversal strategy it is using.
8437 * Views that do not have specified before/after relationships are traversed in order
8438 * determined by the screen-reader.
8441 * Setting that this view is after a view that is not important for accessibility
8442 * or if this view is not important for accessibility will have no effect as the
8443 * screen-reader is not aware of unimportant views.
8446 * @param afterId The id of a view this one succedees in accessibility traversal.
8448 * @attr ref android.R.styleable#View_accessibilityTraversalAfter
8450 * @see #setImportantForAccessibility(int)
8452 @RemotableViewMethod
8453 public void setAccessibilityTraversalAfter(int afterId) {
8454 if (mAccessibilityTraversalAfterId == afterId) {
8457 mAccessibilityTraversalAfterId = afterId;
8458 notifyViewAccessibilityStateChangedIfNeeded(
8459 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED);
8463 * Gets the id of a view after which this one is visited in accessibility traversal.
8465 * @return The id of a view this one succeedes in accessibility traversal if
8466 * specified, otherwise {@link #NO_ID}.
8468 * @see #setAccessibilityTraversalAfter(int)
8470 public int getAccessibilityTraversalAfter() {
8471 return mAccessibilityTraversalAfterId;
8475 * Gets the id of a view for which this view serves as a label for
8476 * accessibility purposes.
8478 * @return The labeled view id.
8480 @ViewDebug.ExportedProperty(category = "accessibility")
8481 public int getLabelFor() {
8486 * Sets the id of a view for which this view serves as a label for
8487 * accessibility purposes.
8489 * @param id The labeled view id.
8491 @RemotableViewMethod
8492 public void setLabelFor(@IdRes int id) {
8493 if (mLabelForId == id) {
8497 if (mLabelForId != View.NO_ID
8498 && mID == View.NO_ID) {
8499 mID = generateViewId();
8501 notifyViewAccessibilityStateChangedIfNeeded(
8502 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED);
8506 * Invoked whenever this view loses focus, either by losing window focus or by losing
8507 * focus within its window. This method can be used to clear any state tied to the
8508 * focus. For instance, if a button is held pressed with the trackball and the window
8509 * loses focus, this method can be used to cancel the press.
8511 * Subclasses of View overriding this method should always call super.onFocusLost().
8513 * @see #onFocusChanged(boolean, int, android.graphics.Rect)
8514 * @see #onWindowFocusChanged(boolean)
8516 * @hide pending API council approval
8519 protected void onFocusLost() {
8520 resetPressedState();
8523 private void resetPressedState() {
8524 if ((mViewFlags & ENABLED_MASK) == DISABLED) {
8531 if (!mHasPerformedLongPress) {
8532 removeLongPressCallback();
8538 * Returns true if this view has focus
8540 * @return True if this view has focus, false otherwise.
8542 @ViewDebug.ExportedProperty(category = "focus")
8543 public boolean isFocused() {
8544 return (mPrivateFlags & PFLAG_FOCUSED) != 0;
8548 * Find the view in the hierarchy rooted at this view that currently has
8551 * @return The view that currently has focus, or null if no focused view can
8554 public View findFocus() {
8555 return (mPrivateFlags & PFLAG_FOCUSED) != 0 ? this : null;
8559 * Indicates whether this view is one of the set of scrollable containers in
8562 * @return whether this view is one of the set of scrollable containers in
8565 * @attr ref android.R.styleable#View_isScrollContainer
8567 public boolean isScrollContainer() {
8568 return (mPrivateFlags & PFLAG_SCROLL_CONTAINER_ADDED) != 0;
8572 * Change whether this view is one of the set of scrollable containers in
8573 * its window. This will be used to determine whether the window can
8574 * resize or must pan when a soft input area is open -- scrollable
8575 * containers allow the window to use resize mode since the container
8576 * will appropriately shrink.
8578 * @attr ref android.R.styleable#View_isScrollContainer
8580 public void setScrollContainer(boolean isScrollContainer) {
8581 if (isScrollContainer) {
8582 if (mAttachInfo != null && (mPrivateFlags&PFLAG_SCROLL_CONTAINER_ADDED) == 0) {
8583 mAttachInfo.mScrollContainers.add(this);
8584 mPrivateFlags |= PFLAG_SCROLL_CONTAINER_ADDED;
8586 mPrivateFlags |= PFLAG_SCROLL_CONTAINER;
8588 if ((mPrivateFlags&PFLAG_SCROLL_CONTAINER_ADDED) != 0) {
8589 mAttachInfo.mScrollContainers.remove(this);
8591 mPrivateFlags &= ~(PFLAG_SCROLL_CONTAINER|PFLAG_SCROLL_CONTAINER_ADDED);
8596 * Returns the quality of the drawing cache.
8598 * @return One of {@link #DRAWING_CACHE_QUALITY_AUTO},
8599 * {@link #DRAWING_CACHE_QUALITY_LOW}, or {@link #DRAWING_CACHE_QUALITY_HIGH}
8601 * @see #setDrawingCacheQuality(int)
8602 * @see #setDrawingCacheEnabled(boolean)
8603 * @see #isDrawingCacheEnabled()
8605 * @attr ref android.R.styleable#View_drawingCacheQuality
8607 @DrawingCacheQuality
8608 public int getDrawingCacheQuality() {
8609 return mViewFlags & DRAWING_CACHE_QUALITY_MASK;
8613 * Set the drawing cache quality of this view. This value is used only when the
8614 * drawing cache is enabled
8616 * @param quality One of {@link #DRAWING_CACHE_QUALITY_AUTO},
8617 * {@link #DRAWING_CACHE_QUALITY_LOW}, or {@link #DRAWING_CACHE_QUALITY_HIGH}
8619 * @see #getDrawingCacheQuality()
8620 * @see #setDrawingCacheEnabled(boolean)
8621 * @see #isDrawingCacheEnabled()
8623 * @attr ref android.R.styleable#View_drawingCacheQuality
8625 public void setDrawingCacheQuality(@DrawingCacheQuality int quality) {
8626 setFlags(quality, DRAWING_CACHE_QUALITY_MASK);
8630 * Returns whether the screen should remain on, corresponding to the current
8631 * value of {@link #KEEP_SCREEN_ON}.
8633 * @return Returns true if {@link #KEEP_SCREEN_ON} is set.
8635 * @see #setKeepScreenOn(boolean)
8637 * @attr ref android.R.styleable#View_keepScreenOn
8639 public boolean getKeepScreenOn() {
8640 return (mViewFlags & KEEP_SCREEN_ON) != 0;
8644 * Controls whether the screen should remain on, modifying the
8645 * value of {@link #KEEP_SCREEN_ON}.
8647 * @param keepScreenOn Supply true to set {@link #KEEP_SCREEN_ON}.
8649 * @see #getKeepScreenOn()
8651 * @attr ref android.R.styleable#View_keepScreenOn
8653 public void setKeepScreenOn(boolean keepScreenOn) {
8654 setFlags(keepScreenOn ? KEEP_SCREEN_ON : 0, KEEP_SCREEN_ON);
8658 * Gets the id of the view to use when the next focus is {@link #FOCUS_LEFT}.
8659 * @return The next focus ID, or {@link #NO_ID} if the framework should decide automatically.
8661 * @attr ref android.R.styleable#View_nextFocusLeft
8663 public int getNextFocusLeftId() {
8664 return mNextFocusLeftId;
8668 * Sets the id of the view to use when the next focus is {@link #FOCUS_LEFT}.
8669 * @param nextFocusLeftId The next focus ID, or {@link #NO_ID} if the framework should
8670 * decide automatically.
8672 * @attr ref android.R.styleable#View_nextFocusLeft
8674 public void setNextFocusLeftId(int nextFocusLeftId) {
8675 mNextFocusLeftId = nextFocusLeftId;
8679 * Gets the id of the view to use when the next focus is {@link #FOCUS_RIGHT}.
8680 * @return The next focus ID, or {@link #NO_ID} if the framework should decide automatically.
8682 * @attr ref android.R.styleable#View_nextFocusRight
8684 public int getNextFocusRightId() {
8685 return mNextFocusRightId;
8689 * Sets the id of the view to use when the next focus is {@link #FOCUS_RIGHT}.
8690 * @param nextFocusRightId The next focus ID, or {@link #NO_ID} if the framework should
8691 * decide automatically.
8693 * @attr ref android.R.styleable#View_nextFocusRight
8695 public void setNextFocusRightId(int nextFocusRightId) {
8696 mNextFocusRightId = nextFocusRightId;
8700 * Gets the id of the view to use when the next focus is {@link #FOCUS_UP}.
8701 * @return The next focus ID, or {@link #NO_ID} if the framework should decide automatically.
8703 * @attr ref android.R.styleable#View_nextFocusUp
8705 public int getNextFocusUpId() {
8706 return mNextFocusUpId;
8710 * Sets the id of the view to use when the next focus is {@link #FOCUS_UP}.
8711 * @param nextFocusUpId The next focus ID, or {@link #NO_ID} if the framework should
8712 * decide automatically.
8714 * @attr ref android.R.styleable#View_nextFocusUp
8716 public void setNextFocusUpId(int nextFocusUpId) {
8717 mNextFocusUpId = nextFocusUpId;
8721 * Gets the id of the view to use when the next focus is {@link #FOCUS_DOWN}.
8722 * @return The next focus ID, or {@link #NO_ID} if the framework should decide automatically.
8724 * @attr ref android.R.styleable#View_nextFocusDown
8726 public int getNextFocusDownId() {
8727 return mNextFocusDownId;
8731 * Sets the id of the view to use when the next focus is {@link #FOCUS_DOWN}.
8732 * @param nextFocusDownId The next focus ID, or {@link #NO_ID} if the framework should
8733 * decide automatically.
8735 * @attr ref android.R.styleable#View_nextFocusDown
8737 public void setNextFocusDownId(int nextFocusDownId) {
8738 mNextFocusDownId = nextFocusDownId;
8742 * Gets the id of the view to use when the next focus is {@link #FOCUS_FORWARD}.
8743 * @return The next focus ID, or {@link #NO_ID} if the framework should decide automatically.
8745 * @attr ref android.R.styleable#View_nextFocusForward
8747 public int getNextFocusForwardId() {
8748 return mNextFocusForwardId;
8752 * Sets the id of the view to use when the next focus is {@link #FOCUS_FORWARD}.
8753 * @param nextFocusForwardId The next focus ID, or {@link #NO_ID} if the framework should
8754 * decide automatically.
8756 * @attr ref android.R.styleable#View_nextFocusForward
8758 public void setNextFocusForwardId(int nextFocusForwardId) {
8759 mNextFocusForwardId = nextFocusForwardId;
8763 * Gets the id of the root of the next keyboard navigation cluster.
8764 * @return The next keyboard navigation cluster ID, or {@link #NO_ID} if the framework should
8765 * decide automatically.
8767 * @attr ref android.R.styleable#View_nextClusterForward
8769 public int getNextClusterForwardId() {
8770 return mNextClusterForwardId;
8774 * Sets the id of the view to use as the root of the next keyboard navigation cluster.
8775 * @param nextClusterForwardId The next cluster ID, or {@link #NO_ID} if the framework should
8776 * decide automatically.
8778 * @attr ref android.R.styleable#View_nextClusterForward
8780 public void setNextClusterForwardId(int nextClusterForwardId) {
8781 mNextClusterForwardId = nextClusterForwardId;
8785 * Returns the visibility of this view and all of its ancestors
8787 * @return True if this view and all of its ancestors are {@link #VISIBLE}
8789 public boolean isShown() {
8790 View current = this;
8791 //noinspection ConstantConditions
8793 if ((current.mViewFlags & VISIBILITY_MASK) != VISIBLE) {
8796 ViewParent parent = current.mParent;
8797 if (parent == null) {
8798 return false; // We are not attached to the view root
8800 if (!(parent instanceof View)) {
8803 current = (View) parent;
8804 } while (current != null);
8810 * Called by the view hierarchy when the content insets for a window have
8811 * changed, to allow it to adjust its content to fit within those windows.
8812 * The content insets tell you the space that the status bar, input method,
8813 * and other system windows infringe on the application's window.
8815 * <p>You do not normally need to deal with this function, since the default
8816 * window decoration given to applications takes care of applying it to the
8817 * content of the window. If you use {@link #SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN}
8818 * or {@link #SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION} this will not be the case,
8819 * and your content can be placed under those system elements. You can then
8820 * use this method within your view hierarchy if you have parts of your UI
8821 * which you would like to ensure are not being covered.
8823 * <p>The default implementation of this method simply applies the content
8824 * insets to the view's padding, consuming that content (modifying the
8825 * insets to be 0), and returning true. This behavior is off by default, but can
8826 * be enabled through {@link #setFitsSystemWindows(boolean)}.
8828 * <p>This function's traversal down the hierarchy is depth-first. The same content
8829 * insets object is propagated down the hierarchy, so any changes made to it will
8830 * be seen by all following views (including potentially ones above in
8831 * the hierarchy since this is a depth-first traversal). The first view
8832 * that returns true will abort the entire traversal.
8834 * <p>The default implementation works well for a situation where it is
8835 * used with a container that covers the entire window, allowing it to
8836 * apply the appropriate insets to its content on all edges. If you need
8837 * a more complicated layout (such as two different views fitting system
8838 * windows, one on the top of the window, and one on the bottom),
8839 * you can override the method and handle the insets however you would like.
8840 * Note that the insets provided by the framework are always relative to the
8841 * far edges of the window, not accounting for the location of the called view
8842 * within that window. (In fact when this method is called you do not yet know
8843 * where the layout will place the view, as it is done before layout happens.)
8845 * <p>Note: unlike many View methods, there is no dispatch phase to this
8846 * call. If you are overriding it in a ViewGroup and want to allow the
8847 * call to continue to your children, you must be sure to call the super
8850 * <p>Here is a sample layout that makes use of fitting system windows
8851 * to have controls for a video view placed inside of the window decorations
8852 * that it hides and shows. This can be used with code like the second
8853 * sample (video player) shown in {@link #setSystemUiVisibility(int)}.
8855 * {@sample development/samples/ApiDemos/res/layout/video_player.xml complete}
8857 * @param insets Current content insets of the window. Prior to
8858 * {@link android.os.Build.VERSION_CODES#JELLY_BEAN} you must not modify
8859 * the insets or else you and Android will be unhappy.
8861 * @return {@code true} if this view applied the insets and it should not
8862 * continue propagating further down the hierarchy, {@code false} otherwise.
8863 * @see #getFitsSystemWindows()
8864 * @see #setFitsSystemWindows(boolean)
8865 * @see #setSystemUiVisibility(int)
8867 * @deprecated As of API 20 use {@link #dispatchApplyWindowInsets(WindowInsets)} to apply
8868 * insets to views. Views should override {@link #onApplyWindowInsets(WindowInsets)} or use
8869 * {@link #setOnApplyWindowInsetsListener(android.view.View.OnApplyWindowInsetsListener)}
8870 * to implement handling their own insets.
8873 protected boolean fitSystemWindows(Rect insets) {
8874 if ((mPrivateFlags3 & PFLAG3_APPLYING_INSETS) == 0) {
8875 if (insets == null) {
8876 // Null insets by definition have already been consumed.
8877 // This call cannot apply insets since there are none to apply,
8881 // If we're not in the process of dispatching the newer apply insets call,
8882 // that means we're not in the compatibility path. Dispatch into the newer
8883 // apply insets path and take things from there.
8885 mPrivateFlags3 |= PFLAG3_FITTING_SYSTEM_WINDOWS;
8886 return dispatchApplyWindowInsets(new WindowInsets(insets)).isConsumed();
8888 mPrivateFlags3 &= ~PFLAG3_FITTING_SYSTEM_WINDOWS;
8891 // We're being called from the newer apply insets path.
8892 // Perform the standard fallback behavior.
8893 return fitSystemWindowsInt(insets);
8897 private boolean fitSystemWindowsInt(Rect insets) {
8898 if ((mViewFlags & FITS_SYSTEM_WINDOWS) == FITS_SYSTEM_WINDOWS) {
8899 mUserPaddingStart = UNDEFINED_PADDING;
8900 mUserPaddingEnd = UNDEFINED_PADDING;
8901 Rect localInsets = sThreadLocal.get();
8902 if (localInsets == null) {
8903 localInsets = new Rect();
8904 sThreadLocal.set(localInsets);
8906 boolean res = computeFitSystemWindows(insets, localInsets);
8907 mUserPaddingLeftInitial = localInsets.left;
8908 mUserPaddingRightInitial = localInsets.right;
8909 internalSetPadding(localInsets.left, localInsets.top,
8910 localInsets.right, localInsets.bottom);
8917 * Called when the view should apply {@link WindowInsets} according to its internal policy.
8919 * <p>This method should be overridden by views that wish to apply a policy different from or
8920 * in addition to the default behavior. Clients that wish to force a view subtree
8921 * to apply insets should call {@link #dispatchApplyWindowInsets(WindowInsets)}.</p>
8923 * <p>Clients may supply an {@link OnApplyWindowInsetsListener} to a view. If one is set
8924 * it will be called during dispatch instead of this method. The listener may optionally
8925 * call this method from its own implementation if it wishes to apply the view's default
8926 * insets policy in addition to its own.</p>
8928 * <p>Implementations of this method should either return the insets parameter unchanged
8929 * or a new {@link WindowInsets} cloned from the supplied insets with any insets consumed
8930 * that this view applied itself. This allows new inset types added in future platform
8931 * versions to pass through existing implementations unchanged without being erroneously
8934 * <p>By default if a view's {@link #setFitsSystemWindows(boolean) fitsSystemWindows}
8935 * property is set then the view will consume the system window insets and apply them
8936 * as padding for the view.</p>
8938 * @param insets Insets to apply
8939 * @return The supplied insets with any applied insets consumed
8941 public WindowInsets onApplyWindowInsets(WindowInsets insets) {
8942 if ((mPrivateFlags3 & PFLAG3_FITTING_SYSTEM_WINDOWS) == 0) {
8943 // We weren't called from within a direct call to fitSystemWindows,
8944 // call into it as a fallback in case we're in a class that overrides it
8945 // and has logic to perform.
8946 if (fitSystemWindows(insets.getSystemWindowInsets())) {
8947 return insets.consumeSystemWindowInsets();
8950 // We were called from within a direct call to fitSystemWindows.
8951 if (fitSystemWindowsInt(insets.getSystemWindowInsets())) {
8952 return insets.consumeSystemWindowInsets();
8959 * Set an {@link OnApplyWindowInsetsListener} to take over the policy for applying
8960 * window insets to this view. The listener's
8961 * {@link OnApplyWindowInsetsListener#onApplyWindowInsets(View, WindowInsets) onApplyWindowInsets}
8962 * method will be called instead of the view's
8963 * {@link #onApplyWindowInsets(WindowInsets) onApplyWindowInsets} method.
8965 * @param listener Listener to set
8967 * @see #onApplyWindowInsets(WindowInsets)
8969 public void setOnApplyWindowInsetsListener(OnApplyWindowInsetsListener listener) {
8970 getListenerInfo().mOnApplyWindowInsetsListener = listener;
8974 * Request to apply the given window insets to this view or another view in its subtree.
8976 * <p>This method should be called by clients wishing to apply insets corresponding to areas
8977 * obscured by window decorations or overlays. This can include the status and navigation bars,
8978 * action bars, input methods and more. New inset categories may be added in the future.
8979 * The method returns the insets provided minus any that were applied by this view or its
8982 * <p>Clients wishing to provide custom behavior should override the
8983 * {@link #onApplyWindowInsets(WindowInsets)} method or alternatively provide a
8984 * {@link OnApplyWindowInsetsListener} via the
8985 * {@link #setOnApplyWindowInsetsListener(View.OnApplyWindowInsetsListener) setOnApplyWindowInsetsListener}
8988 * <p>This method replaces the older {@link #fitSystemWindows(Rect) fitSystemWindows} method.
8991 * @param insets Insets to apply
8992 * @return The provided insets minus the insets that were consumed
8994 public WindowInsets dispatchApplyWindowInsets(WindowInsets insets) {
8996 mPrivateFlags3 |= PFLAG3_APPLYING_INSETS;
8997 if (mListenerInfo != null && mListenerInfo.mOnApplyWindowInsetsListener != null) {
8998 return mListenerInfo.mOnApplyWindowInsetsListener.onApplyWindowInsets(this, insets);
9000 return onApplyWindowInsets(insets);
9003 mPrivateFlags3 &= ~PFLAG3_APPLYING_INSETS;
9008 * Compute the view's coordinate within the surface.
9010 * <p>Computes the coordinates of this view in its surface. The argument
9011 * must be an array of two integers. After the method returns, the array
9012 * contains the x and y location in that order.</p>
9014 * @param location an array of two integers in which to hold the coordinates
9016 public void getLocationInSurface(@Size(2) int[] location) {
9017 getLocationInWindow(location);
9018 if (mAttachInfo != null && mAttachInfo.mViewRootImpl != null) {
9019 location[0] += mAttachInfo.mViewRootImpl.mWindowAttributes.surfaceInsets.left;
9020 location[1] += mAttachInfo.mViewRootImpl.mWindowAttributes.surfaceInsets.top;
9025 * Provide original WindowInsets that are dispatched to the view hierarchy. The insets are
9026 * only available if the view is attached.
9028 * @return WindowInsets from the top of the view hierarchy or null if View is detached
9030 public WindowInsets getRootWindowInsets() {
9031 if (mAttachInfo != null) {
9032 return mAttachInfo.mViewRootImpl.getWindowInsets(false /* forceConstruct */);
9038 * @hide Compute the insets that should be consumed by this view and the ones
9039 * that should propagate to those under it.
9041 protected boolean computeFitSystemWindows(Rect inoutInsets, Rect outLocalInsets) {
9042 if ((mViewFlags & OPTIONAL_FITS_SYSTEM_WINDOWS) == 0
9043 || mAttachInfo == null
9044 || ((mAttachInfo.mSystemUiVisibility & SYSTEM_UI_LAYOUT_FLAGS) == 0
9045 && !mAttachInfo.mOverscanRequested)) {
9046 outLocalInsets.set(inoutInsets);
9047 inoutInsets.set(0, 0, 0, 0);
9050 // The application wants to take care of fitting system window for
9051 // the content... however we still need to take care of any overscan here.
9052 final Rect overscan = mAttachInfo.mOverscanInsets;
9053 outLocalInsets.set(overscan);
9054 inoutInsets.left -= overscan.left;
9055 inoutInsets.top -= overscan.top;
9056 inoutInsets.right -= overscan.right;
9057 inoutInsets.bottom -= overscan.bottom;
9063 * Compute insets that should be consumed by this view and the ones that should propagate
9064 * to those under it.
9066 * @param in Insets currently being processed by this View, likely received as a parameter
9067 * to {@link #onApplyWindowInsets(WindowInsets)}.
9068 * @param outLocalInsets A Rect that will receive the insets that should be consumed
9070 * @return Insets that should be passed along to views under this one
9072 public WindowInsets computeSystemWindowInsets(WindowInsets in, Rect outLocalInsets) {
9073 if ((mViewFlags & OPTIONAL_FITS_SYSTEM_WINDOWS) == 0
9074 || mAttachInfo == null
9075 || (mAttachInfo.mSystemUiVisibility & SYSTEM_UI_LAYOUT_FLAGS) == 0) {
9076 outLocalInsets.set(in.getSystemWindowInsets());
9077 return in.consumeSystemWindowInsets();
9079 outLocalInsets.set(0, 0, 0, 0);
9085 * Sets whether or not this view should account for system screen decorations
9086 * such as the status bar and inset its content; that is, controlling whether
9087 * the default implementation of {@link #fitSystemWindows(Rect)} will be
9088 * executed. See that method for more details.
9090 * <p>Note that if you are providing your own implementation of
9091 * {@link #fitSystemWindows(Rect)}, then there is no need to set this
9092 * flag to true -- your implementation will be overriding the default
9093 * implementation that checks this flag.
9095 * @param fitSystemWindows If true, then the default implementation of
9096 * {@link #fitSystemWindows(Rect)} will be executed.
9098 * @attr ref android.R.styleable#View_fitsSystemWindows
9099 * @see #getFitsSystemWindows()
9100 * @see #fitSystemWindows(Rect)
9101 * @see #setSystemUiVisibility(int)
9103 public void setFitsSystemWindows(boolean fitSystemWindows) {
9104 setFlags(fitSystemWindows ? FITS_SYSTEM_WINDOWS : 0, FITS_SYSTEM_WINDOWS);
9108 * Check for state of {@link #setFitsSystemWindows(boolean)}. If this method
9109 * returns {@code true}, the default implementation of {@link #fitSystemWindows(Rect)}
9112 * @return {@code true} if the default implementation of
9113 * {@link #fitSystemWindows(Rect)} will be executed.
9115 * @attr ref android.R.styleable#View_fitsSystemWindows
9116 * @see #setFitsSystemWindows(boolean)
9117 * @see #fitSystemWindows(Rect)
9118 * @see #setSystemUiVisibility(int)
9120 @ViewDebug.ExportedProperty
9121 public boolean getFitsSystemWindows() {
9122 return (mViewFlags & FITS_SYSTEM_WINDOWS) == FITS_SYSTEM_WINDOWS;
9126 public boolean fitsSystemWindows() {
9127 return getFitsSystemWindows();
9131 * Ask that a new dispatch of {@link #fitSystemWindows(Rect)} be performed.
9132 * @deprecated Use {@link #requestApplyInsets()} for newer platform versions.
9135 public void requestFitSystemWindows() {
9136 if (mParent != null) {
9137 mParent.requestFitSystemWindows();
9142 * Ask that a new dispatch of {@link #onApplyWindowInsets(WindowInsets)} be performed.
9144 public void requestApplyInsets() {
9145 requestFitSystemWindows();
9149 * For use by PhoneWindow to make its own system window fitting optional.
9152 public void makeOptionalFitsSystemWindows() {
9153 setFlags(OPTIONAL_FITS_SYSTEM_WINDOWS, OPTIONAL_FITS_SYSTEM_WINDOWS);
9157 * Returns the outsets, which areas of the device that aren't a surface, but we would like to
9158 * treat them as such.
9161 public void getOutsets(Rect outOutsetRect) {
9162 if (mAttachInfo != null) {
9163 outOutsetRect.set(mAttachInfo.mOutsets);
9165 outOutsetRect.setEmpty();
9170 * Returns the visibility status for this view.
9172 * @return One of {@link #VISIBLE}, {@link #INVISIBLE}, or {@link #GONE}.
9173 * @attr ref android.R.styleable#View_visibility
9175 @ViewDebug.ExportedProperty(mapping = {
9176 @ViewDebug.IntToString(from = VISIBLE, to = "VISIBLE"),
9177 @ViewDebug.IntToString(from = INVISIBLE, to = "INVISIBLE"),
9178 @ViewDebug.IntToString(from = GONE, to = "GONE")
9181 public int getVisibility() {
9182 return mViewFlags & VISIBILITY_MASK;
9186 * Set the visibility state of this view.
9188 * @param visibility One of {@link #VISIBLE}, {@link #INVISIBLE}, or {@link #GONE}.
9189 * @attr ref android.R.styleable#View_visibility
9191 @RemotableViewMethod
9192 public void setVisibility(@Visibility int visibility) {
9193 setFlags(visibility, VISIBILITY_MASK);
9197 * Returns the enabled status for this view. The interpretation of the
9198 * enabled state varies by subclass.
9200 * @return True if this view is enabled, false otherwise.
9202 @ViewDebug.ExportedProperty
9203 public boolean isEnabled() {
9204 return (mViewFlags & ENABLED_MASK) == ENABLED;
9208 * Set the enabled state of this view. The interpretation of the enabled
9209 * state varies by subclass.
9211 * @param enabled True if this view is enabled, false otherwise.
9213 @RemotableViewMethod
9214 public void setEnabled(boolean enabled) {
9215 if (enabled == isEnabled()) return;
9217 setFlags(enabled ? ENABLED : DISABLED, ENABLED_MASK);
9220 * The View most likely has to change its appearance, so refresh
9221 * the drawable state.
9223 refreshDrawableState();
9225 // Invalidate too, since the default behavior for views is to be
9226 // be drawn at 50% alpha rather than to change the drawable.
9230 cancelPendingInputEvents();
9235 * Set whether this view can receive the focus.
9237 * Setting this to false will also ensure that this view is not focusable
9240 * @param focusable If true, this view can receive the focus.
9242 * @see #setFocusableInTouchMode(boolean)
9243 * @see #setFocusable(int)
9244 * @attr ref android.R.styleable#View_focusable
9246 public void setFocusable(boolean focusable) {
9247 setFocusable(focusable ? FOCUSABLE : NOT_FOCUSABLE);
9251 * Sets whether this view can receive focus.
9253 * Setting this to {@link #FOCUSABLE_AUTO} tells the framework to determine focusability
9254 * automatically based on the view's interactivity. This is the default.
9256 * Setting this to NOT_FOCUSABLE will ensure that this view is also not focusable
9259 * @param focusable One of {@link #NOT_FOCUSABLE}, {@link #FOCUSABLE},
9260 * or {@link #FOCUSABLE_AUTO}.
9261 * @see #setFocusableInTouchMode(boolean)
9262 * @attr ref android.R.styleable#View_focusable
9264 public void setFocusable(@Focusable int focusable) {
9265 if ((focusable & (FOCUSABLE_AUTO | FOCUSABLE)) == 0) {
9266 setFlags(0, FOCUSABLE_IN_TOUCH_MODE);
9268 setFlags(focusable, FOCUSABLE_MASK);
9272 * Set whether this view can receive focus while in touch mode.
9274 * Setting this to true will also ensure that this view is focusable.
9276 * @param focusableInTouchMode If true, this view can receive the focus while
9279 * @see #setFocusable(boolean)
9280 * @attr ref android.R.styleable#View_focusableInTouchMode
9282 public void setFocusableInTouchMode(boolean focusableInTouchMode) {
9283 // Focusable in touch mode should always be set before the focusable flag
9284 // otherwise, setting the focusable flag will trigger a focusableViewAvailable()
9285 // which, in touch mode, will not successfully request focus on this view
9286 // because the focusable in touch mode flag is not set
9287 setFlags(focusableInTouchMode ? FOCUSABLE_IN_TOUCH_MODE : 0, FOCUSABLE_IN_TOUCH_MODE);
9289 // Clear FOCUSABLE_AUTO if set.
9290 if (focusableInTouchMode) {
9291 // Clears FOCUSABLE_AUTO if set.
9292 setFlags(FOCUSABLE, FOCUSABLE_MASK);
9297 * Sets the hints that help an {@link android.service.autofill.AutofillService} determine how
9298 * to autofill the view with the user's data.
9300 * <p>Typically, there is only one way to autofill a view, but there could be more than one.
9301 * For example, if the application accepts either an username or email address to identify
9304 * <p>These hints are not validated by the Android System, but passed "as is" to the service.
9305 * Hence, they can have any value, but it's recommended to use the {@code AUTOFILL_HINT_}
9306 * constants such as:
9307 * {@link #AUTOFILL_HINT_USERNAME}, {@link #AUTOFILL_HINT_PASSWORD},
9308 * {@link #AUTOFILL_HINT_EMAIL_ADDRESS},
9309 * {@link #AUTOFILL_HINT_NAME},
9310 * {@link #AUTOFILL_HINT_PHONE},
9311 * {@link #AUTOFILL_HINT_POSTAL_ADDRESS}, {@link #AUTOFILL_HINT_POSTAL_CODE},
9312 * {@link #AUTOFILL_HINT_CREDIT_CARD_NUMBER}, {@link #AUTOFILL_HINT_CREDIT_CARD_SECURITY_CODE},
9313 * {@link #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DATE},
9314 * {@link #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DAY},
9315 * {@link #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_MONTH} or
9316 * {@link #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_YEAR}.
9318 * @param autofillHints The autofill hints to set. If the array is emtpy, {@code null} is set.
9319 * @attr ref android.R.styleable#View_autofillHints
9321 public void setAutofillHints(@Nullable String... autofillHints) {
9322 if (autofillHints == null || autofillHints.length == 0) {
9323 mAutofillHints = null;
9325 mAutofillHints = autofillHints;
9333 public void setAutofilled(boolean isAutofilled) {
9334 boolean wasChanged = isAutofilled != isAutofilled();
9338 mPrivateFlags3 |= PFLAG3_IS_AUTOFILLED;
9340 mPrivateFlags3 &= ~PFLAG3_IS_AUTOFILLED;
9348 * Set whether this view should have sound effects enabled for events such as
9349 * clicking and touching.
9351 * <p>You may wish to disable sound effects for a view if you already play sounds,
9352 * for instance, a dial key that plays dtmf tones.
9354 * @param soundEffectsEnabled whether sound effects are enabled for this view.
9355 * @see #isSoundEffectsEnabled()
9356 * @see #playSoundEffect(int)
9357 * @attr ref android.R.styleable#View_soundEffectsEnabled
9359 public void setSoundEffectsEnabled(boolean soundEffectsEnabled) {
9360 setFlags(soundEffectsEnabled ? SOUND_EFFECTS_ENABLED: 0, SOUND_EFFECTS_ENABLED);
9364 * @return whether this view should have sound effects enabled for events such as
9365 * clicking and touching.
9367 * @see #setSoundEffectsEnabled(boolean)
9368 * @see #playSoundEffect(int)
9369 * @attr ref android.R.styleable#View_soundEffectsEnabled
9371 @ViewDebug.ExportedProperty
9372 public boolean isSoundEffectsEnabled() {
9373 return SOUND_EFFECTS_ENABLED == (mViewFlags & SOUND_EFFECTS_ENABLED);
9377 * Set whether this view should have haptic feedback for events such as
9380 * <p>You may wish to disable haptic feedback if your view already controls
9381 * its own haptic feedback.
9383 * @param hapticFeedbackEnabled whether haptic feedback enabled for this view.
9384 * @see #isHapticFeedbackEnabled()
9385 * @see #performHapticFeedback(int)
9386 * @attr ref android.R.styleable#View_hapticFeedbackEnabled
9388 public void setHapticFeedbackEnabled(boolean hapticFeedbackEnabled) {
9389 setFlags(hapticFeedbackEnabled ? HAPTIC_FEEDBACK_ENABLED: 0, HAPTIC_FEEDBACK_ENABLED);
9393 * @return whether this view should have haptic feedback enabled for events
9396 * @see #setHapticFeedbackEnabled(boolean)
9397 * @see #performHapticFeedback(int)
9398 * @attr ref android.R.styleable#View_hapticFeedbackEnabled
9400 @ViewDebug.ExportedProperty
9401 public boolean isHapticFeedbackEnabled() {
9402 return HAPTIC_FEEDBACK_ENABLED == (mViewFlags & HAPTIC_FEEDBACK_ENABLED);
9406 * Returns the layout direction for this view.
9408 * @return One of {@link #LAYOUT_DIRECTION_LTR},
9409 * {@link #LAYOUT_DIRECTION_RTL},
9410 * {@link #LAYOUT_DIRECTION_INHERIT} or
9411 * {@link #LAYOUT_DIRECTION_LOCALE}.
9413 * @attr ref android.R.styleable#View_layoutDirection
9417 @ViewDebug.ExportedProperty(category = "layout", mapping = {
9418 @ViewDebug.IntToString(from = LAYOUT_DIRECTION_LTR, to = "LTR"),
9419 @ViewDebug.IntToString(from = LAYOUT_DIRECTION_RTL, to = "RTL"),
9420 @ViewDebug.IntToString(from = LAYOUT_DIRECTION_INHERIT, to = "INHERIT"),
9421 @ViewDebug.IntToString(from = LAYOUT_DIRECTION_LOCALE, to = "LOCALE")
9424 public int getRawLayoutDirection() {
9425 return (mPrivateFlags2 & PFLAG2_LAYOUT_DIRECTION_MASK) >> PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT;
9429 * Set the layout direction for this view. This will propagate a reset of layout direction
9430 * resolution to the view's children and resolve layout direction for this view.
9432 * @param layoutDirection the layout direction to set. Should be one of:
9434 * {@link #LAYOUT_DIRECTION_LTR},
9435 * {@link #LAYOUT_DIRECTION_RTL},
9436 * {@link #LAYOUT_DIRECTION_INHERIT},
9437 * {@link #LAYOUT_DIRECTION_LOCALE}.
9439 * Resolution will be done if the value is set to LAYOUT_DIRECTION_INHERIT. The resolution
9440 * proceeds up the parent chain of the view to get the value. If there is no parent, then it
9441 * will return the default {@link #LAYOUT_DIRECTION_LTR}.
9443 * @attr ref android.R.styleable#View_layoutDirection
9445 @RemotableViewMethod
9446 public void setLayoutDirection(@LayoutDir int layoutDirection) {
9447 if (getRawLayoutDirection() != layoutDirection) {
9448 // Reset the current layout direction and the resolved one
9449 mPrivateFlags2 &= ~PFLAG2_LAYOUT_DIRECTION_MASK;
9450 resetRtlProperties();
9451 // Set the new layout direction (filtered)
9453 ((layoutDirection << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT) & PFLAG2_LAYOUT_DIRECTION_MASK);
9454 // We need to resolve all RTL properties as they all depend on layout direction
9455 resolveRtlPropertiesIfNeeded();
9462 * Returns the resolved layout direction for this view.
9464 * @return {@link #LAYOUT_DIRECTION_RTL} if the layout direction is RTL or returns
9465 * {@link #LAYOUT_DIRECTION_LTR} if the layout direction is not RTL.
9467 * For compatibility, this will return {@link #LAYOUT_DIRECTION_LTR} if API version
9468 * is lower than {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR1}.
9470 * @attr ref android.R.styleable#View_layoutDirection
9472 @ViewDebug.ExportedProperty(category = "layout", mapping = {
9473 @ViewDebug.IntToString(from = LAYOUT_DIRECTION_LTR, to = "RESOLVED_DIRECTION_LTR"),
9474 @ViewDebug.IntToString(from = LAYOUT_DIRECTION_RTL, to = "RESOLVED_DIRECTION_RTL")
9477 public int getLayoutDirection() {
9478 final int targetSdkVersion = getContext().getApplicationInfo().targetSdkVersion;
9479 if (targetSdkVersion < Build.VERSION_CODES.JELLY_BEAN_MR1) {
9480 mPrivateFlags2 |= PFLAG2_LAYOUT_DIRECTION_RESOLVED;
9481 return LAYOUT_DIRECTION_RESOLVED_DEFAULT;
9483 return ((mPrivateFlags2 & PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL) ==
9484 PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL) ? LAYOUT_DIRECTION_RTL : LAYOUT_DIRECTION_LTR;
9488 * Indicates whether or not this view's layout is right-to-left. This is resolved from
9489 * layout attribute and/or the inherited value from the parent
9491 * @return true if the layout is right-to-left.
9495 @ViewDebug.ExportedProperty(category = "layout")
9496 public boolean isLayoutRtl() {
9497 return (getLayoutDirection() == LAYOUT_DIRECTION_RTL);
9501 * Indicates whether the view is currently tracking transient state that the
9502 * app should not need to concern itself with saving and restoring, but that
9503 * the framework should take special note to preserve when possible.
9505 * <p>A view with transient state cannot be trivially rebound from an external
9506 * data source, such as an adapter binding item views in a list. This may be
9507 * because the view is performing an animation, tracking user selection
9508 * of content, or similar.</p>
9510 * @return true if the view has transient state
9512 @ViewDebug.ExportedProperty(category = "layout")
9513 public boolean hasTransientState() {
9514 return (mPrivateFlags2 & PFLAG2_HAS_TRANSIENT_STATE) == PFLAG2_HAS_TRANSIENT_STATE;
9518 * Set whether this view is currently tracking transient state that the
9519 * framework should attempt to preserve when possible. This flag is reference counted,
9520 * so every call to setHasTransientState(true) should be paired with a later call
9521 * to setHasTransientState(false).
9523 * <p>A view with transient state cannot be trivially rebound from an external
9524 * data source, such as an adapter binding item views in a list. This may be
9525 * because the view is performing an animation, tracking user selection
9526 * of content, or similar.</p>
9528 * @param hasTransientState true if this view has transient state
9530 public void setHasTransientState(boolean hasTransientState) {
9531 mTransientStateCount = hasTransientState ? mTransientStateCount + 1 :
9532 mTransientStateCount - 1;
9533 if (mTransientStateCount < 0) {
9534 mTransientStateCount = 0;
9535 Log.e(VIEW_LOG_TAG, "hasTransientState decremented below 0: " +
9536 "unmatched pair of setHasTransientState calls");
9537 } else if ((hasTransientState && mTransientStateCount == 1) ||
9538 (!hasTransientState && mTransientStateCount == 0)) {
9539 // update flag if we've just incremented up from 0 or decremented down to 0
9540 mPrivateFlags2 = (mPrivateFlags2 & ~PFLAG2_HAS_TRANSIENT_STATE) |
9541 (hasTransientState ? PFLAG2_HAS_TRANSIENT_STATE : 0);
9542 if (mParent != null) {
9544 mParent.childHasTransientStateChanged(this, hasTransientState);
9545 } catch (AbstractMethodError e) {
9546 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() +
9547 " does not fully implement ViewParent", e);
9554 * Returns true if this view is currently attached to a window.
9556 public boolean isAttachedToWindow() {
9557 return mAttachInfo != null;
9561 * Returns true if this view has been through at least one layout since it
9562 * was last attached to or detached from a window.
9564 public boolean isLaidOut() {
9565 return (mPrivateFlags3 & PFLAG3_IS_LAID_OUT) == PFLAG3_IS_LAID_OUT;
9569 * If this view doesn't do any drawing on its own, set this flag to
9570 * allow further optimizations. By default, this flag is not set on
9571 * View, but could be set on some View subclasses such as ViewGroup.
9573 * Typically, if you override {@link #onDraw(android.graphics.Canvas)}
9574 * you should clear this flag.
9576 * @param willNotDraw whether or not this View draw on its own
9578 public void setWillNotDraw(boolean willNotDraw) {
9579 setFlags(willNotDraw ? WILL_NOT_DRAW : 0, DRAW_MASK);
9583 * Returns whether or not this View draws on its own.
9585 * @return true if this view has nothing to draw, false otherwise
9587 @ViewDebug.ExportedProperty(category = "drawing")
9588 public boolean willNotDraw() {
9589 return (mViewFlags & DRAW_MASK) == WILL_NOT_DRAW;
9593 * When a View's drawing cache is enabled, drawing is redirected to an
9594 * offscreen bitmap. Some views, like an ImageView, must be able to
9595 * bypass this mechanism if they already draw a single bitmap, to avoid
9596 * unnecessary usage of the memory.
9598 * @param willNotCacheDrawing true if this view does not cache its
9599 * drawing, false otherwise
9601 public void setWillNotCacheDrawing(boolean willNotCacheDrawing) {
9602 setFlags(willNotCacheDrawing ? WILL_NOT_CACHE_DRAWING : 0, WILL_NOT_CACHE_DRAWING);
9606 * Returns whether or not this View can cache its drawing or not.
9608 * @return true if this view does not cache its drawing, false otherwise
9610 @ViewDebug.ExportedProperty(category = "drawing")
9611 public boolean willNotCacheDrawing() {
9612 return (mViewFlags & WILL_NOT_CACHE_DRAWING) == WILL_NOT_CACHE_DRAWING;
9616 * Indicates whether this view reacts to click events or not.
9618 * @return true if the view is clickable, false otherwise
9620 * @see #setClickable(boolean)
9621 * @attr ref android.R.styleable#View_clickable
9623 @ViewDebug.ExportedProperty
9624 public boolean isClickable() {
9625 return (mViewFlags & CLICKABLE) == CLICKABLE;
9629 * Enables or disables click events for this view. When a view
9630 * is clickable it will change its state to "pressed" on every click.
9631 * Subclasses should set the view clickable to visually react to
9634 * @param clickable true to make the view clickable, false otherwise
9636 * @see #isClickable()
9637 * @attr ref android.R.styleable#View_clickable
9639 public void setClickable(boolean clickable) {
9640 setFlags(clickable ? CLICKABLE : 0, CLICKABLE);
9644 * Indicates whether this view reacts to long click events or not.
9646 * @return true if the view is long clickable, false otherwise
9648 * @see #setLongClickable(boolean)
9649 * @attr ref android.R.styleable#View_longClickable
9651 public boolean isLongClickable() {
9652 return (mViewFlags & LONG_CLICKABLE) == LONG_CLICKABLE;
9656 * Enables or disables long click events for this view. When a view is long
9657 * clickable it reacts to the user holding down the button for a longer
9658 * duration than a tap. This event can either launch the listener or a
9661 * @param longClickable true to make the view long clickable, false otherwise
9662 * @see #isLongClickable()
9663 * @attr ref android.R.styleable#View_longClickable
9665 public void setLongClickable(boolean longClickable) {
9666 setFlags(longClickable ? LONG_CLICKABLE : 0, LONG_CLICKABLE);
9670 * Indicates whether this view reacts to context clicks or not.
9672 * @return true if the view is context clickable, false otherwise
9673 * @see #setContextClickable(boolean)
9674 * @attr ref android.R.styleable#View_contextClickable
9676 public boolean isContextClickable() {
9677 return (mViewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE;
9681 * Enables or disables context clicking for this view. This event can launch the listener.
9683 * @param contextClickable true to make the view react to a context click, false otherwise
9684 * @see #isContextClickable()
9685 * @attr ref android.R.styleable#View_contextClickable
9687 public void setContextClickable(boolean contextClickable) {
9688 setFlags(contextClickable ? CONTEXT_CLICKABLE : 0, CONTEXT_CLICKABLE);
9692 * Sets the pressed state for this view and provides a touch coordinate for
9693 * animation hinting.
9695 * @param pressed Pass true to set the View's internal state to "pressed",
9696 * or false to reverts the View's internal state from a
9697 * previously set "pressed" state.
9698 * @param x The x coordinate of the touch that caused the press
9699 * @param y The y coordinate of the touch that caused the press
9701 private void setPressed(boolean pressed, float x, float y) {
9703 drawableHotspotChanged(x, y);
9706 setPressed(pressed);
9710 * Sets the pressed state for this view.
9712 * @see #isClickable()
9713 * @see #setClickable(boolean)
9715 * @param pressed Pass true to set the View's internal state to "pressed", or false to reverts
9716 * the View's internal state from a previously set "pressed" state.
9718 public void setPressed(boolean pressed) {
9719 final boolean needsRefresh = pressed != ((mPrivateFlags & PFLAG_PRESSED) == PFLAG_PRESSED);
9722 mPrivateFlags |= PFLAG_PRESSED;
9724 mPrivateFlags &= ~PFLAG_PRESSED;
9728 refreshDrawableState();
9730 dispatchSetPressed(pressed);
9734 * Dispatch setPressed to all of this View's children.
9736 * @see #setPressed(boolean)
9738 * @param pressed The new pressed state
9740 protected void dispatchSetPressed(boolean pressed) {
9744 * Indicates whether the view is currently in pressed state. Unless
9745 * {@link #setPressed(boolean)} is explicitly called, only clickable views can enter
9746 * the pressed state.
9748 * @see #setPressed(boolean)
9749 * @see #isClickable()
9750 * @see #setClickable(boolean)
9752 * @return true if the view is currently pressed, false otherwise
9754 @ViewDebug.ExportedProperty
9755 public boolean isPressed() {
9756 return (mPrivateFlags & PFLAG_PRESSED) == PFLAG_PRESSED;
9761 * Indicates whether this view will participate in data collection through
9762 * {@link ViewStructure}. If true, it will not provide any data
9763 * for itself or its children. If false, the normal data collection will be allowed.
9765 * @return Returns false if assist data collection is not blocked, else true.
9767 * @see #setAssistBlocked(boolean)
9768 * @attr ref android.R.styleable#View_assistBlocked
9770 public boolean isAssistBlocked() {
9771 return (mPrivateFlags3 & PFLAG3_ASSIST_BLOCKED) != 0;
9776 * Controls whether assist data collection from this view and its children is enabled
9777 * (that is, whether {@link #onProvideStructure} and
9778 * {@link #onProvideVirtualStructure} will be called). The default value is false,
9779 * allowing normal assist collection. Setting this to false will disable assist collection.
9781 * @param enabled Set to true to <em>disable</em> assist data collection, or false
9782 * (the default) to allow it.
9784 * @see #isAssistBlocked()
9785 * @see #onProvideStructure
9786 * @see #onProvideVirtualStructure
9787 * @attr ref android.R.styleable#View_assistBlocked
9789 public void setAssistBlocked(boolean enabled) {
9791 mPrivateFlags3 |= PFLAG3_ASSIST_BLOCKED;
9793 mPrivateFlags3 &= ~PFLAG3_ASSIST_BLOCKED;
9798 * Indicates whether this view will save its state (that is,
9799 * whether its {@link #onSaveInstanceState} method will be called).
9801 * @return Returns true if the view state saving is enabled, else false.
9803 * @see #setSaveEnabled(boolean)
9804 * @attr ref android.R.styleable#View_saveEnabled
9806 public boolean isSaveEnabled() {
9807 return (mViewFlags & SAVE_DISABLED_MASK) != SAVE_DISABLED;
9811 * Controls whether the saving of this view's state is
9812 * enabled (that is, whether its {@link #onSaveInstanceState} method
9813 * will be called). Note that even if freezing is enabled, the
9814 * view still must have an id assigned to it (via {@link #setId(int)})
9815 * for its state to be saved. This flag can only disable the
9816 * saving of this view; any child views may still have their state saved.
9818 * @param enabled Set to false to <em>disable</em> state saving, or true
9819 * (the default) to allow it.
9821 * @see #isSaveEnabled()
9823 * @see #onSaveInstanceState()
9824 * @attr ref android.R.styleable#View_saveEnabled
9826 public void setSaveEnabled(boolean enabled) {
9827 setFlags(enabled ? 0 : SAVE_DISABLED, SAVE_DISABLED_MASK);
9831 * Gets whether the framework should discard touches when the view's
9832 * window is obscured by another visible window.
9833 * Refer to the {@link View} security documentation for more details.
9835 * @return True if touch filtering is enabled.
9837 * @see #setFilterTouchesWhenObscured(boolean)
9838 * @attr ref android.R.styleable#View_filterTouchesWhenObscured
9840 @ViewDebug.ExportedProperty
9841 public boolean getFilterTouchesWhenObscured() {
9842 return (mViewFlags & FILTER_TOUCHES_WHEN_OBSCURED) != 0;
9846 * Sets whether the framework should discard touches when the view's
9847 * window is obscured by another visible window.
9848 * Refer to the {@link View} security documentation for more details.
9850 * @param enabled True if touch filtering should be enabled.
9852 * @see #getFilterTouchesWhenObscured
9853 * @attr ref android.R.styleable#View_filterTouchesWhenObscured
9855 public void setFilterTouchesWhenObscured(boolean enabled) {
9856 setFlags(enabled ? FILTER_TOUCHES_WHEN_OBSCURED : 0,
9857 FILTER_TOUCHES_WHEN_OBSCURED);
9861 * Indicates whether the entire hierarchy under this view will save its
9862 * state when a state saving traversal occurs from its parent. The default
9863 * is true; if false, these views will not be saved unless
9864 * {@link #saveHierarchyState(SparseArray)} is called directly on this view.
9866 * @return Returns true if the view state saving from parent is enabled, else false.
9868 * @see #setSaveFromParentEnabled(boolean)
9870 public boolean isSaveFromParentEnabled() {
9871 return (mViewFlags & PARENT_SAVE_DISABLED_MASK) != PARENT_SAVE_DISABLED;
9875 * Controls whether the entire hierarchy under this view will save its
9876 * state when a state saving traversal occurs from its parent. The default
9877 * is true; if false, these views will not be saved unless
9878 * {@link #saveHierarchyState(SparseArray)} is called directly on this view.
9880 * @param enabled Set to false to <em>disable</em> state saving, or true
9881 * (the default) to allow it.
9883 * @see #isSaveFromParentEnabled()
9885 * @see #onSaveInstanceState()
9887 public void setSaveFromParentEnabled(boolean enabled) {
9888 setFlags(enabled ? 0 : PARENT_SAVE_DISABLED, PARENT_SAVE_DISABLED_MASK);
9893 * Returns whether this View is currently able to take focus.
9895 * @return True if this view can take focus, or false otherwise.
9897 @ViewDebug.ExportedProperty(category = "focus")
9898 public final boolean isFocusable() {
9899 return FOCUSABLE == (mViewFlags & FOCUSABLE);
9903 * Returns the focusable setting for this view.
9905 * @return One of {@link #NOT_FOCUSABLE}, {@link #FOCUSABLE}, or {@link #FOCUSABLE_AUTO}.
9906 * @attr ref android.R.styleable#View_focusable
9908 @ViewDebug.ExportedProperty(mapping = {
9909 @ViewDebug.IntToString(from = NOT_FOCUSABLE, to = "NOT_FOCUSABLE"),
9910 @ViewDebug.IntToString(from = FOCUSABLE, to = "FOCUSABLE"),
9911 @ViewDebug.IntToString(from = FOCUSABLE_AUTO, to = "FOCUSABLE_AUTO")
9912 }, category = "focus")
9914 public int getFocusable() {
9915 return (mViewFlags & FOCUSABLE_AUTO) > 0 ? FOCUSABLE_AUTO : mViewFlags & FOCUSABLE;
9919 * When a view is focusable, it may not want to take focus when in touch mode.
9920 * For example, a button would like focus when the user is navigating via a D-pad
9921 * so that the user can click on it, but once the user starts touching the screen,
9922 * the button shouldn't take focus
9923 * @return Whether the view is focusable in touch mode.
9924 * @attr ref android.R.styleable#View_focusableInTouchMode
9926 @ViewDebug.ExportedProperty(category = "focus")
9927 public final boolean isFocusableInTouchMode() {
9928 return FOCUSABLE_IN_TOUCH_MODE == (mViewFlags & FOCUSABLE_IN_TOUCH_MODE);
9932 * Find the nearest view in the specified direction that can take focus.
9933 * This does not actually give focus to that view.
9935 * @param direction One of FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, and FOCUS_RIGHT
9937 * @return The nearest focusable in the specified direction, or null if none
9940 public View focusSearch(@FocusRealDirection int direction) {
9941 if (mParent != null) {
9942 return mParent.focusSearch(this, direction);
9949 * Returns whether this View is a root of a keyboard navigation cluster.
9951 * @return True if this view is a root of a cluster, or false otherwise.
9952 * @attr ref android.R.styleable#View_keyboardNavigationCluster
9954 @ViewDebug.ExportedProperty(category = "focus")
9955 public final boolean isKeyboardNavigationCluster() {
9956 return (mPrivateFlags3 & PFLAG3_CLUSTER) != 0;
9960 * Searches up the view hierarchy to find the top-most cluster. All deeper/nested clusters
9963 * @return the keyboard navigation cluster that this view is in (can be this view)
9964 * or {@code null} if not in one
9966 View findKeyboardNavigationCluster() {
9967 if (mParent instanceof View) {
9968 View cluster = ((View) mParent).findKeyboardNavigationCluster();
9969 if (cluster != null) {
9971 } else if (isKeyboardNavigationCluster()) {
9979 * Set whether this view is a root of a keyboard navigation cluster.
9981 * @param isCluster If true, this view is a root of a cluster.
9983 * @attr ref android.R.styleable#View_keyboardNavigationCluster
9985 public void setKeyboardNavigationCluster(boolean isCluster) {
9987 mPrivateFlags3 |= PFLAG3_CLUSTER;
9989 mPrivateFlags3 &= ~PFLAG3_CLUSTER;
9994 * Sets this View as the one which receives focus the next time cluster navigation jumps
9995 * to the cluster containing this View. This does NOT change focus even if the cluster
9996 * containing this view is current.
10000 public final void setFocusedInCluster() {
10001 setFocusedInCluster(findKeyboardNavigationCluster());
10004 private void setFocusedInCluster(View cluster) {
10005 if (this instanceof ViewGroup) {
10006 ((ViewGroup) this).mFocusedInCluster = null;
10008 if (cluster == this) {
10011 ViewParent parent = mParent;
10013 while (parent instanceof ViewGroup) {
10014 ((ViewGroup) parent).mFocusedInCluster = child;
10015 if (parent == cluster) {
10018 child = (View) parent;
10019 parent = parent.getParent();
10023 private void updateFocusedInCluster(View oldFocus, @FocusDirection int direction) {
10024 if (oldFocus != null) {
10025 View oldCluster = oldFocus.findKeyboardNavigationCluster();
10026 View cluster = findKeyboardNavigationCluster();
10027 if (oldCluster != cluster) {
10028 // Going from one cluster to another, so save last-focused.
10029 // This covers cluster jumps because they are always FOCUS_DOWN
10030 oldFocus.setFocusedInCluster(oldCluster);
10031 if (!(oldFocus.mParent instanceof ViewGroup)) {
10034 if (direction == FOCUS_FORWARD || direction == FOCUS_BACKWARD) {
10035 // This is a result of ordered navigation so consider navigation through
10036 // the previous cluster "complete" and clear its last-focused memory.
10037 ((ViewGroup) oldFocus.mParent).clearFocusedInCluster(oldFocus);
10038 } else if (oldFocus instanceof ViewGroup
10039 && ((ViewGroup) oldFocus).getDescendantFocusability()
10040 == ViewGroup.FOCUS_AFTER_DESCENDANTS
10041 && ViewRootImpl.isViewDescendantOf(this, oldFocus)) {
10042 // This means oldFocus is not focusable since it obviously has a focusable
10043 // child (this). Don't restore focus to it in the future.
10044 ((ViewGroup) oldFocus.mParent).clearFocusedInCluster(oldFocus);
10051 * Returns whether this View should receive focus when the focus is restored for the view
10052 * hierarchy containing this view.
10054 * Focus gets restored for a view hierarchy when the root of the hierarchy gets added to a
10055 * window or serves as a target of cluster navigation.
10057 * @see #restoreDefaultFocus()
10059 * @return {@code true} if this view is the default-focus view, {@code false} otherwise
10060 * @attr ref android.R.styleable#View_focusedByDefault
10062 @ViewDebug.ExportedProperty(category = "focus")
10063 public final boolean isFocusedByDefault() {
10064 return (mPrivateFlags3 & PFLAG3_FOCUSED_BY_DEFAULT) != 0;
10068 * Sets whether this View should receive focus when the focus is restored for the view
10069 * hierarchy containing this view.
10071 * Focus gets restored for a view hierarchy when the root of the hierarchy gets added to a
10072 * window or serves as a target of cluster navigation.
10074 * @param isFocusedByDefault {@code true} to set this view as the default-focus view,
10075 * {@code false} otherwise.
10077 * @see #restoreDefaultFocus()
10079 * @attr ref android.R.styleable#View_focusedByDefault
10081 public void setFocusedByDefault(boolean isFocusedByDefault) {
10082 if (isFocusedByDefault == ((mPrivateFlags3 & PFLAG3_FOCUSED_BY_DEFAULT) != 0)) {
10086 if (isFocusedByDefault) {
10087 mPrivateFlags3 |= PFLAG3_FOCUSED_BY_DEFAULT;
10089 mPrivateFlags3 &= ~PFLAG3_FOCUSED_BY_DEFAULT;
10092 if (mParent instanceof ViewGroup) {
10093 if (isFocusedByDefault) {
10094 ((ViewGroup) mParent).setDefaultFocus(this);
10096 ((ViewGroup) mParent).clearDefaultFocus(this);
10102 * Returns whether the view hierarchy with this view as a root contain a default-focus view.
10104 * @return {@code true} if this view has default focus, {@code false} otherwise
10106 boolean hasDefaultFocus() {
10107 return isFocusedByDefault();
10111 * Find the nearest keyboard navigation cluster in the specified direction.
10112 * This does not actually give focus to that cluster.
10114 * @param currentCluster The starting point of the search. Null means the current cluster is not
10116 * @param direction Direction to look
10118 * @return The nearest keyboard navigation cluster in the specified direction, or null if none
10121 public View keyboardNavigationClusterSearch(View currentCluster,
10122 @FocusDirection int direction) {
10123 if (isKeyboardNavigationCluster()) {
10124 currentCluster = this;
10126 if (isRootNamespace()) {
10127 // Root namespace means we should consider ourselves the top of the
10128 // tree for group searching; otherwise we could be group searching
10129 // into other tabs. see LocalActivityManager and TabHost for more info.
10130 return FocusFinder.getInstance().findNextKeyboardNavigationCluster(
10131 this, currentCluster, direction);
10132 } else if (mParent != null) {
10133 return mParent.keyboardNavigationClusterSearch(currentCluster, direction);
10139 * This method is the last chance for the focused view and its ancestors to
10140 * respond to an arrow key. This is called when the focused view did not
10141 * consume the key internally, nor could the view system find a new view in
10142 * the requested direction to give focus to.
10144 * @param focused The currently focused view.
10145 * @param direction The direction focus wants to move. One of FOCUS_UP,
10146 * FOCUS_DOWN, FOCUS_LEFT, and FOCUS_RIGHT.
10147 * @return True if the this view consumed this unhandled move.
10149 public boolean dispatchUnhandledMove(View focused, @FocusRealDirection int direction) {
10154 * Sets whether this View should use a default focus highlight when it gets focused but doesn't
10155 * have {@link android.R.attr#state_focused} defined in its background.
10157 * @param defaultFocusHighlightEnabled {@code true} to set this view to use a default focus
10158 * highlight, {@code false} otherwise.
10160 * @attr ref android.R.styleable#View_defaultFocusHighlightEnabled
10162 public void setDefaultFocusHighlightEnabled(boolean defaultFocusHighlightEnabled) {
10163 mDefaultFocusHighlightEnabled = defaultFocusHighlightEnabled;
10169 * Returns whether this View should use a default focus highlight when it gets focused but
10170 * doesn't have {@link android.R.attr#state_focused} defined in its background.
10172 * @return True if this View should use a default focus highlight.
10173 * @attr ref android.R.styleable#View_defaultFocusHighlightEnabled
10175 @ViewDebug.ExportedProperty(category = "focus")
10176 public final boolean getDefaultFocusHighlightEnabled() {
10177 return mDefaultFocusHighlightEnabled;
10181 * If a user manually specified the next view id for a particular direction,
10182 * use the root to look up the view.
10183 * @param root The root view of the hierarchy containing this view.
10184 * @param direction One of FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, FOCUS_RIGHT, FOCUS_FORWARD,
10185 * or FOCUS_BACKWARD.
10186 * @return The user specified next view, or null if there is none.
10188 View findUserSetNextFocus(View root, @FocusDirection int direction) {
10189 switch (direction) {
10191 if (mNextFocusLeftId == View.NO_ID) return null;
10192 return findViewInsideOutShouldExist(root, mNextFocusLeftId);
10194 if (mNextFocusRightId == View.NO_ID) return null;
10195 return findViewInsideOutShouldExist(root, mNextFocusRightId);
10197 if (mNextFocusUpId == View.NO_ID) return null;
10198 return findViewInsideOutShouldExist(root, mNextFocusUpId);
10200 if (mNextFocusDownId == View.NO_ID) return null;
10201 return findViewInsideOutShouldExist(root, mNextFocusDownId);
10202 case FOCUS_FORWARD:
10203 if (mNextFocusForwardId == View.NO_ID) return null;
10204 return findViewInsideOutShouldExist(root, mNextFocusForwardId);
10205 case FOCUS_BACKWARD: {
10206 if (mID == View.NO_ID) return null;
10207 final int id = mID;
10208 return root.findViewByPredicateInsideOut(this, new Predicate<View>() {
10210 public boolean test(View t) {
10211 return t.mNextFocusForwardId == id;
10220 * If a user manually specified the next keyboard-navigation cluster for a particular direction,
10221 * use the root to look up the view.
10223 * @param root the root view of the hierarchy containing this view
10224 * @param direction {@link #FOCUS_FORWARD} or {@link #FOCUS_BACKWARD}
10225 * @return the user-specified next cluster, or {@code null} if there is none
10227 View findUserSetNextKeyboardNavigationCluster(View root, @FocusDirection int direction) {
10228 switch (direction) {
10229 case FOCUS_FORWARD:
10230 if (mNextClusterForwardId == View.NO_ID) return null;
10231 return findViewInsideOutShouldExist(root, mNextClusterForwardId);
10232 case FOCUS_BACKWARD: {
10233 if (mID == View.NO_ID) return null;
10234 final int id = mID;
10235 return root.findViewByPredicateInsideOut(this,
10236 (Predicate<View>) t -> t.mNextClusterForwardId == id);
10242 private View findViewInsideOutShouldExist(View root, int id) {
10243 if (mMatchIdPredicate == null) {
10244 mMatchIdPredicate = new MatchIdPredicate();
10246 mMatchIdPredicate.mId = id;
10247 View result = root.findViewByPredicateInsideOut(this, mMatchIdPredicate);
10248 if (result == null) {
10249 Log.w(VIEW_LOG_TAG, "couldn't find view with id " + id);
10255 * Find and return all focusable views that are descendants of this view,
10256 * possibly including this view if it is focusable itself.
10258 * @param direction The direction of the focus
10259 * @return A list of focusable views
10261 public ArrayList<View> getFocusables(@FocusDirection int direction) {
10262 ArrayList<View> result = new ArrayList<View>(24);
10263 addFocusables(result, direction);
10268 * Add any focusable views that are descendants of this view (possibly
10269 * including this view if it is focusable itself) to views. If we are in touch mode,
10270 * only add views that are also focusable in touch mode.
10272 * @param views Focusable views found so far
10273 * @param direction The direction of the focus
10275 public void addFocusables(ArrayList<View> views, @FocusDirection int direction) {
10276 addFocusables(views, direction, isInTouchMode() ? FOCUSABLES_TOUCH_MODE : FOCUSABLES_ALL);
10280 * Adds any focusable views that are descendants of this view (possibly
10281 * including this view if it is focusable itself) to views. This method
10282 * adds all focusable views regardless if we are in touch mode or
10283 * only views focusable in touch mode if we are in touch mode or
10284 * only views that can take accessibility focus if accessibility is enabled
10285 * depending on the focusable mode parameter.
10287 * @param views Focusable views found so far or null if all we are interested is
10288 * the number of focusables.
10289 * @param direction The direction of the focus.
10290 * @param focusableMode The type of focusables to be added.
10292 * @see #FOCUSABLES_ALL
10293 * @see #FOCUSABLES_TOUCH_MODE
10295 public void addFocusables(ArrayList<View> views, @FocusDirection int direction,
10296 @FocusableMode int focusableMode) {
10297 if (views == null) {
10300 if (!isFocusable()) {
10303 if ((focusableMode & FOCUSABLES_TOUCH_MODE) == FOCUSABLES_TOUCH_MODE
10304 && !isFocusableInTouchMode()) {
10311 * Adds any keyboard navigation cluster roots that are descendants of this view (possibly
10312 * including this view if it is a cluster root itself) to views.
10314 * @param views Keyboard navigation cluster roots found so far
10315 * @param direction Direction to look
10317 public void addKeyboardNavigationClusters(
10318 @NonNull Collection<View> views,
10320 if (!isKeyboardNavigationCluster()) {
10323 if (!hasFocusable()) {
10330 * Finds the Views that contain given text. The containment is case insensitive.
10331 * The search is performed by either the text that the View renders or the content
10332 * description that describes the view for accessibility purposes and the view does
10333 * not render or both. Clients can specify how the search is to be performed via
10334 * passing the {@link #FIND_VIEWS_WITH_TEXT} and
10335 * {@link #FIND_VIEWS_WITH_CONTENT_DESCRIPTION} flags.
10337 * @param outViews The output list of matching Views.
10338 * @param searched The text to match against.
10340 * @see #FIND_VIEWS_WITH_TEXT
10341 * @see #FIND_VIEWS_WITH_CONTENT_DESCRIPTION
10342 * @see #setContentDescription(CharSequence)
10344 public void findViewsWithText(ArrayList<View> outViews, CharSequence searched,
10345 @FindViewFlags int flags) {
10346 if (getAccessibilityNodeProvider() != null) {
10347 if ((flags & FIND_VIEWS_WITH_ACCESSIBILITY_NODE_PROVIDERS) != 0) {
10348 outViews.add(this);
10350 } else if ((flags & FIND_VIEWS_WITH_CONTENT_DESCRIPTION) != 0
10351 && (searched != null && searched.length() > 0)
10352 && (mContentDescription != null && mContentDescription.length() > 0)) {
10353 String searchedLowerCase = searched.toString().toLowerCase();
10354 String contentDescriptionLowerCase = mContentDescription.toString().toLowerCase();
10355 if (contentDescriptionLowerCase.contains(searchedLowerCase)) {
10356 outViews.add(this);
10362 * Find and return all touchable views that are descendants of this view,
10363 * possibly including this view if it is touchable itself.
10365 * @return A list of touchable views
10367 public ArrayList<View> getTouchables() {
10368 ArrayList<View> result = new ArrayList<View>();
10369 addTouchables(result);
10374 * Add any touchable views that are descendants of this view (possibly
10375 * including this view if it is touchable itself) to views.
10377 * @param views Touchable views found so far
10379 public void addTouchables(ArrayList<View> views) {
10380 final int viewFlags = mViewFlags;
10382 if (((viewFlags & CLICKABLE) == CLICKABLE || (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE
10383 || (viewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE)
10384 && (viewFlags & ENABLED_MASK) == ENABLED) {
10390 * Returns whether this View is accessibility focused.
10392 * @return True if this View is accessibility focused.
10394 public boolean isAccessibilityFocused() {
10395 return (mPrivateFlags2 & PFLAG2_ACCESSIBILITY_FOCUSED) != 0;
10399 * Call this to try to give accessibility focus to this view.
10401 * A view will not actually take focus if {@link AccessibilityManager#isEnabled()}
10402 * returns false or the view is no visible or the view already has accessibility
10405 * See also {@link #focusSearch(int)}, which is what you call to say that you
10406 * have focus, and you want your parent to look for the next one.
10408 * @return Whether this view actually took accessibility focus.
10412 public boolean requestAccessibilityFocus() {
10413 AccessibilityManager manager = AccessibilityManager.getInstance(mContext);
10414 if (!manager.isEnabled() || !manager.isTouchExplorationEnabled()) {
10417 if ((mViewFlags & VISIBILITY_MASK) != VISIBLE) {
10420 if ((mPrivateFlags2 & PFLAG2_ACCESSIBILITY_FOCUSED) == 0) {
10421 mPrivateFlags2 |= PFLAG2_ACCESSIBILITY_FOCUSED;
10422 ViewRootImpl viewRootImpl = getViewRootImpl();
10423 if (viewRootImpl != null) {
10424 viewRootImpl.setAccessibilityFocus(this, null);
10427 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED);
10434 * Call this to try to clear accessibility focus of this view.
10436 * See also {@link #focusSearch(int)}, which is what you call to say that you
10437 * have focus, and you want your parent to look for the next one.
10441 public void clearAccessibilityFocus() {
10442 clearAccessibilityFocusNoCallbacks(0);
10444 // Clear the global reference of accessibility focus if this view or
10445 // any of its descendants had accessibility focus. This will NOT send
10446 // an event or update internal state if focus is cleared from a
10447 // descendant view, which may leave views in inconsistent states.
10448 final ViewRootImpl viewRootImpl = getViewRootImpl();
10449 if (viewRootImpl != null) {
10450 final View focusHost = viewRootImpl.getAccessibilityFocusedHost();
10451 if (focusHost != null && ViewRootImpl.isViewDescendantOf(focusHost, this)) {
10452 viewRootImpl.setAccessibilityFocus(null, null);
10457 private void sendAccessibilityHoverEvent(int eventType) {
10458 // Since we are not delivering to a client accessibility events from not
10459 // important views (unless the clinet request that) we need to fire the
10460 // event from the deepest view exposed to the client. As a consequence if
10461 // the user crosses a not exposed view the client will see enter and exit
10462 // of the exposed predecessor followed by and enter and exit of that same
10463 // predecessor when entering and exiting the not exposed descendant. This
10464 // is fine since the client has a clear idea which view is hovered at the
10465 // price of a couple more events being sent. This is a simple and
10466 // working solution.
10467 View source = this;
10469 if (source.includeForAccessibility()) {
10470 source.sendAccessibilityEvent(eventType);
10473 ViewParent parent = source.getParent();
10474 if (parent instanceof View) {
10475 source = (View) parent;
10483 * Clears accessibility focus without calling any callback methods
10484 * normally invoked in {@link #clearAccessibilityFocus()}. This method
10485 * is used separately from that one for clearing accessibility focus when
10486 * giving this focus to another view.
10488 * @param action The action, if any, that led to focus being cleared. Set to
10489 * AccessibilityNodeInfo#ACTION_ACCESSIBILITY_FOCUS to specify that focus is moving within
10492 void clearAccessibilityFocusNoCallbacks(int action) {
10493 if ((mPrivateFlags2 & PFLAG2_ACCESSIBILITY_FOCUSED) != 0) {
10494 mPrivateFlags2 &= ~PFLAG2_ACCESSIBILITY_FOCUSED;
10496 if (AccessibilityManager.getInstance(mContext).isEnabled()) {
10497 AccessibilityEvent event = AccessibilityEvent.obtain(
10498 AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED);
10499 event.setAction(action);
10500 if (mAccessibilityDelegate != null) {
10501 mAccessibilityDelegate.sendAccessibilityEventUnchecked(this, event);
10503 sendAccessibilityEventUnchecked(event);
10510 * Call this to try to give focus to a specific view or to one of its
10513 * A view will not actually take focus if it is not focusable ({@link #isFocusable} returns
10514 * false), or if it is focusable and it is not focusable in touch mode
10515 * ({@link #isFocusableInTouchMode}) while the device is in touch mode.
10517 * See also {@link #focusSearch(int)}, which is what you call to say that you
10518 * have focus, and you want your parent to look for the next one.
10520 * This is equivalent to calling {@link #requestFocus(int, Rect)} with arguments
10521 * {@link #FOCUS_DOWN} and <code>null</code>.
10523 * @return Whether this view or one of its descendants actually took focus.
10525 public final boolean requestFocus() {
10526 return requestFocus(View.FOCUS_DOWN);
10530 * This will request focus for whichever View was last focused within this
10531 * cluster before a focus-jump out of it.
10536 public boolean restoreFocusInCluster(@FocusRealDirection int direction) {
10537 // Prioritize focusableByDefault over algorithmic focus selection.
10538 if (restoreDefaultFocus()) {
10541 return requestFocus(direction);
10545 * This will request focus for whichever View not in a cluster was last focused before a
10546 * focus-jump to a cluster. If no non-cluster View has previously had focus, this will focus
10547 * the "first" focusable view it finds.
10552 public boolean restoreFocusNotInCluster() {
10553 return requestFocus(View.FOCUS_DOWN);
10557 * Gives focus to the default-focus view in the view hierarchy that has this view as a root.
10558 * If the default-focus view cannot be found, falls back to calling {@link #requestFocus(int)}.
10560 * @return Whether this view or one of its descendants actually took focus
10562 public boolean restoreDefaultFocus() {
10563 return requestFocus(View.FOCUS_DOWN);
10567 * Call this to try to give focus to a specific view or to one of its
10568 * descendants and give it a hint about what direction focus is heading.
10570 * A view will not actually take focus if it is not focusable ({@link #isFocusable} returns
10571 * false), or if it is focusable and it is not focusable in touch mode
10572 * ({@link #isFocusableInTouchMode}) while the device is in touch mode.
10574 * See also {@link #focusSearch(int)}, which is what you call to say that you
10575 * have focus, and you want your parent to look for the next one.
10577 * This is equivalent to calling {@link #requestFocus(int, Rect)} with
10578 * <code>null</code> set for the previously focused rectangle.
10580 * @param direction One of FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, and FOCUS_RIGHT
10581 * @return Whether this view or one of its descendants actually took focus.
10583 public final boolean requestFocus(int direction) {
10584 return requestFocus(direction, null);
10588 * Call this to try to give focus to a specific view or to one of its descendants
10589 * and give it hints about the direction and a specific rectangle that the focus
10590 * is coming from. The rectangle can help give larger views a finer grained hint
10591 * about where focus is coming from, and therefore, where to show selection, or
10592 * forward focus change internally.
10594 * A view will not actually take focus if it is not focusable ({@link #isFocusable} returns
10595 * false), or if it is focusable and it is not focusable in touch mode
10596 * ({@link #isFocusableInTouchMode}) while the device is in touch mode.
10598 * A View will not take focus if it is not visible.
10600 * A View will not take focus if one of its parents has
10601 * {@link android.view.ViewGroup#getDescendantFocusability()} equal to
10602 * {@link ViewGroup#FOCUS_BLOCK_DESCENDANTS}.
10604 * See also {@link #focusSearch(int)}, which is what you call to say that you
10605 * have focus, and you want your parent to look for the next one.
10607 * You may wish to override this method if your custom {@link View} has an internal
10608 * {@link View} that it wishes to forward the request to.
10610 * @param direction One of FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, and FOCUS_RIGHT
10611 * @param previouslyFocusedRect The rectangle (in this View's coordinate system)
10612 * to give a finer grained hint about where focus is coming from. May be null
10613 * if there is no hint.
10614 * @return Whether this view or one of its descendants actually took focus.
10616 public boolean requestFocus(int direction, Rect previouslyFocusedRect) {
10617 return requestFocusNoSearch(direction, previouslyFocusedRect);
10620 private boolean requestFocusNoSearch(int direction, Rect previouslyFocusedRect) {
10621 // need to be focusable
10622 if ((mViewFlags & FOCUSABLE) != FOCUSABLE
10623 || (mViewFlags & VISIBILITY_MASK) != VISIBLE) {
10627 // need to be focusable in touch mode if in touch mode
10628 if (isInTouchMode() &&
10629 (FOCUSABLE_IN_TOUCH_MODE != (mViewFlags & FOCUSABLE_IN_TOUCH_MODE))) {
10633 // need to not have any parents blocking us
10634 if (hasAncestorThatBlocksDescendantFocus()) {
10638 handleFocusGainInternal(direction, previouslyFocusedRect);
10643 * Call this to try to give focus to a specific view or to one of its descendants. This is a
10644 * special variant of {@link #requestFocus() } that will allow views that are not focusable in
10645 * touch mode to request focus when they are touched.
10647 * @return Whether this view or one of its descendants actually took focus.
10649 * @see #isInTouchMode()
10652 public final boolean requestFocusFromTouch() {
10653 // Leave touch mode if we need to
10654 if (isInTouchMode()) {
10655 ViewRootImpl viewRoot = getViewRootImpl();
10656 if (viewRoot != null) {
10657 viewRoot.ensureTouchMode(false);
10660 return requestFocus(View.FOCUS_DOWN);
10664 * @return Whether any ancestor of this view blocks descendant focus.
10666 private boolean hasAncestorThatBlocksDescendantFocus() {
10667 final boolean focusableInTouchMode = isFocusableInTouchMode();
10668 ViewParent ancestor = mParent;
10669 while (ancestor instanceof ViewGroup) {
10670 final ViewGroup vgAncestor = (ViewGroup) ancestor;
10671 if (vgAncestor.getDescendantFocusability() == ViewGroup.FOCUS_BLOCK_DESCENDANTS
10672 || (!focusableInTouchMode && vgAncestor.shouldBlockFocusForTouchscreen())) {
10675 ancestor = vgAncestor.getParent();
10682 * Gets the mode for determining whether this View is important for accessibility.
10683 * A view is important for accessibility if it fires accessibility events and if it
10684 * is reported to accessibility services that query the screen.
10686 * @return The mode for determining whether a view is important for accessibility, one
10687 * of {@link #IMPORTANT_FOR_ACCESSIBILITY_AUTO}, {@link #IMPORTANT_FOR_ACCESSIBILITY_YES},
10688 * {@link #IMPORTANT_FOR_ACCESSIBILITY_NO}, or
10689 * {@link #IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS}.
10691 * @attr ref android.R.styleable#View_importantForAccessibility
10693 * @see #IMPORTANT_FOR_ACCESSIBILITY_YES
10694 * @see #IMPORTANT_FOR_ACCESSIBILITY_NO
10695 * @see #IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS
10696 * @see #IMPORTANT_FOR_ACCESSIBILITY_AUTO
10698 @ViewDebug.ExportedProperty(category = "accessibility", mapping = {
10699 @ViewDebug.IntToString(from = IMPORTANT_FOR_ACCESSIBILITY_AUTO, to = "auto"),
10700 @ViewDebug.IntToString(from = IMPORTANT_FOR_ACCESSIBILITY_YES, to = "yes"),
10701 @ViewDebug.IntToString(from = IMPORTANT_FOR_ACCESSIBILITY_NO, to = "no"),
10702 @ViewDebug.IntToString(from = IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS,
10703 to = "noHideDescendants")
10705 public int getImportantForAccessibility() {
10706 return (mPrivateFlags2 & PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK)
10707 >> PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT;
10711 * Sets the live region mode for this view. This indicates to accessibility
10712 * services whether they should automatically notify the user about changes
10713 * to the view's content description or text, or to the content descriptions
10714 * or text of the view's children (where applicable).
10716 * For example, in a login screen with a TextView that displays an "incorrect
10717 * password" notification, that view should be marked as a live region with
10718 * mode {@link #ACCESSIBILITY_LIVE_REGION_POLITE}.
10720 * To disable change notifications for this view, use
10721 * {@link #ACCESSIBILITY_LIVE_REGION_NONE}. This is the default live region
10722 * mode for most views.
10724 * To indicate that the user should be notified of changes, use
10725 * {@link #ACCESSIBILITY_LIVE_REGION_POLITE}.
10727 * If the view's changes should interrupt ongoing speech and notify the user
10728 * immediately, use {@link #ACCESSIBILITY_LIVE_REGION_ASSERTIVE}.
10730 * @param mode The live region mode for this view, one of:
10732 * <li>{@link #ACCESSIBILITY_LIVE_REGION_NONE}
10733 * <li>{@link #ACCESSIBILITY_LIVE_REGION_POLITE}
10734 * <li>{@link #ACCESSIBILITY_LIVE_REGION_ASSERTIVE}
10736 * @attr ref android.R.styleable#View_accessibilityLiveRegion
10738 public void setAccessibilityLiveRegion(int mode) {
10739 if (mode != getAccessibilityLiveRegion()) {
10740 mPrivateFlags2 &= ~PFLAG2_ACCESSIBILITY_LIVE_REGION_MASK;
10741 mPrivateFlags2 |= (mode << PFLAG2_ACCESSIBILITY_LIVE_REGION_SHIFT)
10742 & PFLAG2_ACCESSIBILITY_LIVE_REGION_MASK;
10743 notifyViewAccessibilityStateChangedIfNeeded(
10744 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED);
10749 * Gets the live region mode for this View.
10751 * @return The live region mode for the view.
10753 * @attr ref android.R.styleable#View_accessibilityLiveRegion
10755 * @see #setAccessibilityLiveRegion(int)
10757 public int getAccessibilityLiveRegion() {
10758 return (mPrivateFlags2 & PFLAG2_ACCESSIBILITY_LIVE_REGION_MASK)
10759 >> PFLAG2_ACCESSIBILITY_LIVE_REGION_SHIFT;
10763 * Sets how to determine whether this view is important for accessibility
10764 * which is if it fires accessibility events and if it is reported to
10765 * accessibility services that query the screen.
10767 * @param mode How to determine whether this view is important for accessibility.
10769 * @attr ref android.R.styleable#View_importantForAccessibility
10771 * @see #IMPORTANT_FOR_ACCESSIBILITY_YES
10772 * @see #IMPORTANT_FOR_ACCESSIBILITY_NO
10773 * @see #IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS
10774 * @see #IMPORTANT_FOR_ACCESSIBILITY_AUTO
10776 public void setImportantForAccessibility(int mode) {
10777 final int oldMode = getImportantForAccessibility();
10778 if (mode != oldMode) {
10779 final boolean hideDescendants =
10780 mode == IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS;
10782 // If this node or its descendants are no longer important, try to
10783 // clear accessibility focus.
10784 if (mode == IMPORTANT_FOR_ACCESSIBILITY_NO || hideDescendants) {
10785 final View focusHost = findAccessibilityFocusHost(hideDescendants);
10786 if (focusHost != null) {
10787 focusHost.clearAccessibilityFocus();
10791 // If we're moving between AUTO and another state, we might not need
10792 // to send a subtree changed notification. We'll store the computed
10793 // importance, since we'll need to check it later to make sure.
10794 final boolean maySkipNotify = oldMode == IMPORTANT_FOR_ACCESSIBILITY_AUTO
10795 || mode == IMPORTANT_FOR_ACCESSIBILITY_AUTO;
10796 final boolean oldIncludeForAccessibility = maySkipNotify && includeForAccessibility();
10797 mPrivateFlags2 &= ~PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK;
10798 mPrivateFlags2 |= (mode << PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT)
10799 & PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK;
10800 if (!maySkipNotify || oldIncludeForAccessibility != includeForAccessibility()) {
10801 notifySubtreeAccessibilityStateChangedIfNeeded();
10803 notifyViewAccessibilityStateChangedIfNeeded(
10804 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED);
10810 * Returns the view within this view's hierarchy that is hosting
10811 * accessibility focus.
10813 * @param searchDescendants whether to search for focus in descendant views
10814 * @return the view hosting accessibility focus, or {@code null}
10816 private View findAccessibilityFocusHost(boolean searchDescendants) {
10817 if (isAccessibilityFocusedViewOrHost()) {
10821 if (searchDescendants) {
10822 final ViewRootImpl viewRoot = getViewRootImpl();
10823 if (viewRoot != null) {
10824 final View focusHost = viewRoot.getAccessibilityFocusedHost();
10825 if (focusHost != null && ViewRootImpl.isViewDescendantOf(focusHost, this)) {
10835 * Computes whether this view should be exposed for accessibility. In
10836 * general, views that are interactive or provide information are exposed
10837 * while views that serve only as containers are hidden.
10839 * If an ancestor of this view has importance
10840 * {@link #IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS}, this method
10841 * returns <code>false</code>.
10843 * Otherwise, the value is computed according to the view's
10844 * {@link #getImportantForAccessibility()} value:
10846 * <li>{@link #IMPORTANT_FOR_ACCESSIBILITY_NO} or
10847 * {@link #IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS}, return <code>false
10849 * <li>{@link #IMPORTANT_FOR_ACCESSIBILITY_YES}, return <code>true</code>
10850 * <li>{@link #IMPORTANT_FOR_ACCESSIBILITY_AUTO}, return <code>true</code> if
10851 * view satisfies any of the following:
10853 * <li>Is actionable, e.g. {@link #isClickable()},
10854 * {@link #isLongClickable()}, or {@link #isFocusable()}
10855 * <li>Has an {@link AccessibilityDelegate}
10856 * <li>Has an interaction listener, e.g. {@link OnTouchListener},
10857 * {@link OnKeyListener}, etc.
10858 * <li>Is an accessibility live region, e.g.
10859 * {@link #getAccessibilityLiveRegion()} is not
10860 * {@link #ACCESSIBILITY_LIVE_REGION_NONE}.
10864 * @return Whether the view is exposed for accessibility.
10865 * @see #setImportantForAccessibility(int)
10866 * @see #getImportantForAccessibility()
10868 public boolean isImportantForAccessibility() {
10869 final int mode = (mPrivateFlags2 & PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK)
10870 >> PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT;
10871 if (mode == IMPORTANT_FOR_ACCESSIBILITY_NO
10872 || mode == IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS) {
10876 // Check parent mode to ensure we're not hidden.
10877 ViewParent parent = mParent;
10878 while (parent instanceof View) {
10879 if (((View) parent).getImportantForAccessibility()
10880 == IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS) {
10883 parent = parent.getParent();
10886 return mode == IMPORTANT_FOR_ACCESSIBILITY_YES || isActionableForAccessibility()
10887 || hasListenersForAccessibility() || getAccessibilityNodeProvider() != null
10888 || getAccessibilityLiveRegion() != ACCESSIBILITY_LIVE_REGION_NONE;
10892 * Gets the parent for accessibility purposes. Note that the parent for
10893 * accessibility is not necessary the immediate parent. It is the first
10894 * predecessor that is important for accessibility.
10896 * @return The parent for accessibility purposes.
10898 public ViewParent getParentForAccessibility() {
10899 if (mParent instanceof View) {
10900 View parentView = (View) mParent;
10901 if (parentView.includeForAccessibility()) {
10904 return mParent.getParentForAccessibility();
10911 * Adds the children of this View relevant for accessibility to the given list
10912 * as output. Since some Views are not important for accessibility the added
10913 * child views are not necessarily direct children of this view, rather they are
10914 * the first level of descendants important for accessibility.
10916 * @param outChildren The output list that will receive children for accessibility.
10918 public void addChildrenForAccessibility(ArrayList<View> outChildren) {
10923 * Whether to regard this view for accessibility. A view is regarded for
10924 * accessibility if it is important for accessibility or the querying
10925 * accessibility service has explicitly requested that view not
10926 * important for accessibility are regarded.
10928 * @return Whether to regard the view for accessibility.
10932 public boolean includeForAccessibility() {
10933 if (mAttachInfo != null) {
10934 return (mAttachInfo.mAccessibilityFetchFlags
10935 & AccessibilityNodeInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS) != 0
10936 || isImportantForAccessibility();
10942 * Returns whether the View is considered actionable from
10943 * accessibility perspective. Such view are important for
10946 * @return True if the view is actionable for accessibility.
10950 public boolean isActionableForAccessibility() {
10951 return (isClickable() || isLongClickable() || isFocusable());
10955 * Returns whether the View has registered callbacks which makes it
10956 * important for accessibility.
10958 * @return True if the view is actionable for accessibility.
10960 private boolean hasListenersForAccessibility() {
10961 ListenerInfo info = getListenerInfo();
10962 return mTouchDelegate != null || info.mOnKeyListener != null
10963 || info.mOnTouchListener != null || info.mOnGenericMotionListener != null
10964 || info.mOnHoverListener != null || info.mOnDragListener != null;
10968 * Notifies that the accessibility state of this view changed. The change
10969 * is local to this view and does not represent structural changes such
10970 * as children and parent. For example, the view became focusable. The
10971 * notification is at at most once every
10972 * {@link ViewConfiguration#getSendRecurringAccessibilityEventsInterval()}
10973 * to avoid unnecessary load to the system. Also once a view has a pending
10974 * notification this method is a NOP until the notification has been sent.
10978 public void notifyViewAccessibilityStateChangedIfNeeded(int changeType) {
10979 if (!AccessibilityManager.getInstance(mContext).isEnabled() || mAttachInfo == null) {
10982 if (mSendViewStateChangedAccessibilityEvent == null) {
10983 mSendViewStateChangedAccessibilityEvent =
10984 new SendViewStateChangedAccessibilityEvent();
10986 mSendViewStateChangedAccessibilityEvent.runOrPost(changeType);
10990 * Notifies that the accessibility state of this view changed. The change
10991 * is *not* local to this view and does represent structural changes such
10992 * as children and parent. For example, the view size changed. The
10993 * notification is at at most once every
10994 * {@link ViewConfiguration#getSendRecurringAccessibilityEventsInterval()}
10995 * to avoid unnecessary load to the system. Also once a view has a pending
10996 * notification this method is a NOP until the notification has been sent.
11000 public void notifySubtreeAccessibilityStateChangedIfNeeded() {
11001 if (!AccessibilityManager.getInstance(mContext).isEnabled() || mAttachInfo == null) {
11004 if ((mPrivateFlags2 & PFLAG2_SUBTREE_ACCESSIBILITY_STATE_CHANGED) == 0) {
11005 mPrivateFlags2 |= PFLAG2_SUBTREE_ACCESSIBILITY_STATE_CHANGED;
11006 if (mParent != null) {
11008 mParent.notifySubtreeAccessibilityStateChanged(
11009 this, this, AccessibilityEvent.CONTENT_CHANGE_TYPE_SUBTREE);
11010 } catch (AbstractMethodError e) {
11011 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() +
11012 " does not fully implement ViewParent", e);
11019 * Change the visibility of the View without triggering any other changes. This is
11020 * important for transitions, where visibility changes should not adjust focus or
11021 * trigger a new layout. This is only used when the visibility has already been changed
11022 * and we need a transient value during an animation. When the animation completes,
11023 * the original visibility value is always restored.
11025 * @param visibility One of {@link #VISIBLE}, {@link #INVISIBLE}, or {@link #GONE}.
11028 public void setTransitionVisibility(@Visibility int visibility) {
11029 mViewFlags = (mViewFlags & ~View.VISIBILITY_MASK) | visibility;
11033 * Reset the flag indicating the accessibility state of the subtree rooted
11034 * at this view changed.
11036 void resetSubtreeAccessibilityStateChanged() {
11037 mPrivateFlags2 &= ~PFLAG2_SUBTREE_ACCESSIBILITY_STATE_CHANGED;
11041 * Report an accessibility action to this view's parents for delegated processing.
11043 * <p>Implementations of {@link #performAccessibilityAction(int, Bundle)} may internally
11044 * call this method to delegate an accessibility action to a supporting parent. If the parent
11045 * returns true from its
11046 * {@link ViewParent#onNestedPrePerformAccessibilityAction(View, int, android.os.Bundle)}
11047 * method this method will return true to signify that the action was consumed.</p>
11049 * <p>This method is useful for implementing nested scrolling child views. If
11050 * {@link #isNestedScrollingEnabled()} returns true and the action is a scrolling action
11051 * a custom view implementation may invoke this method to allow a parent to consume the
11052 * scroll first. If this method returns true the custom view should skip its own scrolling
11055 * @param action Accessibility action to delegate
11056 * @param arguments Optional action arguments
11057 * @return true if the action was consumed by a parent
11059 public boolean dispatchNestedPrePerformAccessibilityAction(int action, Bundle arguments) {
11060 for (ViewParent p = getParent(); p != null; p = p.getParent()) {
11061 if (p.onNestedPrePerformAccessibilityAction(this, action, arguments)) {
11069 * Performs the specified accessibility action on the view. For
11070 * possible accessibility actions look at {@link AccessibilityNodeInfo}.
11072 * If an {@link AccessibilityDelegate} has been specified via calling
11073 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its
11074 * {@link AccessibilityDelegate#performAccessibilityAction(View, int, Bundle)}
11075 * is responsible for handling this call.
11078 * <p>The default implementation will delegate
11079 * {@link AccessibilityNodeInfo#ACTION_SCROLL_BACKWARD} and
11080 * {@link AccessibilityNodeInfo#ACTION_SCROLL_FORWARD} to nested scrolling parents if
11081 * {@link #isNestedScrollingEnabled() nested scrolling is enabled} on this view.</p>
11083 * @param action The action to perform.
11084 * @param arguments Optional action arguments.
11085 * @return Whether the action was performed.
11087 public boolean performAccessibilityAction(int action, Bundle arguments) {
11088 if (mAccessibilityDelegate != null) {
11089 return mAccessibilityDelegate.performAccessibilityAction(this, action, arguments);
11091 return performAccessibilityActionInternal(action, arguments);
11096 * @see #performAccessibilityAction(int, Bundle)
11098 * Note: Called from the default {@link AccessibilityDelegate}.
11102 public boolean performAccessibilityActionInternal(int action, Bundle arguments) {
11103 if (isNestedScrollingEnabled()
11104 && (action == AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD
11105 || action == AccessibilityNodeInfo.ACTION_SCROLL_FORWARD
11106 || action == R.id.accessibilityActionScrollUp
11107 || action == R.id.accessibilityActionScrollLeft
11108 || action == R.id.accessibilityActionScrollDown
11109 || action == R.id.accessibilityActionScrollRight)) {
11110 if (dispatchNestedPrePerformAccessibilityAction(action, arguments)) {
11116 case AccessibilityNodeInfo.ACTION_CLICK: {
11117 if (isClickable()) {
11122 case AccessibilityNodeInfo.ACTION_LONG_CLICK: {
11123 if (isLongClickable()) {
11124 performLongClick();
11128 case AccessibilityNodeInfo.ACTION_FOCUS: {
11130 // Get out of touch mode since accessibility
11131 // wants to move focus around.
11132 getViewRootImpl().ensureTouchMode(false);
11133 return requestFocus();
11136 case AccessibilityNodeInfo.ACTION_CLEAR_FOCUS: {
11139 return !isFocused();
11142 case AccessibilityNodeInfo.ACTION_SELECT: {
11143 if (!isSelected()) {
11145 return isSelected();
11148 case AccessibilityNodeInfo.ACTION_CLEAR_SELECTION: {
11149 if (isSelected()) {
11150 setSelected(false);
11151 return !isSelected();
11154 case AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS: {
11155 if (!isAccessibilityFocused()) {
11156 return requestAccessibilityFocus();
11159 case AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS: {
11160 if (isAccessibilityFocused()) {
11161 clearAccessibilityFocus();
11165 case AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY: {
11166 if (arguments != null) {
11167 final int granularity = arguments.getInt(
11168 AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT);
11169 final boolean extendSelection = arguments.getBoolean(
11170 AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN);
11171 return traverseAtGranularity(granularity, true, extendSelection);
11174 case AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY: {
11175 if (arguments != null) {
11176 final int granularity = arguments.getInt(
11177 AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT);
11178 final boolean extendSelection = arguments.getBoolean(
11179 AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN);
11180 return traverseAtGranularity(granularity, false, extendSelection);
11183 case AccessibilityNodeInfo.ACTION_SET_SELECTION: {
11184 CharSequence text = getIterableTextForAccessibility();
11185 if (text == null) {
11188 final int start = (arguments != null) ? arguments.getInt(
11189 AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_START_INT, -1) : -1;
11190 final int end = (arguments != null) ? arguments.getInt(
11191 AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_END_INT, -1) : -1;
11192 // Only cursor position can be specified (selection length == 0)
11193 if ((getAccessibilitySelectionStart() != start
11194 || getAccessibilitySelectionEnd() != end)
11195 && (start == end)) {
11196 setAccessibilitySelection(start, end);
11197 notifyViewAccessibilityStateChangedIfNeeded(
11198 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED);
11202 case R.id.accessibilityActionShowOnScreen: {
11203 if (mAttachInfo != null) {
11204 final Rect r = mAttachInfo.mTmpInvalRect;
11206 return requestRectangleOnScreen(r, true);
11209 case R.id.accessibilityActionContextClick: {
11210 if (isContextClickable()) {
11211 performContextClick();
11219 private boolean traverseAtGranularity(int granularity, boolean forward,
11220 boolean extendSelection) {
11221 CharSequence text = getIterableTextForAccessibility();
11222 if (text == null || text.length() == 0) {
11225 TextSegmentIterator iterator = getIteratorForGranularity(granularity);
11226 if (iterator == null) {
11229 int current = getAccessibilitySelectionEnd();
11230 if (current == ACCESSIBILITY_CURSOR_POSITION_UNDEFINED) {
11231 current = forward ? 0 : text.length();
11233 final int[] range = forward ? iterator.following(current) : iterator.preceding(current);
11234 if (range == null) {
11237 final int segmentStart = range[0];
11238 final int segmentEnd = range[1];
11239 int selectionStart;
11241 if (extendSelection && isAccessibilitySelectionExtendable()) {
11242 selectionStart = getAccessibilitySelectionStart();
11243 if (selectionStart == ACCESSIBILITY_CURSOR_POSITION_UNDEFINED) {
11244 selectionStart = forward ? segmentStart : segmentEnd;
11246 selectionEnd = forward ? segmentEnd : segmentStart;
11248 selectionStart = selectionEnd= forward ? segmentEnd : segmentStart;
11250 setAccessibilitySelection(selectionStart, selectionEnd);
11251 final int action = forward ? AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
11252 : AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY;
11253 sendViewTextTraversedAtGranularityEvent(action, granularity, segmentStart, segmentEnd);
11258 * Gets the text reported for accessibility purposes.
11260 * @return The accessibility text.
11264 public CharSequence getIterableTextForAccessibility() {
11265 return getContentDescription();
11269 * Gets whether accessibility selection can be extended.
11271 * @return If selection is extensible.
11275 public boolean isAccessibilitySelectionExtendable() {
11282 public int getAccessibilitySelectionStart() {
11283 return mAccessibilityCursorPosition;
11289 public int getAccessibilitySelectionEnd() {
11290 return getAccessibilitySelectionStart();
11296 public void setAccessibilitySelection(int start, int end) {
11297 if (start == end && end == mAccessibilityCursorPosition) {
11300 if (start >= 0 && start == end && end <= getIterableTextForAccessibility().length()) {
11301 mAccessibilityCursorPosition = start;
11303 mAccessibilityCursorPosition = ACCESSIBILITY_CURSOR_POSITION_UNDEFINED;
11305 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED);
11308 private void sendViewTextTraversedAtGranularityEvent(int action, int granularity,
11309 int fromIndex, int toIndex) {
11310 if (mParent == null) {
11313 AccessibilityEvent event = AccessibilityEvent.obtain(
11314 AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY);
11315 onInitializeAccessibilityEvent(event);
11316 onPopulateAccessibilityEvent(event);
11317 event.setFromIndex(fromIndex);
11318 event.setToIndex(toIndex);
11319 event.setAction(action);
11320 event.setMovementGranularity(granularity);
11321 mParent.requestSendAccessibilityEvent(this, event);
11327 public TextSegmentIterator getIteratorForGranularity(int granularity) {
11328 switch (granularity) {
11329 case AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER: {
11330 CharSequence text = getIterableTextForAccessibility();
11331 if (text != null && text.length() > 0) {
11332 CharacterTextSegmentIterator iterator =
11333 CharacterTextSegmentIterator.getInstance(
11334 mContext.getResources().getConfiguration().locale);
11335 iterator.initialize(text.toString());
11339 case AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD: {
11340 CharSequence text = getIterableTextForAccessibility();
11341 if (text != null && text.length() > 0) {
11342 WordTextSegmentIterator iterator =
11343 WordTextSegmentIterator.getInstance(
11344 mContext.getResources().getConfiguration().locale);
11345 iterator.initialize(text.toString());
11349 case AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH: {
11350 CharSequence text = getIterableTextForAccessibility();
11351 if (text != null && text.length() > 0) {
11352 ParagraphTextSegmentIterator iterator =
11353 ParagraphTextSegmentIterator.getInstance();
11354 iterator.initialize(text.toString());
11363 * Tells whether the {@link View} is in the state between {@link #onStartTemporaryDetach()}
11364 * and {@link #onFinishTemporaryDetach()}.
11366 * <p>This method always returns {@code true} when called directly or indirectly from
11367 * {@link #onStartTemporaryDetach()}. The return value when called directly or indirectly from
11368 * {@link #onFinishTemporaryDetach()}, however, depends on the OS version.
11370 * <li>{@code true} on {@link android.os.Build.VERSION_CODES#N API 24}</li>
11371 * <li>{@code false} on {@link android.os.Build.VERSION_CODES#N_MR1 API 25}} and later</li>
11375 * @return {@code true} when the View is in the state between {@link #onStartTemporaryDetach()}
11376 * and {@link #onFinishTemporaryDetach()}.
11378 public final boolean isTemporarilyDetached() {
11379 return (mPrivateFlags3 & PFLAG3_TEMPORARY_DETACH) != 0;
11383 * Dispatch {@link #onStartTemporaryDetach()} to this View and its direct children if this is
11384 * a container View.
11387 public void dispatchStartTemporaryDetach() {
11388 mPrivateFlags3 |= PFLAG3_TEMPORARY_DETACH;
11389 notifyEnterOrExitForAutoFillIfNeeded(false);
11390 onStartTemporaryDetach();
11394 * This is called when a container is going to temporarily detach a child, with
11395 * {@link ViewGroup#detachViewFromParent(View) ViewGroup.detachViewFromParent}.
11396 * It will either be followed by {@link #onFinishTemporaryDetach()} or
11397 * {@link #onDetachedFromWindow()} when the container is done.
11399 public void onStartTemporaryDetach() {
11400 removeUnsetPressCallback();
11401 mPrivateFlags |= PFLAG_CANCEL_NEXT_UP_EVENT;
11405 * Dispatch {@link #onFinishTemporaryDetach()} to this View and its direct children if this is
11406 * a container View.
11409 public void dispatchFinishTemporaryDetach() {
11410 mPrivateFlags3 &= ~PFLAG3_TEMPORARY_DETACH;
11411 onFinishTemporaryDetach();
11412 if (hasWindowFocus() && hasFocus()) {
11413 InputMethodManager.getInstance().focusIn(this);
11415 notifyEnterOrExitForAutoFillIfNeeded(true);
11419 * Called after {@link #onStartTemporaryDetach} when the container is done
11420 * changing the view.
11422 public void onFinishTemporaryDetach() {
11426 * Return the global {@link KeyEvent.DispatcherState KeyEvent.DispatcherState}
11427 * for this view's window. Returns null if the view is not currently attached
11428 * to the window. Normally you will not need to use this directly, but
11429 * just use the standard high-level event callbacks like
11430 * {@link #onKeyDown(int, KeyEvent)}.
11432 public KeyEvent.DispatcherState getKeyDispatcherState() {
11433 return mAttachInfo != null ? mAttachInfo.mKeyDispatchState : null;
11437 * Dispatch a key event before it is processed by any input method
11438 * associated with the view hierarchy. This can be used to intercept
11439 * key events in special situations before the IME consumes them; a
11440 * typical example would be handling the BACK key to update the application's
11441 * UI instead of allowing the IME to see it and close itself.
11443 * @param event The key event to be dispatched.
11444 * @return True if the event was handled, false otherwise.
11446 public boolean dispatchKeyEventPreIme(KeyEvent event) {
11447 return onKeyPreIme(event.getKeyCode(), event);
11451 * Dispatch a key event to the next view on the focus path. This path runs
11452 * from the top of the view tree down to the currently focused view. If this
11453 * view has focus, it will dispatch to itself. Otherwise it will dispatch
11454 * the next node down the focus path. This method also fires any key
11457 * @param event The key event to be dispatched.
11458 * @return True if the event was handled, false otherwise.
11460 public boolean dispatchKeyEvent(KeyEvent event) {
11461 if (mInputEventConsistencyVerifier != null) {
11462 mInputEventConsistencyVerifier.onKeyEvent(event, 0);
11465 // Give any attached key listener a first crack at the event.
11466 //noinspection SimplifiableIfStatement
11467 ListenerInfo li = mListenerInfo;
11468 if (li != null && li.mOnKeyListener != null && (mViewFlags & ENABLED_MASK) == ENABLED
11469 && li.mOnKeyListener.onKey(this, event.getKeyCode(), event)) {
11473 if (event.dispatch(this, mAttachInfo != null
11474 ? mAttachInfo.mKeyDispatchState : null, this)) {
11478 if (mInputEventConsistencyVerifier != null) {
11479 mInputEventConsistencyVerifier.onUnhandledEvent(event, 0);
11485 * Dispatches a key shortcut event.
11487 * @param event The key event to be dispatched.
11488 * @return True if the event was handled by the view, false otherwise.
11490 public boolean dispatchKeyShortcutEvent(KeyEvent event) {
11491 return onKeyShortcut(event.getKeyCode(), event);
11495 * Pass the touch screen motion event down to the target view, or this
11496 * view if it is the target.
11498 * @param event The motion event to be dispatched.
11499 * @return True if the event was handled by the view, false otherwise.
11501 public boolean dispatchTouchEvent(MotionEvent event) {
11502 // If the event should be handled by accessibility focus first.
11503 if (event.isTargetAccessibilityFocus()) {
11504 // We don't have focus or no virtual descendant has it, do not handle the event.
11505 if (!isAccessibilityFocusedViewOrHost()) {
11508 // We have focus and got the event, then use normal event dispatch.
11509 event.setTargetAccessibilityFocus(false);
11512 boolean result = false;
11514 if (mInputEventConsistencyVerifier != null) {
11515 mInputEventConsistencyVerifier.onTouchEvent(event, 0);
11518 final int actionMasked = event.getActionMasked();
11519 if (actionMasked == MotionEvent.ACTION_DOWN) {
11520 // Defensive cleanup for new gesture
11521 stopNestedScroll();
11524 if (onFilterTouchEventForSecurity(event)) {
11525 if ((mViewFlags & ENABLED_MASK) == ENABLED && handleScrollBarDragging(event)) {
11528 //noinspection SimplifiableIfStatement
11529 ListenerInfo li = mListenerInfo;
11530 if (li != null && li.mOnTouchListener != null
11531 && (mViewFlags & ENABLED_MASK) == ENABLED
11532 && li.mOnTouchListener.onTouch(this, event)) {
11536 if (!result && onTouchEvent(event)) {
11541 if (!result && mInputEventConsistencyVerifier != null) {
11542 mInputEventConsistencyVerifier.onUnhandledEvent(event, 0);
11545 // Clean up after nested scrolls if this is the end of a gesture;
11546 // also cancel it if we tried an ACTION_DOWN but we didn't want the rest
11548 if (actionMasked == MotionEvent.ACTION_UP ||
11549 actionMasked == MotionEvent.ACTION_CANCEL ||
11550 (actionMasked == MotionEvent.ACTION_DOWN && !result)) {
11551 stopNestedScroll();
11557 boolean isAccessibilityFocusedViewOrHost() {
11558 return isAccessibilityFocused() || (getViewRootImpl() != null && getViewRootImpl()
11559 .getAccessibilityFocusedHost() == this);
11563 * Filter the touch event to apply security policies.
11565 * @param event The motion event to be filtered.
11566 * @return True if the event should be dispatched, false if the event should be dropped.
11568 * @see #getFilterTouchesWhenObscured
11570 public boolean onFilterTouchEventForSecurity(MotionEvent event) {
11571 //noinspection RedundantIfStatement
11572 if ((mViewFlags & FILTER_TOUCHES_WHEN_OBSCURED) != 0
11573 && (event.getFlags() & MotionEvent.FLAG_WINDOW_IS_OBSCURED) != 0) {
11574 // Window is obscured, drop this touch.
11581 * Pass a trackball motion event down to the focused view.
11583 * @param event The motion event to be dispatched.
11584 * @return True if the event was handled by the view, false otherwise.
11586 public boolean dispatchTrackballEvent(MotionEvent event) {
11587 if (mInputEventConsistencyVerifier != null) {
11588 mInputEventConsistencyVerifier.onTrackballEvent(event, 0);
11591 return onTrackballEvent(event);
11595 * Pass a captured pointer event down to the focused view.
11597 * @param event The motion event to be dispatched.
11598 * @return True if the event was handled by the view, false otherwise.
11600 public boolean dispatchCapturedPointerEvent(MotionEvent event) {
11601 if (!hasPointerCapture()) {
11604 //noinspection SimplifiableIfStatement
11605 ListenerInfo li = mListenerInfo;
11606 if (li != null && li.mOnCapturedPointerListener != null
11607 && li.mOnCapturedPointerListener.onCapturedPointer(this, event)) {
11610 return onCapturedPointerEvent(event);
11614 * Dispatch a generic motion event.
11616 * Generic motion events with source class {@link InputDevice#SOURCE_CLASS_POINTER}
11617 * are delivered to the view under the pointer. All other generic motion events are
11618 * delivered to the focused view. Hover events are handled specially and are delivered
11619 * to {@link #onHoverEvent(MotionEvent)}.
11622 * @param event The motion event to be dispatched.
11623 * @return True if the event was handled by the view, false otherwise.
11625 public boolean dispatchGenericMotionEvent(MotionEvent event) {
11626 if (mInputEventConsistencyVerifier != null) {
11627 mInputEventConsistencyVerifier.onGenericMotionEvent(event, 0);
11630 final int source = event.getSource();
11631 if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) {
11632 final int action = event.getAction();
11633 if (action == MotionEvent.ACTION_HOVER_ENTER
11634 || action == MotionEvent.ACTION_HOVER_MOVE
11635 || action == MotionEvent.ACTION_HOVER_EXIT) {
11636 if (dispatchHoverEvent(event)) {
11639 } else if (dispatchGenericPointerEvent(event)) {
11642 } else if (dispatchGenericFocusedEvent(event)) {
11646 if (dispatchGenericMotionEventInternal(event)) {
11650 if (mInputEventConsistencyVerifier != null) {
11651 mInputEventConsistencyVerifier.onUnhandledEvent(event, 0);
11656 private boolean dispatchGenericMotionEventInternal(MotionEvent event) {
11657 //noinspection SimplifiableIfStatement
11658 ListenerInfo li = mListenerInfo;
11659 if (li != null && li.mOnGenericMotionListener != null
11660 && (mViewFlags & ENABLED_MASK) == ENABLED
11661 && li.mOnGenericMotionListener.onGenericMotion(this, event)) {
11665 if (onGenericMotionEvent(event)) {
11669 final int actionButton = event.getActionButton();
11670 switch (event.getActionMasked()) {
11671 case MotionEvent.ACTION_BUTTON_PRESS:
11672 if (isContextClickable() && !mInContextButtonPress && !mHasPerformedLongPress
11673 && (actionButton == MotionEvent.BUTTON_STYLUS_PRIMARY
11674 || actionButton == MotionEvent.BUTTON_SECONDARY)) {
11675 if (performContextClick(event.getX(), event.getY())) {
11676 mInContextButtonPress = true;
11677 setPressed(true, event.getX(), event.getY());
11678 removeTapCallback();
11679 removeLongPressCallback();
11685 case MotionEvent.ACTION_BUTTON_RELEASE:
11686 if (mInContextButtonPress && (actionButton == MotionEvent.BUTTON_STYLUS_PRIMARY
11687 || actionButton == MotionEvent.BUTTON_SECONDARY)) {
11688 mInContextButtonPress = false;
11689 mIgnoreNextUpEvent = true;
11694 if (mInputEventConsistencyVerifier != null) {
11695 mInputEventConsistencyVerifier.onUnhandledEvent(event, 0);
11701 * Dispatch a hover event.
11703 * Do not call this method directly.
11704 * Call {@link #dispatchGenericMotionEvent(MotionEvent)} instead.
11707 * @param event The motion event to be dispatched.
11708 * @return True if the event was handled by the view, false otherwise.
11710 protected boolean dispatchHoverEvent(MotionEvent event) {
11711 ListenerInfo li = mListenerInfo;
11712 //noinspection SimplifiableIfStatement
11713 if (li != null && li.mOnHoverListener != null
11714 && (mViewFlags & ENABLED_MASK) == ENABLED
11715 && li.mOnHoverListener.onHover(this, event)) {
11719 return onHoverEvent(event);
11723 * Returns true if the view has a child to which it has recently sent
11724 * {@link MotionEvent#ACTION_HOVER_ENTER}. If this view is hovered and
11725 * it does not have a hovered child, then it must be the innermost hovered view.
11728 protected boolean hasHoveredChild() {
11733 * Dispatch a generic motion event to the view under the first pointer.
11735 * Do not call this method directly.
11736 * Call {@link #dispatchGenericMotionEvent(MotionEvent)} instead.
11739 * @param event The motion event to be dispatched.
11740 * @return True if the event was handled by the view, false otherwise.
11742 protected boolean dispatchGenericPointerEvent(MotionEvent event) {
11747 * Dispatch a generic motion event to the currently focused view.
11749 * Do not call this method directly.
11750 * Call {@link #dispatchGenericMotionEvent(MotionEvent)} instead.
11753 * @param event The motion event to be dispatched.
11754 * @return True if the event was handled by the view, false otherwise.
11756 protected boolean dispatchGenericFocusedEvent(MotionEvent event) {
11761 * Dispatch a pointer event.
11763 * Dispatches touch related pointer events to {@link #onTouchEvent(MotionEvent)} and all
11764 * other events to {@link #onGenericMotionEvent(MotionEvent)}. This separation of concerns
11765 * reinforces the invariant that {@link #onTouchEvent(MotionEvent)} is really about touches
11766 * and should not be expected to handle other pointing device features.
11769 * @param event The motion event to be dispatched.
11770 * @return True if the event was handled by the view, false otherwise.
11773 public final boolean dispatchPointerEvent(MotionEvent event) {
11774 if (event.isTouchEvent()) {
11775 return dispatchTouchEvent(event);
11777 return dispatchGenericMotionEvent(event);
11782 * Called when the window containing this view gains or loses window focus.
11783 * ViewGroups should override to route to their children.
11785 * @param hasFocus True if the window containing this view now has focus,
11788 public void dispatchWindowFocusChanged(boolean hasFocus) {
11789 onWindowFocusChanged(hasFocus);
11793 * Called when the window containing this view gains or loses focus. Note
11794 * that this is separate from view focus: to receive key events, both
11795 * your view and its window must have focus. If a window is displayed
11796 * on top of yours that takes input focus, then your own window will lose
11797 * focus but the view focus will remain unchanged.
11799 * @param hasWindowFocus True if the window containing this view now has
11800 * focus, false otherwise.
11802 public void onWindowFocusChanged(boolean hasWindowFocus) {
11803 InputMethodManager imm = InputMethodManager.peekInstance();
11804 if (!hasWindowFocus) {
11808 mPrivateFlags3 &= ~PFLAG3_FINGER_DOWN;
11809 if (imm != null && (mPrivateFlags & PFLAG_FOCUSED) != 0) {
11810 imm.focusOut(this);
11812 removeLongPressCallback();
11813 removeTapCallback();
11815 } else if (imm != null && (mPrivateFlags & PFLAG_FOCUSED) != 0) {
11819 notifyEnterOrExitForAutoFillIfNeeded(hasWindowFocus);
11821 refreshDrawableState();
11825 * Returns true if this view is in a window that currently has window focus.
11826 * Note that this is not the same as the view itself having focus.
11828 * @return True if this view is in a window that currently has window focus.
11830 public boolean hasWindowFocus() {
11831 return mAttachInfo != null && mAttachInfo.mHasWindowFocus;
11835 * Dispatch a view visibility change down the view hierarchy.
11836 * ViewGroups should override to route to their children.
11837 * @param changedView The view whose visibility changed. Could be 'this' or
11838 * an ancestor view.
11839 * @param visibility The new visibility of changedView: {@link #VISIBLE},
11840 * {@link #INVISIBLE} or {@link #GONE}.
11842 protected void dispatchVisibilityChanged(@NonNull View changedView,
11843 @Visibility int visibility) {
11844 onVisibilityChanged(changedView, visibility);
11848 * Called when the visibility of the view or an ancestor of the view has
11851 * @param changedView The view whose visibility changed. May be
11852 * {@code this} or an ancestor view.
11853 * @param visibility The new visibility, one of {@link #VISIBLE},
11854 * {@link #INVISIBLE} or {@link #GONE}.
11856 protected void onVisibilityChanged(@NonNull View changedView, @Visibility int visibility) {
11860 * Dispatch a hint about whether this view is displayed. For instance, when
11861 * a View moves out of the screen, it might receives a display hint indicating
11862 * the view is not displayed. Applications should not <em>rely</em> on this hint
11863 * as there is no guarantee that they will receive one.
11865 * @param hint A hint about whether or not this view is displayed:
11866 * {@link #VISIBLE} or {@link #INVISIBLE}.
11868 public void dispatchDisplayHint(@Visibility int hint) {
11869 onDisplayHint(hint);
11873 * Gives this view a hint about whether is displayed or not. For instance, when
11874 * a View moves out of the screen, it might receives a display hint indicating
11875 * the view is not displayed. Applications should not <em>rely</em> on this hint
11876 * as there is no guarantee that they will receive one.
11878 * @param hint A hint about whether or not this view is displayed:
11879 * {@link #VISIBLE} or {@link #INVISIBLE}.
11881 protected void onDisplayHint(@Visibility int hint) {
11885 * Dispatch a window visibility change down the view hierarchy.
11886 * ViewGroups should override to route to their children.
11888 * @param visibility The new visibility of the window.
11890 * @see #onWindowVisibilityChanged(int)
11892 public void dispatchWindowVisibilityChanged(@Visibility int visibility) {
11893 onWindowVisibilityChanged(visibility);
11897 * Called when the window containing has change its visibility
11898 * (between {@link #GONE}, {@link #INVISIBLE}, and {@link #VISIBLE}). Note
11899 * that this tells you whether or not your window is being made visible
11900 * to the window manager; this does <em>not</em> tell you whether or not
11901 * your window is obscured by other windows on the screen, even if it
11902 * is itself visible.
11904 * @param visibility The new visibility of the window.
11906 protected void onWindowVisibilityChanged(@Visibility int visibility) {
11907 if (visibility == VISIBLE) {
11908 initialAwakenScrollBars();
11913 * Internal dispatching method for {@link #onVisibilityAggregated}. Overridden by
11914 * ViewGroup. Intended to only be called when {@link #isAttachedToWindow()},
11915 * {@link #getWindowVisibility()} is {@link #VISIBLE} and this view's parent {@link #isShown()}.
11917 * @param isVisible true if this view's visibility to the user is uninterrupted by its
11918 * ancestors or by window visibility
11919 * @return true if this view is visible to the user, not counting clipping or overlapping
11921 boolean dispatchVisibilityAggregated(boolean isVisible) {
11922 final boolean thisVisible = getVisibility() == VISIBLE;
11923 // If we're not visible but something is telling us we are, ignore it.
11924 if (thisVisible || !isVisible) {
11925 onVisibilityAggregated(isVisible);
11927 return thisVisible && isVisible;
11931 * Called when the user-visibility of this View is potentially affected by a change
11932 * to this view itself, an ancestor view or the window this view is attached to.
11934 * @param isVisible true if this view and all of its ancestors are {@link #VISIBLE}
11935 * and this view's window is also visible
11938 public void onVisibilityAggregated(boolean isVisible) {
11939 if (isVisible && mAttachInfo != null) {
11940 initialAwakenScrollBars();
11943 final Drawable dr = mBackground;
11944 if (dr != null && isVisible != dr.isVisible()) {
11945 dr.setVisible(isVisible, false);
11947 final Drawable hl = mDefaultFocusHighlight;
11948 if (hl != null && isVisible != hl.isVisible()) {
11949 hl.setVisible(isVisible, false);
11951 final Drawable fg = mForegroundInfo != null ? mForegroundInfo.mDrawable : null;
11952 if (fg != null && isVisible != fg.isVisible()) {
11953 fg.setVisible(isVisible, false);
11956 if (isAutofillable()) {
11957 AutofillManager afm = getAutofillManager();
11959 if (afm != null && getAccessibilityViewId() > LAST_APP_ACCESSIBILITY_ID) {
11960 if (mVisibilityChangeForAutofillHandler != null) {
11961 mVisibilityChangeForAutofillHandler.removeMessages(0);
11964 // If the view is in the background but still part of the hierarchy this is called
11965 // with isVisible=false. Hence visibility==false requires further checks
11967 afm.notifyViewVisibilityChange(this, true);
11969 if (mVisibilityChangeForAutofillHandler == null) {
11970 mVisibilityChangeForAutofillHandler =
11971 new VisibilityChangeForAutofillHandler(afm, this);
11973 // Let current operation (e.g. removal of the view from the hierarchy)
11974 // finish before checking state
11975 mVisibilityChangeForAutofillHandler.obtainMessage(0, this).sendToTarget();
11982 * Returns the current visibility of the window this view is attached to
11983 * (either {@link #GONE}, {@link #INVISIBLE}, or {@link #VISIBLE}).
11985 * @return Returns the current visibility of the view's window.
11988 public int getWindowVisibility() {
11989 return mAttachInfo != null ? mAttachInfo.mWindowVisibility : GONE;
11993 * Retrieve the overall visible display size in which the window this view is
11994 * attached to has been positioned in. This takes into account screen
11995 * decorations above the window, for both cases where the window itself
11996 * is being position inside of them or the window is being placed under
11997 * then and covered insets are used for the window to position its content
11998 * inside. In effect, this tells you the available area where content can
11999 * be placed and remain visible to users.
12001 * <p>This function requires an IPC back to the window manager to retrieve
12002 * the requested information, so should not be used in performance critical
12003 * code like drawing.
12005 * @param outRect Filled in with the visible display frame. If the view
12006 * is not attached to a window, this is simply the raw display size.
12008 public void getWindowVisibleDisplayFrame(Rect outRect) {
12009 if (mAttachInfo != null) {
12011 mAttachInfo.mSession.getDisplayFrame(mAttachInfo.mWindow, outRect);
12012 } catch (RemoteException e) {
12015 // XXX This is really broken, and probably all needs to be done
12016 // in the window manager, and we need to know more about whether
12017 // we want the area behind or in front of the IME.
12018 final Rect insets = mAttachInfo.mVisibleInsets;
12019 outRect.left += insets.left;
12020 outRect.top += insets.top;
12021 outRect.right -= insets.right;
12022 outRect.bottom -= insets.bottom;
12025 // The view is not attached to a display so we don't have a context.
12026 // Make a best guess about the display size.
12027 Display d = DisplayManagerGlobal.getInstance().getRealDisplay(Display.DEFAULT_DISPLAY);
12028 d.getRectSize(outRect);
12032 * Like {@link #getWindowVisibleDisplayFrame}, but returns the "full" display frame this window
12033 * is currently in without any insets.
12037 public void getWindowDisplayFrame(Rect outRect) {
12038 if (mAttachInfo != null) {
12040 mAttachInfo.mSession.getDisplayFrame(mAttachInfo.mWindow, outRect);
12041 } catch (RemoteException e) {
12046 // The view is not attached to a display so we don't have a context.
12047 // Make a best guess about the display size.
12048 Display d = DisplayManagerGlobal.getInstance().getRealDisplay(Display.DEFAULT_DISPLAY);
12049 d.getRectSize(outRect);
12053 * Dispatch a notification about a resource configuration change down
12054 * the view hierarchy.
12055 * ViewGroups should override to route to their children.
12057 * @param newConfig The new resource configuration.
12059 * @see #onConfigurationChanged(android.content.res.Configuration)
12061 public void dispatchConfigurationChanged(Configuration newConfig) {
12062 onConfigurationChanged(newConfig);
12066 * Called when the current configuration of the resources being used
12067 * by the application have changed. You can use this to decide when
12068 * to reload resources that can changed based on orientation and other
12069 * configuration characteristics. You only need to use this if you are
12070 * not relying on the normal {@link android.app.Activity} mechanism of
12071 * recreating the activity instance upon a configuration change.
12073 * @param newConfig The new resource configuration.
12075 protected void onConfigurationChanged(Configuration newConfig) {
12079 * Private function to aggregate all per-view attributes in to the view
12082 void dispatchCollectViewAttributes(AttachInfo attachInfo, int visibility) {
12083 performCollectViewAttributes(attachInfo, visibility);
12086 void performCollectViewAttributes(AttachInfo attachInfo, int visibility) {
12087 if ((visibility & VISIBILITY_MASK) == VISIBLE) {
12088 if ((mViewFlags & KEEP_SCREEN_ON) == KEEP_SCREEN_ON) {
12089 attachInfo.mKeepScreenOn = true;
12091 attachInfo.mSystemUiVisibility |= mSystemUiVisibility;
12092 ListenerInfo li = mListenerInfo;
12093 if (li != null && li.mOnSystemUiVisibilityChangeListener != null) {
12094 attachInfo.mHasSystemUiListeners = true;
12099 void needGlobalAttributesUpdate(boolean force) {
12100 final AttachInfo ai = mAttachInfo;
12101 if (ai != null && !ai.mRecomputeGlobalAttributes) {
12102 if (force || ai.mKeepScreenOn || (ai.mSystemUiVisibility != 0)
12103 || ai.mHasSystemUiListeners) {
12104 ai.mRecomputeGlobalAttributes = true;
12110 * Returns whether the device is currently in touch mode. Touch mode is entered
12111 * once the user begins interacting with the device by touch, and affects various
12112 * things like whether focus is always visible to the user.
12114 * @return Whether the device is in touch mode.
12116 @ViewDebug.ExportedProperty
12117 public boolean isInTouchMode() {
12118 if (mAttachInfo != null) {
12119 return mAttachInfo.mInTouchMode;
12121 return ViewRootImpl.isInTouchMode();
12126 * Returns the context the view is running in, through which it can
12127 * access the current theme, resources, etc.
12129 * @return The view's Context.
12131 @ViewDebug.CapturedViewProperty
12132 public final Context getContext() {
12137 * Handle a key event before it is processed by any input method
12138 * associated with the view hierarchy. This can be used to intercept
12139 * key events in special situations before the IME consumes them; a
12140 * typical example would be handling the BACK key to update the application's
12141 * UI instead of allowing the IME to see it and close itself.
12143 * @param keyCode The value in event.getKeyCode().
12144 * @param event Description of the key event.
12145 * @return If you handled the event, return true. If you want to allow the
12146 * event to be handled by the next receiver, return false.
12148 public boolean onKeyPreIme(int keyCode, KeyEvent event) {
12153 * Default implementation of {@link KeyEvent.Callback#onKeyDown(int, KeyEvent)
12154 * KeyEvent.Callback.onKeyDown()}: perform press of the view
12155 * when {@link KeyEvent#KEYCODE_DPAD_CENTER} or {@link KeyEvent#KEYCODE_ENTER}
12156 * is released, if the view is enabled and clickable.
12158 * Key presses in software keyboards will generally NOT trigger this
12159 * listener, although some may elect to do so in some situations. Do not
12160 * rely on this to catch software key presses.
12162 * @param keyCode a key code that represents the button pressed, from
12163 * {@link android.view.KeyEvent}
12164 * @param event the KeyEvent object that defines the button action
12166 public boolean onKeyDown(int keyCode, KeyEvent event) {
12167 if (KeyEvent.isConfirmKey(keyCode)) {
12168 if ((mViewFlags & ENABLED_MASK) == DISABLED) {
12172 if (event.getRepeatCount() == 0) {
12173 // Long clickable items don't necessarily have to be clickable.
12174 final boolean clickable = (mViewFlags & CLICKABLE) == CLICKABLE
12175 || (mViewFlags & LONG_CLICKABLE) == LONG_CLICKABLE;
12176 if (clickable || (mViewFlags & TOOLTIP) == TOOLTIP) {
12177 // For the purposes of menu anchoring and drawable hotspots,
12178 // key events are considered to be at the center of the view.
12179 final float x = getWidth() / 2f;
12180 final float y = getHeight() / 2f;
12182 setPressed(true, x, y);
12184 checkForLongClick(0, x, y);
12194 * Default implementation of {@link KeyEvent.Callback#onKeyLongPress(int, KeyEvent)
12195 * KeyEvent.Callback.onKeyLongPress()}: always returns false (doesn't handle
12197 * <p>Key presses in software keyboards will generally NOT trigger this listener,
12198 * although some may elect to do so in some situations. Do not rely on this to
12199 * catch software key presses.
12201 public boolean onKeyLongPress(int keyCode, KeyEvent event) {
12206 * Default implementation of {@link KeyEvent.Callback#onKeyUp(int, KeyEvent)
12207 * KeyEvent.Callback.onKeyUp()}: perform clicking of the view
12208 * when {@link KeyEvent#KEYCODE_DPAD_CENTER}, {@link KeyEvent#KEYCODE_ENTER}
12209 * or {@link KeyEvent#KEYCODE_SPACE} is released.
12210 * <p>Key presses in software keyboards will generally NOT trigger this listener,
12211 * although some may elect to do so in some situations. Do not rely on this to
12212 * catch software key presses.
12214 * @param keyCode A key code that represents the button pressed, from
12215 * {@link android.view.KeyEvent}.
12216 * @param event The KeyEvent object that defines the button action.
12218 public boolean onKeyUp(int keyCode, KeyEvent event) {
12219 if (KeyEvent.isConfirmKey(keyCode)) {
12220 if ((mViewFlags & ENABLED_MASK) == DISABLED) {
12223 if ((mViewFlags & CLICKABLE) == CLICKABLE && isPressed()) {
12226 if (!mHasPerformedLongPress) {
12227 // This is a tap, so remove the longpress check
12228 removeLongPressCallback();
12229 if (!event.isCanceled()) {
12230 return performClick();
12239 * Default implementation of {@link KeyEvent.Callback#onKeyMultiple(int, int, KeyEvent)
12240 * KeyEvent.Callback.onKeyMultiple()}: always returns false (doesn't handle
12242 * <p>Key presses in software keyboards will generally NOT trigger this listener,
12243 * although some may elect to do so in some situations. Do not rely on this to
12244 * catch software key presses.
12246 * @param keyCode A key code that represents the button pressed, from
12247 * {@link android.view.KeyEvent}.
12248 * @param repeatCount The number of times the action was made.
12249 * @param event The KeyEvent object that defines the button action.
12251 public boolean onKeyMultiple(int keyCode, int repeatCount, KeyEvent event) {
12256 * Called on the focused view when a key shortcut event is not handled.
12257 * Override this method to implement local key shortcuts for the View.
12258 * Key shortcuts can also be implemented by setting the
12259 * {@link MenuItem#setShortcut(char, char) shortcut} property of menu items.
12261 * @param keyCode The value in event.getKeyCode().
12262 * @param event Description of the key event.
12263 * @return If you handled the event, return true. If you want to allow the
12264 * event to be handled by the next receiver, return false.
12266 public boolean onKeyShortcut(int keyCode, KeyEvent event) {
12271 * Check whether the called view is a text editor, in which case it
12272 * would make sense to automatically display a soft input window for
12273 * it. Subclasses should override this if they implement
12274 * {@link #onCreateInputConnection(EditorInfo)} to return true if
12275 * a call on that method would return a non-null InputConnection, and
12276 * they are really a first-class editor that the user would normally
12277 * start typing on when the go into a window containing your view.
12279 * <p>The default implementation always returns false. This does
12280 * <em>not</em> mean that its {@link #onCreateInputConnection(EditorInfo)}
12281 * will not be called or the user can not otherwise perform edits on your
12282 * view; it is just a hint to the system that this is not the primary
12283 * purpose of this view.
12285 * @return Returns true if this view is a text editor, else false.
12287 public boolean onCheckIsTextEditor() {
12292 * Create a new InputConnection for an InputMethod to interact
12293 * with the view. The default implementation returns null, since it doesn't
12294 * support input methods. You can override this to implement such support.
12295 * This is only needed for views that take focus and text input.
12297 * <p>When implementing this, you probably also want to implement
12298 * {@link #onCheckIsTextEditor()} to indicate you will return a
12299 * non-null InputConnection.</p>
12301 * <p>Also, take good care to fill in the {@link android.view.inputmethod.EditorInfo}
12302 * object correctly and in its entirety, so that the connected IME can rely
12303 * on its values. For example, {@link android.view.inputmethod.EditorInfo#initialSelStart}
12304 * and {@link android.view.inputmethod.EditorInfo#initialSelEnd} members
12305 * must be filled in with the correct cursor position for IMEs to work correctly
12306 * with your application.</p>
12308 * @param outAttrs Fill in with attribute information about the connection.
12310 public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
12315 * Called by the {@link android.view.inputmethod.InputMethodManager}
12316 * when a view who is not the current
12317 * input connection target is trying to make a call on the manager. The
12318 * default implementation returns false; you can override this to return
12319 * true for certain views if you are performing InputConnection proxying
12321 * @param view The View that is making the InputMethodManager call.
12322 * @return Return true to allow the call, false to reject.
12324 public boolean checkInputConnectionProxy(View view) {
12329 * Show the context menu for this view. It is not safe to hold on to the
12330 * menu after returning from this method.
12332 * You should normally not overload this method. Overload
12333 * {@link #onCreateContextMenu(ContextMenu)} or define an
12334 * {@link OnCreateContextMenuListener} to add items to the context menu.
12336 * @param menu The context menu to populate
12338 public void createContextMenu(ContextMenu menu) {
12339 ContextMenuInfo menuInfo = getContextMenuInfo();
12341 // Sets the current menu info so all items added to menu will have
12342 // my extra info set.
12343 ((MenuBuilder)menu).setCurrentMenuInfo(menuInfo);
12345 onCreateContextMenu(menu);
12346 ListenerInfo li = mListenerInfo;
12347 if (li != null && li.mOnCreateContextMenuListener != null) {
12348 li.mOnCreateContextMenuListener.onCreateContextMenu(menu, this, menuInfo);
12351 // Clear the extra information so subsequent items that aren't mine don't
12352 // have my extra info.
12353 ((MenuBuilder)menu).setCurrentMenuInfo(null);
12355 if (mParent != null) {
12356 mParent.createContextMenu(menu);
12361 * Views should implement this if they have extra information to associate
12362 * with the context menu. The return result is supplied as a parameter to
12363 * the {@link OnCreateContextMenuListener#onCreateContextMenu(ContextMenu, View, ContextMenuInfo)}
12366 * @return Extra information about the item for which the context menu
12367 * should be shown. This information will vary across different
12368 * subclasses of View.
12370 protected ContextMenuInfo getContextMenuInfo() {
12375 * Views should implement this if the view itself is going to add items to
12376 * the context menu.
12378 * @param menu the context menu to populate
12380 protected void onCreateContextMenu(ContextMenu menu) {
12384 * Implement this method to handle trackball motion events. The
12385 * <em>relative</em> movement of the trackball since the last event
12386 * can be retrieve with {@link MotionEvent#getX MotionEvent.getX()} and
12387 * {@link MotionEvent#getY MotionEvent.getY()}. These are normalized so
12388 * that a movement of 1 corresponds to the user pressing one DPAD key (so
12389 * they will often be fractional values, representing the more fine-grained
12390 * movement information available from a trackball).
12392 * @param event The motion event.
12393 * @return True if the event was handled, false otherwise.
12395 public boolean onTrackballEvent(MotionEvent event) {
12400 * Implement this method to handle generic motion events.
12402 * Generic motion events describe joystick movements, mouse hovers, track pad
12403 * touches, scroll wheel movements and other input events. The
12404 * {@link MotionEvent#getSource() source} of the motion event specifies
12405 * the class of input that was received. Implementations of this method
12406 * must examine the bits in the source before processing the event.
12407 * The following code example shows how this is done.
12409 * Generic motion events with source class {@link InputDevice#SOURCE_CLASS_POINTER}
12410 * are delivered to the view under the pointer. All other generic motion events are
12411 * delivered to the focused view.
12413 * <pre> public boolean onGenericMotionEvent(MotionEvent event) {
12414 * if (event.isFromSource(InputDevice.SOURCE_CLASS_JOYSTICK)) {
12415 * if (event.getAction() == MotionEvent.ACTION_MOVE) {
12416 * // process the joystick movement...
12420 * if (event.isFromSource(InputDevice.SOURCE_CLASS_POINTER)) {
12421 * switch (event.getAction()) {
12422 * case MotionEvent.ACTION_HOVER_MOVE:
12423 * // process the mouse hover movement...
12425 * case MotionEvent.ACTION_SCROLL:
12426 * // process the scroll wheel movement...
12430 * return super.onGenericMotionEvent(event);
12433 * @param event The generic motion event being processed.
12434 * @return True if the event was handled, false otherwise.
12436 public boolean onGenericMotionEvent(MotionEvent event) {
12441 * Implement this method to handle hover events.
12443 * This method is called whenever a pointer is hovering into, over, or out of the
12444 * bounds of a view and the view is not currently being touched.
12445 * Hover events are represented as pointer events with action
12446 * {@link MotionEvent#ACTION_HOVER_ENTER}, {@link MotionEvent#ACTION_HOVER_MOVE},
12447 * or {@link MotionEvent#ACTION_HOVER_EXIT}.
12450 * <li>The view receives a hover event with action {@link MotionEvent#ACTION_HOVER_ENTER}
12451 * when the pointer enters the bounds of the view.</li>
12452 * <li>The view receives a hover event with action {@link MotionEvent#ACTION_HOVER_MOVE}
12453 * when the pointer has already entered the bounds of the view and has moved.</li>
12454 * <li>The view receives a hover event with action {@link MotionEvent#ACTION_HOVER_EXIT}
12455 * when the pointer has exited the bounds of the view or when the pointer is
12456 * about to go down due to a button click, tap, or similar user action that
12457 * causes the view to be touched.</li>
12460 * The view should implement this method to return true to indicate that it is
12461 * handling the hover event, such as by changing its drawable state.
12463 * The default implementation calls {@link #setHovered} to update the hovered state
12464 * of the view when a hover enter or hover exit event is received, if the view
12465 * is enabled and is clickable. The default implementation also sends hover
12466 * accessibility events.
12469 * @param event The motion event that describes the hover.
12470 * @return True if the view handled the hover event.
12474 * @see #onHoverChanged
12476 public boolean onHoverEvent(MotionEvent event) {
12477 // The root view may receive hover (or touch) events that are outside the bounds of
12478 // the window. This code ensures that we only send accessibility events for
12479 // hovers that are actually within the bounds of the root view.
12480 final int action = event.getActionMasked();
12481 if (!mSendingHoverAccessibilityEvents) {
12482 if ((action == MotionEvent.ACTION_HOVER_ENTER
12483 || action == MotionEvent.ACTION_HOVER_MOVE)
12484 && !hasHoveredChild()
12485 && pointInView(event.getX(), event.getY())) {
12486 sendAccessibilityHoverEvent(AccessibilityEvent.TYPE_VIEW_HOVER_ENTER);
12487 mSendingHoverAccessibilityEvents = true;
12490 if (action == MotionEvent.ACTION_HOVER_EXIT
12491 || (action == MotionEvent.ACTION_MOVE
12492 && !pointInView(event.getX(), event.getY()))) {
12493 mSendingHoverAccessibilityEvents = false;
12494 sendAccessibilityHoverEvent(AccessibilityEvent.TYPE_VIEW_HOVER_EXIT);
12498 if ((action == MotionEvent.ACTION_HOVER_ENTER || action == MotionEvent.ACTION_HOVER_MOVE)
12499 && event.isFromSource(InputDevice.SOURCE_MOUSE)
12500 && isOnScrollbar(event.getX(), event.getY())) {
12501 awakenScrollBars();
12504 // If we consider ourself hoverable, or if we we're already hovered,
12505 // handle changing state in response to ENTER and EXIT events.
12506 if (isHoverable() || isHovered()) {
12508 case MotionEvent.ACTION_HOVER_ENTER:
12511 case MotionEvent.ACTION_HOVER_EXIT:
12516 // Dispatch the event to onGenericMotionEvent before returning true.
12517 // This is to provide compatibility with existing applications that
12518 // handled HOVER_MOVE events in onGenericMotionEvent and that would
12519 // break because of the new default handling for hoverable views
12520 // in onHoverEvent.
12521 // Note that onGenericMotionEvent will be called by default when
12522 // onHoverEvent returns false (refer to dispatchGenericMotionEvent).
12523 dispatchGenericMotionEventInternal(event);
12524 // The event was already handled by calling setHovered(), so always
12533 * Returns true if the view should handle {@link #onHoverEvent}
12534 * by calling {@link #setHovered} to change its hovered state.
12536 * @return True if the view is hoverable.
12538 private boolean isHoverable() {
12539 final int viewFlags = mViewFlags;
12540 if ((viewFlags & ENABLED_MASK) == DISABLED) {
12544 return (viewFlags & CLICKABLE) == CLICKABLE
12545 || (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE
12546 || (viewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE;
12550 * Returns true if the view is currently hovered.
12552 * @return True if the view is currently hovered.
12555 * @see #onHoverChanged
12557 @ViewDebug.ExportedProperty
12558 public boolean isHovered() {
12559 return (mPrivateFlags & PFLAG_HOVERED) != 0;
12563 * Sets whether the view is currently hovered.
12565 * Calling this method also changes the drawable state of the view. This
12566 * enables the view to react to hover by using different drawable resources
12567 * to change its appearance.
12569 * The {@link #onHoverChanged} method is called when the hovered state changes.
12572 * @param hovered True if the view is hovered.
12575 * @see #onHoverChanged
12577 public void setHovered(boolean hovered) {
12579 if ((mPrivateFlags & PFLAG_HOVERED) == 0) {
12580 mPrivateFlags |= PFLAG_HOVERED;
12581 refreshDrawableState();
12582 onHoverChanged(true);
12585 if ((mPrivateFlags & PFLAG_HOVERED) != 0) {
12586 mPrivateFlags &= ~PFLAG_HOVERED;
12587 refreshDrawableState();
12588 onHoverChanged(false);
12594 * Implement this method to handle hover state changes.
12596 * This method is called whenever the hover state changes as a result of a
12597 * call to {@link #setHovered}.
12600 * @param hovered The current hover state, as returned by {@link #isHovered}.
12605 public void onHoverChanged(boolean hovered) {
12609 * Handles scroll bar dragging by mouse input.
12612 * @param event The motion event.
12614 * @return true if the event was handled as a scroll bar dragging, false otherwise.
12616 protected boolean handleScrollBarDragging(MotionEvent event) {
12617 if (mScrollCache == null) {
12620 final float x = event.getX();
12621 final float y = event.getY();
12622 final int action = event.getAction();
12623 if ((mScrollCache.mScrollBarDraggingState == ScrollabilityCache.NOT_DRAGGING
12624 && action != MotionEvent.ACTION_DOWN)
12625 || !event.isFromSource(InputDevice.SOURCE_MOUSE)
12626 || !event.isButtonPressed(MotionEvent.BUTTON_PRIMARY)) {
12627 mScrollCache.mScrollBarDraggingState = ScrollabilityCache.NOT_DRAGGING;
12632 case MotionEvent.ACTION_MOVE:
12633 if (mScrollCache.mScrollBarDraggingState == ScrollabilityCache.NOT_DRAGGING) {
12636 if (mScrollCache.mScrollBarDraggingState
12637 == ScrollabilityCache.DRAGGING_VERTICAL_SCROLL_BAR) {
12638 final Rect bounds = mScrollCache.mScrollBarBounds;
12639 getVerticalScrollBarBounds(bounds, null);
12640 final int range = computeVerticalScrollRange();
12641 final int offset = computeVerticalScrollOffset();
12642 final int extent = computeVerticalScrollExtent();
12644 final int thumbLength = ScrollBarUtils.getThumbLength(
12645 bounds.height(), bounds.width(), extent, range);
12646 final int thumbOffset = ScrollBarUtils.getThumbOffset(
12647 bounds.height(), thumbLength, extent, range, offset);
12649 final float diff = y - mScrollCache.mScrollBarDraggingPos;
12650 final float maxThumbOffset = bounds.height() - thumbLength;
12651 final float newThumbOffset =
12652 Math.min(Math.max(thumbOffset + diff, 0.0f), maxThumbOffset);
12653 final int height = getHeight();
12654 if (Math.round(newThumbOffset) != thumbOffset && maxThumbOffset > 0
12655 && height > 0 && extent > 0) {
12656 final int newY = Math.round((range - extent)
12657 / ((float)extent / height) * (newThumbOffset / maxThumbOffset));
12658 if (newY != getScrollY()) {
12659 mScrollCache.mScrollBarDraggingPos = y;
12665 if (mScrollCache.mScrollBarDraggingState
12666 == ScrollabilityCache.DRAGGING_HORIZONTAL_SCROLL_BAR) {
12667 final Rect bounds = mScrollCache.mScrollBarBounds;
12668 getHorizontalScrollBarBounds(bounds, null);
12669 final int range = computeHorizontalScrollRange();
12670 final int offset = computeHorizontalScrollOffset();
12671 final int extent = computeHorizontalScrollExtent();
12673 final int thumbLength = ScrollBarUtils.getThumbLength(
12674 bounds.width(), bounds.height(), extent, range);
12675 final int thumbOffset = ScrollBarUtils.getThumbOffset(
12676 bounds.width(), thumbLength, extent, range, offset);
12678 final float diff = x - mScrollCache.mScrollBarDraggingPos;
12679 final float maxThumbOffset = bounds.width() - thumbLength;
12680 final float newThumbOffset =
12681 Math.min(Math.max(thumbOffset + diff, 0.0f), maxThumbOffset);
12682 final int width = getWidth();
12683 if (Math.round(newThumbOffset) != thumbOffset && maxThumbOffset > 0
12684 && width > 0 && extent > 0) {
12685 final int newX = Math.round((range - extent)
12686 / ((float)extent / width) * (newThumbOffset / maxThumbOffset));
12687 if (newX != getScrollX()) {
12688 mScrollCache.mScrollBarDraggingPos = x;
12694 case MotionEvent.ACTION_DOWN:
12695 if (mScrollCache.state == ScrollabilityCache.OFF) {
12698 if (isOnVerticalScrollbarThumb(x, y)) {
12699 mScrollCache.mScrollBarDraggingState =
12700 ScrollabilityCache.DRAGGING_VERTICAL_SCROLL_BAR;
12701 mScrollCache.mScrollBarDraggingPos = y;
12704 if (isOnHorizontalScrollbarThumb(x, y)) {
12705 mScrollCache.mScrollBarDraggingState =
12706 ScrollabilityCache.DRAGGING_HORIZONTAL_SCROLL_BAR;
12707 mScrollCache.mScrollBarDraggingPos = x;
12711 mScrollCache.mScrollBarDraggingState = ScrollabilityCache.NOT_DRAGGING;
12716 * Implement this method to handle touch screen motion events.
12718 * If this method is used to detect click actions, it is recommended that
12719 * the actions be performed by implementing and calling
12720 * {@link #performClick()}. This will ensure consistent system behavior,
12723 * <li>obeying click sound preferences
12724 * <li>dispatching OnClickListener calls
12725 * <li>handling {@link AccessibilityNodeInfo#ACTION_CLICK ACTION_CLICK} when
12726 * accessibility features are enabled
12729 * @param event The motion event.
12730 * @return True if the event was handled, false otherwise.
12732 public boolean onTouchEvent(MotionEvent event) {
12733 final float x = event.getX();
12734 final float y = event.getY();
12735 final int viewFlags = mViewFlags;
12736 final int action = event.getAction();
12738 final boolean clickable = ((viewFlags & CLICKABLE) == CLICKABLE
12739 || (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE)
12740 || (viewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE;
12742 if ((viewFlags & ENABLED_MASK) == DISABLED) {
12743 if (action == MotionEvent.ACTION_UP && (mPrivateFlags & PFLAG_PRESSED) != 0) {
12746 mPrivateFlags3 &= ~PFLAG3_FINGER_DOWN;
12747 // A disabled view that is clickable still consumes the touch
12748 // events, it just doesn't respond to them.
12751 if (mTouchDelegate != null) {
12752 if (mTouchDelegate.onTouchEvent(event)) {
12757 if (clickable || (viewFlags & TOOLTIP) == TOOLTIP) {
12759 case MotionEvent.ACTION_UP:
12760 mPrivateFlags3 &= ~PFLAG3_FINGER_DOWN;
12761 if ((viewFlags & TOOLTIP) == TOOLTIP) {
12765 removeTapCallback();
12766 removeLongPressCallback();
12767 mInContextButtonPress = false;
12768 mHasPerformedLongPress = false;
12769 mIgnoreNextUpEvent = false;
12772 boolean prepressed = (mPrivateFlags & PFLAG_PREPRESSED) != 0;
12773 if ((mPrivateFlags & PFLAG_PRESSED) != 0 || prepressed) {
12774 // take focus if we don't have it already and we should in
12776 boolean focusTaken = false;
12777 if (isFocusable() && isFocusableInTouchMode() && !isFocused()) {
12778 focusTaken = requestFocus();
12782 // The button is being released before we actually
12783 // showed it as pressed. Make it show the pressed
12784 // state now (before scheduling the click) to ensure
12785 // the user sees it.
12786 setPressed(true, x, y);
12789 if (!mHasPerformedLongPress && !mIgnoreNextUpEvent) {
12790 // This is a tap, so remove the longpress check
12791 removeLongPressCallback();
12793 // Only perform take click actions if we were in the pressed state
12795 // Use a Runnable and post this rather than calling
12796 // performClick directly. This lets other visual state
12797 // of the view update before click actions start.
12798 if (mPerformClick == null) {
12799 mPerformClick = new PerformClick();
12801 if (!post(mPerformClick)) {
12807 if (mUnsetPressedState == null) {
12808 mUnsetPressedState = new UnsetPressedState();
12812 postDelayed(mUnsetPressedState,
12813 ViewConfiguration.getPressedStateDuration());
12814 } else if (!post(mUnsetPressedState)) {
12815 // If the post failed, unpress right now
12816 mUnsetPressedState.run();
12819 removeTapCallback();
12821 mIgnoreNextUpEvent = false;
12824 case MotionEvent.ACTION_DOWN:
12825 if (event.getSource() == InputDevice.SOURCE_TOUCHSCREEN) {
12826 mPrivateFlags3 |= PFLAG3_FINGER_DOWN;
12828 mHasPerformedLongPress = false;
12831 checkForLongClick(0, x, y);
12835 if (performButtonActionOnTouchDown(event)) {
12839 // Walk up the hierarchy to determine if we're inside a scrolling container.
12840 boolean isInScrollingContainer = isInScrollingContainer();
12842 // For views inside a scrolling container, delay the pressed feedback for
12843 // a short period in case this is a scroll.
12844 if (isInScrollingContainer) {
12845 mPrivateFlags |= PFLAG_PREPRESSED;
12846 if (mPendingCheckForTap == null) {
12847 mPendingCheckForTap = new CheckForTap();
12849 mPendingCheckForTap.x = event.getX();
12850 mPendingCheckForTap.y = event.getY();
12851 postDelayed(mPendingCheckForTap, ViewConfiguration.getTapTimeout());
12853 // Not inside a scrolling container, so show the feedback right away
12854 setPressed(true, x, y);
12855 checkForLongClick(0, x, y);
12859 case MotionEvent.ACTION_CANCEL:
12863 removeTapCallback();
12864 removeLongPressCallback();
12865 mInContextButtonPress = false;
12866 mHasPerformedLongPress = false;
12867 mIgnoreNextUpEvent = false;
12868 mPrivateFlags3 &= ~PFLAG3_FINGER_DOWN;
12871 case MotionEvent.ACTION_MOVE:
12873 drawableHotspotChanged(x, y);
12876 // Be lenient about moving outside of buttons
12877 if (!pointInView(x, y, mTouchSlop)) {
12879 // Remove any future long press/tap checks
12880 removeTapCallback();
12881 removeLongPressCallback();
12882 if ((mPrivateFlags & PFLAG_PRESSED) != 0) {
12885 mPrivateFlags3 &= ~PFLAG3_FINGER_DOWN;
12899 public boolean isInScrollingContainer() {
12900 ViewParent p = getParent();
12901 while (p != null && p instanceof ViewGroup) {
12902 if (((ViewGroup) p).shouldDelayChildPressedState()) {
12911 * Remove the longpress detection timer.
12913 private void removeLongPressCallback() {
12914 if (mPendingCheckForLongPress != null) {
12915 removeCallbacks(mPendingCheckForLongPress);
12920 * Remove the pending click action
12922 private void removePerformClickCallback() {
12923 if (mPerformClick != null) {
12924 removeCallbacks(mPerformClick);
12929 * Remove the prepress detection timer.
12931 private void removeUnsetPressCallback() {
12932 if ((mPrivateFlags & PFLAG_PRESSED) != 0 && mUnsetPressedState != null) {
12934 removeCallbacks(mUnsetPressedState);
12939 * Remove the tap detection timer.
12941 private void removeTapCallback() {
12942 if (mPendingCheckForTap != null) {
12943 mPrivateFlags &= ~PFLAG_PREPRESSED;
12944 removeCallbacks(mPendingCheckForTap);
12949 * Cancels a pending long press. Your subclass can use this if you
12950 * want the context menu to come up if the user presses and holds
12951 * at the same place, but you don't want it to come up if they press
12952 * and then move around enough to cause scrolling.
12954 public void cancelLongPress() {
12955 removeLongPressCallback();
12958 * The prepressed state handled by the tap callback is a display
12959 * construct, but the tap callback will post a long press callback
12960 * less its own timeout. Remove it here.
12962 removeTapCallback();
12966 * Remove the pending callback for sending a
12967 * {@link AccessibilityEvent#TYPE_VIEW_SCROLLED} accessibility event.
12969 private void removeSendViewScrolledAccessibilityEventCallback() {
12970 if (mSendViewScrolledAccessibilityEvent != null) {
12971 removeCallbacks(mSendViewScrolledAccessibilityEvent);
12972 mSendViewScrolledAccessibilityEvent.mIsPending = false;
12977 * Sets the TouchDelegate for this View.
12979 public void setTouchDelegate(TouchDelegate delegate) {
12980 mTouchDelegate = delegate;
12984 * Gets the TouchDelegate for this View.
12986 public TouchDelegate getTouchDelegate() {
12987 return mTouchDelegate;
12991 * Request unbuffered dispatch of the given stream of MotionEvents to this View.
12993 * Until this View receives a corresponding {@link MotionEvent#ACTION_UP}, ask that the input
12994 * system not batch {@link MotionEvent}s but instead deliver them as soon as they're
12995 * available. This method should only be called for touch events.
12997 * <p class="note">This api is not intended for most applications. Buffered dispatch
12998 * provides many of benefits, and just requesting unbuffered dispatch on most MotionEvent
12999 * streams will not improve your input latency. Side effects include: increased latency,
13000 * jittery scrolls and inability to take advantage of system resampling. Talk to your input
13001 * professional to see if {@link #requestUnbufferedDispatch(MotionEvent)} is right for
13004 public final void requestUnbufferedDispatch(MotionEvent event) {
13005 final int action = event.getAction();
13006 if (mAttachInfo == null
13007 || action != MotionEvent.ACTION_DOWN && action != MotionEvent.ACTION_MOVE
13008 || !event.isTouchEvent()) {
13011 mAttachInfo.mUnbufferedDispatchRequested = true;
13015 * Set flags controlling behavior of this view.
13017 * @param flags Constant indicating the value which should be set
13018 * @param mask Constant indicating the bit range that should be changed
13020 void setFlags(int flags, int mask) {
13021 final boolean accessibilityEnabled =
13022 AccessibilityManager.getInstance(mContext).isEnabled();
13023 final boolean oldIncludeForAccessibility = accessibilityEnabled && includeForAccessibility();
13025 int old = mViewFlags;
13026 mViewFlags = (mViewFlags & ~mask) | (flags & mask);
13028 int changed = mViewFlags ^ old;
13029 if (changed == 0) {
13032 int privateFlags = mPrivateFlags;
13034 // If focusable is auto, update the FOCUSABLE bit.
13035 int focusableChangedByAuto = 0;
13036 if (((mViewFlags & FOCUSABLE_AUTO) != 0)
13037 && (changed & (FOCUSABLE_MASK | CLICKABLE)) != 0) {
13038 // Heuristic only takes into account whether view is clickable.
13039 final int newFocus;
13040 if ((mViewFlags & CLICKABLE) != 0) {
13041 newFocus = FOCUSABLE;
13043 newFocus = NOT_FOCUSABLE;
13045 mViewFlags = (mViewFlags & ~FOCUSABLE) | newFocus;
13046 focusableChangedByAuto = (old & FOCUSABLE) ^ (newFocus & FOCUSABLE);
13047 changed = (changed & ~FOCUSABLE) | focusableChangedByAuto;
13050 /* Check if the FOCUSABLE bit has changed */
13051 if (((changed & FOCUSABLE) != 0) && ((privateFlags & PFLAG_HAS_BOUNDS) != 0)) {
13052 if (((old & FOCUSABLE) == FOCUSABLE)
13053 && ((privateFlags & PFLAG_FOCUSED) != 0)) {
13054 /* Give up focus if we are no longer focusable */
13056 } else if (((old & FOCUSABLE) == NOT_FOCUSABLE)
13057 && ((privateFlags & PFLAG_FOCUSED) == 0)) {
13059 * Tell the view system that we are now available to take focus
13060 * if no one else already has it.
13062 if (mParent != null) {
13063 ViewRootImpl viewRootImpl = getViewRootImpl();
13064 if (!sAutoFocusableOffUIThreadWontNotifyParents
13065 || focusableChangedByAuto == 0
13066 || viewRootImpl == null
13067 || viewRootImpl.mThread == Thread.currentThread()) {
13068 mParent.focusableViewAvailable(this);
13074 final int newVisibility = flags & VISIBILITY_MASK;
13075 if (newVisibility == VISIBLE) {
13076 if ((changed & VISIBILITY_MASK) != 0) {
13078 * If this view is becoming visible, invalidate it in case it changed while
13079 * it was not visible. Marking it drawn ensures that the invalidation will
13082 mPrivateFlags |= PFLAG_DRAWN;
13085 needGlobalAttributesUpdate(true);
13087 // a view becoming visible is worth notifying the parent
13088 // about in case nothing has focus. even if this specific view
13089 // isn't focusable, it may contain something that is, so let
13090 // the root view try to give this focus if nothing else does.
13091 if ((mParent != null)) {
13092 mParent.focusableViewAvailable(this);
13097 /* Check if the GONE bit has changed */
13098 if ((changed & GONE) != 0) {
13099 needGlobalAttributesUpdate(false);
13102 if (((mViewFlags & VISIBILITY_MASK) == GONE)) {
13103 if (hasFocus()) clearFocus();
13104 clearAccessibilityFocus();
13105 destroyDrawingCache();
13106 if (mParent instanceof View) {
13107 // GONE views noop invalidation, so invalidate the parent
13108 ((View) mParent).invalidate(true);
13110 // Mark the view drawn to ensure that it gets invalidated properly the next
13111 // time it is visible and gets invalidated
13112 mPrivateFlags |= PFLAG_DRAWN;
13114 if (mAttachInfo != null) {
13115 mAttachInfo.mViewVisibilityChanged = true;
13119 /* Check if the VISIBLE bit has changed */
13120 if ((changed & INVISIBLE) != 0) {
13121 needGlobalAttributesUpdate(false);
13123 * If this view is becoming invisible, set the DRAWN flag so that
13124 * the next invalidate() will not be skipped.
13126 mPrivateFlags |= PFLAG_DRAWN;
13128 if (((mViewFlags & VISIBILITY_MASK) == INVISIBLE)) {
13129 // root view becoming invisible shouldn't clear focus and accessibility focus
13130 if (getRootView() != this) {
13131 if (hasFocus()) clearFocus();
13132 clearAccessibilityFocus();
13135 if (mAttachInfo != null) {
13136 mAttachInfo.mViewVisibilityChanged = true;
13140 if ((changed & VISIBILITY_MASK) != 0) {
13141 // If the view is invisible, cleanup its display list to free up resources
13142 if (newVisibility != VISIBLE && mAttachInfo != null) {
13146 if (mParent instanceof ViewGroup) {
13147 ((ViewGroup) mParent).onChildVisibilityChanged(this,
13148 (changed & VISIBILITY_MASK), newVisibility);
13149 ((View) mParent).invalidate(true);
13150 } else if (mParent != null) {
13151 mParent.invalidateChild(this, null);
13154 if (mAttachInfo != null) {
13155 dispatchVisibilityChanged(this, newVisibility);
13157 // Aggregated visibility changes are dispatched to attached views
13158 // in visible windows where the parent is currently shown/drawn
13159 // or the parent is not a ViewGroup (and therefore assumed to be a ViewRoot),
13160 // discounting clipping or overlapping. This makes it a good place
13161 // to change animation states.
13162 if (mParent != null && getWindowVisibility() == VISIBLE &&
13163 ((!(mParent instanceof ViewGroup)) || ((ViewGroup) mParent).isShown())) {
13164 dispatchVisibilityAggregated(newVisibility == VISIBLE);
13166 notifySubtreeAccessibilityStateChangedIfNeeded();
13170 if ((changed & WILL_NOT_CACHE_DRAWING) != 0) {
13171 destroyDrawingCache();
13174 if ((changed & DRAWING_CACHE_ENABLED) != 0) {
13175 destroyDrawingCache();
13176 mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID;
13177 invalidateParentCaches();
13180 if ((changed & DRAWING_CACHE_QUALITY_MASK) != 0) {
13181 destroyDrawingCache();
13182 mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID;
13185 if ((changed & DRAW_MASK) != 0) {
13186 if ((mViewFlags & WILL_NOT_DRAW) != 0) {
13187 if (mBackground != null
13188 || mDefaultFocusHighlight != null
13189 || (mForegroundInfo != null && mForegroundInfo.mDrawable != null)) {
13190 mPrivateFlags &= ~PFLAG_SKIP_DRAW;
13192 mPrivateFlags |= PFLAG_SKIP_DRAW;
13195 mPrivateFlags &= ~PFLAG_SKIP_DRAW;
13201 if ((changed & KEEP_SCREEN_ON) != 0) {
13202 if (mParent != null && mAttachInfo != null && !mAttachInfo.mRecomputeGlobalAttributes) {
13203 mParent.recomputeViewAttributes(this);
13207 if (accessibilityEnabled) {
13208 if ((changed & FOCUSABLE) != 0 || (changed & VISIBILITY_MASK) != 0
13209 || (changed & CLICKABLE) != 0 || (changed & LONG_CLICKABLE) != 0
13210 || (changed & CONTEXT_CLICKABLE) != 0) {
13211 if (oldIncludeForAccessibility != includeForAccessibility()) {
13212 notifySubtreeAccessibilityStateChangedIfNeeded();
13214 notifyViewAccessibilityStateChangedIfNeeded(
13215 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED);
13217 } else if ((changed & ENABLED_MASK) != 0) {
13218 notifyViewAccessibilityStateChangedIfNeeded(
13219 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED);
13225 * Change the view's z order in the tree, so it's on top of other sibling
13226 * views. This ordering change may affect layout, if the parent container
13227 * uses an order-dependent layout scheme (e.g., LinearLayout). Prior
13228 * to {@link android.os.Build.VERSION_CODES#KITKAT} this
13229 * method should be followed by calls to {@link #requestLayout()} and
13230 * {@link View#invalidate()} on the view's parent to force the parent to redraw
13231 * with the new child ordering.
13233 * @see ViewGroup#bringChildToFront(View)
13235 public void bringToFront() {
13236 if (mParent != null) {
13237 mParent.bringChildToFront(this);
13242 * This is called in response to an internal scroll in this view (i.e., the
13243 * view scrolled its own contents). This is typically as a result of
13244 * {@link #scrollBy(int, int)} or {@link #scrollTo(int, int)} having been
13247 * @param l Current horizontal scroll origin.
13248 * @param t Current vertical scroll origin.
13249 * @param oldl Previous horizontal scroll origin.
13250 * @param oldt Previous vertical scroll origin.
13252 protected void onScrollChanged(int l, int t, int oldl, int oldt) {
13253 notifySubtreeAccessibilityStateChangedIfNeeded();
13255 if (AccessibilityManager.getInstance(mContext).isEnabled()) {
13256 postSendViewScrolledAccessibilityEventCallback();
13259 mBackgroundSizeChanged = true;
13260 mDefaultFocusHighlightSizeChanged = true;
13261 if (mForegroundInfo != null) {
13262 mForegroundInfo.mBoundsChanged = true;
13265 final AttachInfo ai = mAttachInfo;
13267 ai.mViewScrollChanged = true;
13270 if (mListenerInfo != null && mListenerInfo.mOnScrollChangeListener != null) {
13271 mListenerInfo.mOnScrollChangeListener.onScrollChange(this, l, t, oldl, oldt);
13276 * Interface definition for a callback to be invoked when the scroll
13277 * X or Y positions of a view change.
13279 * <b>Note:</b> Some views handle scrolling independently from View and may
13280 * have their own separate listeners for scroll-type events. For example,
13281 * {@link android.widget.ListView ListView} allows clients to register an
13282 * {@link android.widget.ListView#setOnScrollListener(android.widget.AbsListView.OnScrollListener) AbsListView.OnScrollListener}
13283 * to listen for changes in list scroll position.
13285 * @see #setOnScrollChangeListener(View.OnScrollChangeListener)
13287 public interface OnScrollChangeListener {
13289 * Called when the scroll position of a view changes.
13291 * @param v The view whose scroll position has changed.
13292 * @param scrollX Current horizontal scroll origin.
13293 * @param scrollY Current vertical scroll origin.
13294 * @param oldScrollX Previous horizontal scroll origin.
13295 * @param oldScrollY Previous vertical scroll origin.
13297 void onScrollChange(View v, int scrollX, int scrollY, int oldScrollX, int oldScrollY);
13301 * Interface definition for a callback to be invoked when the layout bounds of a view
13302 * changes due to layout processing.
13304 public interface OnLayoutChangeListener {
13306 * Called when the layout bounds of a view changes due to layout processing.
13308 * @param v The view whose bounds have changed.
13309 * @param left The new value of the view's left property.
13310 * @param top The new value of the view's top property.
13311 * @param right The new value of the view's right property.
13312 * @param bottom The new value of the view's bottom property.
13313 * @param oldLeft The previous value of the view's left property.
13314 * @param oldTop The previous value of the view's top property.
13315 * @param oldRight The previous value of the view's right property.
13316 * @param oldBottom The previous value of the view's bottom property.
13318 void onLayoutChange(View v, int left, int top, int right, int bottom,
13319 int oldLeft, int oldTop, int oldRight, int oldBottom);
13323 * This is called during layout when the size of this view has changed. If
13324 * you were just added to the view hierarchy, you're called with the old
13327 * @param w Current width of this view.
13328 * @param h Current height of this view.
13329 * @param oldw Old width of this view.
13330 * @param oldh Old height of this view.
13332 protected void onSizeChanged(int w, int h, int oldw, int oldh) {
13336 * Called by draw to draw the child views. This may be overridden
13337 * by derived classes to gain control just before its children are drawn
13338 * (but after its own view has been drawn).
13339 * @param canvas the canvas on which to draw the view
13341 protected void dispatchDraw(Canvas canvas) {
13346 * Gets the parent of this view. Note that the parent is a
13347 * ViewParent and not necessarily a View.
13349 * @return Parent of this view.
13351 public final ViewParent getParent() {
13356 * Set the horizontal scrolled position of your view. This will cause a call to
13357 * {@link #onScrollChanged(int, int, int, int)} and the view will be
13359 * @param value the x position to scroll to
13361 public void setScrollX(int value) {
13362 scrollTo(value, mScrollY);
13366 * Set the vertical scrolled position of your view. This will cause a call to
13367 * {@link #onScrollChanged(int, int, int, int)} and the view will be
13369 * @param value the y position to scroll to
13371 public void setScrollY(int value) {
13372 scrollTo(mScrollX, value);
13376 * Return the scrolled left position of this view. This is the left edge of
13377 * the displayed part of your view. You do not need to draw any pixels
13378 * farther left, since those are outside of the frame of your view on
13381 * @return The left edge of the displayed part of your view, in pixels.
13383 public final int getScrollX() {
13388 * Return the scrolled top position of this view. This is the top edge of
13389 * the displayed part of your view. You do not need to draw any pixels above
13390 * it, since those are outside of the frame of your view on screen.
13392 * @return The top edge of the displayed part of your view, in pixels.
13394 public final int getScrollY() {
13399 * Return the width of the your view.
13401 * @return The width of your view, in pixels.
13403 @ViewDebug.ExportedProperty(category = "layout")
13404 public final int getWidth() {
13405 return mRight - mLeft;
13409 * Return the height of your view.
13411 * @return The height of your view, in pixels.
13413 @ViewDebug.ExportedProperty(category = "layout")
13414 public final int getHeight() {
13415 return mBottom - mTop;
13419 * Return the visible drawing bounds of your view. Fills in the output
13420 * rectangle with the values from getScrollX(), getScrollY(),
13421 * getWidth(), and getHeight(). These bounds do not account for any
13422 * transformation properties currently set on the view, such as
13423 * {@link #setScaleX(float)} or {@link #setRotation(float)}.
13425 * @param outRect The (scrolled) drawing bounds of the view.
13427 public void getDrawingRect(Rect outRect) {
13428 outRect.left = mScrollX;
13429 outRect.top = mScrollY;
13430 outRect.right = mScrollX + (mRight - mLeft);
13431 outRect.bottom = mScrollY + (mBottom - mTop);
13435 * Like {@link #getMeasuredWidthAndState()}, but only returns the
13436 * raw width component (that is the result is masked by
13437 * {@link #MEASURED_SIZE_MASK}).
13439 * @return The raw measured width of this view.
13441 public final int getMeasuredWidth() {
13442 return mMeasuredWidth & MEASURED_SIZE_MASK;
13446 * Return the full width measurement information for this view as computed
13447 * by the most recent call to {@link #measure(int, int)}. This result is a bit mask
13448 * as defined by {@link #MEASURED_SIZE_MASK} and {@link #MEASURED_STATE_TOO_SMALL}.
13449 * This should be used during measurement and layout calculations only. Use
13450 * {@link #getWidth()} to see how wide a view is after layout.
13452 * @return The measured width of this view as a bit mask.
13454 @ViewDebug.ExportedProperty(category = "measurement", flagMapping = {
13455 @ViewDebug.FlagToString(mask = MEASURED_STATE_MASK, equals = MEASURED_STATE_TOO_SMALL,
13456 name = "MEASURED_STATE_TOO_SMALL"),
13458 public final int getMeasuredWidthAndState() {
13459 return mMeasuredWidth;
13463 * Like {@link #getMeasuredHeightAndState()}, but only returns the
13464 * raw height component (that is the result is masked by
13465 * {@link #MEASURED_SIZE_MASK}).
13467 * @return The raw measured height of this view.
13469 public final int getMeasuredHeight() {
13470 return mMeasuredHeight & MEASURED_SIZE_MASK;
13474 * Return the full height measurement information for this view as computed
13475 * by the most recent call to {@link #measure(int, int)}. This result is a bit mask
13476 * as defined by {@link #MEASURED_SIZE_MASK} and {@link #MEASURED_STATE_TOO_SMALL}.
13477 * This should be used during measurement and layout calculations only. Use
13478 * {@link #getHeight()} to see how wide a view is after layout.
13480 * @return The measured height of this view as a bit mask.
13482 @ViewDebug.ExportedProperty(category = "measurement", flagMapping = {
13483 @ViewDebug.FlagToString(mask = MEASURED_STATE_MASK, equals = MEASURED_STATE_TOO_SMALL,
13484 name = "MEASURED_STATE_TOO_SMALL"),
13486 public final int getMeasuredHeightAndState() {
13487 return mMeasuredHeight;
13491 * Return only the state bits of {@link #getMeasuredWidthAndState()}
13492 * and {@link #getMeasuredHeightAndState()}, combined into one integer.
13493 * The width component is in the regular bits {@link #MEASURED_STATE_MASK}
13494 * and the height component is at the shifted bits
13495 * {@link #MEASURED_HEIGHT_STATE_SHIFT}>>{@link #MEASURED_STATE_MASK}.
13497 public final int getMeasuredState() {
13498 return (mMeasuredWidth&MEASURED_STATE_MASK)
13499 | ((mMeasuredHeight>>MEASURED_HEIGHT_STATE_SHIFT)
13500 & (MEASURED_STATE_MASK>>MEASURED_HEIGHT_STATE_SHIFT));
13504 * The transform matrix of this view, which is calculated based on the current
13505 * rotation, scale, and pivot properties.
13507 * @see #getRotation()
13508 * @see #getScaleX()
13509 * @see #getScaleY()
13510 * @see #getPivotX()
13511 * @see #getPivotY()
13512 * @return The current transform matrix for the view
13514 public Matrix getMatrix() {
13515 ensureTransformationInfo();
13516 final Matrix matrix = mTransformationInfo.mMatrix;
13517 mRenderNode.getMatrix(matrix);
13522 * Returns true if the transform matrix is the identity matrix.
13523 * Recomputes the matrix if necessary.
13525 * @return True if the transform matrix is the identity matrix, false otherwise.
13527 final boolean hasIdentityMatrix() {
13528 return mRenderNode.hasIdentityMatrix();
13531 void ensureTransformationInfo() {
13532 if (mTransformationInfo == null) {
13533 mTransformationInfo = new TransformationInfo();
13538 * Utility method to retrieve the inverse of the current mMatrix property.
13539 * We cache the matrix to avoid recalculating it when transform properties
13540 * have not changed.
13542 * @return The inverse of the current matrix of this view.
13545 public final Matrix getInverseMatrix() {
13546 ensureTransformationInfo();
13547 if (mTransformationInfo.mInverseMatrix == null) {
13548 mTransformationInfo.mInverseMatrix = new Matrix();
13550 final Matrix matrix = mTransformationInfo.mInverseMatrix;
13551 mRenderNode.getInverseMatrix(matrix);
13556 * Gets the distance along the Z axis from the camera to this view.
13558 * @see #setCameraDistance(float)
13560 * @return The distance along the Z axis.
13562 public float getCameraDistance() {
13563 final float dpi = mResources.getDisplayMetrics().densityDpi;
13564 return -(mRenderNode.getCameraDistance() * dpi);
13568 * <p>Sets the distance along the Z axis (orthogonal to the X/Y plane on which
13569 * views are drawn) from the camera to this view. The camera's distance
13570 * affects 3D transformations, for instance rotations around the X and Y
13571 * axis. If the rotationX or rotationY properties are changed and this view is
13572 * large (more than half the size of the screen), it is recommended to always
13573 * use a camera distance that's greater than the height (X axis rotation) or
13574 * the width (Y axis rotation) of this view.</p>
13576 * <p>The distance of the camera from the view plane can have an affect on the
13577 * perspective distortion of the view when it is rotated around the x or y axis.
13578 * For example, a large distance will result in a large viewing angle, and there
13579 * will not be much perspective distortion of the view as it rotates. A short
13580 * distance may cause much more perspective distortion upon rotation, and can
13581 * also result in some drawing artifacts if the rotated view ends up partially
13582 * behind the camera (which is why the recommendation is to use a distance at
13583 * least as far as the size of the view, if the view is to be rotated.)</p>
13585 * <p>The distance is expressed in "depth pixels." The default distance depends
13586 * on the screen density. For instance, on a medium density display, the
13587 * default distance is 1280. On a high density display, the default distance
13590 * <p>If you want to specify a distance that leads to visually consistent
13591 * results across various densities, use the following formula:</p>
13593 * float scale = context.getResources().getDisplayMetrics().density;
13594 * view.setCameraDistance(distance * scale);
13597 * <p>The density scale factor of a high density display is 1.5,
13598 * and 1920 = 1280 * 1.5.</p>
13600 * @param distance The distance in "depth pixels", if negative the opposite
13603 * @see #setRotationX(float)
13604 * @see #setRotationY(float)
13606 public void setCameraDistance(float distance) {
13607 final float dpi = mResources.getDisplayMetrics().densityDpi;
13609 invalidateViewProperty(true, false);
13610 mRenderNode.setCameraDistance(-Math.abs(distance) / dpi);
13611 invalidateViewProperty(false, false);
13613 invalidateParentIfNeededAndWasQuickRejected();
13617 * The degrees that the view is rotated around the pivot point.
13619 * @see #setRotation(float)
13620 * @see #getPivotX()
13621 * @see #getPivotY()
13623 * @return The degrees of rotation.
13625 @ViewDebug.ExportedProperty(category = "drawing")
13626 public float getRotation() {
13627 return mRenderNode.getRotation();
13631 * Sets the degrees that the view is rotated around the pivot point. Increasing values
13632 * result in clockwise rotation.
13634 * @param rotation The degrees of rotation.
13636 * @see #getRotation()
13637 * @see #getPivotX()
13638 * @see #getPivotY()
13639 * @see #setRotationX(float)
13640 * @see #setRotationY(float)
13642 * @attr ref android.R.styleable#View_rotation
13644 public void setRotation(float rotation) {
13645 if (rotation != getRotation()) {
13646 // Double-invalidation is necessary to capture view's old and new areas
13647 invalidateViewProperty(true, false);
13648 mRenderNode.setRotation(rotation);
13649 invalidateViewProperty(false, true);
13651 invalidateParentIfNeededAndWasQuickRejected();
13652 notifySubtreeAccessibilityStateChangedIfNeeded();
13657 * The degrees that the view is rotated around the vertical axis through the pivot point.
13659 * @see #getPivotX()
13660 * @see #getPivotY()
13661 * @see #setRotationY(float)
13663 * @return The degrees of Y rotation.
13665 @ViewDebug.ExportedProperty(category = "drawing")
13666 public float getRotationY() {
13667 return mRenderNode.getRotationY();
13671 * Sets the degrees that the view is rotated around the vertical axis through the pivot point.
13672 * Increasing values result in counter-clockwise rotation from the viewpoint of looking
13675 * When rotating large views, it is recommended to adjust the camera distance
13676 * accordingly. Refer to {@link #setCameraDistance(float)} for more information.
13678 * @param rotationY The degrees of Y rotation.
13680 * @see #getRotationY()
13681 * @see #getPivotX()
13682 * @see #getPivotY()
13683 * @see #setRotation(float)
13684 * @see #setRotationX(float)
13685 * @see #setCameraDistance(float)
13687 * @attr ref android.R.styleable#View_rotationY
13689 public void setRotationY(float rotationY) {
13690 if (rotationY != getRotationY()) {
13691 invalidateViewProperty(true, false);
13692 mRenderNode.setRotationY(rotationY);
13693 invalidateViewProperty(false, true);
13695 invalidateParentIfNeededAndWasQuickRejected();
13696 notifySubtreeAccessibilityStateChangedIfNeeded();
13701 * The degrees that the view is rotated around the horizontal axis through the pivot point.
13703 * @see #getPivotX()
13704 * @see #getPivotY()
13705 * @see #setRotationX(float)
13707 * @return The degrees of X rotation.
13709 @ViewDebug.ExportedProperty(category = "drawing")
13710 public float getRotationX() {
13711 return mRenderNode.getRotationX();
13715 * Sets the degrees that the view is rotated around the horizontal axis through the pivot point.
13716 * Increasing values result in clockwise rotation from the viewpoint of looking down the
13719 * When rotating large views, it is recommended to adjust the camera distance
13720 * accordingly. Refer to {@link #setCameraDistance(float)} for more information.
13722 * @param rotationX The degrees of X rotation.
13724 * @see #getRotationX()
13725 * @see #getPivotX()
13726 * @see #getPivotY()
13727 * @see #setRotation(float)
13728 * @see #setRotationY(float)
13729 * @see #setCameraDistance(float)
13731 * @attr ref android.R.styleable#View_rotationX
13733 public void setRotationX(float rotationX) {
13734 if (rotationX != getRotationX()) {
13735 invalidateViewProperty(true, false);
13736 mRenderNode.setRotationX(rotationX);
13737 invalidateViewProperty(false, true);
13739 invalidateParentIfNeededAndWasQuickRejected();
13740 notifySubtreeAccessibilityStateChangedIfNeeded();
13745 * The amount that the view is scaled in x around the pivot point, as a proportion of
13746 * the view's unscaled width. A value of 1, the default, means that no scaling is applied.
13748 * <p>By default, this is 1.0f.
13750 * @see #getPivotX()
13751 * @see #getPivotY()
13752 * @return The scaling factor.
13754 @ViewDebug.ExportedProperty(category = "drawing")
13755 public float getScaleX() {
13756 return mRenderNode.getScaleX();
13760 * Sets the amount that the view is scaled in x around the pivot point, as a proportion of
13761 * the view's unscaled width. A value of 1 means that no scaling is applied.
13763 * @param scaleX The scaling factor.
13764 * @see #getPivotX()
13765 * @see #getPivotY()
13767 * @attr ref android.R.styleable#View_scaleX
13769 public void setScaleX(float scaleX) {
13770 if (scaleX != getScaleX()) {
13771 invalidateViewProperty(true, false);
13772 mRenderNode.setScaleX(scaleX);
13773 invalidateViewProperty(false, true);
13775 invalidateParentIfNeededAndWasQuickRejected();
13776 notifySubtreeAccessibilityStateChangedIfNeeded();
13781 * The amount that the view is scaled in y around the pivot point, as a proportion of
13782 * the view's unscaled height. A value of 1, the default, means that no scaling is applied.
13784 * <p>By default, this is 1.0f.
13786 * @see #getPivotX()
13787 * @see #getPivotY()
13788 * @return The scaling factor.
13790 @ViewDebug.ExportedProperty(category = "drawing")
13791 public float getScaleY() {
13792 return mRenderNode.getScaleY();
13796 * Sets the amount that the view is scaled in Y around the pivot point, as a proportion of
13797 * the view's unscaled width. A value of 1 means that no scaling is applied.
13799 * @param scaleY The scaling factor.
13800 * @see #getPivotX()
13801 * @see #getPivotY()
13803 * @attr ref android.R.styleable#View_scaleY
13805 public void setScaleY(float scaleY) {
13806 if (scaleY != getScaleY()) {
13807 invalidateViewProperty(true, false);
13808 mRenderNode.setScaleY(scaleY);
13809 invalidateViewProperty(false, true);
13811 invalidateParentIfNeededAndWasQuickRejected();
13812 notifySubtreeAccessibilityStateChangedIfNeeded();
13817 * The x location of the point around which the view is {@link #setRotation(float) rotated}
13818 * and {@link #setScaleX(float) scaled}.
13820 * @see #getRotation()
13821 * @see #getScaleX()
13822 * @see #getScaleY()
13823 * @see #getPivotY()
13824 * @return The x location of the pivot point.
13826 * @attr ref android.R.styleable#View_transformPivotX
13828 @ViewDebug.ExportedProperty(category = "drawing")
13829 public float getPivotX() {
13830 return mRenderNode.getPivotX();
13834 * Sets the x location of the point around which the view is
13835 * {@link #setRotation(float) rotated} and {@link #setScaleX(float) scaled}.
13836 * By default, the pivot point is centered on the object.
13837 * Setting this property disables this behavior and causes the view to use only the
13838 * explicitly set pivotX and pivotY values.
13840 * @param pivotX The x location of the pivot point.
13841 * @see #getRotation()
13842 * @see #getScaleX()
13843 * @see #getScaleY()
13844 * @see #getPivotY()
13846 * @attr ref android.R.styleable#View_transformPivotX
13848 public void setPivotX(float pivotX) {
13849 if (!mRenderNode.isPivotExplicitlySet() || pivotX != getPivotX()) {
13850 invalidateViewProperty(true, false);
13851 mRenderNode.setPivotX(pivotX);
13852 invalidateViewProperty(false, true);
13854 invalidateParentIfNeededAndWasQuickRejected();
13859 * The y location of the point around which the view is {@link #setRotation(float) rotated}
13860 * and {@link #setScaleY(float) scaled}.
13862 * @see #getRotation()
13863 * @see #getScaleX()
13864 * @see #getScaleY()
13865 * @see #getPivotY()
13866 * @return The y location of the pivot point.
13868 * @attr ref android.R.styleable#View_transformPivotY
13870 @ViewDebug.ExportedProperty(category = "drawing")
13871 public float getPivotY() {
13872 return mRenderNode.getPivotY();
13876 * Sets the y location of the point around which the view is {@link #setRotation(float) rotated}
13877 * and {@link #setScaleY(float) scaled}. By default, the pivot point is centered on the object.
13878 * Setting this property disables this behavior and causes the view to use only the
13879 * explicitly set pivotX and pivotY values.
13881 * @param pivotY The y location of the pivot point.
13882 * @see #getRotation()
13883 * @see #getScaleX()
13884 * @see #getScaleY()
13885 * @see #getPivotY()
13887 * @attr ref android.R.styleable#View_transformPivotY
13889 public void setPivotY(float pivotY) {
13890 if (!mRenderNode.isPivotExplicitlySet() || pivotY != getPivotY()) {
13891 invalidateViewProperty(true, false);
13892 mRenderNode.setPivotY(pivotY);
13893 invalidateViewProperty(false, true);
13895 invalidateParentIfNeededAndWasQuickRejected();
13900 * The opacity of the view. This is a value from 0 to 1, where 0 means the view is
13901 * completely transparent and 1 means the view is completely opaque.
13903 * <p>By default this is 1.0f.
13904 * @return The opacity of the view.
13906 @ViewDebug.ExportedProperty(category = "drawing")
13907 public float getAlpha() {
13908 return mTransformationInfo != null ? mTransformationInfo.mAlpha : 1;
13912 * Sets the behavior for overlapping rendering for this view (see {@link
13913 * #hasOverlappingRendering()} for more details on this behavior). Calling this method
13914 * is an alternative to overriding {@link #hasOverlappingRendering()} in a subclass,
13915 * providing the value which is then used internally. That is, when {@link
13916 * #forceHasOverlappingRendering(boolean)} is called, the value of {@link
13917 * #hasOverlappingRendering()} is ignored and the value passed into this method is used
13920 * @param hasOverlappingRendering The value for overlapping rendering to be used internally
13921 * instead of that returned by {@link #hasOverlappingRendering()}.
13923 * @attr ref android.R.styleable#View_forceHasOverlappingRendering
13925 public void forceHasOverlappingRendering(boolean hasOverlappingRendering) {
13926 mPrivateFlags3 |= PFLAG3_HAS_OVERLAPPING_RENDERING_FORCED;
13927 if (hasOverlappingRendering) {
13928 mPrivateFlags3 |= PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE;
13930 mPrivateFlags3 &= ~PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE;
13935 * Returns the value for overlapping rendering that is used internally. This is either
13936 * the value passed into {@link #forceHasOverlappingRendering(boolean)}, if called, or
13937 * the return value of {@link #hasOverlappingRendering()}, otherwise.
13939 * @return The value for overlapping rendering being used internally.
13941 public final boolean getHasOverlappingRendering() {
13942 return (mPrivateFlags3 & PFLAG3_HAS_OVERLAPPING_RENDERING_FORCED) != 0 ?
13943 (mPrivateFlags3 & PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE) != 0 :
13944 hasOverlappingRendering();
13948 * Returns whether this View has content which overlaps.
13950 * <p>This function, intended to be overridden by specific View types, is an optimization when
13951 * alpha is set on a view. If rendering overlaps in a view with alpha < 1, that view is drawn to
13952 * an offscreen buffer and then composited into place, which can be expensive. If the view has
13953 * no overlapping rendering, the view can draw each primitive with the appropriate alpha value
13954 * directly. An example of overlapping rendering is a TextView with a background image, such as
13955 * a Button. An example of non-overlapping rendering is a TextView with no background, or an
13956 * ImageView with only the foreground image. The default implementation returns true; subclasses
13957 * should override if they have cases which can be optimized.</p>
13959 * <p>The current implementation of the saveLayer and saveLayerAlpha methods in {@link Canvas}
13960 * necessitates that a View return true if it uses the methods internally without passing the
13961 * {@link Canvas#CLIP_TO_LAYER_SAVE_FLAG}.</p>
13963 * <p><strong>Note:</strong> The return value of this method is ignored if {@link
13964 * #forceHasOverlappingRendering(boolean)} has been called on this view.</p>
13966 * @return true if the content in this view might overlap, false otherwise.
13968 @ViewDebug.ExportedProperty(category = "drawing")
13969 public boolean hasOverlappingRendering() {
13974 * Sets the opacity of the view to a value from 0 to 1, where 0 means the view is
13975 * completely transparent and 1 means the view is completely opaque.
13977 * <p class="note"><strong>Note:</strong> setting alpha to a translucent value (0 < alpha < 1)
13978 * can have significant performance implications, especially for large views. It is best to use
13979 * the alpha property sparingly and transiently, as in the case of fading animations.</p>
13981 * <p>For a view with a frequently changing alpha, such as during a fading animation, it is
13982 * strongly recommended for performance reasons to either override
13983 * {@link #hasOverlappingRendering()} to return <code>false</code> if appropriate, or setting a
13984 * {@link #setLayerType(int, android.graphics.Paint) layer type} on the view for the duration
13985 * of the animation. On versions {@link android.os.Build.VERSION_CODES#M} and below,
13986 * the default path for rendering an unlayered View with alpha could add multiple milliseconds
13987 * of rendering cost, even for simple or small views. Starting with
13988 * {@link android.os.Build.VERSION_CODES#M}, {@link #LAYER_TYPE_HARDWARE} is automatically
13989 * applied to the view at the rendering level.</p>
13991 * <p>If this view overrides {@link #onSetAlpha(int)} to return true, then this view is
13992 * responsible for applying the opacity itself.</p>
13994 * <p>On versions {@link android.os.Build.VERSION_CODES#LOLLIPOP_MR1} and below, note that if
13995 * the view is backed by a {@link #setLayerType(int, android.graphics.Paint) layer} and is
13996 * associated with a {@link #setLayerPaint(android.graphics.Paint) layer paint}, setting an
13997 * alpha value less than 1.0 will supersede the alpha of the layer paint.</p>
13999 * <p>Starting with {@link android.os.Build.VERSION_CODES#M}, setting a translucent alpha
14000 * value will clip a View to its bounds, unless the View returns <code>false</code> from
14001 * {@link #hasOverlappingRendering}.</p>
14003 * @param alpha The opacity of the view.
14005 * @see #hasOverlappingRendering()
14006 * @see #setLayerType(int, android.graphics.Paint)
14008 * @attr ref android.R.styleable#View_alpha
14010 public void setAlpha(@FloatRange(from=0.0, to=1.0) float alpha) {
14011 ensureTransformationInfo();
14012 if (mTransformationInfo.mAlpha != alpha) {
14013 // Report visibility changes, which can affect children, to accessibility
14014 if ((alpha == 0) ^ (mTransformationInfo.mAlpha == 0)) {
14015 notifySubtreeAccessibilityStateChangedIfNeeded();
14017 mTransformationInfo.mAlpha = alpha;
14018 if (onSetAlpha((int) (alpha * 255))) {
14019 mPrivateFlags |= PFLAG_ALPHA_SET;
14020 // subclass is handling alpha - don't optimize rendering cache invalidation
14021 invalidateParentCaches();
14024 mPrivateFlags &= ~PFLAG_ALPHA_SET;
14025 invalidateViewProperty(true, false);
14026 mRenderNode.setAlpha(getFinalAlpha());
14032 * Faster version of setAlpha() which performs the same steps except there are
14033 * no calls to invalidate(). The caller of this function should perform proper invalidation
14034 * on the parent and this object. The return value indicates whether the subclass handles
14035 * alpha (the return value for onSetAlpha()).
14037 * @param alpha The new value for the alpha property
14038 * @return true if the View subclass handles alpha (the return value for onSetAlpha()) and
14039 * the new value for the alpha property is different from the old value
14041 boolean setAlphaNoInvalidation(float alpha) {
14042 ensureTransformationInfo();
14043 if (mTransformationInfo.mAlpha != alpha) {
14044 mTransformationInfo.mAlpha = alpha;
14045 boolean subclassHandlesAlpha = onSetAlpha((int) (alpha * 255));
14046 if (subclassHandlesAlpha) {
14047 mPrivateFlags |= PFLAG_ALPHA_SET;
14050 mPrivateFlags &= ~PFLAG_ALPHA_SET;
14051 mRenderNode.setAlpha(getFinalAlpha());
14058 * This property is hidden and intended only for use by the Fade transition, which
14059 * animates it to produce a visual translucency that does not side-effect (or get
14060 * affected by) the real alpha property. This value is composited with the other
14061 * alpha value (and the AlphaAnimation value, when that is present) to produce
14062 * a final visual translucency result, which is what is passed into the DisplayList.
14066 public void setTransitionAlpha(float alpha) {
14067 ensureTransformationInfo();
14068 if (mTransformationInfo.mTransitionAlpha != alpha) {
14069 mTransformationInfo.mTransitionAlpha = alpha;
14070 mPrivateFlags &= ~PFLAG_ALPHA_SET;
14071 invalidateViewProperty(true, false);
14072 mRenderNode.setAlpha(getFinalAlpha());
14077 * Calculates the visual alpha of this view, which is a combination of the actual
14078 * alpha value and the transitionAlpha value (if set).
14080 private float getFinalAlpha() {
14081 if (mTransformationInfo != null) {
14082 return mTransformationInfo.mAlpha * mTransformationInfo.mTransitionAlpha;
14088 * This property is hidden and intended only for use by the Fade transition, which
14089 * animates it to produce a visual translucency that does not side-effect (or get
14090 * affected by) the real alpha property. This value is composited with the other
14091 * alpha value (and the AlphaAnimation value, when that is present) to produce
14092 * a final visual translucency result, which is what is passed into the DisplayList.
14096 @ViewDebug.ExportedProperty(category = "drawing")
14097 public float getTransitionAlpha() {
14098 return mTransformationInfo != null ? mTransformationInfo.mTransitionAlpha : 1;
14102 * Top position of this view relative to its parent.
14104 * @return The top of this view, in pixels.
14106 @ViewDebug.CapturedViewProperty
14107 public final int getTop() {
14112 * Sets the top position of this view relative to its parent. This method is meant to be called
14113 * by the layout system and should not generally be called otherwise, because the property
14114 * may be changed at any time by the layout.
14116 * @param top The top of this view, in pixels.
14118 public final void setTop(int top) {
14120 final boolean matrixIsIdentity = hasIdentityMatrix();
14121 if (matrixIsIdentity) {
14122 if (mAttachInfo != null) {
14132 invalidate(0, yLoc, mRight - mLeft, mBottom - minTop);
14135 // Double-invalidation is necessary to capture view's old and new areas
14139 int width = mRight - mLeft;
14140 int oldHeight = mBottom - mTop;
14143 mRenderNode.setTop(mTop);
14145 sizeChange(width, mBottom - mTop, width, oldHeight);
14147 if (!matrixIsIdentity) {
14148 mPrivateFlags |= PFLAG_DRAWN; // force another invalidation with the new orientation
14151 mBackgroundSizeChanged = true;
14152 mDefaultFocusHighlightSizeChanged = true;
14153 if (mForegroundInfo != null) {
14154 mForegroundInfo.mBoundsChanged = true;
14156 invalidateParentIfNeeded();
14157 if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) == PFLAG2_VIEW_QUICK_REJECTED) {
14158 // View was rejected last time it was drawn by its parent; this may have changed
14159 invalidateParentIfNeeded();
14165 * Bottom position of this view relative to its parent.
14167 * @return The bottom of this view, in pixels.
14169 @ViewDebug.CapturedViewProperty
14170 public final int getBottom() {
14175 * True if this view has changed since the last time being drawn.
14177 * @return The dirty state of this view.
14179 public boolean isDirty() {
14180 return (mPrivateFlags & PFLAG_DIRTY_MASK) != 0;
14184 * Sets the bottom position of this view relative to its parent. This method is meant to be
14185 * called by the layout system and should not generally be called otherwise, because the
14186 * property may be changed at any time by the layout.
14188 * @param bottom The bottom of this view, in pixels.
14190 public final void setBottom(int bottom) {
14191 if (bottom != mBottom) {
14192 final boolean matrixIsIdentity = hasIdentityMatrix();
14193 if (matrixIsIdentity) {
14194 if (mAttachInfo != null) {
14196 if (bottom < mBottom) {
14197 maxBottom = mBottom;
14199 maxBottom = bottom;
14201 invalidate(0, 0, mRight - mLeft, maxBottom - mTop);
14204 // Double-invalidation is necessary to capture view's old and new areas
14208 int width = mRight - mLeft;
14209 int oldHeight = mBottom - mTop;
14212 mRenderNode.setBottom(mBottom);
14214 sizeChange(width, mBottom - mTop, width, oldHeight);
14216 if (!matrixIsIdentity) {
14217 mPrivateFlags |= PFLAG_DRAWN; // force another invalidation with the new orientation
14220 mBackgroundSizeChanged = true;
14221 mDefaultFocusHighlightSizeChanged = true;
14222 if (mForegroundInfo != null) {
14223 mForegroundInfo.mBoundsChanged = true;
14225 invalidateParentIfNeeded();
14226 if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) == PFLAG2_VIEW_QUICK_REJECTED) {
14227 // View was rejected last time it was drawn by its parent; this may have changed
14228 invalidateParentIfNeeded();
14234 * Left position of this view relative to its parent.
14236 * @return The left edge of this view, in pixels.
14238 @ViewDebug.CapturedViewProperty
14239 public final int getLeft() {
14244 * Sets the left position of this view relative to its parent. This method is meant to be called
14245 * by the layout system and should not generally be called otherwise, because the property
14246 * may be changed at any time by the layout.
14248 * @param left The left of this view, in pixels.
14250 public final void setLeft(int left) {
14251 if (left != mLeft) {
14252 final boolean matrixIsIdentity = hasIdentityMatrix();
14253 if (matrixIsIdentity) {
14254 if (mAttachInfo != null) {
14257 if (left < mLeft) {
14259 xLoc = left - mLeft;
14264 invalidate(xLoc, 0, mRight - minLeft, mBottom - mTop);
14267 // Double-invalidation is necessary to capture view's old and new areas
14271 int oldWidth = mRight - mLeft;
14272 int height = mBottom - mTop;
14275 mRenderNode.setLeft(left);
14277 sizeChange(mRight - mLeft, height, oldWidth, height);
14279 if (!matrixIsIdentity) {
14280 mPrivateFlags |= PFLAG_DRAWN; // force another invalidation with the new orientation
14283 mBackgroundSizeChanged = true;
14284 mDefaultFocusHighlightSizeChanged = true;
14285 if (mForegroundInfo != null) {
14286 mForegroundInfo.mBoundsChanged = true;
14288 invalidateParentIfNeeded();
14289 if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) == PFLAG2_VIEW_QUICK_REJECTED) {
14290 // View was rejected last time it was drawn by its parent; this may have changed
14291 invalidateParentIfNeeded();
14297 * Right position of this view relative to its parent.
14299 * @return The right edge of this view, in pixels.
14301 @ViewDebug.CapturedViewProperty
14302 public final int getRight() {
14307 * Sets the right position of this view relative to its parent. This method is meant to be called
14308 * by the layout system and should not generally be called otherwise, because the property
14309 * may be changed at any time by the layout.
14311 * @param right The right of this view, in pixels.
14313 public final void setRight(int right) {
14314 if (right != mRight) {
14315 final boolean matrixIsIdentity = hasIdentityMatrix();
14316 if (matrixIsIdentity) {
14317 if (mAttachInfo != null) {
14319 if (right < mRight) {
14324 invalidate(0, 0, maxRight - mLeft, mBottom - mTop);
14327 // Double-invalidation is necessary to capture view's old and new areas
14331 int oldWidth = mRight - mLeft;
14332 int height = mBottom - mTop;
14335 mRenderNode.setRight(mRight);
14337 sizeChange(mRight - mLeft, height, oldWidth, height);
14339 if (!matrixIsIdentity) {
14340 mPrivateFlags |= PFLAG_DRAWN; // force another invalidation with the new orientation
14343 mBackgroundSizeChanged = true;
14344 mDefaultFocusHighlightSizeChanged = true;
14345 if (mForegroundInfo != null) {
14346 mForegroundInfo.mBoundsChanged = true;
14348 invalidateParentIfNeeded();
14349 if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) == PFLAG2_VIEW_QUICK_REJECTED) {
14350 // View was rejected last time it was drawn by its parent; this may have changed
14351 invalidateParentIfNeeded();
14357 * The visual x position of this view, in pixels. This is equivalent to the
14358 * {@link #setTranslationX(float) translationX} property plus the current
14359 * {@link #getLeft() left} property.
14361 * @return The visual x position of this view, in pixels.
14363 @ViewDebug.ExportedProperty(category = "drawing")
14364 public float getX() {
14365 return mLeft + getTranslationX();
14369 * Sets the visual x position of this view, in pixels. This is equivalent to setting the
14370 * {@link #setTranslationX(float) translationX} property to be the difference between
14371 * the x value passed in and the current {@link #getLeft() left} property.
14373 * @param x The visual x position of this view, in pixels.
14375 public void setX(float x) {
14376 setTranslationX(x - mLeft);
14380 * The visual y position of this view, in pixels. This is equivalent to the
14381 * {@link #setTranslationY(float) translationY} property plus the current
14382 * {@link #getTop() top} property.
14384 * @return The visual y position of this view, in pixels.
14386 @ViewDebug.ExportedProperty(category = "drawing")
14387 public float getY() {
14388 return mTop + getTranslationY();
14392 * Sets the visual y position of this view, in pixels. This is equivalent to setting the
14393 * {@link #setTranslationY(float) translationY} property to be the difference between
14394 * the y value passed in and the current {@link #getTop() top} property.
14396 * @param y The visual y position of this view, in pixels.
14398 public void setY(float y) {
14399 setTranslationY(y - mTop);
14403 * The visual z position of this view, in pixels. This is equivalent to the
14404 * {@link #setTranslationZ(float) translationZ} property plus the current
14405 * {@link #getElevation() elevation} property.
14407 * @return The visual z position of this view, in pixels.
14409 @ViewDebug.ExportedProperty(category = "drawing")
14410 public float getZ() {
14411 return getElevation() + getTranslationZ();
14415 * Sets the visual z position of this view, in pixels. This is equivalent to setting the
14416 * {@link #setTranslationZ(float) translationZ} property to be the difference between
14417 * the x value passed in and the current {@link #getElevation() elevation} property.
14419 * @param z The visual z position of this view, in pixels.
14421 public void setZ(float z) {
14422 setTranslationZ(z - getElevation());
14426 * The base elevation of this view relative to its parent, in pixels.
14428 * @return The base depth position of the view, in pixels.
14430 @ViewDebug.ExportedProperty(category = "drawing")
14431 public float getElevation() {
14432 return mRenderNode.getElevation();
14436 * Sets the base elevation of this view, in pixels.
14438 * @attr ref android.R.styleable#View_elevation
14440 public void setElevation(float elevation) {
14441 if (elevation != getElevation()) {
14442 invalidateViewProperty(true, false);
14443 mRenderNode.setElevation(elevation);
14444 invalidateViewProperty(false, true);
14446 invalidateParentIfNeededAndWasQuickRejected();
14451 * The horizontal location of this view relative to its {@link #getLeft() left} position.
14452 * This position is post-layout, in addition to wherever the object's
14453 * layout placed it.
14455 * @return The horizontal position of this view relative to its left position, in pixels.
14457 @ViewDebug.ExportedProperty(category = "drawing")
14458 public float getTranslationX() {
14459 return mRenderNode.getTranslationX();
14463 * Sets the horizontal location of this view relative to its {@link #getLeft() left} position.
14464 * This effectively positions the object post-layout, in addition to wherever the object's
14465 * layout placed it.
14467 * @param translationX The horizontal position of this view relative to its left position,
14470 * @attr ref android.R.styleable#View_translationX
14472 public void setTranslationX(float translationX) {
14473 if (translationX != getTranslationX()) {
14474 invalidateViewProperty(true, false);
14475 mRenderNode.setTranslationX(translationX);
14476 invalidateViewProperty(false, true);
14478 invalidateParentIfNeededAndWasQuickRejected();
14479 notifySubtreeAccessibilityStateChangedIfNeeded();
14484 * The vertical location of this view relative to its {@link #getTop() top} position.
14485 * This position is post-layout, in addition to wherever the object's
14486 * layout placed it.
14488 * @return The vertical position of this view relative to its top position,
14491 @ViewDebug.ExportedProperty(category = "drawing")
14492 public float getTranslationY() {
14493 return mRenderNode.getTranslationY();
14497 * Sets the vertical location of this view relative to its {@link #getTop() top} position.
14498 * This effectively positions the object post-layout, in addition to wherever the object's
14499 * layout placed it.
14501 * @param translationY The vertical position of this view relative to its top position,
14504 * @attr ref android.R.styleable#View_translationY
14506 public void setTranslationY(float translationY) {
14507 if (translationY != getTranslationY()) {
14508 invalidateViewProperty(true, false);
14509 mRenderNode.setTranslationY(translationY);
14510 invalidateViewProperty(false, true);
14512 invalidateParentIfNeededAndWasQuickRejected();
14513 notifySubtreeAccessibilityStateChangedIfNeeded();
14518 * The depth location of this view relative to its {@link #getElevation() elevation}.
14520 * @return The depth of this view relative to its elevation.
14522 @ViewDebug.ExportedProperty(category = "drawing")
14523 public float getTranslationZ() {
14524 return mRenderNode.getTranslationZ();
14528 * Sets the depth location of this view relative to its {@link #getElevation() elevation}.
14530 * @attr ref android.R.styleable#View_translationZ
14532 public void setTranslationZ(float translationZ) {
14533 if (translationZ != getTranslationZ()) {
14534 invalidateViewProperty(true, false);
14535 mRenderNode.setTranslationZ(translationZ);
14536 invalidateViewProperty(false, true);
14538 invalidateParentIfNeededAndWasQuickRejected();
14543 public void setAnimationMatrix(Matrix matrix) {
14544 invalidateViewProperty(true, false);
14545 mRenderNode.setAnimationMatrix(matrix);
14546 invalidateViewProperty(false, true);
14548 invalidateParentIfNeededAndWasQuickRejected();
14552 * Returns the current StateListAnimator if exists.
14554 * @return StateListAnimator or null if it does not exists
14555 * @see #setStateListAnimator(android.animation.StateListAnimator)
14557 public StateListAnimator getStateListAnimator() {
14558 return mStateListAnimator;
14562 * Attaches the provided StateListAnimator to this View.
14564 * Any previously attached StateListAnimator will be detached.
14566 * @param stateListAnimator The StateListAnimator to update the view
14567 * @see android.animation.StateListAnimator
14569 public void setStateListAnimator(StateListAnimator stateListAnimator) {
14570 if (mStateListAnimator == stateListAnimator) {
14573 if (mStateListAnimator != null) {
14574 mStateListAnimator.setTarget(null);
14576 mStateListAnimator = stateListAnimator;
14577 if (stateListAnimator != null) {
14578 stateListAnimator.setTarget(this);
14579 if (isAttachedToWindow()) {
14580 stateListAnimator.setState(getDrawableState());
14586 * Returns whether the Outline should be used to clip the contents of the View.
14588 * Note that this flag will only be respected if the View's Outline returns true from
14589 * {@link Outline#canClip()}.
14591 * @see #setOutlineProvider(ViewOutlineProvider)
14592 * @see #setClipToOutline(boolean)
14594 public final boolean getClipToOutline() {
14595 return mRenderNode.getClipToOutline();
14599 * Sets whether the View's Outline should be used to clip the contents of the View.
14601 * Only a single non-rectangular clip can be applied on a View at any time.
14602 * Circular clips from a {@link ViewAnimationUtils#createCircularReveal(View, int, int, float, float)
14603 * circular reveal} animation take priority over Outline clipping, and
14604 * child Outline clipping takes priority over Outline clipping done by a
14607 * Note that this flag will only be respected if the View's Outline returns true from
14608 * {@link Outline#canClip()}.
14610 * @see #setOutlineProvider(ViewOutlineProvider)
14611 * @see #getClipToOutline()
14613 public void setClipToOutline(boolean clipToOutline) {
14615 if (getClipToOutline() != clipToOutline) {
14616 mRenderNode.setClipToOutline(clipToOutline);
14620 // correspond to the enum values of View_outlineProvider
14621 private static final int PROVIDER_BACKGROUND = 0;
14622 private static final int PROVIDER_NONE = 1;
14623 private static final int PROVIDER_BOUNDS = 2;
14624 private static final int PROVIDER_PADDED_BOUNDS = 3;
14625 private void setOutlineProviderFromAttribute(int providerInt) {
14626 switch (providerInt) {
14627 case PROVIDER_BACKGROUND:
14628 setOutlineProvider(ViewOutlineProvider.BACKGROUND);
14630 case PROVIDER_NONE:
14631 setOutlineProvider(null);
14633 case PROVIDER_BOUNDS:
14634 setOutlineProvider(ViewOutlineProvider.BOUNDS);
14636 case PROVIDER_PADDED_BOUNDS:
14637 setOutlineProvider(ViewOutlineProvider.PADDED_BOUNDS);
14643 * Sets the {@link ViewOutlineProvider} of the view, which generates the Outline that defines
14644 * the shape of the shadow it casts, and enables outline clipping.
14646 * The default ViewOutlineProvider, {@link ViewOutlineProvider#BACKGROUND}, queries the Outline
14647 * from the View's background drawable, via {@link Drawable#getOutline(Outline)}. Changing the
14648 * outline provider with this method allows this behavior to be overridden.
14650 * If the ViewOutlineProvider is null, if querying it for an outline returns false,
14651 * or if the produced Outline is {@link Outline#isEmpty()}, shadows will not be cast.
14653 * Only outlines that return true from {@link Outline#canClip()} may be used for clipping.
14655 * @see #setClipToOutline(boolean)
14656 * @see #getClipToOutline()
14657 * @see #getOutlineProvider()
14659 public void setOutlineProvider(ViewOutlineProvider provider) {
14660 mOutlineProvider = provider;
14661 invalidateOutline();
14665 * Returns the current {@link ViewOutlineProvider} of the view, which generates the Outline
14666 * that defines the shape of the shadow it casts, and enables outline clipping.
14668 * @see #setOutlineProvider(ViewOutlineProvider)
14670 public ViewOutlineProvider getOutlineProvider() {
14671 return mOutlineProvider;
14675 * Called to rebuild this View's Outline from its {@link ViewOutlineProvider outline provider}
14677 * @see #setOutlineProvider(ViewOutlineProvider)
14679 public void invalidateOutline() {
14682 notifySubtreeAccessibilityStateChangedIfNeeded();
14683 invalidateViewProperty(false, false);
14687 * Internal version of {@link #invalidateOutline()} which invalidates the
14688 * outline without invalidating the view itself. This is intended to be called from
14689 * within methods in the View class itself which are the result of the view being
14690 * invalidated already. For example, when we are drawing the background of a View,
14691 * we invalidate the outline in case it changed in the meantime, but we do not
14692 * need to invalidate the view because we're already drawing the background as part
14693 * of drawing the view in response to an earlier invalidation of the view.
14695 private void rebuildOutline() {
14696 // Unattached views ignore this signal, and outline is recomputed in onAttachedToWindow()
14697 if (mAttachInfo == null) return;
14699 if (mOutlineProvider == null) {
14700 // no provider, remove outline
14701 mRenderNode.setOutline(null);
14703 final Outline outline = mAttachInfo.mTmpOutline;
14704 outline.setEmpty();
14705 outline.setAlpha(1.0f);
14707 mOutlineProvider.getOutline(this, outline);
14708 mRenderNode.setOutline(outline);
14713 * HierarchyViewer only
14717 @ViewDebug.ExportedProperty(category = "drawing")
14718 public boolean hasShadow() {
14719 return mRenderNode.hasShadow();
14724 public void setRevealClip(boolean shouldClip, float x, float y, float radius) {
14725 mRenderNode.setRevealClip(shouldClip, x, y, radius);
14726 invalidateViewProperty(false, false);
14730 * Hit rectangle in parent's coordinates
14732 * @param outRect The hit rectangle of the view.
14734 public void getHitRect(Rect outRect) {
14735 if (hasIdentityMatrix() || mAttachInfo == null) {
14736 outRect.set(mLeft, mTop, mRight, mBottom);
14738 final RectF tmpRect = mAttachInfo.mTmpTransformRect;
14739 tmpRect.set(0, 0, getWidth(), getHeight());
14740 getMatrix().mapRect(tmpRect); // TODO: mRenderNode.mapRect(tmpRect)
14741 outRect.set((int) tmpRect.left + mLeft, (int) tmpRect.top + mTop,
14742 (int) tmpRect.right + mLeft, (int) tmpRect.bottom + mTop);
14747 * Determines whether the given point, in local coordinates is inside the view.
14749 /*package*/ final boolean pointInView(float localX, float localY) {
14750 return pointInView(localX, localY, 0);
14754 * Utility method to determine whether the given point, in local coordinates,
14755 * is inside the view, where the area of the view is expanded by the slop factor.
14756 * This method is called while processing touch-move events to determine if the event
14757 * is still within the view.
14761 public boolean pointInView(float localX, float localY, float slop) {
14762 return localX >= -slop && localY >= -slop && localX < ((mRight - mLeft) + slop) &&
14763 localY < ((mBottom - mTop) + slop);
14767 * When a view has focus and the user navigates away from it, the next view is searched for
14768 * starting from the rectangle filled in by this method.
14770 * By default, the rectangle is the {@link #getDrawingRect(android.graphics.Rect)})
14771 * of the view. However, if your view maintains some idea of internal selection,
14772 * such as a cursor, or a selected row or column, you should override this method and
14773 * fill in a more specific rectangle.
14775 * @param r The rectangle to fill in, in this view's coordinates.
14777 public void getFocusedRect(Rect r) {
14782 * If some part of this view is not clipped by any of its parents, then
14783 * return that area in r in global (root) coordinates. To convert r to local
14784 * coordinates (without taking possible View rotations into account), offset
14785 * it by -globalOffset (e.g. r.offset(-globalOffset.x, -globalOffset.y)).
14786 * If the view is completely clipped or translated out, return false.
14788 * @param r If true is returned, r holds the global coordinates of the
14789 * visible portion of this view.
14790 * @param globalOffset If true is returned, globalOffset holds the dx,dy
14791 * between this view and its root. globalOffet may be null.
14792 * @return true if r is non-empty (i.e. part of the view is visible at the
14795 public boolean getGlobalVisibleRect(Rect r, Point globalOffset) {
14796 int width = mRight - mLeft;
14797 int height = mBottom - mTop;
14798 if (width > 0 && height > 0) {
14799 r.set(0, 0, width, height);
14800 if (globalOffset != null) {
14801 globalOffset.set(-mScrollX, -mScrollY);
14803 return mParent == null || mParent.getChildVisibleRect(this, r, globalOffset);
14808 public final boolean getGlobalVisibleRect(Rect r) {
14809 return getGlobalVisibleRect(r, null);
14812 public final boolean getLocalVisibleRect(Rect r) {
14813 final Point offset = mAttachInfo != null ? mAttachInfo.mPoint : new Point();
14814 if (getGlobalVisibleRect(r, offset)) {
14815 r.offset(-offset.x, -offset.y); // make r local
14822 * Offset this view's vertical location by the specified number of pixels.
14824 * @param offset the number of pixels to offset the view by
14826 public void offsetTopAndBottom(int offset) {
14828 final boolean matrixIsIdentity = hasIdentityMatrix();
14829 if (matrixIsIdentity) {
14830 if (isHardwareAccelerated()) {
14831 invalidateViewProperty(false, false);
14833 final ViewParent p = mParent;
14834 if (p != null && mAttachInfo != null) {
14835 final Rect r = mAttachInfo.mTmpInvalRect;
14840 minTop = mTop + offset;
14841 maxBottom = mBottom;
14845 maxBottom = mBottom + offset;
14848 r.set(0, yLoc, mRight - mLeft, maxBottom - minTop);
14849 p.invalidateChild(this, r);
14853 invalidateViewProperty(false, false);
14858 mRenderNode.offsetTopAndBottom(offset);
14859 if (isHardwareAccelerated()) {
14860 invalidateViewProperty(false, false);
14861 invalidateParentIfNeededAndWasQuickRejected();
14863 if (!matrixIsIdentity) {
14864 invalidateViewProperty(false, true);
14866 invalidateParentIfNeeded();
14868 notifySubtreeAccessibilityStateChangedIfNeeded();
14873 * Offset this view's horizontal location by the specified amount of pixels.
14875 * @param offset the number of pixels to offset the view by
14877 public void offsetLeftAndRight(int offset) {
14879 final boolean matrixIsIdentity = hasIdentityMatrix();
14880 if (matrixIsIdentity) {
14881 if (isHardwareAccelerated()) {
14882 invalidateViewProperty(false, false);
14884 final ViewParent p = mParent;
14885 if (p != null && mAttachInfo != null) {
14886 final Rect r = mAttachInfo.mTmpInvalRect;
14890 minLeft = mLeft + offset;
14894 maxRight = mRight + offset;
14896 r.set(0, 0, maxRight - minLeft, mBottom - mTop);
14897 p.invalidateChild(this, r);
14901 invalidateViewProperty(false, false);
14906 mRenderNode.offsetLeftAndRight(offset);
14907 if (isHardwareAccelerated()) {
14908 invalidateViewProperty(false, false);
14909 invalidateParentIfNeededAndWasQuickRejected();
14911 if (!matrixIsIdentity) {
14912 invalidateViewProperty(false, true);
14914 invalidateParentIfNeeded();
14916 notifySubtreeAccessibilityStateChangedIfNeeded();
14921 * Get the LayoutParams associated with this view. All views should have
14922 * layout parameters. These supply parameters to the <i>parent</i> of this
14923 * view specifying how it should be arranged. There are many subclasses of
14924 * ViewGroup.LayoutParams, and these correspond to the different subclasses
14925 * of ViewGroup that are responsible for arranging their children.
14927 * This method may return null if this View is not attached to a parent
14928 * ViewGroup or {@link #setLayoutParams(android.view.ViewGroup.LayoutParams)}
14929 * was not invoked successfully. When a View is attached to a parent
14930 * ViewGroup, this method must not return null.
14932 * @return The LayoutParams associated with this view, or null if no
14933 * parameters have been set yet
14935 @ViewDebug.ExportedProperty(deepExport = true, prefix = "layout_")
14936 public ViewGroup.LayoutParams getLayoutParams() {
14937 return mLayoutParams;
14941 * Set the layout parameters associated with this view. These supply
14942 * parameters to the <i>parent</i> of this view specifying how it should be
14943 * arranged. There are many subclasses of ViewGroup.LayoutParams, and these
14944 * correspond to the different subclasses of ViewGroup that are responsible
14945 * for arranging their children.
14947 * @param params The layout parameters for this view, cannot be null
14949 public void setLayoutParams(ViewGroup.LayoutParams params) {
14950 if (params == null) {
14951 throw new NullPointerException("Layout parameters cannot be null");
14953 mLayoutParams = params;
14954 resolveLayoutParams();
14955 if (mParent instanceof ViewGroup) {
14956 ((ViewGroup) mParent).onSetLayoutParams(this, params);
14962 * Resolve the layout parameters depending on the resolved layout direction
14966 public void resolveLayoutParams() {
14967 if (mLayoutParams != null) {
14968 mLayoutParams.resolveLayoutDirection(getLayoutDirection());
14973 * Set the scrolled position of your view. This will cause a call to
14974 * {@link #onScrollChanged(int, int, int, int)} and the view will be
14976 * @param x the x position to scroll to
14977 * @param y the y position to scroll to
14979 public void scrollTo(int x, int y) {
14980 if (mScrollX != x || mScrollY != y) {
14981 int oldX = mScrollX;
14982 int oldY = mScrollY;
14985 invalidateParentCaches();
14986 onScrollChanged(mScrollX, mScrollY, oldX, oldY);
14987 if (!awakenScrollBars()) {
14988 postInvalidateOnAnimation();
14994 * Move the scrolled position of your view. This will cause a call to
14995 * {@link #onScrollChanged(int, int, int, int)} and the view will be
14997 * @param x the amount of pixels to scroll by horizontally
14998 * @param y the amount of pixels to scroll by vertically
15000 public void scrollBy(int x, int y) {
15001 scrollTo(mScrollX + x, mScrollY + y);
15005 * <p>Trigger the scrollbars to draw. When invoked this method starts an
15006 * animation to fade the scrollbars out after a default delay. If a subclass
15007 * provides animated scrolling, the start delay should equal the duration
15008 * of the scrolling animation.</p>
15010 * <p>The animation starts only if at least one of the scrollbars is
15011 * enabled, as specified by {@link #isHorizontalScrollBarEnabled()} and
15012 * {@link #isVerticalScrollBarEnabled()}. When the animation is started,
15013 * this method returns true, and false otherwise. If the animation is
15014 * started, this method calls {@link #invalidate()}; in that case the
15015 * caller should not call {@link #invalidate()}.</p>
15017 * <p>This method should be invoked every time a subclass directly updates
15018 * the scroll parameters.</p>
15020 * <p>This method is automatically invoked by {@link #scrollBy(int, int)}
15021 * and {@link #scrollTo(int, int)}.</p>
15023 * @return true if the animation is played, false otherwise
15025 * @see #awakenScrollBars(int)
15026 * @see #scrollBy(int, int)
15027 * @see #scrollTo(int, int)
15028 * @see #isHorizontalScrollBarEnabled()
15029 * @see #isVerticalScrollBarEnabled()
15030 * @see #setHorizontalScrollBarEnabled(boolean)
15031 * @see #setVerticalScrollBarEnabled(boolean)
15033 protected boolean awakenScrollBars() {
15034 return mScrollCache != null &&
15035 awakenScrollBars(mScrollCache.scrollBarDefaultDelayBeforeFade, true);
15039 * Trigger the scrollbars to draw.
15040 * This method differs from awakenScrollBars() only in its default duration.
15041 * initialAwakenScrollBars() will show the scroll bars for longer than
15042 * usual to give the user more of a chance to notice them.
15044 * @return true if the animation is played, false otherwise.
15046 private boolean initialAwakenScrollBars() {
15047 return mScrollCache != null &&
15048 awakenScrollBars(mScrollCache.scrollBarDefaultDelayBeforeFade * 4, true);
15053 * Trigger the scrollbars to draw. When invoked this method starts an
15054 * animation to fade the scrollbars out after a fixed delay. If a subclass
15055 * provides animated scrolling, the start delay should equal the duration of
15056 * the scrolling animation.
15060 * The animation starts only if at least one of the scrollbars is enabled,
15061 * as specified by {@link #isHorizontalScrollBarEnabled()} and
15062 * {@link #isVerticalScrollBarEnabled()}. When the animation is started,
15063 * this method returns true, and false otherwise. If the animation is
15064 * started, this method calls {@link #invalidate()}; in that case the caller
15065 * should not call {@link #invalidate()}.
15069 * This method should be invoked every time a subclass directly updates the
15070 * scroll parameters.
15073 * @param startDelay the delay, in milliseconds, after which the animation
15074 * should start; when the delay is 0, the animation starts
15076 * @return true if the animation is played, false otherwise
15078 * @see #scrollBy(int, int)
15079 * @see #scrollTo(int, int)
15080 * @see #isHorizontalScrollBarEnabled()
15081 * @see #isVerticalScrollBarEnabled()
15082 * @see #setHorizontalScrollBarEnabled(boolean)
15083 * @see #setVerticalScrollBarEnabled(boolean)
15085 protected boolean awakenScrollBars(int startDelay) {
15086 return awakenScrollBars(startDelay, true);
15091 * Trigger the scrollbars to draw. When invoked this method starts an
15092 * animation to fade the scrollbars out after a fixed delay. If a subclass
15093 * provides animated scrolling, the start delay should equal the duration of
15094 * the scrolling animation.
15098 * The animation starts only if at least one of the scrollbars is enabled,
15099 * as specified by {@link #isHorizontalScrollBarEnabled()} and
15100 * {@link #isVerticalScrollBarEnabled()}. When the animation is started,
15101 * this method returns true, and false otherwise. If the animation is
15102 * started, this method calls {@link #invalidate()} if the invalidate parameter
15103 * is set to true; in that case the caller
15104 * should not call {@link #invalidate()}.
15108 * This method should be invoked every time a subclass directly updates the
15109 * scroll parameters.
15112 * @param startDelay the delay, in milliseconds, after which the animation
15113 * should start; when the delay is 0, the animation starts
15116 * @param invalidate Whether this method should call invalidate
15118 * @return true if the animation is played, false otherwise
15120 * @see #scrollBy(int, int)
15121 * @see #scrollTo(int, int)
15122 * @see #isHorizontalScrollBarEnabled()
15123 * @see #isVerticalScrollBarEnabled()
15124 * @see #setHorizontalScrollBarEnabled(boolean)
15125 * @see #setVerticalScrollBarEnabled(boolean)
15127 protected boolean awakenScrollBars(int startDelay, boolean invalidate) {
15128 final ScrollabilityCache scrollCache = mScrollCache;
15130 if (scrollCache == null || !scrollCache.fadeScrollBars) {
15134 if (scrollCache.scrollBar == null) {
15135 scrollCache.scrollBar = new ScrollBarDrawable();
15136 scrollCache.scrollBar.setState(getDrawableState());
15137 scrollCache.scrollBar.setCallback(this);
15140 if (isHorizontalScrollBarEnabled() || isVerticalScrollBarEnabled()) {
15143 // Invalidate to show the scrollbars
15144 postInvalidateOnAnimation();
15147 if (scrollCache.state == ScrollabilityCache.OFF) {
15148 // FIXME: this is copied from WindowManagerService.
15149 // We should get this value from the system when it
15150 // is possible to do so.
15151 final int KEY_REPEAT_FIRST_DELAY = 750;
15152 startDelay = Math.max(KEY_REPEAT_FIRST_DELAY, startDelay);
15155 // Tell mScrollCache when we should start fading. This may
15156 // extend the fade start time if one was already scheduled
15157 long fadeStartTime = AnimationUtils.currentAnimationTimeMillis() + startDelay;
15158 scrollCache.fadeStartTime = fadeStartTime;
15159 scrollCache.state = ScrollabilityCache.ON;
15161 // Schedule our fader to run, unscheduling any old ones first
15162 if (mAttachInfo != null) {
15163 mAttachInfo.mHandler.removeCallbacks(scrollCache);
15164 mAttachInfo.mHandler.postAtTime(scrollCache, fadeStartTime);
15174 * Do not invalidate views which are not visible and which are not running an animation. They
15175 * will not get drawn and they should not set dirty flags as if they will be drawn
15177 private boolean skipInvalidate() {
15178 return (mViewFlags & VISIBILITY_MASK) != VISIBLE && mCurrentAnimation == null &&
15179 (!(mParent instanceof ViewGroup) ||
15180 !((ViewGroup) mParent).isViewTransitioning(this));
15184 * Mark the area defined by dirty as needing to be drawn. If the view is
15185 * visible, {@link #onDraw(android.graphics.Canvas)} will be called at some
15186 * point in the future.
15188 * This must be called from a UI thread. To call from a non-UI thread, call
15189 * {@link #postInvalidate()}.
15191 * <b>WARNING:</b> In API 19 and below, this method may be destructive to
15194 * @param dirty the rectangle representing the bounds of the dirty region
15196 public void invalidate(Rect dirty) {
15197 final int scrollX = mScrollX;
15198 final int scrollY = mScrollY;
15199 invalidateInternal(dirty.left - scrollX, dirty.top - scrollY,
15200 dirty.right - scrollX, dirty.bottom - scrollY, true, false);
15204 * Mark the area defined by the rect (l,t,r,b) as needing to be drawn. The
15205 * coordinates of the dirty rect are relative to the view. If the view is
15206 * visible, {@link #onDraw(android.graphics.Canvas)} will be called at some
15207 * point in the future.
15209 * This must be called from a UI thread. To call from a non-UI thread, call
15210 * {@link #postInvalidate()}.
15212 * @param l the left position of the dirty region
15213 * @param t the top position of the dirty region
15214 * @param r the right position of the dirty region
15215 * @param b the bottom position of the dirty region
15217 public void invalidate(int l, int t, int r, int b) {
15218 final int scrollX = mScrollX;
15219 final int scrollY = mScrollY;
15220 invalidateInternal(l - scrollX, t - scrollY, r - scrollX, b - scrollY, true, false);
15224 * Invalidate the whole view. If the view is visible,
15225 * {@link #onDraw(android.graphics.Canvas)} will be called at some point in
15228 * This must be called from a UI thread. To call from a non-UI thread, call
15229 * {@link #postInvalidate()}.
15231 public void invalidate() {
15236 * This is where the invalidate() work actually happens. A full invalidate()
15237 * causes the drawing cache to be invalidated, but this function can be
15238 * called with invalidateCache set to false to skip that invalidation step
15239 * for cases that do not need it (for example, a component that remains at
15240 * the same dimensions with the same content).
15242 * @param invalidateCache Whether the drawing cache for this view should be
15243 * invalidated as well. This is usually true for a full
15244 * invalidate, but may be set to false if the View's contents or
15245 * dimensions have not changed.
15248 public void invalidate(boolean invalidateCache) {
15249 invalidateInternal(0, 0, mRight - mLeft, mBottom - mTop, invalidateCache, true);
15252 void invalidateInternal(int l, int t, int r, int b, boolean invalidateCache,
15253 boolean fullInvalidate) {
15254 if (mGhostView != null) {
15255 mGhostView.invalidate(true);
15259 if (skipInvalidate()) {
15263 if ((mPrivateFlags & (PFLAG_DRAWN | PFLAG_HAS_BOUNDS)) == (PFLAG_DRAWN | PFLAG_HAS_BOUNDS)
15264 || (invalidateCache && (mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == PFLAG_DRAWING_CACHE_VALID)
15265 || (mPrivateFlags & PFLAG_INVALIDATED) != PFLAG_INVALIDATED
15266 || (fullInvalidate && isOpaque() != mLastIsOpaque)) {
15267 if (fullInvalidate) {
15268 mLastIsOpaque = isOpaque();
15269 mPrivateFlags &= ~PFLAG_DRAWN;
15272 mPrivateFlags |= PFLAG_DIRTY;
15274 if (invalidateCache) {
15275 mPrivateFlags |= PFLAG_INVALIDATED;
15276 mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID;
15279 // Propagate the damage rectangle to the parent view.
15280 final AttachInfo ai = mAttachInfo;
15281 final ViewParent p = mParent;
15282 if (p != null && ai != null && l < r && t < b) {
15283 final Rect damage = ai.mTmpInvalRect;
15284 damage.set(l, t, r, b);
15285 p.invalidateChild(this, damage);
15288 // Damage the entire projection receiver, if necessary.
15289 if (mBackground != null && mBackground.isProjected()) {
15290 final View receiver = getProjectionReceiver();
15291 if (receiver != null) {
15292 receiver.damageInParent();
15299 * @return this view's projection receiver, or {@code null} if none exists
15301 private View getProjectionReceiver() {
15302 ViewParent p = getParent();
15303 while (p != null && p instanceof View) {
15304 final View v = (View) p;
15305 if (v.isProjectionReceiver()) {
15315 * @return whether the view is a projection receiver
15317 private boolean isProjectionReceiver() {
15318 return mBackground != null;
15322 * Quick invalidation for View property changes (alpha, translationXY, etc.). We don't want to
15323 * set any flags or handle all of the cases handled by the default invalidation methods.
15324 * Instead, we just want to schedule a traversal in ViewRootImpl with the appropriate
15325 * dirty rect. This method calls into fast invalidation methods in ViewGroup that
15326 * walk up the hierarchy, transforming the dirty rect as necessary.
15328 * The method also handles normal invalidation logic if display list properties are not
15329 * being used in this view. The invalidateParent and forceRedraw flags are used by that
15330 * backup approach, to handle these cases used in the various property-setting methods.
15332 * @param invalidateParent Force a call to invalidateParentCaches() if display list properties
15333 * are not being used in this view
15334 * @param forceRedraw Mark the view as DRAWN to force the invalidation to propagate, if display
15335 * list properties are not being used in this view
15337 void invalidateViewProperty(boolean invalidateParent, boolean forceRedraw) {
15338 if (!isHardwareAccelerated()
15339 || !mRenderNode.isValid()
15340 || (mPrivateFlags & PFLAG_DRAW_ANIMATION) != 0) {
15341 if (invalidateParent) {
15342 invalidateParentCaches();
15345 mPrivateFlags |= PFLAG_DRAWN; // force another invalidation with the new orientation
15354 * Tells the parent view to damage this view's bounds.
15358 protected void damageInParent() {
15359 if (mParent != null && mAttachInfo != null) {
15360 mParent.onDescendantInvalidated(this, this);
15365 * Utility method to transform a given Rect by the current matrix of this view.
15367 void transformRect(final Rect rect) {
15368 if (!getMatrix().isIdentity()) {
15369 RectF boundingRect = mAttachInfo.mTmpTransformRect;
15370 boundingRect.set(rect);
15371 getMatrix().mapRect(boundingRect);
15372 rect.set((int) Math.floor(boundingRect.left),
15373 (int) Math.floor(boundingRect.top),
15374 (int) Math.ceil(boundingRect.right),
15375 (int) Math.ceil(boundingRect.bottom));
15380 * Used to indicate that the parent of this view should clear its caches. This functionality
15381 * is used to force the parent to rebuild its display list (when hardware-accelerated),
15382 * which is necessary when various parent-managed properties of the view change, such as
15383 * alpha, translationX/Y, scrollX/Y, scaleX/Y, and rotation/X/Y. This method only
15384 * clears the parent caches and does not causes an invalidate event.
15388 protected void invalidateParentCaches() {
15389 if (mParent instanceof View) {
15390 ((View) mParent).mPrivateFlags |= PFLAG_INVALIDATED;
15395 * Used to indicate that the parent of this view should be invalidated. This functionality
15396 * is used to force the parent to rebuild its display list (when hardware-accelerated),
15397 * which is necessary when various parent-managed properties of the view change, such as
15398 * alpha, translationX/Y, scrollX/Y, scaleX/Y, and rotation/X/Y. This method will propagate
15399 * an invalidation event to the parent.
15403 protected void invalidateParentIfNeeded() {
15404 if (isHardwareAccelerated() && mParent instanceof View) {
15405 ((View) mParent).invalidate(true);
15412 protected void invalidateParentIfNeededAndWasQuickRejected() {
15413 if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) != 0) {
15414 // View was rejected last time it was drawn by its parent; this may have changed
15415 invalidateParentIfNeeded();
15420 * Indicates whether this View is opaque. An opaque View guarantees that it will
15421 * draw all the pixels overlapping its bounds using a fully opaque color.
15423 * Subclasses of View should override this method whenever possible to indicate
15424 * whether an instance is opaque. Opaque Views are treated in a special way by
15425 * the View hierarchy, possibly allowing it to perform optimizations during
15426 * invalidate/draw passes.
15428 * @return True if this View is guaranteed to be fully opaque, false otherwise.
15430 @ViewDebug.ExportedProperty(category = "drawing")
15431 public boolean isOpaque() {
15432 return (mPrivateFlags & PFLAG_OPAQUE_MASK) == PFLAG_OPAQUE_MASK &&
15433 getFinalAlpha() >= 1.0f;
15439 protected void computeOpaqueFlags() {
15441 // - Has a background
15442 // - Background is opaque
15443 // - Doesn't have scrollbars or scrollbars overlay
15445 if (mBackground != null && mBackground.getOpacity() == PixelFormat.OPAQUE) {
15446 mPrivateFlags |= PFLAG_OPAQUE_BACKGROUND;
15448 mPrivateFlags &= ~PFLAG_OPAQUE_BACKGROUND;
15451 final int flags = mViewFlags;
15452 if (((flags & SCROLLBARS_VERTICAL) == 0 && (flags & SCROLLBARS_HORIZONTAL) == 0) ||
15453 (flags & SCROLLBARS_STYLE_MASK) == SCROLLBARS_INSIDE_OVERLAY ||
15454 (flags & SCROLLBARS_STYLE_MASK) == SCROLLBARS_OUTSIDE_OVERLAY) {
15455 mPrivateFlags |= PFLAG_OPAQUE_SCROLLBARS;
15457 mPrivateFlags &= ~PFLAG_OPAQUE_SCROLLBARS;
15464 protected boolean hasOpaqueScrollbars() {
15465 return (mPrivateFlags & PFLAG_OPAQUE_SCROLLBARS) == PFLAG_OPAQUE_SCROLLBARS;
15469 * @return A handler associated with the thread running the View. This
15470 * handler can be used to pump events in the UI events queue.
15472 public Handler getHandler() {
15473 final AttachInfo attachInfo = mAttachInfo;
15474 if (attachInfo != null) {
15475 return attachInfo.mHandler;
15481 * Returns the queue of runnable for this view.
15483 * @return the queue of runnables for this view
15485 private HandlerActionQueue getRunQueue() {
15486 if (mRunQueue == null) {
15487 mRunQueue = new HandlerActionQueue();
15493 * Gets the view root associated with the View.
15494 * @return The view root, or null if none.
15497 public ViewRootImpl getViewRootImpl() {
15498 if (mAttachInfo != null) {
15499 return mAttachInfo.mViewRootImpl;
15507 public ThreadedRenderer getThreadedRenderer() {
15508 return mAttachInfo != null ? mAttachInfo.mThreadedRenderer : null;
15512 * <p>Causes the Runnable to be added to the message queue.
15513 * The runnable will be run on the user interface thread.</p>
15515 * @param action The Runnable that will be executed.
15517 * @return Returns true if the Runnable was successfully placed in to the
15518 * message queue. Returns false on failure, usually because the
15519 * looper processing the message queue is exiting.
15521 * @see #postDelayed
15522 * @see #removeCallbacks
15524 public boolean post(Runnable action) {
15525 final AttachInfo attachInfo = mAttachInfo;
15526 if (attachInfo != null) {
15527 return attachInfo.mHandler.post(action);
15530 // Postpone the runnable until we know on which thread it needs to run.
15531 // Assume that the runnable will be successfully placed after attach.
15532 getRunQueue().post(action);
15537 * <p>Causes the Runnable to be added to the message queue, to be run
15538 * after the specified amount of time elapses.
15539 * The runnable will be run on the user interface thread.</p>
15541 * @param action The Runnable that will be executed.
15542 * @param delayMillis The delay (in milliseconds) until the Runnable
15543 * will be executed.
15545 * @return true if the Runnable was successfully placed in to the
15546 * message queue. Returns false on failure, usually because the
15547 * looper processing the message queue is exiting. Note that a
15548 * result of true does not mean the Runnable will be processed --
15549 * if the looper is quit before the delivery time of the message
15550 * occurs then the message will be dropped.
15553 * @see #removeCallbacks
15555 public boolean postDelayed(Runnable action, long delayMillis) {
15556 final AttachInfo attachInfo = mAttachInfo;
15557 if (attachInfo != null) {
15558 return attachInfo.mHandler.postDelayed(action, delayMillis);
15561 // Postpone the runnable until we know on which thread it needs to run.
15562 // Assume that the runnable will be successfully placed after attach.
15563 getRunQueue().postDelayed(action, delayMillis);
15568 * <p>Causes the Runnable to execute on the next animation time step.
15569 * The runnable will be run on the user interface thread.</p>
15571 * @param action The Runnable that will be executed.
15573 * @see #postOnAnimationDelayed
15574 * @see #removeCallbacks
15576 public void postOnAnimation(Runnable action) {
15577 final AttachInfo attachInfo = mAttachInfo;
15578 if (attachInfo != null) {
15579 attachInfo.mViewRootImpl.mChoreographer.postCallback(
15580 Choreographer.CALLBACK_ANIMATION, action, null);
15582 // Postpone the runnable until we know
15583 // on which thread it needs to run.
15584 getRunQueue().post(action);
15589 * <p>Causes the Runnable to execute on the next animation time step,
15590 * after the specified amount of time elapses.
15591 * The runnable will be run on the user interface thread.</p>
15593 * @param action The Runnable that will be executed.
15594 * @param delayMillis The delay (in milliseconds) until the Runnable
15595 * will be executed.
15597 * @see #postOnAnimation
15598 * @see #removeCallbacks
15600 public void postOnAnimationDelayed(Runnable action, long delayMillis) {
15601 final AttachInfo attachInfo = mAttachInfo;
15602 if (attachInfo != null) {
15603 attachInfo.mViewRootImpl.mChoreographer.postCallbackDelayed(
15604 Choreographer.CALLBACK_ANIMATION, action, null, delayMillis);
15606 // Postpone the runnable until we know
15607 // on which thread it needs to run.
15608 getRunQueue().postDelayed(action, delayMillis);
15613 * <p>Removes the specified Runnable from the message queue.</p>
15615 * @param action The Runnable to remove from the message handling queue
15617 * @return true if this view could ask the Handler to remove the Runnable,
15618 * false otherwise. When the returned value is true, the Runnable
15619 * may or may not have been actually removed from the message queue
15620 * (for instance, if the Runnable was not in the queue already.)
15623 * @see #postDelayed
15624 * @see #postOnAnimation
15625 * @see #postOnAnimationDelayed
15627 public boolean removeCallbacks(Runnable action) {
15628 if (action != null) {
15629 final AttachInfo attachInfo = mAttachInfo;
15630 if (attachInfo != null) {
15631 attachInfo.mHandler.removeCallbacks(action);
15632 attachInfo.mViewRootImpl.mChoreographer.removeCallbacks(
15633 Choreographer.CALLBACK_ANIMATION, action, null);
15635 getRunQueue().removeCallbacks(action);
15641 * <p>Cause an invalidate to happen on a subsequent cycle through the event loop.
15642 * Use this to invalidate the View from a non-UI thread.</p>
15644 * <p>This method can be invoked from outside of the UI thread
15645 * only when this View is attached to a window.</p>
15647 * @see #invalidate()
15648 * @see #postInvalidateDelayed(long)
15650 public void postInvalidate() {
15651 postInvalidateDelayed(0);
15655 * <p>Cause an invalidate of the specified area to happen on a subsequent cycle
15656 * through the event loop. Use this to invalidate the View from a non-UI thread.</p>
15658 * <p>This method can be invoked from outside of the UI thread
15659 * only when this View is attached to a window.</p>
15661 * @param left The left coordinate of the rectangle to invalidate.
15662 * @param top The top coordinate of the rectangle to invalidate.
15663 * @param right The right coordinate of the rectangle to invalidate.
15664 * @param bottom The bottom coordinate of the rectangle to invalidate.
15666 * @see #invalidate(int, int, int, int)
15667 * @see #invalidate(Rect)
15668 * @see #postInvalidateDelayed(long, int, int, int, int)
15670 public void postInvalidate(int left, int top, int right, int bottom) {
15671 postInvalidateDelayed(0, left, top, right, bottom);
15675 * <p>Cause an invalidate to happen on a subsequent cycle through the event
15676 * loop. Waits for the specified amount of time.</p>
15678 * <p>This method can be invoked from outside of the UI thread
15679 * only when this View is attached to a window.</p>
15681 * @param delayMilliseconds the duration in milliseconds to delay the
15684 * @see #invalidate()
15685 * @see #postInvalidate()
15687 public void postInvalidateDelayed(long delayMilliseconds) {
15688 // We try only with the AttachInfo because there's no point in invalidating
15689 // if we are not attached to our window
15690 final AttachInfo attachInfo = mAttachInfo;
15691 if (attachInfo != null) {
15692 attachInfo.mViewRootImpl.dispatchInvalidateDelayed(this, delayMilliseconds);
15697 * <p>Cause an invalidate of the specified area to happen on a subsequent cycle
15698 * through the event loop. Waits for the specified amount of time.</p>
15700 * <p>This method can be invoked from outside of the UI thread
15701 * only when this View is attached to a window.</p>
15703 * @param delayMilliseconds the duration in milliseconds to delay the
15705 * @param left The left coordinate of the rectangle to invalidate.
15706 * @param top The top coordinate of the rectangle to invalidate.
15707 * @param right The right coordinate of the rectangle to invalidate.
15708 * @param bottom The bottom coordinate of the rectangle to invalidate.
15710 * @see #invalidate(int, int, int, int)
15711 * @see #invalidate(Rect)
15712 * @see #postInvalidate(int, int, int, int)
15714 public void postInvalidateDelayed(long delayMilliseconds, int left, int top,
15715 int right, int bottom) {
15717 // We try only with the AttachInfo because there's no point in invalidating
15718 // if we are not attached to our window
15719 final AttachInfo attachInfo = mAttachInfo;
15720 if (attachInfo != null) {
15721 final AttachInfo.InvalidateInfo info = AttachInfo.InvalidateInfo.obtain();
15722 info.target = this;
15725 info.right = right;
15726 info.bottom = bottom;
15728 attachInfo.mViewRootImpl.dispatchInvalidateRectDelayed(info, delayMilliseconds);
15733 * <p>Cause an invalidate to happen on the next animation time step, typically the
15734 * next display frame.</p>
15736 * <p>This method can be invoked from outside of the UI thread
15737 * only when this View is attached to a window.</p>
15739 * @see #invalidate()
15741 public void postInvalidateOnAnimation() {
15742 // We try only with the AttachInfo because there's no point in invalidating
15743 // if we are not attached to our window
15744 final AttachInfo attachInfo = mAttachInfo;
15745 if (attachInfo != null) {
15746 attachInfo.mViewRootImpl.dispatchInvalidateOnAnimation(this);
15751 * <p>Cause an invalidate of the specified area to happen on the next animation
15752 * time step, typically the next display frame.</p>
15754 * <p>This method can be invoked from outside of the UI thread
15755 * only when this View is attached to a window.</p>
15757 * @param left The left coordinate of the rectangle to invalidate.
15758 * @param top The top coordinate of the rectangle to invalidate.
15759 * @param right The right coordinate of the rectangle to invalidate.
15760 * @param bottom The bottom coordinate of the rectangle to invalidate.
15762 * @see #invalidate(int, int, int, int)
15763 * @see #invalidate(Rect)
15765 public void postInvalidateOnAnimation(int left, int top, int right, int bottom) {
15766 // We try only with the AttachInfo because there's no point in invalidating
15767 // if we are not attached to our window
15768 final AttachInfo attachInfo = mAttachInfo;
15769 if (attachInfo != null) {
15770 final AttachInfo.InvalidateInfo info = AttachInfo.InvalidateInfo.obtain();
15771 info.target = this;
15774 info.right = right;
15775 info.bottom = bottom;
15777 attachInfo.mViewRootImpl.dispatchInvalidateRectOnAnimation(info);
15782 * Post a callback to send a {@link AccessibilityEvent#TYPE_VIEW_SCROLLED} event.
15783 * This event is sent at most once every
15784 * {@link ViewConfiguration#getSendRecurringAccessibilityEventsInterval()}.
15786 private void postSendViewScrolledAccessibilityEventCallback() {
15787 if (mSendViewScrolledAccessibilityEvent == null) {
15788 mSendViewScrolledAccessibilityEvent = new SendViewScrolledAccessibilityEvent();
15790 if (!mSendViewScrolledAccessibilityEvent.mIsPending) {
15791 mSendViewScrolledAccessibilityEvent.mIsPending = true;
15792 postDelayed(mSendViewScrolledAccessibilityEvent,
15793 ViewConfiguration.getSendRecurringAccessibilityEventsInterval());
15798 * Called by a parent to request that a child update its values for mScrollX
15799 * and mScrollY if necessary. This will typically be done if the child is
15800 * animating a scroll using a {@link android.widget.Scroller Scroller}
15803 public void computeScroll() {
15807 * <p>Indicate whether the horizontal edges are faded when the view is
15808 * scrolled horizontally.</p>
15810 * @return true if the horizontal edges should are faded on scroll, false
15813 * @see #setHorizontalFadingEdgeEnabled(boolean)
15815 * @attr ref android.R.styleable#View_requiresFadingEdge
15817 public boolean isHorizontalFadingEdgeEnabled() {
15818 return (mViewFlags & FADING_EDGE_HORIZONTAL) == FADING_EDGE_HORIZONTAL;
15822 * <p>Define whether the horizontal edges should be faded when this view
15823 * is scrolled horizontally.</p>
15825 * @param horizontalFadingEdgeEnabled true if the horizontal edges should
15826 * be faded when the view is scrolled
15829 * @see #isHorizontalFadingEdgeEnabled()
15831 * @attr ref android.R.styleable#View_requiresFadingEdge
15833 public void setHorizontalFadingEdgeEnabled(boolean horizontalFadingEdgeEnabled) {
15834 if (isHorizontalFadingEdgeEnabled() != horizontalFadingEdgeEnabled) {
15835 if (horizontalFadingEdgeEnabled) {
15839 mViewFlags ^= FADING_EDGE_HORIZONTAL;
15844 * <p>Indicate whether the vertical edges are faded when the view is
15845 * scrolled horizontally.</p>
15847 * @return true if the vertical edges should are faded on scroll, false
15850 * @see #setVerticalFadingEdgeEnabled(boolean)
15852 * @attr ref android.R.styleable#View_requiresFadingEdge
15854 public boolean isVerticalFadingEdgeEnabled() {
15855 return (mViewFlags & FADING_EDGE_VERTICAL) == FADING_EDGE_VERTICAL;
15859 * <p>Define whether the vertical edges should be faded when this view
15860 * is scrolled vertically.</p>
15862 * @param verticalFadingEdgeEnabled true if the vertical edges should
15863 * be faded when the view is scrolled
15866 * @see #isVerticalFadingEdgeEnabled()
15868 * @attr ref android.R.styleable#View_requiresFadingEdge
15870 public void setVerticalFadingEdgeEnabled(boolean verticalFadingEdgeEnabled) {
15871 if (isVerticalFadingEdgeEnabled() != verticalFadingEdgeEnabled) {
15872 if (verticalFadingEdgeEnabled) {
15876 mViewFlags ^= FADING_EDGE_VERTICAL;
15881 * Returns the strength, or intensity, of the top faded edge. The strength is
15882 * a value between 0.0 (no fade) and 1.0 (full fade). The default implementation
15883 * returns 0.0 or 1.0 but no value in between.
15885 * Subclasses should override this method to provide a smoother fade transition
15886 * when scrolling occurs.
15888 * @return the intensity of the top fade as a float between 0.0f and 1.0f
15890 protected float getTopFadingEdgeStrength() {
15891 return computeVerticalScrollOffset() > 0 ? 1.0f : 0.0f;
15895 * Returns the strength, or intensity, of the bottom faded edge. The strength is
15896 * a value between 0.0 (no fade) and 1.0 (full fade). The default implementation
15897 * returns 0.0 or 1.0 but no value in between.
15899 * Subclasses should override this method to provide a smoother fade transition
15900 * when scrolling occurs.
15902 * @return the intensity of the bottom fade as a float between 0.0f and 1.0f
15904 protected float getBottomFadingEdgeStrength() {
15905 return computeVerticalScrollOffset() + computeVerticalScrollExtent() <
15906 computeVerticalScrollRange() ? 1.0f : 0.0f;
15910 * Returns the strength, or intensity, of the left faded edge. The strength is
15911 * a value between 0.0 (no fade) and 1.0 (full fade). The default implementation
15912 * returns 0.0 or 1.0 but no value in between.
15914 * Subclasses should override this method to provide a smoother fade transition
15915 * when scrolling occurs.
15917 * @return the intensity of the left fade as a float between 0.0f and 1.0f
15919 protected float getLeftFadingEdgeStrength() {
15920 return computeHorizontalScrollOffset() > 0 ? 1.0f : 0.0f;
15924 * Returns the strength, or intensity, of the right faded edge. The strength is
15925 * a value between 0.0 (no fade) and 1.0 (full fade). The default implementation
15926 * returns 0.0 or 1.0 but no value in between.
15928 * Subclasses should override this method to provide a smoother fade transition
15929 * when scrolling occurs.
15931 * @return the intensity of the right fade as a float between 0.0f and 1.0f
15933 protected float getRightFadingEdgeStrength() {
15934 return computeHorizontalScrollOffset() + computeHorizontalScrollExtent() <
15935 computeHorizontalScrollRange() ? 1.0f : 0.0f;
15939 * <p>Indicate whether the horizontal scrollbar should be drawn or not. The
15940 * scrollbar is not drawn by default.</p>
15942 * @return true if the horizontal scrollbar should be painted, false
15945 * @see #setHorizontalScrollBarEnabled(boolean)
15947 public boolean isHorizontalScrollBarEnabled() {
15948 return (mViewFlags & SCROLLBARS_HORIZONTAL) == SCROLLBARS_HORIZONTAL;
15952 * <p>Define whether the horizontal scrollbar should be drawn or not. The
15953 * scrollbar is not drawn by default.</p>
15955 * @param horizontalScrollBarEnabled true if the horizontal scrollbar should
15958 * @see #isHorizontalScrollBarEnabled()
15960 public void setHorizontalScrollBarEnabled(boolean horizontalScrollBarEnabled) {
15961 if (isHorizontalScrollBarEnabled() != horizontalScrollBarEnabled) {
15962 mViewFlags ^= SCROLLBARS_HORIZONTAL;
15963 computeOpaqueFlags();
15969 * <p>Indicate whether the vertical scrollbar should be drawn or not. The
15970 * scrollbar is not drawn by default.</p>
15972 * @return true if the vertical scrollbar should be painted, false
15975 * @see #setVerticalScrollBarEnabled(boolean)
15977 public boolean isVerticalScrollBarEnabled() {
15978 return (mViewFlags & SCROLLBARS_VERTICAL) == SCROLLBARS_VERTICAL;
15982 * <p>Define whether the vertical scrollbar should be drawn or not. The
15983 * scrollbar is not drawn by default.</p>
15985 * @param verticalScrollBarEnabled true if the vertical scrollbar should
15988 * @see #isVerticalScrollBarEnabled()
15990 public void setVerticalScrollBarEnabled(boolean verticalScrollBarEnabled) {
15991 if (isVerticalScrollBarEnabled() != verticalScrollBarEnabled) {
15992 mViewFlags ^= SCROLLBARS_VERTICAL;
15993 computeOpaqueFlags();
16001 protected void recomputePadding() {
16002 internalSetPadding(mUserPaddingLeft, mPaddingTop, mUserPaddingRight, mUserPaddingBottom);
16006 * Define whether scrollbars will fade when the view is not scrolling.
16008 * @param fadeScrollbars whether to enable fading
16010 * @attr ref android.R.styleable#View_fadeScrollbars
16012 public void setScrollbarFadingEnabled(boolean fadeScrollbars) {
16014 final ScrollabilityCache scrollabilityCache = mScrollCache;
16015 scrollabilityCache.fadeScrollBars = fadeScrollbars;
16016 if (fadeScrollbars) {
16017 scrollabilityCache.state = ScrollabilityCache.OFF;
16019 scrollabilityCache.state = ScrollabilityCache.ON;
16025 * Returns true if scrollbars will fade when this view is not scrolling
16027 * @return true if scrollbar fading is enabled
16029 * @attr ref android.R.styleable#View_fadeScrollbars
16031 public boolean isScrollbarFadingEnabled() {
16032 return mScrollCache != null && mScrollCache.fadeScrollBars;
16037 * Returns the delay before scrollbars fade.
16039 * @return the delay before scrollbars fade
16041 * @attr ref android.R.styleable#View_scrollbarDefaultDelayBeforeFade
16043 public int getScrollBarDefaultDelayBeforeFade() {
16044 return mScrollCache == null ? ViewConfiguration.getScrollDefaultDelay() :
16045 mScrollCache.scrollBarDefaultDelayBeforeFade;
16049 * Define the delay before scrollbars fade.
16051 * @param scrollBarDefaultDelayBeforeFade - the delay before scrollbars fade
16053 * @attr ref android.R.styleable#View_scrollbarDefaultDelayBeforeFade
16055 public void setScrollBarDefaultDelayBeforeFade(int scrollBarDefaultDelayBeforeFade) {
16056 getScrollCache().scrollBarDefaultDelayBeforeFade = scrollBarDefaultDelayBeforeFade;
16061 * Returns the scrollbar fade duration.
16063 * @return the scrollbar fade duration, in milliseconds
16065 * @attr ref android.R.styleable#View_scrollbarFadeDuration
16067 public int getScrollBarFadeDuration() {
16068 return mScrollCache == null ? ViewConfiguration.getScrollBarFadeDuration() :
16069 mScrollCache.scrollBarFadeDuration;
16073 * Define the scrollbar fade duration.
16075 * @param scrollBarFadeDuration - the scrollbar fade duration, in milliseconds
16077 * @attr ref android.R.styleable#View_scrollbarFadeDuration
16079 public void setScrollBarFadeDuration(int scrollBarFadeDuration) {
16080 getScrollCache().scrollBarFadeDuration = scrollBarFadeDuration;
16085 * Returns the scrollbar size.
16087 * @return the scrollbar size
16089 * @attr ref android.R.styleable#View_scrollbarSize
16091 public int getScrollBarSize() {
16092 return mScrollCache == null ? ViewConfiguration.get(mContext).getScaledScrollBarSize() :
16093 mScrollCache.scrollBarSize;
16097 * Define the scrollbar size.
16099 * @param scrollBarSize - the scrollbar size
16101 * @attr ref android.R.styleable#View_scrollbarSize
16103 public void setScrollBarSize(int scrollBarSize) {
16104 getScrollCache().scrollBarSize = scrollBarSize;
16108 * <p>Specify the style of the scrollbars. The scrollbars can be overlaid or
16109 * inset. When inset, they add to the padding of the view. And the scrollbars
16110 * can be drawn inside the padding area or on the edge of the view. For example,
16111 * if a view has a background drawable and you want to draw the scrollbars
16112 * inside the padding specified by the drawable, you can use
16113 * SCROLLBARS_INSIDE_OVERLAY or SCROLLBARS_INSIDE_INSET. If you want them to
16114 * appear at the edge of the view, ignoring the padding, then you can use
16115 * SCROLLBARS_OUTSIDE_OVERLAY or SCROLLBARS_OUTSIDE_INSET.</p>
16116 * @param style the style of the scrollbars. Should be one of
16117 * SCROLLBARS_INSIDE_OVERLAY, SCROLLBARS_INSIDE_INSET,
16118 * SCROLLBARS_OUTSIDE_OVERLAY or SCROLLBARS_OUTSIDE_INSET.
16119 * @see #SCROLLBARS_INSIDE_OVERLAY
16120 * @see #SCROLLBARS_INSIDE_INSET
16121 * @see #SCROLLBARS_OUTSIDE_OVERLAY
16122 * @see #SCROLLBARS_OUTSIDE_INSET
16124 * @attr ref android.R.styleable#View_scrollbarStyle
16126 public void setScrollBarStyle(@ScrollBarStyle int style) {
16127 if (style != (mViewFlags & SCROLLBARS_STYLE_MASK)) {
16128 mViewFlags = (mViewFlags & ~SCROLLBARS_STYLE_MASK) | (style & SCROLLBARS_STYLE_MASK);
16129 computeOpaqueFlags();
16135 * <p>Returns the current scrollbar style.</p>
16136 * @return the current scrollbar style
16137 * @see #SCROLLBARS_INSIDE_OVERLAY
16138 * @see #SCROLLBARS_INSIDE_INSET
16139 * @see #SCROLLBARS_OUTSIDE_OVERLAY
16140 * @see #SCROLLBARS_OUTSIDE_INSET
16142 * @attr ref android.R.styleable#View_scrollbarStyle
16144 @ViewDebug.ExportedProperty(mapping = {
16145 @ViewDebug.IntToString(from = SCROLLBARS_INSIDE_OVERLAY, to = "INSIDE_OVERLAY"),
16146 @ViewDebug.IntToString(from = SCROLLBARS_INSIDE_INSET, to = "INSIDE_INSET"),
16147 @ViewDebug.IntToString(from = SCROLLBARS_OUTSIDE_OVERLAY, to = "OUTSIDE_OVERLAY"),
16148 @ViewDebug.IntToString(from = SCROLLBARS_OUTSIDE_INSET, to = "OUTSIDE_INSET")
16151 public int getScrollBarStyle() {
16152 return mViewFlags & SCROLLBARS_STYLE_MASK;
16156 * <p>Compute the horizontal range that the horizontal scrollbar
16159 * <p>The range is expressed in arbitrary units that must be the same as the
16160 * units used by {@link #computeHorizontalScrollExtent()} and
16161 * {@link #computeHorizontalScrollOffset()}.</p>
16163 * <p>The default range is the drawing width of this view.</p>
16165 * @return the total horizontal range represented by the horizontal
16168 * @see #computeHorizontalScrollExtent()
16169 * @see #computeHorizontalScrollOffset()
16170 * @see android.widget.ScrollBarDrawable
16172 protected int computeHorizontalScrollRange() {
16177 * <p>Compute the horizontal offset of the horizontal scrollbar's thumb
16178 * within the horizontal range. This value is used to compute the position
16179 * of the thumb within the scrollbar's track.</p>
16181 * <p>The range is expressed in arbitrary units that must be the same as the
16182 * units used by {@link #computeHorizontalScrollRange()} and
16183 * {@link #computeHorizontalScrollExtent()}.</p>
16185 * <p>The default offset is the scroll offset of this view.</p>
16187 * @return the horizontal offset of the scrollbar's thumb
16189 * @see #computeHorizontalScrollRange()
16190 * @see #computeHorizontalScrollExtent()
16191 * @see android.widget.ScrollBarDrawable
16193 protected int computeHorizontalScrollOffset() {
16198 * <p>Compute the horizontal extent of the horizontal scrollbar's thumb
16199 * within the horizontal range. This value is used to compute the length
16200 * of the thumb within the scrollbar's track.</p>
16202 * <p>The range is expressed in arbitrary units that must be the same as the
16203 * units used by {@link #computeHorizontalScrollRange()} and
16204 * {@link #computeHorizontalScrollOffset()}.</p>
16206 * <p>The default extent is the drawing width of this view.</p>
16208 * @return the horizontal extent of the scrollbar's thumb
16210 * @see #computeHorizontalScrollRange()
16211 * @see #computeHorizontalScrollOffset()
16212 * @see android.widget.ScrollBarDrawable
16214 protected int computeHorizontalScrollExtent() {
16219 * <p>Compute the vertical range that the vertical scrollbar represents.</p>
16221 * <p>The range is expressed in arbitrary units that must be the same as the
16222 * units used by {@link #computeVerticalScrollExtent()} and
16223 * {@link #computeVerticalScrollOffset()}.</p>
16225 * @return the total vertical range represented by the vertical scrollbar
16227 * <p>The default range is the drawing height of this view.</p>
16229 * @see #computeVerticalScrollExtent()
16230 * @see #computeVerticalScrollOffset()
16231 * @see android.widget.ScrollBarDrawable
16233 protected int computeVerticalScrollRange() {
16234 return getHeight();
16238 * <p>Compute the vertical offset of the vertical scrollbar's thumb
16239 * within the horizontal range. This value is used to compute the position
16240 * of the thumb within the scrollbar's track.</p>
16242 * <p>The range is expressed in arbitrary units that must be the same as the
16243 * units used by {@link #computeVerticalScrollRange()} and
16244 * {@link #computeVerticalScrollExtent()}.</p>
16246 * <p>The default offset is the scroll offset of this view.</p>
16248 * @return the vertical offset of the scrollbar's thumb
16250 * @see #computeVerticalScrollRange()
16251 * @see #computeVerticalScrollExtent()
16252 * @see android.widget.ScrollBarDrawable
16254 protected int computeVerticalScrollOffset() {
16259 * <p>Compute the vertical extent of the vertical scrollbar's thumb
16260 * within the vertical range. This value is used to compute the length
16261 * of the thumb within the scrollbar's track.</p>
16263 * <p>The range is expressed in arbitrary units that must be the same as the
16264 * units used by {@link #computeVerticalScrollRange()} and
16265 * {@link #computeVerticalScrollOffset()}.</p>
16267 * <p>The default extent is the drawing height of this view.</p>
16269 * @return the vertical extent of the scrollbar's thumb
16271 * @see #computeVerticalScrollRange()
16272 * @see #computeVerticalScrollOffset()
16273 * @see android.widget.ScrollBarDrawable
16275 protected int computeVerticalScrollExtent() {
16276 return getHeight();
16280 * Check if this view can be scrolled horizontally in a certain direction.
16282 * @param direction Negative to check scrolling left, positive to check scrolling right.
16283 * @return true if this view can be scrolled in the specified direction, false otherwise.
16285 public boolean canScrollHorizontally(int direction) {
16286 final int offset = computeHorizontalScrollOffset();
16287 final int range = computeHorizontalScrollRange() - computeHorizontalScrollExtent();
16288 if (range == 0) return false;
16289 if (direction < 0) {
16292 return offset < range - 1;
16297 * Check if this view can be scrolled vertically in a certain direction.
16299 * @param direction Negative to check scrolling up, positive to check scrolling down.
16300 * @return true if this view can be scrolled in the specified direction, false otherwise.
16302 public boolean canScrollVertically(int direction) {
16303 final int offset = computeVerticalScrollOffset();
16304 final int range = computeVerticalScrollRange() - computeVerticalScrollExtent();
16305 if (range == 0) return false;
16306 if (direction < 0) {
16309 return offset < range - 1;
16313 void getScrollIndicatorBounds(@NonNull Rect out) {
16314 out.left = mScrollX;
16315 out.right = mScrollX + mRight - mLeft;
16316 out.top = mScrollY;
16317 out.bottom = mScrollY + mBottom - mTop;
16320 private void onDrawScrollIndicators(Canvas c) {
16321 if ((mPrivateFlags3 & SCROLL_INDICATORS_PFLAG3_MASK) == 0) {
16322 // No scroll indicators enabled.
16326 final Drawable dr = mScrollIndicatorDrawable;
16328 // Scroll indicators aren't supported here.
16332 final int h = dr.getIntrinsicHeight();
16333 final int w = dr.getIntrinsicWidth();
16334 final Rect rect = mAttachInfo.mTmpInvalRect;
16335 getScrollIndicatorBounds(rect);
16337 if ((mPrivateFlags3 & PFLAG3_SCROLL_INDICATOR_TOP) != 0) {
16338 final boolean canScrollUp = canScrollVertically(-1);
16340 dr.setBounds(rect.left, rect.top, rect.right, rect.top + h);
16345 if ((mPrivateFlags3 & PFLAG3_SCROLL_INDICATOR_BOTTOM) != 0) {
16346 final boolean canScrollDown = canScrollVertically(1);
16347 if (canScrollDown) {
16348 dr.setBounds(rect.left, rect.bottom - h, rect.right, rect.bottom);
16354 final int rightRtl;
16355 if (getLayoutDirection() == LAYOUT_DIRECTION_RTL) {
16356 leftRtl = PFLAG3_SCROLL_INDICATOR_END;
16357 rightRtl = PFLAG3_SCROLL_INDICATOR_START;
16359 leftRtl = PFLAG3_SCROLL_INDICATOR_START;
16360 rightRtl = PFLAG3_SCROLL_INDICATOR_END;
16363 final int leftMask = PFLAG3_SCROLL_INDICATOR_LEFT | leftRtl;
16364 if ((mPrivateFlags3 & leftMask) != 0) {
16365 final boolean canScrollLeft = canScrollHorizontally(-1);
16366 if (canScrollLeft) {
16367 dr.setBounds(rect.left, rect.top, rect.left + w, rect.bottom);
16372 final int rightMask = PFLAG3_SCROLL_INDICATOR_RIGHT | rightRtl;
16373 if ((mPrivateFlags3 & rightMask) != 0) {
16374 final boolean canScrollRight = canScrollHorizontally(1);
16375 if (canScrollRight) {
16376 dr.setBounds(rect.right - w, rect.top, rect.right, rect.bottom);
16382 private void getHorizontalScrollBarBounds(@Nullable Rect drawBounds,
16383 @Nullable Rect touchBounds) {
16384 final Rect bounds = drawBounds != null ? drawBounds : touchBounds;
16385 if (bounds == null) {
16388 final int inside = (mViewFlags & SCROLLBARS_OUTSIDE_MASK) == 0 ? ~0 : 0;
16389 final boolean drawVerticalScrollBar = isVerticalScrollBarEnabled()
16390 && !isVerticalScrollBarHidden();
16391 final int size = getHorizontalScrollbarHeight();
16392 final int verticalScrollBarGap = drawVerticalScrollBar ?
16393 getVerticalScrollbarWidth() : 0;
16394 final int width = mRight - mLeft;
16395 final int height = mBottom - mTop;
16396 bounds.top = mScrollY + height - size - (mUserPaddingBottom & inside);
16397 bounds.left = mScrollX + (mPaddingLeft & inside);
16398 bounds.right = mScrollX + width - (mUserPaddingRight & inside) - verticalScrollBarGap;
16399 bounds.bottom = bounds.top + size;
16401 if (touchBounds == null) {
16404 if (touchBounds != bounds) {
16405 touchBounds.set(bounds);
16407 final int minTouchTarget = mScrollCache.scrollBarMinTouchTarget;
16408 if (touchBounds.height() < minTouchTarget) {
16409 final int adjust = (minTouchTarget - touchBounds.height()) / 2;
16410 touchBounds.bottom = Math.min(touchBounds.bottom + adjust, mScrollY + height);
16411 touchBounds.top = touchBounds.bottom - minTouchTarget;
16413 if (touchBounds.width() < minTouchTarget) {
16414 final int adjust = (minTouchTarget - touchBounds.width()) / 2;
16415 touchBounds.left -= adjust;
16416 touchBounds.right = touchBounds.left + minTouchTarget;
16420 private void getVerticalScrollBarBounds(@Nullable Rect bounds, @Nullable Rect touchBounds) {
16421 if (mRoundScrollbarRenderer == null) {
16422 getStraightVerticalScrollBarBounds(bounds, touchBounds);
16424 getRoundVerticalScrollBarBounds(bounds != null ? bounds : touchBounds);
16428 private void getRoundVerticalScrollBarBounds(Rect bounds) {
16429 final int width = mRight - mLeft;
16430 final int height = mBottom - mTop;
16431 // Do not take padding into account as we always want the scrollbars
16432 // to hug the screen for round wearable devices.
16433 bounds.left = mScrollX;
16434 bounds.top = mScrollY;
16435 bounds.right = bounds.left + width;
16436 bounds.bottom = mScrollY + height;
16439 private void getStraightVerticalScrollBarBounds(@Nullable Rect drawBounds,
16440 @Nullable Rect touchBounds) {
16441 final Rect bounds = drawBounds != null ? drawBounds : touchBounds;
16442 if (bounds == null) {
16445 final int inside = (mViewFlags & SCROLLBARS_OUTSIDE_MASK) == 0 ? ~0 : 0;
16446 final int size = getVerticalScrollbarWidth();
16447 int verticalScrollbarPosition = mVerticalScrollbarPosition;
16448 if (verticalScrollbarPosition == SCROLLBAR_POSITION_DEFAULT) {
16449 verticalScrollbarPosition = isLayoutRtl() ?
16450 SCROLLBAR_POSITION_LEFT : SCROLLBAR_POSITION_RIGHT;
16452 final int width = mRight - mLeft;
16453 final int height = mBottom - mTop;
16454 switch (verticalScrollbarPosition) {
16456 case SCROLLBAR_POSITION_RIGHT:
16457 bounds.left = mScrollX + width - size - (mUserPaddingRight & inside);
16459 case SCROLLBAR_POSITION_LEFT:
16460 bounds.left = mScrollX + (mUserPaddingLeft & inside);
16463 bounds.top = mScrollY + (mPaddingTop & inside);
16464 bounds.right = bounds.left + size;
16465 bounds.bottom = mScrollY + height - (mUserPaddingBottom & inside);
16467 if (touchBounds == null) {
16470 if (touchBounds != bounds) {
16471 touchBounds.set(bounds);
16473 final int minTouchTarget = mScrollCache.scrollBarMinTouchTarget;
16474 if (touchBounds.width() < minTouchTarget) {
16475 final int adjust = (minTouchTarget - touchBounds.width()) / 2;
16476 if (verticalScrollbarPosition == SCROLLBAR_POSITION_RIGHT) {
16477 touchBounds.right = Math.min(touchBounds.right + adjust, mScrollX + width);
16478 touchBounds.left = touchBounds.right - minTouchTarget;
16480 touchBounds.left = Math.max(touchBounds.left + adjust, mScrollX);
16481 touchBounds.right = touchBounds.left + minTouchTarget;
16484 if (touchBounds.height() < minTouchTarget) {
16485 final int adjust = (minTouchTarget - touchBounds.height()) / 2;
16486 touchBounds.top -= adjust;
16487 touchBounds.bottom = touchBounds.top + minTouchTarget;
16492 * <p>Request the drawing of the horizontal and the vertical scrollbar. The
16493 * scrollbars are painted only if they have been awakened first.</p>
16495 * @param canvas the canvas on which to draw the scrollbars
16497 * @see #awakenScrollBars(int)
16499 protected final void onDrawScrollBars(Canvas canvas) {
16500 // scrollbars are drawn only when the animation is running
16501 final ScrollabilityCache cache = mScrollCache;
16503 if (cache != null) {
16505 int state = cache.state;
16507 if (state == ScrollabilityCache.OFF) {
16511 boolean invalidate = false;
16513 if (state == ScrollabilityCache.FADING) {
16514 // We're fading -- get our fade interpolation
16515 if (cache.interpolatorValues == null) {
16516 cache.interpolatorValues = new float[1];
16519 float[] values = cache.interpolatorValues;
16521 // Stops the animation if we're done
16522 if (cache.scrollBarInterpolator.timeToValues(values) ==
16523 Interpolator.Result.FREEZE_END) {
16524 cache.state = ScrollabilityCache.OFF;
16526 cache.scrollBar.mutate().setAlpha(Math.round(values[0]));
16529 // This will make the scroll bars inval themselves after
16530 // drawing. We only want this when we're fading so that
16531 // we prevent excessive redraws
16534 // We're just on -- but we may have been fading before so
16536 cache.scrollBar.mutate().setAlpha(255);
16539 final boolean drawHorizontalScrollBar = isHorizontalScrollBarEnabled();
16540 final boolean drawVerticalScrollBar = isVerticalScrollBarEnabled()
16541 && !isVerticalScrollBarHidden();
16543 // Fork out the scroll bar drawing for round wearable devices.
16544 if (mRoundScrollbarRenderer != null) {
16545 if (drawVerticalScrollBar) {
16546 final Rect bounds = cache.mScrollBarBounds;
16547 getVerticalScrollBarBounds(bounds, null);
16548 mRoundScrollbarRenderer.drawRoundScrollbars(
16549 canvas, (float) cache.scrollBar.getAlpha() / 255f, bounds);
16554 // Do not draw horizontal scroll bars for round wearable devices.
16555 } else if (drawVerticalScrollBar || drawHorizontalScrollBar) {
16556 final ScrollBarDrawable scrollBar = cache.scrollBar;
16558 if (drawHorizontalScrollBar) {
16559 scrollBar.setParameters(computeHorizontalScrollRange(),
16560 computeHorizontalScrollOffset(),
16561 computeHorizontalScrollExtent(), false);
16562 final Rect bounds = cache.mScrollBarBounds;
16563 getHorizontalScrollBarBounds(bounds, null);
16564 onDrawHorizontalScrollBar(canvas, scrollBar, bounds.left, bounds.top,
16565 bounds.right, bounds.bottom);
16567 invalidate(bounds);
16571 if (drawVerticalScrollBar) {
16572 scrollBar.setParameters(computeVerticalScrollRange(),
16573 computeVerticalScrollOffset(),
16574 computeVerticalScrollExtent(), true);
16575 final Rect bounds = cache.mScrollBarBounds;
16576 getVerticalScrollBarBounds(bounds, null);
16577 onDrawVerticalScrollBar(canvas, scrollBar, bounds.left, bounds.top,
16578 bounds.right, bounds.bottom);
16580 invalidate(bounds);
16588 * Override this if the vertical scrollbar needs to be hidden in a subclass, like when
16589 * FastScroller is visible.
16590 * @return whether to temporarily hide the vertical scrollbar
16593 protected boolean isVerticalScrollBarHidden() {
16598 * <p>Draw the horizontal scrollbar if
16599 * {@link #isHorizontalScrollBarEnabled()} returns true.</p>
16601 * @param canvas the canvas on which to draw the scrollbar
16602 * @param scrollBar the scrollbar's drawable
16604 * @see #isHorizontalScrollBarEnabled()
16605 * @see #computeHorizontalScrollRange()
16606 * @see #computeHorizontalScrollExtent()
16607 * @see #computeHorizontalScrollOffset()
16608 * @see android.widget.ScrollBarDrawable
16611 protected void onDrawHorizontalScrollBar(Canvas canvas, Drawable scrollBar,
16612 int l, int t, int r, int b) {
16613 scrollBar.setBounds(l, t, r, b);
16614 scrollBar.draw(canvas);
16618 * <p>Draw the vertical scrollbar if {@link #isVerticalScrollBarEnabled()}
16619 * returns true.</p>
16621 * @param canvas the canvas on which to draw the scrollbar
16622 * @param scrollBar the scrollbar's drawable
16624 * @see #isVerticalScrollBarEnabled()
16625 * @see #computeVerticalScrollRange()
16626 * @see #computeVerticalScrollExtent()
16627 * @see #computeVerticalScrollOffset()
16628 * @see android.widget.ScrollBarDrawable
16631 protected void onDrawVerticalScrollBar(Canvas canvas, Drawable scrollBar,
16632 int l, int t, int r, int b) {
16633 scrollBar.setBounds(l, t, r, b);
16634 scrollBar.draw(canvas);
16638 * Implement this to do your drawing.
16640 * @param canvas the canvas on which the background will be drawn
16642 protected void onDraw(Canvas canvas) {
16646 * Caller is responsible for calling requestLayout if necessary.
16647 * (This allows addViewInLayout to not request a new layout.)
16649 void assignParent(ViewParent parent) {
16650 if (mParent == null) {
16652 } else if (parent == null) {
16655 throw new RuntimeException("view " + this + " being added, but"
16656 + " it already has a parent");
16661 * This is called when the view is attached to a window. At this point it
16662 * has a Surface and will start drawing. Note that this function is
16663 * guaranteed to be called before {@link #onDraw(android.graphics.Canvas)},
16664 * however it may be called any time before the first onDraw -- including
16665 * before or after {@link #onMeasure(int, int)}.
16667 * @see #onDetachedFromWindow()
16670 protected void onAttachedToWindow() {
16671 if ((mPrivateFlags & PFLAG_REQUEST_TRANSPARENT_REGIONS) != 0) {
16672 mParent.requestTransparentRegion(this);
16675 mPrivateFlags3 &= ~PFLAG3_IS_LAID_OUT;
16677 jumpDrawablesToCurrentState();
16679 resetSubtreeAccessibilityStateChanged();
16681 // rebuild, since Outline not maintained while View is detached
16685 InputMethodManager imm = InputMethodManager.peekInstance();
16693 * Resolve all RTL related properties.
16695 * @return true if resolution of RTL properties has been done
16699 public boolean resolveRtlPropertiesIfNeeded() {
16700 if (!needRtlPropertiesResolution()) return false;
16702 // Order is important here: LayoutDirection MUST be resolved first
16703 if (!isLayoutDirectionResolved()) {
16704 resolveLayoutDirection();
16705 resolveLayoutParams();
16707 // ... then we can resolve the others properties depending on the resolved LayoutDirection.
16708 if (!isTextDirectionResolved()) {
16709 resolveTextDirection();
16711 if (!isTextAlignmentResolved()) {
16712 resolveTextAlignment();
16714 // Should resolve Drawables before Padding because we need the layout direction of the
16715 // Drawable to correctly resolve Padding.
16716 if (!areDrawablesResolved()) {
16717 resolveDrawables();
16719 if (!isPaddingResolved()) {
16722 onRtlPropertiesChanged(getLayoutDirection());
16727 * Reset resolution of all RTL related properties.
16731 public void resetRtlProperties() {
16732 resetResolvedLayoutDirection();
16733 resetResolvedTextDirection();
16734 resetResolvedTextAlignment();
16735 resetResolvedPadding();
16736 resetResolvedDrawables();
16740 * @see #onScreenStateChanged(int)
16742 void dispatchScreenStateChanged(int screenState) {
16743 onScreenStateChanged(screenState);
16747 * This method is called whenever the state of the screen this view is
16748 * attached to changes. A state change will usually occurs when the screen
16749 * turns on or off (whether it happens automatically or the user does it
16752 * @param screenState The new state of the screen. Can be either
16753 * {@link #SCREEN_STATE_ON} or {@link #SCREEN_STATE_OFF}
16755 public void onScreenStateChanged(int screenState) {
16759 * @see #onMovedToDisplay(int, Configuration)
16761 void dispatchMovedToDisplay(Display display, Configuration config) {
16762 mAttachInfo.mDisplay = display;
16763 mAttachInfo.mDisplayState = display.getState();
16764 onMovedToDisplay(display.getDisplayId(), config);
16768 * Called by the system when the hosting activity is moved from one display to another without
16769 * recreation. This means that the activity is declared to handle all changes to configuration
16770 * that happened when it was switched to another display, so it wasn't destroyed and created
16773 * <p>This call will be followed by {@link #onConfigurationChanged(Configuration)} if the
16774 * applied configuration actually changed. It is up to app developer to choose whether to handle
16775 * the change in this method or in the following {@link #onConfigurationChanged(Configuration)}
16778 * <p>Use this callback to track changes to the displays if some functionality relies on an
16779 * association with some display properties.
16781 * @param displayId The id of the display to which the view was moved.
16782 * @param config Configuration of the resources on new display after move.
16784 * @see #onConfigurationChanged(Configuration)
16787 public void onMovedToDisplay(int displayId, Configuration config) {
16791 * Return true if the application tag in the AndroidManifest has set "supportRtl" to true
16793 private boolean hasRtlSupport() {
16794 return mContext.getApplicationInfo().hasRtlSupport();
16798 * Return true if we are in RTL compatibility mode (either before Jelly Bean MR1 or
16799 * RTL not supported)
16801 private boolean isRtlCompatibilityMode() {
16802 final int targetSdkVersion = getContext().getApplicationInfo().targetSdkVersion;
16803 return targetSdkVersion < Build.VERSION_CODES.JELLY_BEAN_MR1 || !hasRtlSupport();
16807 * @return true if RTL properties need resolution.
16810 private boolean needRtlPropertiesResolution() {
16811 return (mPrivateFlags2 & ALL_RTL_PROPERTIES_RESOLVED) != ALL_RTL_PROPERTIES_RESOLVED;
16815 * Called when any RTL property (layout direction or text direction or text alignment) has
16818 * Subclasses need to override this method to take care of cached information that depends on the
16819 * resolved layout direction, or to inform child views that inherit their layout direction.
16821 * The default implementation does nothing.
16823 * @param layoutDirection the direction of the layout
16825 * @see #LAYOUT_DIRECTION_LTR
16826 * @see #LAYOUT_DIRECTION_RTL
16828 public void onRtlPropertiesChanged(@ResolvedLayoutDir int layoutDirection) {
16832 * Resolve and cache the layout direction. LTR is set initially. This is implicitly supposing
16833 * that the parent directionality can and will be resolved before its children.
16835 * @return true if resolution has been done, false otherwise.
16839 public boolean resolveLayoutDirection() {
16840 // Clear any previous layout direction resolution
16841 mPrivateFlags2 &= ~PFLAG2_LAYOUT_DIRECTION_RESOLVED_MASK;
16843 if (hasRtlSupport()) {
16844 // Set resolved depending on layout direction
16845 switch ((mPrivateFlags2 & PFLAG2_LAYOUT_DIRECTION_MASK) >>
16846 PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT) {
16847 case LAYOUT_DIRECTION_INHERIT:
16848 // We cannot resolve yet. LTR is by default and let the resolution happen again
16849 // later to get the correct resolved value
16850 if (!canResolveLayoutDirection()) return false;
16852 // Parent has not yet resolved, LTR is still the default
16854 if (!mParent.isLayoutDirectionResolved()) return false;
16856 if (mParent.getLayoutDirection() == LAYOUT_DIRECTION_RTL) {
16857 mPrivateFlags2 |= PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL;
16859 } catch (AbstractMethodError e) {
16860 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() +
16861 " does not fully implement ViewParent", e);
16864 case LAYOUT_DIRECTION_RTL:
16865 mPrivateFlags2 |= PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL;
16867 case LAYOUT_DIRECTION_LOCALE:
16868 if((LAYOUT_DIRECTION_RTL ==
16869 TextUtils.getLayoutDirectionFromLocale(Locale.getDefault()))) {
16870 mPrivateFlags2 |= PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL;
16874 // Nothing to do, LTR by default
16879 mPrivateFlags2 |= PFLAG2_LAYOUT_DIRECTION_RESOLVED;
16884 * Check if layout direction resolution can be done.
16886 * @return true if layout direction resolution can be done otherwise return false.
16888 public boolean canResolveLayoutDirection() {
16889 switch (getRawLayoutDirection()) {
16890 case LAYOUT_DIRECTION_INHERIT:
16891 if (mParent != null) {
16893 return mParent.canResolveLayoutDirection();
16894 } catch (AbstractMethodError e) {
16895 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() +
16896 " does not fully implement ViewParent", e);
16907 * Reset the resolved layout direction. Layout direction will be resolved during a call to
16908 * {@link #onMeasure(int, int)}.
16912 public void resetResolvedLayoutDirection() {
16913 // Reset the current resolved bits
16914 mPrivateFlags2 &= ~PFLAG2_LAYOUT_DIRECTION_RESOLVED_MASK;
16918 * @return true if the layout direction is inherited.
16922 public boolean isLayoutDirectionInherited() {
16923 return (getRawLayoutDirection() == LAYOUT_DIRECTION_INHERIT);
16927 * @return true if layout direction has been resolved.
16929 public boolean isLayoutDirectionResolved() {
16930 return (mPrivateFlags2 & PFLAG2_LAYOUT_DIRECTION_RESOLVED) == PFLAG2_LAYOUT_DIRECTION_RESOLVED;
16934 * Return if padding has been resolved
16938 boolean isPaddingResolved() {
16939 return (mPrivateFlags2 & PFLAG2_PADDING_RESOLVED) == PFLAG2_PADDING_RESOLVED;
16943 * Resolves padding depending on layout direction, if applicable, and
16944 * recomputes internal padding values to adjust for scroll bars.
16948 public void resolvePadding() {
16949 final int resolvedLayoutDirection = getLayoutDirection();
16951 if (!isRtlCompatibilityMode()) {
16952 // Post Jelly Bean MR1 case: we need to take the resolved layout direction into account.
16953 // If start / end padding are defined, they will be resolved (hence overriding) to
16954 // left / right or right / left depending on the resolved layout direction.
16955 // If start / end padding are not defined, use the left / right ones.
16956 if (mBackground != null && (!mLeftPaddingDefined || !mRightPaddingDefined)) {
16957 Rect padding = sThreadLocal.get();
16958 if (padding == null) {
16959 padding = new Rect();
16960 sThreadLocal.set(padding);
16962 mBackground.getPadding(padding);
16963 if (!mLeftPaddingDefined) {
16964 mUserPaddingLeftInitial = padding.left;
16966 if (!mRightPaddingDefined) {
16967 mUserPaddingRightInitial = padding.right;
16970 switch (resolvedLayoutDirection) {
16971 case LAYOUT_DIRECTION_RTL:
16972 if (mUserPaddingStart != UNDEFINED_PADDING) {
16973 mUserPaddingRight = mUserPaddingStart;
16975 mUserPaddingRight = mUserPaddingRightInitial;
16977 if (mUserPaddingEnd != UNDEFINED_PADDING) {
16978 mUserPaddingLeft = mUserPaddingEnd;
16980 mUserPaddingLeft = mUserPaddingLeftInitial;
16983 case LAYOUT_DIRECTION_LTR:
16985 if (mUserPaddingStart != UNDEFINED_PADDING) {
16986 mUserPaddingLeft = mUserPaddingStart;
16988 mUserPaddingLeft = mUserPaddingLeftInitial;
16990 if (mUserPaddingEnd != UNDEFINED_PADDING) {
16991 mUserPaddingRight = mUserPaddingEnd;
16993 mUserPaddingRight = mUserPaddingRightInitial;
16997 mUserPaddingBottom = (mUserPaddingBottom >= 0) ? mUserPaddingBottom : mPaddingBottom;
17000 internalSetPadding(mUserPaddingLeft, mPaddingTop, mUserPaddingRight, mUserPaddingBottom);
17001 onRtlPropertiesChanged(resolvedLayoutDirection);
17003 mPrivateFlags2 |= PFLAG2_PADDING_RESOLVED;
17007 * Reset the resolved layout direction.
17011 public void resetResolvedPadding() {
17012 resetResolvedPaddingInternal();
17016 * Used when we only want to reset *this* view's padding and not trigger overrides
17017 * in ViewGroup that reset children too.
17019 void resetResolvedPaddingInternal() {
17020 mPrivateFlags2 &= ~PFLAG2_PADDING_RESOLVED;
17024 * This is called when the view is detached from a window. At this point it
17025 * no longer has a surface for drawing.
17027 * @see #onAttachedToWindow()
17030 protected void onDetachedFromWindow() {
17034 * This is a framework-internal mirror of onDetachedFromWindow() that's called
17035 * after onDetachedFromWindow().
17037 * If you override this you *MUST* call super.onDetachedFromWindowInternal()!
17038 * The super method should be called at the end of the overridden method to ensure
17039 * subclasses are destroyed first
17044 protected void onDetachedFromWindowInternal() {
17045 mPrivateFlags &= ~PFLAG_CANCEL_NEXT_UP_EVENT;
17046 mPrivateFlags3 &= ~PFLAG3_IS_LAID_OUT;
17047 mPrivateFlags3 &= ~PFLAG3_TEMPORARY_DETACH;
17049 removeUnsetPressCallback();
17050 removeLongPressCallback();
17051 removePerformClickCallback();
17052 removeSendViewScrolledAccessibilityEventCallback();
17053 stopNestedScroll();
17055 // Anything that started animating right before detach should already
17056 // be in its final state when re-attached.
17057 jumpDrawablesToCurrentState();
17059 destroyDrawingCache();
17062 mCurrentAnimation = null;
17064 if ((mViewFlags & TOOLTIP) == TOOLTIP) {
17069 private void cleanupDraw() {
17070 resetDisplayList();
17071 if (mAttachInfo != null) {
17072 mAttachInfo.mViewRootImpl.cancelInvalidate(this);
17076 void invalidateInheritedLayoutMode(int layoutModeOfRoot) {
17080 * @return The number of times this view has been attached to a window
17082 protected int getWindowAttachCount() {
17083 return mWindowAttachCount;
17087 * Retrieve a unique token identifying the window this view is attached to.
17088 * @return Return the window's token for use in
17089 * {@link WindowManager.LayoutParams#token WindowManager.LayoutParams.token}.
17091 public IBinder getWindowToken() {
17092 return mAttachInfo != null ? mAttachInfo.mWindowToken : null;
17096 * Retrieve the {@link WindowId} for the window this view is
17097 * currently attached to.
17099 public WindowId getWindowId() {
17100 if (mAttachInfo == null) {
17103 if (mAttachInfo.mWindowId == null) {
17105 mAttachInfo.mIWindowId = mAttachInfo.mSession.getWindowId(
17106 mAttachInfo.mWindowToken);
17107 mAttachInfo.mWindowId = new WindowId(
17108 mAttachInfo.mIWindowId);
17109 } catch (RemoteException e) {
17112 return mAttachInfo.mWindowId;
17116 * Retrieve a unique token identifying the top-level "real" window of
17117 * the window that this view is attached to. That is, this is like
17118 * {@link #getWindowToken}, except if the window this view in is a panel
17119 * window (attached to another containing window), then the token of
17120 * the containing window is returned instead.
17122 * @return Returns the associated window token, either
17123 * {@link #getWindowToken()} or the containing window's token.
17125 public IBinder getApplicationWindowToken() {
17126 AttachInfo ai = mAttachInfo;
17128 IBinder appWindowToken = ai.mPanelParentWindowToken;
17129 if (appWindowToken == null) {
17130 appWindowToken = ai.mWindowToken;
17132 return appWindowToken;
17138 * Gets the logical display to which the view's window has been attached.
17140 * @return The logical display, or null if the view is not currently attached to a window.
17142 public Display getDisplay() {
17143 return mAttachInfo != null ? mAttachInfo.mDisplay : null;
17147 * Retrieve private session object this view hierarchy is using to
17148 * communicate with the window manager.
17149 * @return the session object to communicate with the window manager
17151 /*package*/ IWindowSession getWindowSession() {
17152 return mAttachInfo != null ? mAttachInfo.mSession : null;
17156 * Return the visibility value of the least visible component passed.
17158 int combineVisibility(int vis1, int vis2) {
17159 // This works because VISIBLE < INVISIBLE < GONE.
17160 return Math.max(vis1, vis2);
17164 * @param info the {@link android.view.View.AttachInfo} to associated with
17167 void dispatchAttachedToWindow(AttachInfo info, int visibility) {
17168 mAttachInfo = info;
17169 if (mOverlay != null) {
17170 mOverlay.getOverlayView().dispatchAttachedToWindow(info, visibility);
17172 mWindowAttachCount++;
17173 // We will need to evaluate the drawable state at least once.
17174 mPrivateFlags |= PFLAG_DRAWABLE_STATE_DIRTY;
17175 if (mFloatingTreeObserver != null) {
17176 info.mTreeObserver.merge(mFloatingTreeObserver);
17177 mFloatingTreeObserver = null;
17180 registerPendingFrameMetricsObservers();
17182 if ((mPrivateFlags&PFLAG_SCROLL_CONTAINER) != 0) {
17183 mAttachInfo.mScrollContainers.add(this);
17184 mPrivateFlags |= PFLAG_SCROLL_CONTAINER_ADDED;
17186 // Transfer all pending runnables.
17187 if (mRunQueue != null) {
17188 mRunQueue.executeActions(info.mHandler);
17191 performCollectViewAttributes(mAttachInfo, visibility);
17192 onAttachedToWindow();
17194 ListenerInfo li = mListenerInfo;
17195 final CopyOnWriteArrayList<OnAttachStateChangeListener> listeners =
17196 li != null ? li.mOnAttachStateChangeListeners : null;
17197 if (listeners != null && listeners.size() > 0) {
17198 // NOTE: because of the use of CopyOnWriteArrayList, we *must* use an iterator to
17199 // perform the dispatching. The iterator is a safe guard against listeners that
17200 // could mutate the list by calling the various add/remove methods. This prevents
17201 // the array from being modified while we iterate it.
17202 for (OnAttachStateChangeListener listener : listeners) {
17203 listener.onViewAttachedToWindow(this);
17207 int vis = info.mWindowVisibility;
17209 onWindowVisibilityChanged(vis);
17211 // Calling onVisibilityAggregated directly here since the subtree will also
17212 // receive dispatchAttachedToWindow and this same call
17213 onVisibilityAggregated(vis == VISIBLE);
17217 // Send onVisibilityChanged directly instead of dispatchVisibilityChanged.
17218 // As all views in the subtree will already receive dispatchAttachedToWindow
17219 // traversing the subtree again here is not desired.
17220 onVisibilityChanged(this, visibility);
17222 if ((mPrivateFlags&PFLAG_DRAWABLE_STATE_DIRTY) != 0) {
17223 // If nobody has evaluated the drawable state yet, then do it now.
17224 refreshDrawableState();
17226 needGlobalAttributesUpdate(false);
17228 notifyEnterOrExitForAutoFillIfNeeded(true);
17231 void dispatchDetachedFromWindow() {
17232 AttachInfo info = mAttachInfo;
17233 if (info != null) {
17234 int vis = info.mWindowVisibility;
17236 onWindowVisibilityChanged(GONE);
17238 // Invoking onVisibilityAggregated directly here since the subtree
17239 // will also receive detached from window
17240 onVisibilityAggregated(false);
17245 onDetachedFromWindow();
17246 onDetachedFromWindowInternal();
17248 InputMethodManager imm = InputMethodManager.peekInstance();
17250 imm.onViewDetachedFromWindow(this);
17253 ListenerInfo li = mListenerInfo;
17254 final CopyOnWriteArrayList<OnAttachStateChangeListener> listeners =
17255 li != null ? li.mOnAttachStateChangeListeners : null;
17256 if (listeners != null && listeners.size() > 0) {
17257 // NOTE: because of the use of CopyOnWriteArrayList, we *must* use an iterator to
17258 // perform the dispatching. The iterator is a safe guard against listeners that
17259 // could mutate the list by calling the various add/remove methods. This prevents
17260 // the array from being modified while we iterate it.
17261 for (OnAttachStateChangeListener listener : listeners) {
17262 listener.onViewDetachedFromWindow(this);
17266 if ((mPrivateFlags & PFLAG_SCROLL_CONTAINER_ADDED) != 0) {
17267 mAttachInfo.mScrollContainers.remove(this);
17268 mPrivateFlags &= ~PFLAG_SCROLL_CONTAINER_ADDED;
17271 mAttachInfo = null;
17272 if (mOverlay != null) {
17273 mOverlay.getOverlayView().dispatchDetachedFromWindow();
17276 notifyEnterOrExitForAutoFillIfNeeded(false);
17280 * Cancel any deferred high-level input events that were previously posted to the event queue.
17282 * <p>Many views post high-level events such as click handlers to the event queue
17283 * to run deferred in order to preserve a desired user experience - clearing visible
17284 * pressed states before executing, etc. This method will abort any events of this nature
17285 * that are currently in flight.</p>
17287 * <p>Custom views that generate their own high-level deferred input events should override
17288 * {@link #onCancelPendingInputEvents()} and remove those pending events from the queue.</p>
17290 * <p>This will also cancel pending input events for any child views.</p>
17292 * <p>Note that this may not be sufficient as a debouncing strategy for clicks in all cases.
17293 * This will not impact newer events posted after this call that may occur as a result of
17294 * lower-level input events still waiting in the queue. If you are trying to prevent
17295 * double-submitted events for the duration of some sort of asynchronous transaction
17296 * you should also take other steps to protect against unexpected double inputs e.g. calling
17297 * {@link #setEnabled(boolean) setEnabled(false)} and re-enabling the view when
17298 * the transaction completes, tracking already submitted transaction IDs, etc.</p>
17300 public final void cancelPendingInputEvents() {
17301 dispatchCancelPendingInputEvents();
17305 * Called by {@link #cancelPendingInputEvents()} to cancel input events in flight.
17306 * Overridden by ViewGroup to dispatch. Package scoped to prevent app-side meddling.
17308 void dispatchCancelPendingInputEvents() {
17309 mPrivateFlags3 &= ~PFLAG3_CALLED_SUPER;
17310 onCancelPendingInputEvents();
17311 if ((mPrivateFlags3 & PFLAG3_CALLED_SUPER) != PFLAG3_CALLED_SUPER) {
17312 throw new SuperNotCalledException("View " + getClass().getSimpleName() +
17313 " did not call through to super.onCancelPendingInputEvents()");
17318 * Called as the result of a call to {@link #cancelPendingInputEvents()} on this view or
17321 * <p>This method is responsible for removing any pending high-level input events that were
17322 * posted to the event queue to run later. Custom view classes that post their own deferred
17323 * high-level events via {@link #post(Runnable)}, {@link #postDelayed(Runnable, long)} or
17324 * {@link android.os.Handler} should override this method, call
17325 * <code>super.onCancelPendingInputEvents()</code> and remove those callbacks as appropriate.
17328 public void onCancelPendingInputEvents() {
17329 removePerformClickCallback();
17331 mPrivateFlags3 |= PFLAG3_CALLED_SUPER;
17335 * Store this view hierarchy's frozen state into the given container.
17337 * @param container The SparseArray in which to save the view's state.
17339 * @see #restoreHierarchyState(android.util.SparseArray)
17340 * @see #dispatchSaveInstanceState(android.util.SparseArray)
17341 * @see #onSaveInstanceState()
17343 public void saveHierarchyState(SparseArray<Parcelable> container) {
17344 dispatchSaveInstanceState(container);
17348 * Called by {@link #saveHierarchyState(android.util.SparseArray)} to store the state for
17349 * this view and its children. May be overridden to modify how freezing happens to a
17350 * view's children; for example, some views may want to not store state for their children.
17352 * @param container The SparseArray in which to save the view's state.
17354 * @see #dispatchRestoreInstanceState(android.util.SparseArray)
17355 * @see #saveHierarchyState(android.util.SparseArray)
17356 * @see #onSaveInstanceState()
17358 protected void dispatchSaveInstanceState(SparseArray<Parcelable> container) {
17359 if (mID != NO_ID && (mViewFlags & SAVE_DISABLED_MASK) == 0) {
17360 mPrivateFlags &= ~PFLAG_SAVE_STATE_CALLED;
17361 Parcelable state = onSaveInstanceState();
17362 if ((mPrivateFlags & PFLAG_SAVE_STATE_CALLED) == 0) {
17363 throw new IllegalStateException(
17364 "Derived class did not call super.onSaveInstanceState()");
17366 if (state != null) {
17367 // Log.i("View", "Freezing #" + Integer.toHexString(mID)
17368 // + ": " + state);
17369 container.put(mID, state);
17375 * Hook allowing a view to generate a representation of its internal state
17376 * that can later be used to create a new instance with that same state.
17377 * This state should only contain information that is not persistent or can
17378 * not be reconstructed later. For example, you will never store your
17379 * current position on screen because that will be computed again when a
17380 * new instance of the view is placed in its view hierarchy.
17382 * Some examples of things you may store here: the current cursor position
17383 * in a text view (but usually not the text itself since that is stored in a
17384 * content provider or other persistent storage), the currently selected
17385 * item in a list view.
17387 * @return Returns a Parcelable object containing the view's current dynamic
17388 * state, or null if there is nothing interesting to save.
17389 * @see #onRestoreInstanceState(android.os.Parcelable)
17390 * @see #saveHierarchyState(android.util.SparseArray)
17391 * @see #dispatchSaveInstanceState(android.util.SparseArray)
17392 * @see #setSaveEnabled(boolean)
17395 @Nullable protected Parcelable onSaveInstanceState() {
17396 mPrivateFlags |= PFLAG_SAVE_STATE_CALLED;
17397 if (mStartActivityRequestWho != null || isAutofilled()
17398 || mAccessibilityViewId > LAST_APP_ACCESSIBILITY_ID) {
17399 BaseSavedState state = new BaseSavedState(AbsSavedState.EMPTY_STATE);
17401 if (mStartActivityRequestWho != null) {
17402 state.mSavedData |= BaseSavedState.START_ACTIVITY_REQUESTED_WHO_SAVED;
17405 if (isAutofilled()) {
17406 state.mSavedData |= BaseSavedState.IS_AUTOFILLED;
17409 if (mAccessibilityViewId > LAST_APP_ACCESSIBILITY_ID) {
17410 state.mSavedData |= BaseSavedState.ACCESSIBILITY_ID;
17413 state.mStartActivityRequestWhoSaved = mStartActivityRequestWho;
17414 state.mIsAutofilled = isAutofilled();
17415 state.mAccessibilityViewId = mAccessibilityViewId;
17418 return BaseSavedState.EMPTY_STATE;
17422 * Restore this view hierarchy's frozen state from the given container.
17424 * @param container The SparseArray which holds previously frozen states.
17426 * @see #saveHierarchyState(android.util.SparseArray)
17427 * @see #dispatchRestoreInstanceState(android.util.SparseArray)
17428 * @see #onRestoreInstanceState(android.os.Parcelable)
17430 public void restoreHierarchyState(SparseArray<Parcelable> container) {
17431 dispatchRestoreInstanceState(container);
17435 * Called by {@link #restoreHierarchyState(android.util.SparseArray)} to retrieve the
17436 * state for this view and its children. May be overridden to modify how restoring
17437 * happens to a view's children; for example, some views may want to not store state
17438 * for their children.
17440 * @param container The SparseArray which holds previously saved state.
17442 * @see #dispatchSaveInstanceState(android.util.SparseArray)
17443 * @see #restoreHierarchyState(android.util.SparseArray)
17444 * @see #onRestoreInstanceState(android.os.Parcelable)
17446 protected void dispatchRestoreInstanceState(SparseArray<Parcelable> container) {
17447 if (mID != NO_ID) {
17448 Parcelable state = container.get(mID);
17449 if (state != null) {
17450 // Log.i("View", "Restoreing #" + Integer.toHexString(mID)
17451 // + ": " + state);
17452 mPrivateFlags &= ~PFLAG_SAVE_STATE_CALLED;
17453 onRestoreInstanceState(state);
17454 if ((mPrivateFlags & PFLAG_SAVE_STATE_CALLED) == 0) {
17455 throw new IllegalStateException(
17456 "Derived class did not call super.onRestoreInstanceState()");
17463 * Hook allowing a view to re-apply a representation of its internal state that had previously
17464 * been generated by {@link #onSaveInstanceState}. This function will never be called with a
17467 * @param state The frozen state that had previously been returned by
17468 * {@link #onSaveInstanceState}.
17470 * @see #onSaveInstanceState()
17471 * @see #restoreHierarchyState(android.util.SparseArray)
17472 * @see #dispatchRestoreInstanceState(android.util.SparseArray)
17475 protected void onRestoreInstanceState(Parcelable state) {
17476 mPrivateFlags |= PFLAG_SAVE_STATE_CALLED;
17477 if (state != null && !(state instanceof AbsSavedState)) {
17478 throw new IllegalArgumentException("Wrong state class, expecting View State but "
17479 + "received " + state.getClass().toString() + " instead. This usually happens "
17480 + "when two views of different type have the same id in the same hierarchy. "
17481 + "This view's id is " + ViewDebug.resolveId(mContext, getId()) + ". Make sure "
17482 + "other views do not use the same id.");
17484 if (state != null && state instanceof BaseSavedState) {
17485 BaseSavedState baseState = (BaseSavedState) state;
17487 if ((baseState.mSavedData & BaseSavedState.START_ACTIVITY_REQUESTED_WHO_SAVED) != 0) {
17488 mStartActivityRequestWho = baseState.mStartActivityRequestWhoSaved;
17490 if ((baseState.mSavedData & BaseSavedState.IS_AUTOFILLED) != 0) {
17491 setAutofilled(baseState.mIsAutofilled);
17493 if ((baseState.mSavedData & BaseSavedState.ACCESSIBILITY_ID) != 0) {
17494 mAccessibilityViewId = baseState.mAccessibilityViewId;
17500 * <p>Return the time at which the drawing of the view hierarchy started.</p>
17502 * @return the drawing start time in milliseconds
17504 public long getDrawingTime() {
17505 return mAttachInfo != null ? mAttachInfo.mDrawingTime : 0;
17509 * <p>Enables or disables the duplication of the parent's state into this view. When
17510 * duplication is enabled, this view gets its drawable state from its parent rather
17511 * than from its own internal properties.</p>
17513 * <p>Note: in the current implementation, setting this property to true after the
17514 * view was added to a ViewGroup might have no effect at all. This property should
17515 * always be used from XML or set to true before adding this view to a ViewGroup.</p>
17517 * <p>Note: if this view's parent addStateFromChildren property is enabled and this
17518 * property is enabled, an exception will be thrown.</p>
17520 * <p>Note: if the child view uses and updates additional states which are unknown to the
17521 * parent, these states should not be affected by this method.</p>
17523 * @param enabled True to enable duplication of the parent's drawable state, false
17526 * @see #getDrawableState()
17527 * @see #isDuplicateParentStateEnabled()
17529 public void setDuplicateParentStateEnabled(boolean enabled) {
17530 setFlags(enabled ? DUPLICATE_PARENT_STATE : 0, DUPLICATE_PARENT_STATE);
17534 * <p>Indicates whether this duplicates its drawable state from its parent.</p>
17536 * @return True if this view's drawable state is duplicated from the parent,
17539 * @see #getDrawableState()
17540 * @see #setDuplicateParentStateEnabled(boolean)
17542 public boolean isDuplicateParentStateEnabled() {
17543 return (mViewFlags & DUPLICATE_PARENT_STATE) == DUPLICATE_PARENT_STATE;
17547 * <p>Specifies the type of layer backing this view. The layer can be
17548 * {@link #LAYER_TYPE_NONE}, {@link #LAYER_TYPE_SOFTWARE} or
17549 * {@link #LAYER_TYPE_HARDWARE}.</p>
17551 * <p>A layer is associated with an optional {@link android.graphics.Paint}
17552 * instance that controls how the layer is composed on screen. The following
17553 * properties of the paint are taken into account when composing the layer:</p>
17555 * <li>{@link android.graphics.Paint#getAlpha() Translucency (alpha)}</li>
17556 * <li>{@link android.graphics.Paint#getXfermode() Blending mode}</li>
17557 * <li>{@link android.graphics.Paint#getColorFilter() Color filter}</li>
17560 * <p>If this view has an alpha value set to < 1.0 by calling
17561 * {@link #setAlpha(float)}, the alpha value of the layer's paint is superseded
17562 * by this view's alpha value.</p>
17564 * <p>Refer to the documentation of {@link #LAYER_TYPE_NONE},
17565 * {@link #LAYER_TYPE_SOFTWARE} and {@link #LAYER_TYPE_HARDWARE}
17566 * for more information on when and how to use layers.</p>
17568 * @param layerType The type of layer to use with this view, must be one of
17569 * {@link #LAYER_TYPE_NONE}, {@link #LAYER_TYPE_SOFTWARE} or
17570 * {@link #LAYER_TYPE_HARDWARE}
17571 * @param paint The paint used to compose the layer. This argument is optional
17572 * and can be null. It is ignored when the layer type is
17573 * {@link #LAYER_TYPE_NONE}
17575 * @see #getLayerType()
17576 * @see #LAYER_TYPE_NONE
17577 * @see #LAYER_TYPE_SOFTWARE
17578 * @see #LAYER_TYPE_HARDWARE
17579 * @see #setAlpha(float)
17581 * @attr ref android.R.styleable#View_layerType
17583 public void setLayerType(int layerType, @Nullable Paint paint) {
17584 if (layerType < LAYER_TYPE_NONE || layerType > LAYER_TYPE_HARDWARE) {
17585 throw new IllegalArgumentException("Layer type can only be one of: LAYER_TYPE_NONE, "
17586 + "LAYER_TYPE_SOFTWARE or LAYER_TYPE_HARDWARE");
17589 boolean typeChanged = mRenderNode.setLayerType(layerType);
17591 if (!typeChanged) {
17592 setLayerPaint(paint);
17596 if (layerType != LAYER_TYPE_SOFTWARE) {
17597 // Destroy any previous software drawing cache if present
17598 // NOTE: even if previous layer type is HW, we do this to ensure we've cleaned up
17599 // drawing cache created in View#draw when drawing to a SW canvas.
17600 destroyDrawingCache();
17603 mLayerType = layerType;
17604 mLayerPaint = mLayerType == LAYER_TYPE_NONE ? null : paint;
17605 mRenderNode.setLayerPaint(mLayerPaint);
17607 // draw() behaves differently if we are on a layer, so we need to
17608 // invalidate() here
17609 invalidateParentCaches();
17614 * Updates the {@link Paint} object used with the current layer (used only if the current
17615 * layer type is not set to {@link #LAYER_TYPE_NONE}). Changed properties of the Paint
17616 * provided to {@link #setLayerType(int, android.graphics.Paint)} will be used the next time
17617 * the View is redrawn, but {@link #setLayerPaint(android.graphics.Paint)} must be called to
17618 * ensure that the view gets redrawn immediately.
17620 * <p>A layer is associated with an optional {@link android.graphics.Paint}
17621 * instance that controls how the layer is composed on screen. The following
17622 * properties of the paint are taken into account when composing the layer:</p>
17624 * <li>{@link android.graphics.Paint#getAlpha() Translucency (alpha)}</li>
17625 * <li>{@link android.graphics.Paint#getXfermode() Blending mode}</li>
17626 * <li>{@link android.graphics.Paint#getColorFilter() Color filter}</li>
17629 * <p>If this view has an alpha value set to < 1.0 by calling {@link #setAlpha(float)}, the
17630 * alpha value of the layer's paint is superseded by this view's alpha value.</p>
17632 * @param paint The paint used to compose the layer. This argument is optional
17633 * and can be null. It is ignored when the layer type is
17634 * {@link #LAYER_TYPE_NONE}
17636 * @see #setLayerType(int, android.graphics.Paint)
17638 public void setLayerPaint(@Nullable Paint paint) {
17639 int layerType = getLayerType();
17640 if (layerType != LAYER_TYPE_NONE) {
17641 mLayerPaint = paint;
17642 if (layerType == LAYER_TYPE_HARDWARE) {
17643 if (mRenderNode.setLayerPaint(paint)) {
17644 invalidateViewProperty(false, false);
17653 * Indicates what type of layer is currently associated with this view. By default
17654 * a view does not have a layer, and the layer type is {@link #LAYER_TYPE_NONE}.
17655 * Refer to the documentation of {@link #setLayerType(int, android.graphics.Paint)}
17656 * for more information on the different types of layers.
17658 * @return {@link #LAYER_TYPE_NONE}, {@link #LAYER_TYPE_SOFTWARE} or
17659 * {@link #LAYER_TYPE_HARDWARE}
17661 * @see #setLayerType(int, android.graphics.Paint)
17662 * @see #buildLayer()
17663 * @see #LAYER_TYPE_NONE
17664 * @see #LAYER_TYPE_SOFTWARE
17665 * @see #LAYER_TYPE_HARDWARE
17667 public int getLayerType() {
17672 * Forces this view's layer to be created and this view to be rendered
17673 * into its layer. If this view's layer type is set to {@link #LAYER_TYPE_NONE},
17674 * invoking this method will have no effect.
17676 * This method can for instance be used to render a view into its layer before
17677 * starting an animation. If this view is complex, rendering into the layer
17678 * before starting the animation will avoid skipping frames.
17680 * @throws IllegalStateException If this view is not attached to a window
17682 * @see #setLayerType(int, android.graphics.Paint)
17684 public void buildLayer() {
17685 if (mLayerType == LAYER_TYPE_NONE) return;
17687 final AttachInfo attachInfo = mAttachInfo;
17688 if (attachInfo == null) {
17689 throw new IllegalStateException("This view must be attached to a window first");
17692 if (getWidth() == 0 || getHeight() == 0) {
17696 switch (mLayerType) {
17697 case LAYER_TYPE_HARDWARE:
17698 updateDisplayListIfDirty();
17699 if (attachInfo.mThreadedRenderer != null && mRenderNode.isValid()) {
17700 attachInfo.mThreadedRenderer.buildLayer(mRenderNode);
17703 case LAYER_TYPE_SOFTWARE:
17704 buildDrawingCache(true);
17710 * Destroys all hardware rendering resources. This method is invoked
17711 * when the system needs to reclaim resources. Upon execution of this
17712 * method, you should free any OpenGL resources created by the view.
17714 * Note: you <strong>must</strong> call
17715 * <code>super.destroyHardwareResources()</code> when overriding
17721 protected void destroyHardwareResources() {
17722 if (mOverlay != null) {
17723 mOverlay.getOverlayView().destroyHardwareResources();
17725 if (mGhostView != null) {
17726 mGhostView.destroyHardwareResources();
17731 * <p>Enables or disables the drawing cache. When the drawing cache is enabled, the next call
17732 * to {@link #getDrawingCache()} or {@link #buildDrawingCache()} will draw the view in a
17733 * bitmap. Calling {@link #draw(android.graphics.Canvas)} will not draw from the cache when
17734 * the cache is enabled. To benefit from the cache, you must request the drawing cache by
17735 * calling {@link #getDrawingCache()} and draw it on screen if the returned bitmap is not
17738 * <p>Enabling the drawing cache is similar to
17739 * {@link #setLayerType(int, android.graphics.Paint) setting a layer} when hardware
17740 * acceleration is turned off. When hardware acceleration is turned on, enabling the
17741 * drawing cache has no effect on rendering because the system uses a different mechanism
17742 * for acceleration which ignores the flag. If you want to use a Bitmap for the view, even
17743 * when hardware acceleration is enabled, see {@link #setLayerType(int, android.graphics.Paint)}
17744 * for information on how to enable software and hardware layers.</p>
17746 * <p>This API can be used to manually generate
17747 * a bitmap copy of this view, by setting the flag to <code>true</code> and calling
17748 * {@link #getDrawingCache()}.</p>
17750 * @param enabled true to enable the drawing cache, false otherwise
17752 * @see #isDrawingCacheEnabled()
17753 * @see #getDrawingCache()
17754 * @see #buildDrawingCache()
17755 * @see #setLayerType(int, android.graphics.Paint)
17757 public void setDrawingCacheEnabled(boolean enabled) {
17758 mCachingFailed = false;
17759 setFlags(enabled ? DRAWING_CACHE_ENABLED : 0, DRAWING_CACHE_ENABLED);
17763 * <p>Indicates whether the drawing cache is enabled for this view.</p>
17765 * @return true if the drawing cache is enabled
17767 * @see #setDrawingCacheEnabled(boolean)
17768 * @see #getDrawingCache()
17770 @ViewDebug.ExportedProperty(category = "drawing")
17771 public boolean isDrawingCacheEnabled() {
17772 return (mViewFlags & DRAWING_CACHE_ENABLED) == DRAWING_CACHE_ENABLED;
17776 * Debugging utility which recursively outputs the dirty state of a view and its
17781 @SuppressWarnings({"UnusedDeclaration"})
17782 public void outputDirtyFlags(String indent, boolean clear, int clearMask) {
17783 Log.d("View", indent + this + " DIRTY(" + (mPrivateFlags & View.PFLAG_DIRTY_MASK) +
17784 ") DRAWN(" + (mPrivateFlags & PFLAG_DRAWN) + ")" + " CACHE_VALID(" +
17785 (mPrivateFlags & View.PFLAG_DRAWING_CACHE_VALID) +
17786 ") INVALIDATED(" + (mPrivateFlags & PFLAG_INVALIDATED) + ")");
17788 mPrivateFlags &= clearMask;
17790 if (this instanceof ViewGroup) {
17791 ViewGroup parent = (ViewGroup) this;
17792 final int count = parent.getChildCount();
17793 for (int i = 0; i < count; i++) {
17794 final View child = parent.getChildAt(i);
17795 child.outputDirtyFlags(indent + " ", clear, clearMask);
17801 * This method is used by ViewGroup to cause its children to restore or recreate their
17802 * display lists. It is called by getDisplayList() when the parent ViewGroup does not need
17803 * to recreate its own display list, which would happen if it went through the normal
17804 * draw/dispatchDraw mechanisms.
17808 protected void dispatchGetDisplayList() {}
17811 * A view that is not attached or hardware accelerated cannot create a display list.
17812 * This method checks these conditions and returns the appropriate result.
17814 * @return true if view has the ability to create a display list, false otherwise.
17818 public boolean canHaveDisplayList() {
17819 return !(mAttachInfo == null || mAttachInfo.mThreadedRenderer == null);
17823 * Gets the RenderNode for the view, and updates its DisplayList (if needed and supported)
17827 public RenderNode updateDisplayListIfDirty() {
17828 final RenderNode renderNode = mRenderNode;
17829 if (!canHaveDisplayList()) {
17830 // can't populate RenderNode, don't try
17834 if ((mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == 0
17835 || !renderNode.isValid()
17836 || (mRecreateDisplayList)) {
17837 // Don't need to recreate the display list, just need to tell our
17838 // children to restore/recreate theirs
17839 if (renderNode.isValid()
17840 && !mRecreateDisplayList) {
17841 mPrivateFlags |= PFLAG_DRAWN | PFLAG_DRAWING_CACHE_VALID;
17842 mPrivateFlags &= ~PFLAG_DIRTY_MASK;
17843 dispatchGetDisplayList();
17845 return renderNode; // no work needed
17848 // If we got here, we're recreating it. Mark it as such to ensure that
17849 // we copy in child display lists into ours in drawChild()
17850 mRecreateDisplayList = true;
17852 int width = mRight - mLeft;
17853 int height = mBottom - mTop;
17854 int layerType = getLayerType();
17856 final DisplayListCanvas canvas = renderNode.start(width, height);
17857 canvas.setHighContrastText(mAttachInfo.mHighContrastText);
17860 if (layerType == LAYER_TYPE_SOFTWARE) {
17861 buildDrawingCache(true);
17862 Bitmap cache = getDrawingCache(true);
17863 if (cache != null) {
17864 canvas.drawBitmap(cache, 0, 0, mLayerPaint);
17869 canvas.translate(-mScrollX, -mScrollY);
17870 mPrivateFlags |= PFLAG_DRAWN | PFLAG_DRAWING_CACHE_VALID;
17871 mPrivateFlags &= ~PFLAG_DIRTY_MASK;
17873 // Fast path for layouts with no backgrounds
17874 if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) {
17875 dispatchDraw(canvas);
17876 drawAutofilledHighlight(canvas);
17877 if (mOverlay != null && !mOverlay.isEmpty()) {
17878 mOverlay.getOverlayView().draw(canvas);
17881 debugDrawFocus(canvas);
17888 renderNode.end(canvas);
17889 setDisplayListProperties(renderNode);
17892 mPrivateFlags |= PFLAG_DRAWN | PFLAG_DRAWING_CACHE_VALID;
17893 mPrivateFlags &= ~PFLAG_DIRTY_MASK;
17898 private void resetDisplayList() {
17899 mRenderNode.discardDisplayList();
17900 if (mBackgroundRenderNode != null) {
17901 mBackgroundRenderNode.discardDisplayList();
17906 * <p>Calling this method is equivalent to calling <code>getDrawingCache(false)</code>.</p>
17908 * @return A non-scaled bitmap representing this view or null if cache is disabled.
17910 * @see #getDrawingCache(boolean)
17912 public Bitmap getDrawingCache() {
17913 return getDrawingCache(false);
17917 * <p>Returns the bitmap in which this view drawing is cached. The returned bitmap
17918 * is null when caching is disabled. If caching is enabled and the cache is not ready,
17919 * this method will create it. Calling {@link #draw(android.graphics.Canvas)} will not
17920 * draw from the cache when the cache is enabled. To benefit from the cache, you must
17921 * request the drawing cache by calling this method and draw it on screen if the
17922 * returned bitmap is not null.</p>
17924 * <p>Note about auto scaling in compatibility mode: When auto scaling is not enabled,
17925 * this method will create a bitmap of the same size as this view. Because this bitmap
17926 * will be drawn scaled by the parent ViewGroup, the result on screen might show
17927 * scaling artifacts. To avoid such artifacts, you should call this method by setting
17928 * the auto scaling to true. Doing so, however, will generate a bitmap of a different
17929 * size than the view. This implies that your application must be able to handle this
17932 * @param autoScale Indicates whether the generated bitmap should be scaled based on
17933 * the current density of the screen when the application is in compatibility
17936 * @return A bitmap representing this view or null if cache is disabled.
17938 * @see #setDrawingCacheEnabled(boolean)
17939 * @see #isDrawingCacheEnabled()
17940 * @see #buildDrawingCache(boolean)
17941 * @see #destroyDrawingCache()
17943 public Bitmap getDrawingCache(boolean autoScale) {
17944 if ((mViewFlags & WILL_NOT_CACHE_DRAWING) == WILL_NOT_CACHE_DRAWING) {
17947 if ((mViewFlags & DRAWING_CACHE_ENABLED) == DRAWING_CACHE_ENABLED) {
17948 buildDrawingCache(autoScale);
17950 return autoScale ? mDrawingCache : mUnscaledDrawingCache;
17954 * <p>Frees the resources used by the drawing cache. If you call
17955 * {@link #buildDrawingCache()} manually without calling
17956 * {@link #setDrawingCacheEnabled(boolean) setDrawingCacheEnabled(true)}, you
17957 * should cleanup the cache with this method afterwards.</p>
17959 * @see #setDrawingCacheEnabled(boolean)
17960 * @see #buildDrawingCache()
17961 * @see #getDrawingCache()
17963 public void destroyDrawingCache() {
17964 if (mDrawingCache != null) {
17965 mDrawingCache.recycle();
17966 mDrawingCache = null;
17968 if (mUnscaledDrawingCache != null) {
17969 mUnscaledDrawingCache.recycle();
17970 mUnscaledDrawingCache = null;
17975 * Setting a solid background color for the drawing cache's bitmaps will improve
17976 * performance and memory usage. Note, though that this should only be used if this
17977 * view will always be drawn on top of a solid color.
17979 * @param color The background color to use for the drawing cache's bitmap
17981 * @see #setDrawingCacheEnabled(boolean)
17982 * @see #buildDrawingCache()
17983 * @see #getDrawingCache()
17985 public void setDrawingCacheBackgroundColor(@ColorInt int color) {
17986 if (color != mDrawingCacheBackgroundColor) {
17987 mDrawingCacheBackgroundColor = color;
17988 mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID;
17993 * @see #setDrawingCacheBackgroundColor(int)
17995 * @return The background color to used for the drawing cache's bitmap
17998 public int getDrawingCacheBackgroundColor() {
17999 return mDrawingCacheBackgroundColor;
18003 * <p>Calling this method is equivalent to calling <code>buildDrawingCache(false)</code>.</p>
18005 * @see #buildDrawingCache(boolean)
18007 public void buildDrawingCache() {
18008 buildDrawingCache(false);
18012 * <p>Forces the drawing cache to be built if the drawing cache is invalid.</p>
18014 * <p>If you call {@link #buildDrawingCache()} manually without calling
18015 * {@link #setDrawingCacheEnabled(boolean) setDrawingCacheEnabled(true)}, you
18016 * should cleanup the cache by calling {@link #destroyDrawingCache()} afterwards.</p>
18018 * <p>Note about auto scaling in compatibility mode: When auto scaling is not enabled,
18019 * this method will create a bitmap of the same size as this view. Because this bitmap
18020 * will be drawn scaled by the parent ViewGroup, the result on screen might show
18021 * scaling artifacts. To avoid such artifacts, you should call this method by setting
18022 * the auto scaling to true. Doing so, however, will generate a bitmap of a different
18023 * size than the view. This implies that your application must be able to handle this
18026 * <p>You should avoid calling this method when hardware acceleration is enabled. If
18027 * you do not need the drawing cache bitmap, calling this method will increase memory
18028 * usage and cause the view to be rendered in software once, thus negatively impacting
18031 * @see #getDrawingCache()
18032 * @see #destroyDrawingCache()
18034 public void buildDrawingCache(boolean autoScale) {
18035 if ((mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == 0 || (autoScale ?
18036 mDrawingCache == null : mUnscaledDrawingCache == null)) {
18037 if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) {
18038 Trace.traceBegin(Trace.TRACE_TAG_VIEW,
18039 "buildDrawingCache/SW Layer for " + getClass().getSimpleName());
18042 buildDrawingCacheImpl(autoScale);
18044 Trace.traceEnd(Trace.TRACE_TAG_VIEW);
18050 * private, internal implementation of buildDrawingCache, used to enable tracing
18052 private void buildDrawingCacheImpl(boolean autoScale) {
18053 mCachingFailed = false;
18055 int width = mRight - mLeft;
18056 int height = mBottom - mTop;
18058 final AttachInfo attachInfo = mAttachInfo;
18059 final boolean scalingRequired = attachInfo != null && attachInfo.mScalingRequired;
18061 if (autoScale && scalingRequired) {
18062 width = (int) ((width * attachInfo.mApplicationScale) + 0.5f);
18063 height = (int) ((height * attachInfo.mApplicationScale) + 0.5f);
18066 final int drawingCacheBackgroundColor = mDrawingCacheBackgroundColor;
18067 final boolean opaque = drawingCacheBackgroundColor != 0 || isOpaque();
18068 final boolean use32BitCache = attachInfo != null && attachInfo.mUse32BitDrawingCache;
18070 final long projectedBitmapSize = width * height * (opaque && !use32BitCache ? 2 : 4);
18071 final long drawingCacheSize =
18072 ViewConfiguration.get(mContext).getScaledMaximumDrawingCacheSize();
18073 if (width <= 0 || height <= 0 || projectedBitmapSize > drawingCacheSize) {
18074 if (width > 0 && height > 0) {
18075 Log.w(VIEW_LOG_TAG, getClass().getSimpleName() + " not displayed because it is"
18076 + " too large to fit into a software layer (or drawing cache), needs "
18077 + projectedBitmapSize + " bytes, only "
18078 + drawingCacheSize + " available");
18080 destroyDrawingCache();
18081 mCachingFailed = true;
18085 boolean clear = true;
18086 Bitmap bitmap = autoScale ? mDrawingCache : mUnscaledDrawingCache;
18088 if (bitmap == null || bitmap.getWidth() != width || bitmap.getHeight() != height) {
18089 Bitmap.Config quality;
18091 // Never pick ARGB_4444 because it looks awful
18092 // Keep the DRAWING_CACHE_QUALITY_LOW flag just in case
18093 switch (mViewFlags & DRAWING_CACHE_QUALITY_MASK) {
18094 case DRAWING_CACHE_QUALITY_AUTO:
18095 case DRAWING_CACHE_QUALITY_LOW:
18096 case DRAWING_CACHE_QUALITY_HIGH:
18098 quality = Bitmap.Config.ARGB_8888;
18102 // Optimization for translucent windows
18103 // If the window is translucent, use a 32 bits bitmap to benefit from memcpy()
18104 quality = use32BitCache ? Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565;
18107 // Try to cleanup memory
18108 if (bitmap != null) bitmap.recycle();
18111 bitmap = Bitmap.createBitmap(mResources.getDisplayMetrics(),
18112 width, height, quality);
18113 bitmap.setDensity(getResources().getDisplayMetrics().densityDpi);
18115 mDrawingCache = bitmap;
18117 mUnscaledDrawingCache = bitmap;
18119 if (opaque && use32BitCache) bitmap.setHasAlpha(false);
18120 } catch (OutOfMemoryError e) {
18121 // If there is not enough memory to create the bitmap cache, just
18122 // ignore the issue as bitmap caches are not required to draw the
18125 mDrawingCache = null;
18127 mUnscaledDrawingCache = null;
18129 mCachingFailed = true;
18133 clear = drawingCacheBackgroundColor != 0;
18137 if (attachInfo != null) {
18138 canvas = attachInfo.mCanvas;
18139 if (canvas == null) {
18140 canvas = new Canvas();
18142 canvas.setBitmap(bitmap);
18143 // Temporarily clobber the cached Canvas in case one of our children
18144 // is also using a drawing cache. Without this, the children would
18145 // steal the canvas by attaching their own bitmap to it and bad, bad
18146 // thing would happen (invisible views, corrupted drawings, etc.)
18147 attachInfo.mCanvas = null;
18149 // This case should hopefully never or seldom happen
18150 canvas = new Canvas(bitmap);
18154 bitmap.eraseColor(drawingCacheBackgroundColor);
18158 final int restoreCount = canvas.save();
18160 if (autoScale && scalingRequired) {
18161 final float scale = attachInfo.mApplicationScale;
18162 canvas.scale(scale, scale);
18165 canvas.translate(-mScrollX, -mScrollY);
18167 mPrivateFlags |= PFLAG_DRAWN;
18168 if (mAttachInfo == null || !mAttachInfo.mHardwareAccelerated ||
18169 mLayerType != LAYER_TYPE_NONE) {
18170 mPrivateFlags |= PFLAG_DRAWING_CACHE_VALID;
18173 // Fast path for layouts with no backgrounds
18174 if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) {
18175 mPrivateFlags &= ~PFLAG_DIRTY_MASK;
18176 dispatchDraw(canvas);
18177 drawAutofilledHighlight(canvas);
18178 if (mOverlay != null && !mOverlay.isEmpty()) {
18179 mOverlay.getOverlayView().draw(canvas);
18185 canvas.restoreToCount(restoreCount);
18186 canvas.setBitmap(null);
18188 if (attachInfo != null) {
18189 // Restore the cached Canvas for our siblings
18190 attachInfo.mCanvas = canvas;
18195 * Create a snapshot of the view into a bitmap. We should probably make
18196 * some form of this public, but should think about the API.
18200 public Bitmap createSnapshot(Bitmap.Config quality, int backgroundColor, boolean skipChildren) {
18201 int width = mRight - mLeft;
18202 int height = mBottom - mTop;
18204 final AttachInfo attachInfo = mAttachInfo;
18205 final float scale = attachInfo != null ? attachInfo.mApplicationScale : 1.0f;
18206 width = (int) ((width * scale) + 0.5f);
18207 height = (int) ((height * scale) + 0.5f);
18209 Bitmap bitmap = Bitmap.createBitmap(mResources.getDisplayMetrics(),
18210 width > 0 ? width : 1, height > 0 ? height : 1, quality);
18211 if (bitmap == null) {
18212 throw new OutOfMemoryError();
18215 Resources resources = getResources();
18216 if (resources != null) {
18217 bitmap.setDensity(resources.getDisplayMetrics().densityDpi);
18221 if (attachInfo != null) {
18222 canvas = attachInfo.mCanvas;
18223 if (canvas == null) {
18224 canvas = new Canvas();
18226 canvas.setBitmap(bitmap);
18227 // Temporarily clobber the cached Canvas in case one of our children
18228 // is also using a drawing cache. Without this, the children would
18229 // steal the canvas by attaching their own bitmap to it and bad, bad
18230 // things would happen (invisible views, corrupted drawings, etc.)
18231 attachInfo.mCanvas = null;
18233 // This case should hopefully never or seldom happen
18234 canvas = new Canvas(bitmap);
18236 boolean enabledHwBitmapsInSwMode = canvas.isHwBitmapsInSwModeEnabled();
18237 canvas.setHwBitmapsInSwModeEnabled(true);
18238 if ((backgroundColor & 0xff000000) != 0) {
18239 bitmap.eraseColor(backgroundColor);
18243 final int restoreCount = canvas.save();
18244 canvas.scale(scale, scale);
18245 canvas.translate(-mScrollX, -mScrollY);
18247 // Temporarily remove the dirty mask
18248 int flags = mPrivateFlags;
18249 mPrivateFlags &= ~PFLAG_DIRTY_MASK;
18251 // Fast path for layouts with no backgrounds
18252 if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) {
18253 dispatchDraw(canvas);
18254 drawAutofilledHighlight(canvas);
18255 if (mOverlay != null && !mOverlay.isEmpty()) {
18256 mOverlay.getOverlayView().draw(canvas);
18262 mPrivateFlags = flags;
18264 canvas.restoreToCount(restoreCount);
18265 canvas.setBitmap(null);
18266 canvas.setHwBitmapsInSwModeEnabled(enabledHwBitmapsInSwMode);
18268 if (attachInfo != null) {
18269 // Restore the cached Canvas for our siblings
18270 attachInfo.mCanvas = canvas;
18277 * Indicates whether this View is currently in edit mode. A View is usually
18278 * in edit mode when displayed within a developer tool. For instance, if
18279 * this View is being drawn by a visual user interface builder, this method
18280 * should return true.
18282 * Subclasses should check the return value of this method to provide
18283 * different behaviors if their normal behavior might interfere with the
18284 * host environment. For instance: the class spawns a thread in its
18285 * constructor, the drawing code relies on device-specific features, etc.
18287 * This method is usually checked in the drawing code of custom widgets.
18289 * @return True if this View is in edit mode, false otherwise.
18291 public boolean isInEditMode() {
18296 * If the View draws content inside its padding and enables fading edges,
18297 * it needs to support padding offsets. Padding offsets are added to the
18298 * fading edges to extend the length of the fade so that it covers pixels
18299 * drawn inside the padding.
18301 * Subclasses of this class should override this method if they need
18302 * to draw content inside the padding.
18304 * @return True if padding offset must be applied, false otherwise.
18306 * @see #getLeftPaddingOffset()
18307 * @see #getRightPaddingOffset()
18308 * @see #getTopPaddingOffset()
18309 * @see #getBottomPaddingOffset()
18313 protected boolean isPaddingOffsetRequired() {
18318 * Amount by which to extend the left fading region. Called only when
18319 * {@link #isPaddingOffsetRequired()} returns true.
18321 * @return The left padding offset in pixels.
18323 * @see #isPaddingOffsetRequired()
18327 protected int getLeftPaddingOffset() {
18332 * Amount by which to extend the right fading region. Called only when
18333 * {@link #isPaddingOffsetRequired()} returns true.
18335 * @return The right padding offset in pixels.
18337 * @see #isPaddingOffsetRequired()
18341 protected int getRightPaddingOffset() {
18346 * Amount by which to extend the top fading region. Called only when
18347 * {@link #isPaddingOffsetRequired()} returns true.
18349 * @return The top padding offset in pixels.
18351 * @see #isPaddingOffsetRequired()
18355 protected int getTopPaddingOffset() {
18360 * Amount by which to extend the bottom fading region. Called only when
18361 * {@link #isPaddingOffsetRequired()} returns true.
18363 * @return The bottom padding offset in pixels.
18365 * @see #isPaddingOffsetRequired()
18369 protected int getBottomPaddingOffset() {
18375 * @param offsetRequired
18377 protected int getFadeTop(boolean offsetRequired) {
18378 int top = mPaddingTop;
18379 if (offsetRequired) top += getTopPaddingOffset();
18385 * @param offsetRequired
18387 protected int getFadeHeight(boolean offsetRequired) {
18388 int padding = mPaddingTop;
18389 if (offsetRequired) padding += getTopPaddingOffset();
18390 return mBottom - mTop - mPaddingBottom - padding;
18394 * <p>Indicates whether this view is attached to a hardware accelerated
18395 * window or not.</p>
18397 * <p>Even if this method returns true, it does not mean that every call
18398 * to {@link #draw(android.graphics.Canvas)} will be made with an hardware
18399 * accelerated {@link android.graphics.Canvas}. For instance, if this view
18400 * is drawn onto an offscreen {@link android.graphics.Bitmap} and its
18401 * window is hardware accelerated,
18402 * {@link android.graphics.Canvas#isHardwareAccelerated()} will likely
18403 * return false, and this method will return true.</p>
18405 * @return True if the view is attached to a window and the window is
18406 * hardware accelerated; false in any other case.
18408 @ViewDebug.ExportedProperty(category = "drawing")
18409 public boolean isHardwareAccelerated() {
18410 return mAttachInfo != null && mAttachInfo.mHardwareAccelerated;
18414 * Sets a rectangular area on this view to which the view will be clipped
18415 * when it is drawn. Setting the value to null will remove the clip bounds
18416 * and the view will draw normally, using its full bounds.
18418 * @param clipBounds The rectangular area, in the local coordinates of
18419 * this view, to which future drawing operations will be clipped.
18421 public void setClipBounds(Rect clipBounds) {
18422 if (clipBounds == mClipBounds
18423 || (clipBounds != null && clipBounds.equals(mClipBounds))) {
18426 if (clipBounds != null) {
18427 if (mClipBounds == null) {
18428 mClipBounds = new Rect(clipBounds);
18430 mClipBounds.set(clipBounds);
18433 mClipBounds = null;
18435 mRenderNode.setClipBounds(mClipBounds);
18436 invalidateViewProperty(false, false);
18440 * Returns a copy of the current {@link #setClipBounds(Rect) clipBounds}.
18442 * @return A copy of the current clip bounds if clip bounds are set,
18445 public Rect getClipBounds() {
18446 return (mClipBounds != null) ? new Rect(mClipBounds) : null;
18451 * Populates an output rectangle with the clip bounds of the view,
18452 * returning {@code true} if successful or {@code false} if the view's
18453 * clip bounds are {@code null}.
18455 * @param outRect rectangle in which to place the clip bounds of the view
18456 * @return {@code true} if successful or {@code false} if the view's
18457 * clip bounds are {@code null}
18459 public boolean getClipBounds(Rect outRect) {
18460 if (mClipBounds != null) {
18461 outRect.set(mClipBounds);
18468 * Utility function, called by draw(canvas, parent, drawingTime) to handle the less common
18469 * case of an active Animation being run on the view.
18471 private boolean applyLegacyAnimation(ViewGroup parent, long drawingTime,
18472 Animation a, boolean scalingRequired) {
18473 Transformation invalidationTransform;
18474 final int flags = parent.mGroupFlags;
18475 final boolean initialized = a.isInitialized();
18476 if (!initialized) {
18477 a.initialize(mRight - mLeft, mBottom - mTop, parent.getWidth(), parent.getHeight());
18478 a.initializeInvalidateRegion(0, 0, mRight - mLeft, mBottom - mTop);
18479 if (mAttachInfo != null) a.setListenerHandler(mAttachInfo.mHandler);
18480 onAnimationStart();
18483 final Transformation t = parent.getChildTransformation();
18484 boolean more = a.getTransformation(drawingTime, t, 1f);
18485 if (scalingRequired && mAttachInfo.mApplicationScale != 1f) {
18486 if (parent.mInvalidationTransformation == null) {
18487 parent.mInvalidationTransformation = new Transformation();
18489 invalidationTransform = parent.mInvalidationTransformation;
18490 a.getTransformation(drawingTime, invalidationTransform, 1f);
18492 invalidationTransform = t;
18496 if (!a.willChangeBounds()) {
18497 if ((flags & (ViewGroup.FLAG_OPTIMIZE_INVALIDATE | ViewGroup.FLAG_ANIMATION_DONE)) ==
18498 ViewGroup.FLAG_OPTIMIZE_INVALIDATE) {
18499 parent.mGroupFlags |= ViewGroup.FLAG_INVALIDATE_REQUIRED;
18500 } else if ((flags & ViewGroup.FLAG_INVALIDATE_REQUIRED) == 0) {
18501 // The child need to draw an animation, potentially offscreen, so
18502 // make sure we do not cancel invalidate requests
18503 parent.mPrivateFlags |= PFLAG_DRAW_ANIMATION;
18504 parent.invalidate(mLeft, mTop, mRight, mBottom);
18507 if (parent.mInvalidateRegion == null) {
18508 parent.mInvalidateRegion = new RectF();
18510 final RectF region = parent.mInvalidateRegion;
18511 a.getInvalidateRegion(0, 0, mRight - mLeft, mBottom - mTop, region,
18512 invalidationTransform);
18514 // The child need to draw an animation, potentially offscreen, so
18515 // make sure we do not cancel invalidate requests
18516 parent.mPrivateFlags |= PFLAG_DRAW_ANIMATION;
18518 final int left = mLeft + (int) region.left;
18519 final int top = mTop + (int) region.top;
18520 parent.invalidate(left, top, left + (int) (region.width() + .5f),
18521 top + (int) (region.height() + .5f));
18528 * This method is called by getDisplayList() when a display list is recorded for a View.
18529 * It pushes any properties to the RenderNode that aren't managed by the RenderNode.
18531 void setDisplayListProperties(RenderNode renderNode) {
18532 if (renderNode != null) {
18533 renderNode.setHasOverlappingRendering(getHasOverlappingRendering());
18534 renderNode.setClipToBounds(mParent instanceof ViewGroup
18535 && ((ViewGroup) mParent).getClipChildren());
18538 if (mParent instanceof ViewGroup && (((ViewGroup) mParent).mGroupFlags &
18539 ViewGroup.FLAG_SUPPORT_STATIC_TRANSFORMATIONS) != 0) {
18540 ViewGroup parentVG = (ViewGroup) mParent;
18541 final Transformation t = parentVG.getChildTransformation();
18542 if (parentVG.getChildStaticTransformation(this, t)) {
18543 final int transformType = t.getTransformationType();
18544 if (transformType != Transformation.TYPE_IDENTITY) {
18545 if ((transformType & Transformation.TYPE_ALPHA) != 0) {
18546 alpha = t.getAlpha();
18548 if ((transformType & Transformation.TYPE_MATRIX) != 0) {
18549 renderNode.setStaticMatrix(t.getMatrix());
18554 if (mTransformationInfo != null) {
18555 alpha *= getFinalAlpha();
18557 final int multipliedAlpha = (int) (255 * alpha);
18558 if (onSetAlpha(multipliedAlpha)) {
18562 renderNode.setAlpha(alpha);
18563 } else if (alpha < 1) {
18564 renderNode.setAlpha(alpha);
18570 * This method is called by ViewGroup.drawChild() to have each child view draw itself.
18572 * This is where the View specializes rendering behavior based on layer type,
18573 * and hardware acceleration.
18575 boolean draw(Canvas canvas, ViewGroup parent, long drawingTime) {
18576 final boolean hardwareAcceleratedCanvas = canvas.isHardwareAccelerated();
18577 /* If an attached view draws to a HW canvas, it may use its RenderNode + DisplayList.
18579 * If a view is dettached, its DisplayList shouldn't exist. If the canvas isn't
18580 * HW accelerated, it can't handle drawing RenderNodes.
18582 boolean drawingWithRenderNode = mAttachInfo != null
18583 && mAttachInfo.mHardwareAccelerated
18584 && hardwareAcceleratedCanvas;
18586 boolean more = false;
18587 final boolean childHasIdentityMatrix = hasIdentityMatrix();
18588 final int parentFlags = parent.mGroupFlags;
18590 if ((parentFlags & ViewGroup.FLAG_CLEAR_TRANSFORMATION) != 0) {
18591 parent.getChildTransformation().clear();
18592 parent.mGroupFlags &= ~ViewGroup.FLAG_CLEAR_TRANSFORMATION;
18595 Transformation transformToApply = null;
18596 boolean concatMatrix = false;
18597 final boolean scalingRequired = mAttachInfo != null && mAttachInfo.mScalingRequired;
18598 final Animation a = getAnimation();
18600 more = applyLegacyAnimation(parent, drawingTime, a, scalingRequired);
18601 concatMatrix = a.willChangeTransformationMatrix();
18602 if (concatMatrix) {
18603 mPrivateFlags3 |= PFLAG3_VIEW_IS_ANIMATING_TRANSFORM;
18605 transformToApply = parent.getChildTransformation();
18607 if ((mPrivateFlags3 & PFLAG3_VIEW_IS_ANIMATING_TRANSFORM) != 0) {
18608 // No longer animating: clear out old animation matrix
18609 mRenderNode.setAnimationMatrix(null);
18610 mPrivateFlags3 &= ~PFLAG3_VIEW_IS_ANIMATING_TRANSFORM;
18612 if (!drawingWithRenderNode
18613 && (parentFlags & ViewGroup.FLAG_SUPPORT_STATIC_TRANSFORMATIONS) != 0) {
18614 final Transformation t = parent.getChildTransformation();
18615 final boolean hasTransform = parent.getChildStaticTransformation(this, t);
18616 if (hasTransform) {
18617 final int transformType = t.getTransformationType();
18618 transformToApply = transformType != Transformation.TYPE_IDENTITY ? t : null;
18619 concatMatrix = (transformType & Transformation.TYPE_MATRIX) != 0;
18624 concatMatrix |= !childHasIdentityMatrix;
18626 // Sets the flag as early as possible to allow draw() implementations
18627 // to call invalidate() successfully when doing animations
18628 mPrivateFlags |= PFLAG_DRAWN;
18630 if (!concatMatrix &&
18631 (parentFlags & (ViewGroup.FLAG_SUPPORT_STATIC_TRANSFORMATIONS |
18632 ViewGroup.FLAG_CLIP_CHILDREN)) == ViewGroup.FLAG_CLIP_CHILDREN &&
18633 canvas.quickReject(mLeft, mTop, mRight, mBottom, Canvas.EdgeType.BW) &&
18634 (mPrivateFlags & PFLAG_DRAW_ANIMATION) == 0) {
18635 mPrivateFlags2 |= PFLAG2_VIEW_QUICK_REJECTED;
18638 mPrivateFlags2 &= ~PFLAG2_VIEW_QUICK_REJECTED;
18640 if (hardwareAcceleratedCanvas) {
18641 // Clear INVALIDATED flag to allow invalidation to occur during rendering, but
18642 // retain the flag's value temporarily in the mRecreateDisplayList flag
18643 mRecreateDisplayList = (mPrivateFlags & PFLAG_INVALIDATED) != 0;
18644 mPrivateFlags &= ~PFLAG_INVALIDATED;
18647 RenderNode renderNode = null;
18648 Bitmap cache = null;
18649 int layerType = getLayerType(); // TODO: signify cache state with just 'cache' local
18650 if (layerType == LAYER_TYPE_SOFTWARE || !drawingWithRenderNode) {
18651 if (layerType != LAYER_TYPE_NONE) {
18652 // If not drawing with RenderNode, treat HW layers as SW
18653 layerType = LAYER_TYPE_SOFTWARE;
18654 buildDrawingCache(true);
18656 cache = getDrawingCache(true);
18659 if (drawingWithRenderNode) {
18660 // Delay getting the display list until animation-driven alpha values are
18661 // set up and possibly passed on to the view
18662 renderNode = updateDisplayListIfDirty();
18663 if (!renderNode.isValid()) {
18664 // Uncommon, but possible. If a view is removed from the hierarchy during the call
18665 // to getDisplayList(), the display list will be marked invalid and we should not
18666 // try to use it again.
18668 drawingWithRenderNode = false;
18674 if (!drawingWithRenderNode) {
18680 final boolean drawingWithDrawingCache = cache != null && !drawingWithRenderNode;
18681 final boolean offsetForScroll = cache == null && !drawingWithRenderNode;
18683 int restoreTo = -1;
18684 if (!drawingWithRenderNode || transformToApply != null) {
18685 restoreTo = canvas.save();
18687 if (offsetForScroll) {
18688 canvas.translate(mLeft - sx, mTop - sy);
18690 if (!drawingWithRenderNode) {
18691 canvas.translate(mLeft, mTop);
18693 if (scalingRequired) {
18694 if (drawingWithRenderNode) {
18695 // TODO: Might not need this if we put everything inside the DL
18696 restoreTo = canvas.save();
18698 // mAttachInfo cannot be null, otherwise scalingRequired == false
18699 final float scale = 1.0f / mAttachInfo.mApplicationScale;
18700 canvas.scale(scale, scale);
18704 float alpha = drawingWithRenderNode ? 1 : (getAlpha() * getTransitionAlpha());
18705 if (transformToApply != null
18707 || !hasIdentityMatrix()
18708 || (mPrivateFlags3 & PFLAG3_VIEW_IS_ANIMATING_ALPHA) != 0) {
18709 if (transformToApply != null || !childHasIdentityMatrix) {
18713 if (offsetForScroll) {
18718 if (transformToApply != null) {
18719 if (concatMatrix) {
18720 if (drawingWithRenderNode) {
18721 renderNode.setAnimationMatrix(transformToApply.getMatrix());
18723 // Undo the scroll translation, apply the transformation matrix,
18724 // then redo the scroll translate to get the correct result.
18725 canvas.translate(-transX, -transY);
18726 canvas.concat(transformToApply.getMatrix());
18727 canvas.translate(transX, transY);
18729 parent.mGroupFlags |= ViewGroup.FLAG_CLEAR_TRANSFORMATION;
18732 float transformAlpha = transformToApply.getAlpha();
18733 if (transformAlpha < 1) {
18734 alpha *= transformAlpha;
18735 parent.mGroupFlags |= ViewGroup.FLAG_CLEAR_TRANSFORMATION;
18739 if (!childHasIdentityMatrix && !drawingWithRenderNode) {
18740 canvas.translate(-transX, -transY);
18741 canvas.concat(getMatrix());
18742 canvas.translate(transX, transY);
18746 // Deal with alpha if it is or used to be <1
18747 if (alpha < 1 || (mPrivateFlags3 & PFLAG3_VIEW_IS_ANIMATING_ALPHA) != 0) {
18749 mPrivateFlags3 |= PFLAG3_VIEW_IS_ANIMATING_ALPHA;
18751 mPrivateFlags3 &= ~PFLAG3_VIEW_IS_ANIMATING_ALPHA;
18753 parent.mGroupFlags |= ViewGroup.FLAG_CLEAR_TRANSFORMATION;
18754 if (!drawingWithDrawingCache) {
18755 final int multipliedAlpha = (int) (255 * alpha);
18756 if (!onSetAlpha(multipliedAlpha)) {
18757 if (drawingWithRenderNode) {
18758 renderNode.setAlpha(alpha * getAlpha() * getTransitionAlpha());
18759 } else if (layerType == LAYER_TYPE_NONE) {
18760 canvas.saveLayerAlpha(sx, sy, sx + getWidth(), sy + getHeight(),
18764 // Alpha is handled by the child directly, clobber the layer's alpha
18765 mPrivateFlags |= PFLAG_ALPHA_SET;
18769 } else if ((mPrivateFlags & PFLAG_ALPHA_SET) == PFLAG_ALPHA_SET) {
18771 mPrivateFlags &= ~PFLAG_ALPHA_SET;
18774 if (!drawingWithRenderNode) {
18775 // apply clips directly, since RenderNode won't do it for this draw
18776 if ((parentFlags & ViewGroup.FLAG_CLIP_CHILDREN) != 0 && cache == null) {
18777 if (offsetForScroll) {
18778 canvas.clipRect(sx, sy, sx + getWidth(), sy + getHeight());
18780 if (!scalingRequired || cache == null) {
18781 canvas.clipRect(0, 0, getWidth(), getHeight());
18783 canvas.clipRect(0, 0, cache.getWidth(), cache.getHeight());
18788 if (mClipBounds != null) {
18789 // clip bounds ignore scroll
18790 canvas.clipRect(mClipBounds);
18794 if (!drawingWithDrawingCache) {
18795 if (drawingWithRenderNode) {
18796 mPrivateFlags &= ~PFLAG_DIRTY_MASK;
18797 ((DisplayListCanvas) canvas).drawRenderNode(renderNode);
18799 // Fast path for layouts with no backgrounds
18800 if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) {
18801 mPrivateFlags &= ~PFLAG_DIRTY_MASK;
18802 dispatchDraw(canvas);
18807 } else if (cache != null) {
18808 mPrivateFlags &= ~PFLAG_DIRTY_MASK;
18809 if (layerType == LAYER_TYPE_NONE || mLayerPaint == null) {
18810 // no layer paint, use temporary paint to draw bitmap
18811 Paint cachePaint = parent.mCachePaint;
18812 if (cachePaint == null) {
18813 cachePaint = new Paint();
18814 cachePaint.setDither(false);
18815 parent.mCachePaint = cachePaint;
18817 cachePaint.setAlpha((int) (alpha * 255));
18818 canvas.drawBitmap(cache, 0.0f, 0.0f, cachePaint);
18820 // use layer paint to draw the bitmap, merging the two alphas, but also restore
18821 int layerPaintAlpha = mLayerPaint.getAlpha();
18823 mLayerPaint.setAlpha((int) (alpha * layerPaintAlpha));
18825 canvas.drawBitmap(cache, 0.0f, 0.0f, mLayerPaint);
18827 mLayerPaint.setAlpha(layerPaintAlpha);
18832 if (restoreTo >= 0) {
18833 canvas.restoreToCount(restoreTo);
18836 if (a != null && !more) {
18837 if (!hardwareAcceleratedCanvas && !a.getFillAfter()) {
18840 parent.finishAnimatingView(this, a);
18843 if (more && hardwareAcceleratedCanvas) {
18844 if (a.hasAlpha() && (mPrivateFlags & PFLAG_ALPHA_SET) == PFLAG_ALPHA_SET) {
18845 // alpha animations should cause the child to recreate its display list
18850 mRecreateDisplayList = false;
18855 static Paint getDebugPaint() {
18856 if (sDebugPaint == null) {
18857 sDebugPaint = new Paint();
18858 sDebugPaint.setAntiAlias(false);
18860 return sDebugPaint;
18863 final int dipsToPixels(int dips) {
18864 float scale = getContext().getResources().getDisplayMetrics().density;
18865 return (int) (dips * scale + 0.5f);
18868 final private void debugDrawFocus(Canvas canvas) {
18870 final int cornerSquareSize = dipsToPixels(DEBUG_CORNERS_SIZE_DIP);
18871 final int l = mScrollX;
18872 final int r = l + mRight - mLeft;
18873 final int t = mScrollY;
18874 final int b = t + mBottom - mTop;
18876 final Paint paint = getDebugPaint();
18877 paint.setColor(DEBUG_CORNERS_COLOR);
18879 // Draw squares in corners.
18880 paint.setStyle(Paint.Style.FILL);
18881 canvas.drawRect(l, t, l + cornerSquareSize, t + cornerSquareSize, paint);
18882 canvas.drawRect(r - cornerSquareSize, t, r, t + cornerSquareSize, paint);
18883 canvas.drawRect(l, b - cornerSquareSize, l + cornerSquareSize, b, paint);
18884 canvas.drawRect(r - cornerSquareSize, b - cornerSquareSize, r, b, paint);
18886 // Draw big X across the view.
18887 paint.setStyle(Paint.Style.STROKE);
18888 canvas.drawLine(l, t, r, b, paint);
18889 canvas.drawLine(l, b, r, t, paint);
18894 * Manually render this view (and all of its children) to the given Canvas.
18895 * The view must have already done a full layout before this function is
18896 * called. When implementing a view, implement
18897 * {@link #onDraw(android.graphics.Canvas)} instead of overriding this method.
18898 * If you do need to override this method, call the superclass version.
18900 * @param canvas The Canvas to which the View is rendered.
18903 public void draw(Canvas canvas) {
18904 final int privateFlags = mPrivateFlags;
18905 final boolean dirtyOpaque = (privateFlags & PFLAG_DIRTY_MASK) == PFLAG_DIRTY_OPAQUE &&
18906 (mAttachInfo == null || !mAttachInfo.mIgnoreDirtyState);
18907 mPrivateFlags = (privateFlags & ~PFLAG_DIRTY_MASK) | PFLAG_DRAWN;
18910 * Draw traversal performs several drawing steps which must be executed
18911 * in the appropriate order:
18913 * 1. Draw the background
18914 * 2. If necessary, save the canvas' layers to prepare for fading
18915 * 3. Draw view's content
18917 * 5. If necessary, draw the fading edges and restore layers
18918 * 6. Draw decorations (scrollbars for instance)
18921 // Step 1, draw the background, if needed
18924 if (!dirtyOpaque) {
18925 drawBackground(canvas);
18928 // skip step 2 & 5 if possible (common case)
18929 final int viewFlags = mViewFlags;
18930 boolean horizontalEdges = (viewFlags & FADING_EDGE_HORIZONTAL) != 0;
18931 boolean verticalEdges = (viewFlags & FADING_EDGE_VERTICAL) != 0;
18932 if (!verticalEdges && !horizontalEdges) {
18933 // Step 3, draw the content
18934 if (!dirtyOpaque) onDraw(canvas);
18936 // Step 4, draw the children
18937 dispatchDraw(canvas);
18939 drawAutofilledHighlight(canvas);
18941 // Overlay is part of the content and draws beneath Foreground
18942 if (mOverlay != null && !mOverlay.isEmpty()) {
18943 mOverlay.getOverlayView().dispatchDraw(canvas);
18946 // Step 6, draw decorations (foreground, scrollbars)
18947 onDrawForeground(canvas);
18949 // Step 7, draw the default focus highlight
18950 drawDefaultFocusHighlight(canvas);
18953 debugDrawFocus(canvas);
18961 * Here we do the full fledged routine...
18962 * (this is an uncommon case where speed matters less,
18963 * this is why we repeat some of the tests that have been
18967 boolean drawTop = false;
18968 boolean drawBottom = false;
18969 boolean drawLeft = false;
18970 boolean drawRight = false;
18972 float topFadeStrength = 0.0f;
18973 float bottomFadeStrength = 0.0f;
18974 float leftFadeStrength = 0.0f;
18975 float rightFadeStrength = 0.0f;
18977 // Step 2, save the canvas' layers
18978 int paddingLeft = mPaddingLeft;
18980 final boolean offsetRequired = isPaddingOffsetRequired();
18981 if (offsetRequired) {
18982 paddingLeft += getLeftPaddingOffset();
18985 int left = mScrollX + paddingLeft;
18986 int right = left + mRight - mLeft - mPaddingRight - paddingLeft;
18987 int top = mScrollY + getFadeTop(offsetRequired);
18988 int bottom = top + getFadeHeight(offsetRequired);
18990 if (offsetRequired) {
18991 right += getRightPaddingOffset();
18992 bottom += getBottomPaddingOffset();
18995 final ScrollabilityCache scrollabilityCache = mScrollCache;
18996 final float fadeHeight = scrollabilityCache.fadingEdgeLength;
18997 int length = (int) fadeHeight;
18999 // clip the fade length if top and bottom fades overlap
19000 // overlapping fades produce odd-looking artifacts
19001 if (verticalEdges && (top + length > bottom - length)) {
19002 length = (bottom - top) / 2;
19005 // also clip horizontal fades if necessary
19006 if (horizontalEdges && (left + length > right - length)) {
19007 length = (right - left) / 2;
19010 if (verticalEdges) {
19011 topFadeStrength = Math.max(0.0f, Math.min(1.0f, getTopFadingEdgeStrength()));
19012 drawTop = topFadeStrength * fadeHeight > 1.0f;
19013 bottomFadeStrength = Math.max(0.0f, Math.min(1.0f, getBottomFadingEdgeStrength()));
19014 drawBottom = bottomFadeStrength * fadeHeight > 1.0f;
19017 if (horizontalEdges) {
19018 leftFadeStrength = Math.max(0.0f, Math.min(1.0f, getLeftFadingEdgeStrength()));
19019 drawLeft = leftFadeStrength * fadeHeight > 1.0f;
19020 rightFadeStrength = Math.max(0.0f, Math.min(1.0f, getRightFadingEdgeStrength()));
19021 drawRight = rightFadeStrength * fadeHeight > 1.0f;
19024 saveCount = canvas.getSaveCount();
19026 int solidColor = getSolidColor();
19027 if (solidColor == 0) {
19028 final int flags = Canvas.HAS_ALPHA_LAYER_SAVE_FLAG;
19031 canvas.saveLayer(left, top, right, top + length, null, flags);
19035 canvas.saveLayer(left, bottom - length, right, bottom, null, flags);
19039 canvas.saveLayer(left, top, left + length, bottom, null, flags);
19043 canvas.saveLayer(right - length, top, right, bottom, null, flags);
19046 scrollabilityCache.setFadeColor(solidColor);
19049 // Step 3, draw the content
19050 if (!dirtyOpaque) onDraw(canvas);
19052 // Step 4, draw the children
19053 dispatchDraw(canvas);
19055 // Step 5, draw the fade effect and restore layers
19056 final Paint p = scrollabilityCache.paint;
19057 final Matrix matrix = scrollabilityCache.matrix;
19058 final Shader fade = scrollabilityCache.shader;
19061 matrix.setScale(1, fadeHeight * topFadeStrength);
19062 matrix.postTranslate(left, top);
19063 fade.setLocalMatrix(matrix);
19065 canvas.drawRect(left, top, right, top + length, p);
19069 matrix.setScale(1, fadeHeight * bottomFadeStrength);
19070 matrix.postRotate(180);
19071 matrix.postTranslate(left, bottom);
19072 fade.setLocalMatrix(matrix);
19074 canvas.drawRect(left, bottom - length, right, bottom, p);
19078 matrix.setScale(1, fadeHeight * leftFadeStrength);
19079 matrix.postRotate(-90);
19080 matrix.postTranslate(left, top);
19081 fade.setLocalMatrix(matrix);
19083 canvas.drawRect(left, top, left + length, bottom, p);
19087 matrix.setScale(1, fadeHeight * rightFadeStrength);
19088 matrix.postRotate(90);
19089 matrix.postTranslate(right, top);
19090 fade.setLocalMatrix(matrix);
19092 canvas.drawRect(right - length, top, right, bottom, p);
19095 canvas.restoreToCount(saveCount);
19097 drawAutofilledHighlight(canvas);
19099 // Overlay is part of the content and draws beneath Foreground
19100 if (mOverlay != null && !mOverlay.isEmpty()) {
19101 mOverlay.getOverlayView().dispatchDraw(canvas);
19104 // Step 6, draw decorations (foreground, scrollbars)
19105 onDrawForeground(canvas);
19108 debugDrawFocus(canvas);
19113 * Draws the background onto the specified canvas.
19115 * @param canvas Canvas on which to draw the background
19117 private void drawBackground(Canvas canvas) {
19118 final Drawable background = mBackground;
19119 if (background == null) {
19123 setBackgroundBounds();
19125 // Attempt to use a display list if requested.
19126 if (canvas.isHardwareAccelerated() && mAttachInfo != null
19127 && mAttachInfo.mThreadedRenderer != null) {
19128 mBackgroundRenderNode = getDrawableRenderNode(background, mBackgroundRenderNode);
19130 final RenderNode renderNode = mBackgroundRenderNode;
19131 if (renderNode != null && renderNode.isValid()) {
19132 setBackgroundRenderNodeProperties(renderNode);
19133 ((DisplayListCanvas) canvas).drawRenderNode(renderNode);
19138 final int scrollX = mScrollX;
19139 final int scrollY = mScrollY;
19140 if ((scrollX | scrollY) == 0) {
19141 background.draw(canvas);
19143 canvas.translate(scrollX, scrollY);
19144 background.draw(canvas);
19145 canvas.translate(-scrollX, -scrollY);
19150 * Sets the correct background bounds and rebuilds the outline, if needed.
19152 * This is called by LayoutLib.
19154 void setBackgroundBounds() {
19155 if (mBackgroundSizeChanged && mBackground != null) {
19156 mBackground.setBounds(0, 0, mRight - mLeft, mBottom - mTop);
19157 mBackgroundSizeChanged = false;
19162 private void setBackgroundRenderNodeProperties(RenderNode renderNode) {
19163 renderNode.setTranslationX(mScrollX);
19164 renderNode.setTranslationY(mScrollY);
19168 * Creates a new display list or updates the existing display list for the
19169 * specified Drawable.
19171 * @param drawable Drawable for which to create a display list
19172 * @param renderNode Existing RenderNode, or {@code null}
19173 * @return A valid display list for the specified drawable
19175 private RenderNode getDrawableRenderNode(Drawable drawable, RenderNode renderNode) {
19176 if (renderNode == null) {
19177 renderNode = RenderNode.create(drawable.getClass().getName(), this);
19180 final Rect bounds = drawable.getBounds();
19181 final int width = bounds.width();
19182 final int height = bounds.height();
19183 final DisplayListCanvas canvas = renderNode.start(width, height);
19185 // Reverse left/top translation done by drawable canvas, which will
19186 // instead be applied by rendernode's LTRB bounds below. This way, the
19187 // drawable's bounds match with its rendernode bounds and its content
19188 // will lie within those bounds in the rendernode tree.
19189 canvas.translate(-bounds.left, -bounds.top);
19192 drawable.draw(canvas);
19194 renderNode.end(canvas);
19197 // Set up drawable properties that are view-independent.
19198 renderNode.setLeftTopRightBottom(bounds.left, bounds.top, bounds.right, bounds.bottom);
19199 renderNode.setProjectBackwards(drawable.isProjected());
19200 renderNode.setProjectionReceiver(true);
19201 renderNode.setClipToBounds(false);
19206 * Returns the overlay for this view, creating it if it does not yet exist.
19207 * Adding drawables to the overlay will cause them to be displayed whenever
19208 * the view itself is redrawn. Objects in the overlay should be actively
19209 * managed: remove them when they should not be displayed anymore. The
19210 * overlay will always have the same size as its host view.
19212 * <p>Note: Overlays do not currently work correctly with {@link
19213 * SurfaceView} or {@link TextureView}; contents in overlays for these
19214 * types of views may not display correctly.</p>
19216 * @return The ViewOverlay object for this view.
19219 public ViewOverlay getOverlay() {
19220 if (mOverlay == null) {
19221 mOverlay = new ViewOverlay(mContext, this);
19227 * Override this if your view is known to always be drawn on top of a solid color background,
19228 * and needs to draw fading edges. Returning a non-zero color enables the view system to
19229 * optimize the drawing of the fading edges. If you do return a non-zero color, the alpha
19230 * should be set to 0xFF.
19232 * @see #setVerticalFadingEdgeEnabled(boolean)
19233 * @see #setHorizontalFadingEdgeEnabled(boolean)
19235 * @return The known solid color background for this view, or 0 if the color may vary
19237 @ViewDebug.ExportedProperty(category = "drawing")
19239 public int getSolidColor() {
19244 * Build a human readable string representation of the specified view flags.
19246 * @param flags the view flags to convert to a string
19247 * @return a String representing the supplied flags
19249 private static String printFlags(int flags) {
19250 String output = "";
19252 if ((flags & FOCUSABLE) == FOCUSABLE) {
19253 output += "TAKES_FOCUS";
19257 switch (flags & VISIBILITY_MASK) {
19259 if (numFlags > 0) {
19262 output += "INVISIBLE";
19263 // USELESS HERE numFlags++;
19266 if (numFlags > 0) {
19270 // USELESS HERE numFlags++;
19279 * Build a human readable string representation of the specified private
19282 * @param privateFlags the private view flags to convert to a string
19283 * @return a String representing the supplied flags
19285 private static String printPrivateFlags(int privateFlags) {
19286 String output = "";
19289 if ((privateFlags & PFLAG_WANTS_FOCUS) == PFLAG_WANTS_FOCUS) {
19290 output += "WANTS_FOCUS";
19294 if ((privateFlags & PFLAG_FOCUSED) == PFLAG_FOCUSED) {
19295 if (numFlags > 0) {
19298 output += "FOCUSED";
19302 if ((privateFlags & PFLAG_SELECTED) == PFLAG_SELECTED) {
19303 if (numFlags > 0) {
19306 output += "SELECTED";
19310 if ((privateFlags & PFLAG_IS_ROOT_NAMESPACE) == PFLAG_IS_ROOT_NAMESPACE) {
19311 if (numFlags > 0) {
19314 output += "IS_ROOT_NAMESPACE";
19318 if ((privateFlags & PFLAG_HAS_BOUNDS) == PFLAG_HAS_BOUNDS) {
19319 if (numFlags > 0) {
19322 output += "HAS_BOUNDS";
19326 if ((privateFlags & PFLAG_DRAWN) == PFLAG_DRAWN) {
19327 if (numFlags > 0) {
19331 // USELESS HERE numFlags++;
19337 * <p>Indicates whether or not this view's layout will be requested during
19338 * the next hierarchy layout pass.</p>
19340 * @return true if the layout will be forced during next layout pass
19342 public boolean isLayoutRequested() {
19343 return (mPrivateFlags & PFLAG_FORCE_LAYOUT) == PFLAG_FORCE_LAYOUT;
19347 * Return true if o is a ViewGroup that is laying out using optical bounds.
19350 public static boolean isLayoutModeOptical(Object o) {
19351 return o instanceof ViewGroup && ((ViewGroup) o).isLayoutModeOptical();
19354 private boolean setOpticalFrame(int left, int top, int right, int bottom) {
19355 Insets parentInsets = mParent instanceof View ?
19356 ((View) mParent).getOpticalInsets() : Insets.NONE;
19357 Insets childInsets = getOpticalInsets();
19359 left + parentInsets.left - childInsets.left,
19360 top + parentInsets.top - childInsets.top,
19361 right + parentInsets.left + childInsets.right,
19362 bottom + parentInsets.top + childInsets.bottom);
19366 * Assign a size and position to a view and all of its
19369 * <p>This is the second phase of the layout mechanism.
19370 * (The first is measuring). In this phase, each parent calls
19371 * layout on all of its children to position them.
19372 * This is typically done using the child measurements
19373 * that were stored in the measure pass().</p>
19375 * <p>Derived classes should not override this method.
19376 * Derived classes with children should override
19377 * onLayout. In that method, they should
19378 * call layout on each of their children.</p>
19380 * @param l Left position, relative to parent
19381 * @param t Top position, relative to parent
19382 * @param r Right position, relative to parent
19383 * @param b Bottom position, relative to parent
19385 @SuppressWarnings({"unchecked"})
19386 public void layout(int l, int t, int r, int b) {
19387 if ((mPrivateFlags3 & PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT) != 0) {
19388 onMeasure(mOldWidthMeasureSpec, mOldHeightMeasureSpec);
19389 mPrivateFlags3 &= ~PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT;
19394 int oldB = mBottom;
19397 boolean changed = isLayoutModeOptical(mParent) ?
19398 setOpticalFrame(l, t, r, b) : setFrame(l, t, r, b);
19400 if (changed || (mPrivateFlags & PFLAG_LAYOUT_REQUIRED) == PFLAG_LAYOUT_REQUIRED) {
19401 onLayout(changed, l, t, r, b);
19403 if (shouldDrawRoundScrollbar()) {
19404 if(mRoundScrollbarRenderer == null) {
19405 mRoundScrollbarRenderer = new RoundScrollbarRenderer(this);
19408 mRoundScrollbarRenderer = null;
19411 mPrivateFlags &= ~PFLAG_LAYOUT_REQUIRED;
19413 ListenerInfo li = mListenerInfo;
19414 if (li != null && li.mOnLayoutChangeListeners != null) {
19415 ArrayList<OnLayoutChangeListener> listenersCopy =
19416 (ArrayList<OnLayoutChangeListener>)li.mOnLayoutChangeListeners.clone();
19417 int numListeners = listenersCopy.size();
19418 for (int i = 0; i < numListeners; ++i) {
19419 listenersCopy.get(i).onLayoutChange(this, l, t, r, b, oldL, oldT, oldR, oldB);
19424 mPrivateFlags &= ~PFLAG_FORCE_LAYOUT;
19425 mPrivateFlags3 |= PFLAG3_IS_LAID_OUT;
19427 if ((mPrivateFlags3 & PFLAG3_NOTIFY_AUTOFILL_ENTER_ON_LAYOUT) != 0) {
19428 mPrivateFlags3 &= ~PFLAG3_NOTIFY_AUTOFILL_ENTER_ON_LAYOUT;
19429 notifyEnterOrExitForAutoFillIfNeeded(true);
19434 * Called from layout when this view should
19435 * assign a size and position to each of its children.
19437 * Derived classes with children should override
19438 * this method and call layout on each of
19440 * @param changed This is a new size or position for this view
19441 * @param left Left position, relative to parent
19442 * @param top Top position, relative to parent
19443 * @param right Right position, relative to parent
19444 * @param bottom Bottom position, relative to parent
19446 protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
19450 * Assign a size and position to this view.
19452 * This is called from layout.
19454 * @param left Left position, relative to parent
19455 * @param top Top position, relative to parent
19456 * @param right Right position, relative to parent
19457 * @param bottom Bottom position, relative to parent
19458 * @return true if the new size and position are different than the
19462 protected boolean setFrame(int left, int top, int right, int bottom) {
19463 boolean changed = false;
19466 Log.d("View", this + " View.setFrame(" + left + "," + top + ","
19467 + right + "," + bottom + ")");
19470 if (mLeft != left || mRight != right || mTop != top || mBottom != bottom) {
19473 // Remember our drawn bit
19474 int drawn = mPrivateFlags & PFLAG_DRAWN;
19476 int oldWidth = mRight - mLeft;
19477 int oldHeight = mBottom - mTop;
19478 int newWidth = right - left;
19479 int newHeight = bottom - top;
19480 boolean sizeChanged = (newWidth != oldWidth) || (newHeight != oldHeight);
19482 // Invalidate our old position
19483 invalidate(sizeChanged);
19489 mRenderNode.setLeftTopRightBottom(mLeft, mTop, mRight, mBottom);
19491 mPrivateFlags |= PFLAG_HAS_BOUNDS;
19495 sizeChange(newWidth, newHeight, oldWidth, oldHeight);
19498 if ((mViewFlags & VISIBILITY_MASK) == VISIBLE || mGhostView != null) {
19499 // If we are visible, force the DRAWN bit to on so that
19500 // this invalidate will go through (at least to our parent).
19501 // This is because someone may have invalidated this view
19502 // before this call to setFrame came in, thereby clearing
19504 mPrivateFlags |= PFLAG_DRAWN;
19505 invalidate(sizeChanged);
19506 // parent display list may need to be recreated based on a change in the bounds
19508 invalidateParentCaches();
19511 // Reset drawn bit to original value (invalidate turns it off)
19512 mPrivateFlags |= drawn;
19514 mBackgroundSizeChanged = true;
19515 mDefaultFocusHighlightSizeChanged = true;
19516 if (mForegroundInfo != null) {
19517 mForegroundInfo.mBoundsChanged = true;
19520 notifySubtreeAccessibilityStateChangedIfNeeded();
19526 * Same as setFrame, but public and hidden. For use in {@link android.transition.ChangeBounds}.
19529 public void setLeftTopRightBottom(int left, int top, int right, int bottom) {
19530 setFrame(left, top, right, bottom);
19533 private void sizeChange(int newWidth, int newHeight, int oldWidth, int oldHeight) {
19534 onSizeChanged(newWidth, newHeight, oldWidth, oldHeight);
19535 if (mOverlay != null) {
19536 mOverlay.getOverlayView().setRight(newWidth);
19537 mOverlay.getOverlayView().setBottom(newHeight);
19543 * Finalize inflating a view from XML. This is called as the last phase
19544 * of inflation, after all child views have been added.
19546 * <p>Even if the subclass overrides onFinishInflate, they should always be
19547 * sure to call the super method, so that we get called.
19550 protected void onFinishInflate() {
19554 * Returns the resources associated with this view.
19556 * @return Resources object.
19558 public Resources getResources() {
19563 * Invalidates the specified Drawable.
19565 * @param drawable the drawable to invalidate
19568 public void invalidateDrawable(@NonNull Drawable drawable) {
19569 if (verifyDrawable(drawable)) {
19570 final Rect dirty = drawable.getDirtyBounds();
19571 final int scrollX = mScrollX;
19572 final int scrollY = mScrollY;
19574 invalidate(dirty.left + scrollX, dirty.top + scrollY,
19575 dirty.right + scrollX, dirty.bottom + scrollY);
19581 * Schedules an action on a drawable to occur at a specified time.
19583 * @param who the recipient of the action
19584 * @param what the action to run on the drawable
19585 * @param when the time at which the action must occur. Uses the
19586 * {@link SystemClock#uptimeMillis} timebase.
19589 public void scheduleDrawable(@NonNull Drawable who, @NonNull Runnable what, long when) {
19590 if (verifyDrawable(who) && what != null) {
19591 final long delay = when - SystemClock.uptimeMillis();
19592 if (mAttachInfo != null) {
19593 mAttachInfo.mViewRootImpl.mChoreographer.postCallbackDelayed(
19594 Choreographer.CALLBACK_ANIMATION, what, who,
19595 Choreographer.subtractFrameDelay(delay));
19597 // Postpone the runnable until we know
19598 // on which thread it needs to run.
19599 getRunQueue().postDelayed(what, delay);
19605 * Cancels a scheduled action on a drawable.
19607 * @param who the recipient of the action
19608 * @param what the action to cancel
19611 public void unscheduleDrawable(@NonNull Drawable who, @NonNull Runnable what) {
19612 if (verifyDrawable(who) && what != null) {
19613 if (mAttachInfo != null) {
19614 mAttachInfo.mViewRootImpl.mChoreographer.removeCallbacks(
19615 Choreographer.CALLBACK_ANIMATION, what, who);
19617 getRunQueue().removeCallbacks(what);
19622 * Unschedule any events associated with the given Drawable. This can be
19623 * used when selecting a new Drawable into a view, so that the previous
19624 * one is completely unscheduled.
19626 * @param who The Drawable to unschedule.
19628 * @see #drawableStateChanged
19630 public void unscheduleDrawable(Drawable who) {
19631 if (mAttachInfo != null && who != null) {
19632 mAttachInfo.mViewRootImpl.mChoreographer.removeCallbacks(
19633 Choreographer.CALLBACK_ANIMATION, null, who);
19638 * Resolve the Drawables depending on the layout direction. This is implicitly supposing
19639 * that the View directionality can and will be resolved before its Drawables.
19641 * Will call {@link View#onResolveDrawables} when resolution is done.
19645 protected void resolveDrawables() {
19646 // Drawables resolution may need to happen before resolving the layout direction (which is
19647 // done only during the measure() call).
19648 // If the layout direction is not resolved yet, we cannot resolve the Drawables except in
19649 // one case: when the raw layout direction has not been defined as LAYOUT_DIRECTION_INHERIT.
19650 // So, if the raw layout direction is LAYOUT_DIRECTION_LTR or LAYOUT_DIRECTION_RTL or
19651 // LAYOUT_DIRECTION_LOCALE, we can "cheat" and we don't need to wait for the layout
19652 // direction to be resolved as its resolved value will be the same as its raw value.
19653 if (!isLayoutDirectionResolved() &&
19654 getRawLayoutDirection() == View.LAYOUT_DIRECTION_INHERIT) {
19658 final int layoutDirection = isLayoutDirectionResolved() ?
19659 getLayoutDirection() : getRawLayoutDirection();
19661 if (mBackground != null) {
19662 mBackground.setLayoutDirection(layoutDirection);
19664 if (mForegroundInfo != null && mForegroundInfo.mDrawable != null) {
19665 mForegroundInfo.mDrawable.setLayoutDirection(layoutDirection);
19667 if (mDefaultFocusHighlight != null) {
19668 mDefaultFocusHighlight.setLayoutDirection(layoutDirection);
19670 mPrivateFlags2 |= PFLAG2_DRAWABLE_RESOLVED;
19671 onResolveDrawables(layoutDirection);
19674 boolean areDrawablesResolved() {
19675 return (mPrivateFlags2 & PFLAG2_DRAWABLE_RESOLVED) == PFLAG2_DRAWABLE_RESOLVED;
19679 * Called when layout direction has been resolved.
19681 * The default implementation does nothing.
19683 * @param layoutDirection The resolved layout direction.
19685 * @see #LAYOUT_DIRECTION_LTR
19686 * @see #LAYOUT_DIRECTION_RTL
19690 public void onResolveDrawables(@ResolvedLayoutDir int layoutDirection) {
19696 protected void resetResolvedDrawables() {
19697 resetResolvedDrawablesInternal();
19700 void resetResolvedDrawablesInternal() {
19701 mPrivateFlags2 &= ~PFLAG2_DRAWABLE_RESOLVED;
19705 * If your view subclass is displaying its own Drawable objects, it should
19706 * override this function and return true for any Drawable it is
19707 * displaying. This allows animations for those drawables to be
19710 * <p>Be sure to call through to the super class when overriding this
19713 * @param who The Drawable to verify. Return true if it is one you are
19714 * displaying, else return the result of calling through to the
19717 * @return boolean If true than the Drawable is being displayed in the
19718 * view; else false and it is not allowed to animate.
19720 * @see #unscheduleDrawable(android.graphics.drawable.Drawable)
19721 * @see #drawableStateChanged()
19724 protected boolean verifyDrawable(@NonNull Drawable who) {
19725 // Avoid verifying the scroll bar drawable so that we don't end up in
19726 // an invalidation loop. This effectively prevents the scroll bar
19727 // drawable from triggering invalidations and scheduling runnables.
19728 return who == mBackground || (mForegroundInfo != null && mForegroundInfo.mDrawable == who)
19729 || (mDefaultFocusHighlight == who);
19733 * This function is called whenever the state of the view changes in such
19734 * a way that it impacts the state of drawables being shown.
19736 * If the View has a StateListAnimator, it will also be called to run necessary state
19737 * change animations.
19739 * Be sure to call through to the superclass when overriding this function.
19741 * @see Drawable#setState(int[])
19744 protected void drawableStateChanged() {
19745 final int[] state = getDrawableState();
19746 boolean changed = false;
19748 final Drawable bg = mBackground;
19749 if (bg != null && bg.isStateful()) {
19750 changed |= bg.setState(state);
19753 final Drawable hl = mDefaultFocusHighlight;
19754 if (hl != null && hl.isStateful()) {
19755 changed |= hl.setState(state);
19758 final Drawable fg = mForegroundInfo != null ? mForegroundInfo.mDrawable : null;
19759 if (fg != null && fg.isStateful()) {
19760 changed |= fg.setState(state);
19763 if (mScrollCache != null) {
19764 final Drawable scrollBar = mScrollCache.scrollBar;
19765 if (scrollBar != null && scrollBar.isStateful()) {
19766 changed |= scrollBar.setState(state)
19767 && mScrollCache.state != ScrollabilityCache.OFF;
19771 if (mStateListAnimator != null) {
19772 mStateListAnimator.setState(state);
19781 * This function is called whenever the view hotspot changes and needs to
19782 * be propagated to drawables or child views managed by the view.
19784 * Dispatching to child views is handled by
19785 * {@link #dispatchDrawableHotspotChanged(float, float)}.
19787 * Be sure to call through to the superclass when overriding this function.
19789 * @param x hotspot x coordinate
19790 * @param y hotspot y coordinate
19793 public void drawableHotspotChanged(float x, float y) {
19794 if (mBackground != null) {
19795 mBackground.setHotspot(x, y);
19797 if (mDefaultFocusHighlight != null) {
19798 mDefaultFocusHighlight.setHotspot(x, y);
19800 if (mForegroundInfo != null && mForegroundInfo.mDrawable != null) {
19801 mForegroundInfo.mDrawable.setHotspot(x, y);
19804 dispatchDrawableHotspotChanged(x, y);
19808 * Dispatches drawableHotspotChanged to all of this View's children.
19810 * @param x hotspot x coordinate
19811 * @param y hotspot y coordinate
19812 * @see #drawableHotspotChanged(float, float)
19814 public void dispatchDrawableHotspotChanged(float x, float y) {
19818 * Call this to force a view to update its drawable state. This will cause
19819 * drawableStateChanged to be called on this view. Views that are interested
19820 * in the new state should call getDrawableState.
19822 * @see #drawableStateChanged
19823 * @see #getDrawableState
19825 public void refreshDrawableState() {
19826 mPrivateFlags |= PFLAG_DRAWABLE_STATE_DIRTY;
19827 drawableStateChanged();
19829 ViewParent parent = mParent;
19830 if (parent != null) {
19831 parent.childDrawableStateChanged(this);
19836 * Create a default focus highlight if it doesn't exist.
19837 * @return a default focus highlight.
19839 private Drawable getDefaultFocusHighlightDrawable() {
19840 if (mDefaultFocusHighlightCache == null) {
19841 if (mContext != null) {
19842 final int[] attrs = new int[] { android.R.attr.selectableItemBackground };
19843 final TypedArray ta = mContext.obtainStyledAttributes(attrs);
19844 mDefaultFocusHighlightCache = ta.getDrawable(0);
19848 return mDefaultFocusHighlightCache;
19852 * Set the current default focus highlight.
19853 * @param highlight the highlight drawable, or {@code null} if it's no longer needed.
19855 private void setDefaultFocusHighlight(Drawable highlight) {
19856 mDefaultFocusHighlight = highlight;
19857 mDefaultFocusHighlightSizeChanged = true;
19858 if (highlight != null) {
19859 if ((mPrivateFlags & PFLAG_SKIP_DRAW) != 0) {
19860 mPrivateFlags &= ~PFLAG_SKIP_DRAW;
19862 highlight.setLayoutDirection(getLayoutDirection());
19863 if (highlight.isStateful()) {
19864 highlight.setState(getDrawableState());
19866 if (isAttachedToWindow()) {
19867 highlight.setVisible(getWindowVisibility() == VISIBLE && isShown(), false);
19869 // Set callback last, since the view may still be initializing.
19870 highlight.setCallback(this);
19871 } else if ((mViewFlags & WILL_NOT_DRAW) != 0 && mBackground == null
19872 && (mForegroundInfo == null || mForegroundInfo.mDrawable == null)) {
19873 mPrivateFlags |= PFLAG_SKIP_DRAW;
19879 * Check whether we need to draw a default focus highlight when this view gets focused,
19882 * <li>In both background and foreground, {@link android.R.attr#state_focused}
19883 * is not defined.</li>
19884 * <li>This view is not in touch mode.</li>
19885 * <li>This view doesn't opt out for a default focus highlight, via
19886 * {@link #setDefaultFocusHighlightEnabled(boolean)}.</li>
19887 * <li>This view is attached to window.</li>
19889 * @return {@code true} if a default focus highlight is needed.
19893 public boolean isDefaultFocusHighlightNeeded(Drawable background, Drawable foreground) {
19894 final boolean lackFocusState = (background == null || !background.isStateful()
19895 || !background.hasFocusStateSpecified())
19896 && (foreground == null || !foreground.isStateful()
19897 || !foreground.hasFocusStateSpecified());
19898 return !isInTouchMode() && getDefaultFocusHighlightEnabled() && lackFocusState
19899 && isAttachedToWindow() && sUseDefaultFocusHighlight;
19903 * When this view is focused, switches on/off the default focused highlight.
19905 * This always happens when this view is focused, and only at this moment the default focus
19906 * highlight can be visible.
19908 private void switchDefaultFocusHighlight() {
19910 final boolean needed = isDefaultFocusHighlightNeeded(mBackground,
19911 mForegroundInfo == null ? null : mForegroundInfo.mDrawable);
19912 final boolean active = mDefaultFocusHighlight != null;
19913 if (needed && !active) {
19914 setDefaultFocusHighlight(getDefaultFocusHighlightDrawable());
19915 } else if (!needed && active) {
19916 // The highlight is no longer needed, so tear it down.
19917 setDefaultFocusHighlight(null);
19923 * Draw the default focus highlight onto the canvas.
19924 * @param canvas the canvas where we're drawing the highlight.
19926 private void drawDefaultFocusHighlight(Canvas canvas) {
19927 if (mDefaultFocusHighlight != null) {
19928 if (mDefaultFocusHighlightSizeChanged) {
19929 mDefaultFocusHighlightSizeChanged = false;
19930 final int l = mScrollX;
19931 final int r = l + mRight - mLeft;
19932 final int t = mScrollY;
19933 final int b = t + mBottom - mTop;
19934 mDefaultFocusHighlight.setBounds(l, t, r, b);
19936 mDefaultFocusHighlight.draw(canvas);
19941 * Return an array of resource IDs of the drawable states representing the
19942 * current state of the view.
19944 * @return The current drawable state
19946 * @see Drawable#setState(int[])
19947 * @see #drawableStateChanged()
19948 * @see #onCreateDrawableState(int)
19950 public final int[] getDrawableState() {
19951 if ((mDrawableState != null) && ((mPrivateFlags & PFLAG_DRAWABLE_STATE_DIRTY) == 0)) {
19952 return mDrawableState;
19954 mDrawableState = onCreateDrawableState(0);
19955 mPrivateFlags &= ~PFLAG_DRAWABLE_STATE_DIRTY;
19956 return mDrawableState;
19961 * Generate the new {@link android.graphics.drawable.Drawable} state for
19962 * this view. This is called by the view
19963 * system when the cached Drawable state is determined to be invalid. To
19964 * retrieve the current state, you should use {@link #getDrawableState}.
19966 * @param extraSpace if non-zero, this is the number of extra entries you
19967 * would like in the returned array in which you can place your own
19970 * @return Returns an array holding the current {@link Drawable} state of
19973 * @see #mergeDrawableStates(int[], int[])
19975 protected int[] onCreateDrawableState(int extraSpace) {
19976 if ((mViewFlags & DUPLICATE_PARENT_STATE) == DUPLICATE_PARENT_STATE &&
19977 mParent instanceof View) {
19978 return ((View) mParent).onCreateDrawableState(extraSpace);
19981 int[] drawableState;
19983 int privateFlags = mPrivateFlags;
19985 int viewStateIndex = 0;
19986 if ((privateFlags & PFLAG_PRESSED) != 0) viewStateIndex |= StateSet.VIEW_STATE_PRESSED;
19987 if ((mViewFlags & ENABLED_MASK) == ENABLED) viewStateIndex |= StateSet.VIEW_STATE_ENABLED;
19988 if (isFocused()) viewStateIndex |= StateSet.VIEW_STATE_FOCUSED;
19989 if ((privateFlags & PFLAG_SELECTED) != 0) viewStateIndex |= StateSet.VIEW_STATE_SELECTED;
19990 if (hasWindowFocus()) viewStateIndex |= StateSet.VIEW_STATE_WINDOW_FOCUSED;
19991 if ((privateFlags & PFLAG_ACTIVATED) != 0) viewStateIndex |= StateSet.VIEW_STATE_ACTIVATED;
19992 if (mAttachInfo != null && mAttachInfo.mHardwareAccelerationRequested &&
19993 ThreadedRenderer.isAvailable()) {
19994 // This is set if HW acceleration is requested, even if the current
19995 // process doesn't allow it. This is just to allow app preview
19996 // windows to better match their app.
19997 viewStateIndex |= StateSet.VIEW_STATE_ACCELERATED;
19999 if ((privateFlags & PFLAG_HOVERED) != 0) viewStateIndex |= StateSet.VIEW_STATE_HOVERED;
20001 final int privateFlags2 = mPrivateFlags2;
20002 if ((privateFlags2 & PFLAG2_DRAG_CAN_ACCEPT) != 0) {
20003 viewStateIndex |= StateSet.VIEW_STATE_DRAG_CAN_ACCEPT;
20005 if ((privateFlags2 & PFLAG2_DRAG_HOVERED) != 0) {
20006 viewStateIndex |= StateSet.VIEW_STATE_DRAG_HOVERED;
20009 drawableState = StateSet.get(viewStateIndex);
20011 //noinspection ConstantIfStatement
20013 Log.i("View", "drawableStateIndex=" + viewStateIndex);
20014 Log.i("View", toString()
20015 + " pressed=" + ((privateFlags & PFLAG_PRESSED) != 0)
20016 + " en=" + ((mViewFlags & ENABLED_MASK) == ENABLED)
20017 + " fo=" + hasFocus()
20018 + " sl=" + ((privateFlags & PFLAG_SELECTED) != 0)
20019 + " wf=" + hasWindowFocus()
20020 + ": " + Arrays.toString(drawableState));
20023 if (extraSpace == 0) {
20024 return drawableState;
20027 final int[] fullState;
20028 if (drawableState != null) {
20029 fullState = new int[drawableState.length + extraSpace];
20030 System.arraycopy(drawableState, 0, fullState, 0, drawableState.length);
20032 fullState = new int[extraSpace];
20039 * Merge your own state values in <var>additionalState</var> into the base
20040 * state values <var>baseState</var> that were returned by
20041 * {@link #onCreateDrawableState(int)}.
20043 * @param baseState The base state values returned by
20044 * {@link #onCreateDrawableState(int)}, which will be modified to also hold your
20045 * own additional state values.
20047 * @param additionalState The additional state values you would like
20048 * added to <var>baseState</var>; this array is not modified.
20050 * @return As a convenience, the <var>baseState</var> array you originally
20051 * passed into the function is returned.
20053 * @see #onCreateDrawableState(int)
20055 protected static int[] mergeDrawableStates(int[] baseState, int[] additionalState) {
20056 final int N = baseState.length;
20058 while (i >= 0 && baseState[i] == 0) {
20061 System.arraycopy(additionalState, 0, baseState, i + 1, additionalState.length);
20066 * Call {@link Drawable#jumpToCurrentState() Drawable.jumpToCurrentState()}
20067 * on all Drawable objects associated with this view.
20069 * Also calls {@link StateListAnimator#jumpToCurrentState()} if there is a StateListAnimator
20070 * attached to this view.
20073 public void jumpDrawablesToCurrentState() {
20074 if (mBackground != null) {
20075 mBackground.jumpToCurrentState();
20077 if (mStateListAnimator != null) {
20078 mStateListAnimator.jumpToCurrentState();
20080 if (mDefaultFocusHighlight != null) {
20081 mDefaultFocusHighlight.jumpToCurrentState();
20083 if (mForegroundInfo != null && mForegroundInfo.mDrawable != null) {
20084 mForegroundInfo.mDrawable.jumpToCurrentState();
20089 * Sets the background color for this view.
20090 * @param color the color of the background
20092 @RemotableViewMethod
20093 public void setBackgroundColor(@ColorInt int color) {
20094 if (mBackground instanceof ColorDrawable) {
20095 ((ColorDrawable) mBackground.mutate()).setColor(color);
20096 computeOpaqueFlags();
20097 mBackgroundResource = 0;
20099 setBackground(new ColorDrawable(color));
20104 * Set the background to a given resource. The resource should refer to
20105 * a Drawable object or 0 to remove the background.
20106 * @param resid The identifier of the resource.
20108 * @attr ref android.R.styleable#View_background
20110 @RemotableViewMethod
20111 public void setBackgroundResource(@DrawableRes int resid) {
20112 if (resid != 0 && resid == mBackgroundResource) {
20118 d = mContext.getDrawable(resid);
20122 mBackgroundResource = resid;
20126 * Set the background to a given Drawable, or remove the background. If the
20127 * background has padding, this View's padding is set to the background's
20128 * padding. However, when a background is removed, this View's padding isn't
20129 * touched. If setting the padding is desired, please use
20130 * {@link #setPadding(int, int, int, int)}.
20132 * @param background The Drawable to use as the background, or null to remove the
20135 public void setBackground(Drawable background) {
20136 //noinspection deprecation
20137 setBackgroundDrawable(background);
20141 * @deprecated use {@link #setBackground(Drawable)} instead
20144 public void setBackgroundDrawable(Drawable background) {
20145 computeOpaqueFlags();
20147 if (background == mBackground) {
20151 boolean requestLayout = false;
20153 mBackgroundResource = 0;
20156 * Regardless of whether we're setting a new background or not, we want
20157 * to clear the previous drawable. setVisible first while we still have the callback set.
20159 if (mBackground != null) {
20160 if (isAttachedToWindow()) {
20161 mBackground.setVisible(false, false);
20163 mBackground.setCallback(null);
20164 unscheduleDrawable(mBackground);
20167 if (background != null) {
20168 Rect padding = sThreadLocal.get();
20169 if (padding == null) {
20170 padding = new Rect();
20171 sThreadLocal.set(padding);
20173 resetResolvedDrawablesInternal();
20174 background.setLayoutDirection(getLayoutDirection());
20175 if (background.getPadding(padding)) {
20176 resetResolvedPaddingInternal();
20177 switch (background.getLayoutDirection()) {
20178 case LAYOUT_DIRECTION_RTL:
20179 mUserPaddingLeftInitial = padding.right;
20180 mUserPaddingRightInitial = padding.left;
20181 internalSetPadding(padding.right, padding.top, padding.left, padding.bottom);
20183 case LAYOUT_DIRECTION_LTR:
20185 mUserPaddingLeftInitial = padding.left;
20186 mUserPaddingRightInitial = padding.right;
20187 internalSetPadding(padding.left, padding.top, padding.right, padding.bottom);
20189 mLeftPaddingDefined = false;
20190 mRightPaddingDefined = false;
20193 // Compare the minimum sizes of the old Drawable and the new. If there isn't an old or
20194 // if it has a different minimum size, we should layout again
20195 if (mBackground == null
20196 || mBackground.getMinimumHeight() != background.getMinimumHeight()
20197 || mBackground.getMinimumWidth() != background.getMinimumWidth()) {
20198 requestLayout = true;
20201 // Set mBackground before we set this as the callback and start making other
20202 // background drawable state change calls. In particular, the setVisible call below
20203 // can result in drawables attempting to start animations or otherwise invalidate,
20204 // which requires the view set as the callback (us) to recognize the drawable as
20205 // belonging to it as per verifyDrawable.
20206 mBackground = background;
20207 if (background.isStateful()) {
20208 background.setState(getDrawableState());
20210 if (isAttachedToWindow()) {
20211 background.setVisible(getWindowVisibility() == VISIBLE && isShown(), false);
20214 applyBackgroundTint();
20216 // Set callback last, since the view may still be initializing.
20217 background.setCallback(this);
20219 if ((mPrivateFlags & PFLAG_SKIP_DRAW) != 0) {
20220 mPrivateFlags &= ~PFLAG_SKIP_DRAW;
20221 requestLayout = true;
20224 /* Remove the background */
20225 mBackground = null;
20226 if ((mViewFlags & WILL_NOT_DRAW) != 0
20227 && (mDefaultFocusHighlight == null)
20228 && (mForegroundInfo == null || mForegroundInfo.mDrawable == null)) {
20229 mPrivateFlags |= PFLAG_SKIP_DRAW;
20233 * When the background is set, we try to apply its padding to this
20234 * View. When the background is removed, we don't touch this View's
20235 * padding. This is noted in the Javadocs. Hence, we don't need to
20236 * requestLayout(), the invalidate() below is sufficient.
20239 // The old background's minimum size could have affected this
20240 // View's layout, so let's requestLayout
20241 requestLayout = true;
20244 computeOpaqueFlags();
20246 if (requestLayout) {
20250 mBackgroundSizeChanged = true;
20252 invalidateOutline();
20256 * Gets the background drawable
20258 * @return The drawable used as the background for this view, if any.
20260 * @see #setBackground(Drawable)
20262 * @attr ref android.R.styleable#View_background
20264 public Drawable getBackground() {
20265 return mBackground;
20269 * Applies a tint to the background drawable. Does not modify the current tint
20270 * mode, which is {@link PorterDuff.Mode#SRC_IN} by default.
20272 * Subsequent calls to {@link #setBackground(Drawable)} will automatically
20273 * mutate the drawable and apply the specified tint and tint mode using
20274 * {@link Drawable#setTintList(ColorStateList)}.
20276 * @param tint the tint to apply, may be {@code null} to clear tint
20278 * @attr ref android.R.styleable#View_backgroundTint
20279 * @see #getBackgroundTintList()
20280 * @see Drawable#setTintList(ColorStateList)
20282 public void setBackgroundTintList(@Nullable ColorStateList tint) {
20283 if (mBackgroundTint == null) {
20284 mBackgroundTint = new TintInfo();
20286 mBackgroundTint.mTintList = tint;
20287 mBackgroundTint.mHasTintList = true;
20289 applyBackgroundTint();
20293 * Return the tint applied to the background drawable, if specified.
20295 * @return the tint applied to the background drawable
20296 * @attr ref android.R.styleable#View_backgroundTint
20297 * @see #setBackgroundTintList(ColorStateList)
20300 public ColorStateList getBackgroundTintList() {
20301 return mBackgroundTint != null ? mBackgroundTint.mTintList : null;
20305 * Specifies the blending mode used to apply the tint specified by
20306 * {@link #setBackgroundTintList(ColorStateList)}} to the background
20307 * drawable. The default mode is {@link PorterDuff.Mode#SRC_IN}.
20309 * @param tintMode the blending mode used to apply the tint, may be
20310 * {@code null} to clear tint
20311 * @attr ref android.R.styleable#View_backgroundTintMode
20312 * @see #getBackgroundTintMode()
20313 * @see Drawable#setTintMode(PorterDuff.Mode)
20315 public void setBackgroundTintMode(@Nullable PorterDuff.Mode tintMode) {
20316 if (mBackgroundTint == null) {
20317 mBackgroundTint = new TintInfo();
20319 mBackgroundTint.mTintMode = tintMode;
20320 mBackgroundTint.mHasTintMode = true;
20322 applyBackgroundTint();
20326 * Return the blending mode used to apply the tint to the background
20327 * drawable, if specified.
20329 * @return the blending mode used to apply the tint to the background
20331 * @attr ref android.R.styleable#View_backgroundTintMode
20332 * @see #setBackgroundTintMode(PorterDuff.Mode)
20335 public PorterDuff.Mode getBackgroundTintMode() {
20336 return mBackgroundTint != null ? mBackgroundTint.mTintMode : null;
20339 private void applyBackgroundTint() {
20340 if (mBackground != null && mBackgroundTint != null) {
20341 final TintInfo tintInfo = mBackgroundTint;
20342 if (tintInfo.mHasTintList || tintInfo.mHasTintMode) {
20343 mBackground = mBackground.mutate();
20345 if (tintInfo.mHasTintList) {
20346 mBackground.setTintList(tintInfo.mTintList);
20349 if (tintInfo.mHasTintMode) {
20350 mBackground.setTintMode(tintInfo.mTintMode);
20353 // The drawable (or one of its children) may not have been
20354 // stateful before applying the tint, so let's try again.
20355 if (mBackground.isStateful()) {
20356 mBackground.setState(getDrawableState());
20363 * Returns the drawable used as the foreground of this View. The
20364 * foreground drawable, if non-null, is always drawn on top of the view's content.
20366 * @return a Drawable or null if no foreground was set
20368 * @see #onDrawForeground(Canvas)
20370 public Drawable getForeground() {
20371 return mForegroundInfo != null ? mForegroundInfo.mDrawable : null;
20375 * Supply a Drawable that is to be rendered on top of all of the content in the view.
20377 * @param foreground the Drawable to be drawn on top of the children
20379 * @attr ref android.R.styleable#View_foreground
20381 public void setForeground(Drawable foreground) {
20382 if (mForegroundInfo == null) {
20383 if (foreground == null) {
20387 mForegroundInfo = new ForegroundInfo();
20390 if (foreground == mForegroundInfo.mDrawable) {
20395 if (mForegroundInfo.mDrawable != null) {
20396 if (isAttachedToWindow()) {
20397 mForegroundInfo.mDrawable.setVisible(false, false);
20399 mForegroundInfo.mDrawable.setCallback(null);
20400 unscheduleDrawable(mForegroundInfo.mDrawable);
20403 mForegroundInfo.mDrawable = foreground;
20404 mForegroundInfo.mBoundsChanged = true;
20405 if (foreground != null) {
20406 if ((mPrivateFlags & PFLAG_SKIP_DRAW) != 0) {
20407 mPrivateFlags &= ~PFLAG_SKIP_DRAW;
20409 foreground.setLayoutDirection(getLayoutDirection());
20410 if (foreground.isStateful()) {
20411 foreground.setState(getDrawableState());
20413 applyForegroundTint();
20414 if (isAttachedToWindow()) {
20415 foreground.setVisible(getWindowVisibility() == VISIBLE && isShown(), false);
20417 // Set callback last, since the view may still be initializing.
20418 foreground.setCallback(this);
20419 } else if ((mViewFlags & WILL_NOT_DRAW) != 0 && mBackground == null
20420 && (mDefaultFocusHighlight == null)) {
20421 mPrivateFlags |= PFLAG_SKIP_DRAW;
20428 * Magic bit used to support features of framework-internal window decor implementation details.
20429 * This used to live exclusively in FrameLayout.
20431 * @return true if the foreground should draw inside the padding region or false
20432 * if it should draw inset by the view's padding
20433 * @hide internal use only; only used by FrameLayout and internal screen layouts.
20435 public boolean isForegroundInsidePadding() {
20436 return mForegroundInfo != null ? mForegroundInfo.mInsidePadding : true;
20440 * Describes how the foreground is positioned.
20442 * @return foreground gravity.
20444 * @see #setForegroundGravity(int)
20446 * @attr ref android.R.styleable#View_foregroundGravity
20448 public int getForegroundGravity() {
20449 return mForegroundInfo != null ? mForegroundInfo.mGravity
20450 : Gravity.START | Gravity.TOP;
20454 * Describes how the foreground is positioned. Defaults to START and TOP.
20456 * @param gravity see {@link android.view.Gravity}
20458 * @see #getForegroundGravity()
20460 * @attr ref android.R.styleable#View_foregroundGravity
20462 public void setForegroundGravity(int gravity) {
20463 if (mForegroundInfo == null) {
20464 mForegroundInfo = new ForegroundInfo();
20467 if (mForegroundInfo.mGravity != gravity) {
20468 if ((gravity & Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK) == 0) {
20469 gravity |= Gravity.START;
20472 if ((gravity & Gravity.VERTICAL_GRAVITY_MASK) == 0) {
20473 gravity |= Gravity.TOP;
20476 mForegroundInfo.mGravity = gravity;
20482 * Applies a tint to the foreground drawable. Does not modify the current tint
20483 * mode, which is {@link PorterDuff.Mode#SRC_IN} by default.
20485 * Subsequent calls to {@link #setForeground(Drawable)} will automatically
20486 * mutate the drawable and apply the specified tint and tint mode using
20487 * {@link Drawable#setTintList(ColorStateList)}.
20489 * @param tint the tint to apply, may be {@code null} to clear tint
20491 * @attr ref android.R.styleable#View_foregroundTint
20492 * @see #getForegroundTintList()
20493 * @see Drawable#setTintList(ColorStateList)
20495 public void setForegroundTintList(@Nullable ColorStateList tint) {
20496 if (mForegroundInfo == null) {
20497 mForegroundInfo = new ForegroundInfo();
20499 if (mForegroundInfo.mTintInfo == null) {
20500 mForegroundInfo.mTintInfo = new TintInfo();
20502 mForegroundInfo.mTintInfo.mTintList = tint;
20503 mForegroundInfo.mTintInfo.mHasTintList = true;
20505 applyForegroundTint();
20509 * Return the tint applied to the foreground drawable, if specified.
20511 * @return the tint applied to the foreground drawable
20512 * @attr ref android.R.styleable#View_foregroundTint
20513 * @see #setForegroundTintList(ColorStateList)
20516 public ColorStateList getForegroundTintList() {
20517 return mForegroundInfo != null && mForegroundInfo.mTintInfo != null
20518 ? mForegroundInfo.mTintInfo.mTintList : null;
20522 * Specifies the blending mode used to apply the tint specified by
20523 * {@link #setForegroundTintList(ColorStateList)}} to the background
20524 * drawable. The default mode is {@link PorterDuff.Mode#SRC_IN}.
20526 * @param tintMode the blending mode used to apply the tint, may be
20527 * {@code null} to clear tint
20528 * @attr ref android.R.styleable#View_foregroundTintMode
20529 * @see #getForegroundTintMode()
20530 * @see Drawable#setTintMode(PorterDuff.Mode)
20532 public void setForegroundTintMode(@Nullable PorterDuff.Mode tintMode) {
20533 if (mForegroundInfo == null) {
20534 mForegroundInfo = new ForegroundInfo();
20536 if (mForegroundInfo.mTintInfo == null) {
20537 mForegroundInfo.mTintInfo = new TintInfo();
20539 mForegroundInfo.mTintInfo.mTintMode = tintMode;
20540 mForegroundInfo.mTintInfo.mHasTintMode = true;
20542 applyForegroundTint();
20546 * Return the blending mode used to apply the tint to the foreground
20547 * drawable, if specified.
20549 * @return the blending mode used to apply the tint to the foreground
20551 * @attr ref android.R.styleable#View_foregroundTintMode
20552 * @see #setForegroundTintMode(PorterDuff.Mode)
20555 public PorterDuff.Mode getForegroundTintMode() {
20556 return mForegroundInfo != null && mForegroundInfo.mTintInfo != null
20557 ? mForegroundInfo.mTintInfo.mTintMode : null;
20560 private void applyForegroundTint() {
20561 if (mForegroundInfo != null && mForegroundInfo.mDrawable != null
20562 && mForegroundInfo.mTintInfo != null) {
20563 final TintInfo tintInfo = mForegroundInfo.mTintInfo;
20564 if (tintInfo.mHasTintList || tintInfo.mHasTintMode) {
20565 mForegroundInfo.mDrawable = mForegroundInfo.mDrawable.mutate();
20567 if (tintInfo.mHasTintList) {
20568 mForegroundInfo.mDrawable.setTintList(tintInfo.mTintList);
20571 if (tintInfo.mHasTintMode) {
20572 mForegroundInfo.mDrawable.setTintMode(tintInfo.mTintMode);
20575 // The drawable (or one of its children) may not have been
20576 // stateful before applying the tint, so let's try again.
20577 if (mForegroundInfo.mDrawable.isStateful()) {
20578 mForegroundInfo.mDrawable.setState(getDrawableState());
20585 * Get the drawable to be overlayed when a view is autofilled
20587 * @return The drawable
20589 * @throws IllegalStateException if the drawable could not be found.
20591 @Nullable private Drawable getAutofilledDrawable() {
20592 if (mAttachInfo == null) {
20595 // Lazily load the isAutofilled drawable.
20596 if (mAttachInfo.mAutofilledDrawable == null) {
20597 Context rootContext = getRootView().getContext();
20598 TypedArray a = rootContext.getTheme().obtainStyledAttributes(AUTOFILL_HIGHLIGHT_ATTR);
20599 int attributeResourceId = a.getResourceId(0, 0);
20600 mAttachInfo.mAutofilledDrawable = rootContext.getDrawable(attributeResourceId);
20604 return mAttachInfo.mAutofilledDrawable;
20608 * Draw {@link View#isAutofilled()} highlight over view if the view is autofilled.
20610 * @param canvas The canvas to draw on
20612 private void drawAutofilledHighlight(@NonNull Canvas canvas) {
20613 if (isAutofilled()) {
20614 Drawable autofilledHighlight = getAutofilledDrawable();
20616 if (autofilledHighlight != null) {
20617 autofilledHighlight.setBounds(0, 0, getWidth(), getHeight());
20618 autofilledHighlight.draw(canvas);
20624 * Draw any foreground content for this view.
20626 * <p>Foreground content may consist of scroll bars, a {@link #setForeground foreground}
20627 * drawable or other view-specific decorations. The foreground is drawn on top of the
20628 * primary view content.</p>
20630 * @param canvas canvas to draw into
20632 public void onDrawForeground(Canvas canvas) {
20633 onDrawScrollIndicators(canvas);
20634 onDrawScrollBars(canvas);
20636 final Drawable foreground = mForegroundInfo != null ? mForegroundInfo.mDrawable : null;
20637 if (foreground != null) {
20638 if (mForegroundInfo.mBoundsChanged) {
20639 mForegroundInfo.mBoundsChanged = false;
20640 final Rect selfBounds = mForegroundInfo.mSelfBounds;
20641 final Rect overlayBounds = mForegroundInfo.mOverlayBounds;
20643 if (mForegroundInfo.mInsidePadding) {
20644 selfBounds.set(0, 0, getWidth(), getHeight());
20646 selfBounds.set(getPaddingLeft(), getPaddingTop(),
20647 getWidth() - getPaddingRight(), getHeight() - getPaddingBottom());
20650 final int ld = getLayoutDirection();
20651 Gravity.apply(mForegroundInfo.mGravity, foreground.getIntrinsicWidth(),
20652 foreground.getIntrinsicHeight(), selfBounds, overlayBounds, ld);
20653 foreground.setBounds(overlayBounds);
20656 foreground.draw(canvas);
20661 * Sets the padding. The view may add on the space required to display
20662 * the scrollbars, depending on the style and visibility of the scrollbars.
20663 * So the values returned from {@link #getPaddingLeft}, {@link #getPaddingTop},
20664 * {@link #getPaddingRight} and {@link #getPaddingBottom} may be different
20665 * from the values set in this call.
20667 * @attr ref android.R.styleable#View_padding
20668 * @attr ref android.R.styleable#View_paddingBottom
20669 * @attr ref android.R.styleable#View_paddingLeft
20670 * @attr ref android.R.styleable#View_paddingRight
20671 * @attr ref android.R.styleable#View_paddingTop
20672 * @param left the left padding in pixels
20673 * @param top the top padding in pixels
20674 * @param right the right padding in pixels
20675 * @param bottom the bottom padding in pixels
20677 public void setPadding(int left, int top, int right, int bottom) {
20678 resetResolvedPaddingInternal();
20680 mUserPaddingStart = UNDEFINED_PADDING;
20681 mUserPaddingEnd = UNDEFINED_PADDING;
20683 mUserPaddingLeftInitial = left;
20684 mUserPaddingRightInitial = right;
20686 mLeftPaddingDefined = true;
20687 mRightPaddingDefined = true;
20689 internalSetPadding(left, top, right, bottom);
20695 protected void internalSetPadding(int left, int top, int right, int bottom) {
20696 mUserPaddingLeft = left;
20697 mUserPaddingRight = right;
20698 mUserPaddingBottom = bottom;
20700 final int viewFlags = mViewFlags;
20701 boolean changed = false;
20703 // Common case is there are no scroll bars.
20704 if ((viewFlags & (SCROLLBARS_VERTICAL|SCROLLBARS_HORIZONTAL)) != 0) {
20705 if ((viewFlags & SCROLLBARS_VERTICAL) != 0) {
20706 final int offset = (viewFlags & SCROLLBARS_INSET_MASK) == 0
20707 ? 0 : getVerticalScrollbarWidth();
20708 switch (mVerticalScrollbarPosition) {
20709 case SCROLLBAR_POSITION_DEFAULT:
20710 if (isLayoutRtl()) {
20716 case SCROLLBAR_POSITION_RIGHT:
20719 case SCROLLBAR_POSITION_LEFT:
20724 if ((viewFlags & SCROLLBARS_HORIZONTAL) != 0) {
20725 bottom += (viewFlags & SCROLLBARS_INSET_MASK) == 0
20726 ? 0 : getHorizontalScrollbarHeight();
20730 if (mPaddingLeft != left) {
20732 mPaddingLeft = left;
20734 if (mPaddingTop != top) {
20738 if (mPaddingRight != right) {
20740 mPaddingRight = right;
20742 if (mPaddingBottom != bottom) {
20744 mPaddingBottom = bottom;
20749 invalidateOutline();
20754 * Sets the relative padding. The view may add on the space required to display
20755 * the scrollbars, depending on the style and visibility of the scrollbars.
20756 * So the values returned from {@link #getPaddingStart}, {@link #getPaddingTop},
20757 * {@link #getPaddingEnd} and {@link #getPaddingBottom} may be different
20758 * from the values set in this call.
20760 * @attr ref android.R.styleable#View_padding
20761 * @attr ref android.R.styleable#View_paddingBottom
20762 * @attr ref android.R.styleable#View_paddingStart
20763 * @attr ref android.R.styleable#View_paddingEnd
20764 * @attr ref android.R.styleable#View_paddingTop
20765 * @param start the start padding in pixels
20766 * @param top the top padding in pixels
20767 * @param end the end padding in pixels
20768 * @param bottom the bottom padding in pixels
20770 public void setPaddingRelative(int start, int top, int end, int bottom) {
20771 resetResolvedPaddingInternal();
20773 mUserPaddingStart = start;
20774 mUserPaddingEnd = end;
20775 mLeftPaddingDefined = true;
20776 mRightPaddingDefined = true;
20778 switch(getLayoutDirection()) {
20779 case LAYOUT_DIRECTION_RTL:
20780 mUserPaddingLeftInitial = end;
20781 mUserPaddingRightInitial = start;
20782 internalSetPadding(end, top, start, bottom);
20784 case LAYOUT_DIRECTION_LTR:
20786 mUserPaddingLeftInitial = start;
20787 mUserPaddingRightInitial = end;
20788 internalSetPadding(start, top, end, bottom);
20793 * Returns the top padding of this view.
20795 * @return the top padding in pixels
20797 public int getPaddingTop() {
20798 return mPaddingTop;
20802 * Returns the bottom padding of this view. If there are inset and enabled
20803 * scrollbars, this value may include the space required to display the
20804 * scrollbars as well.
20806 * @return the bottom padding in pixels
20808 public int getPaddingBottom() {
20809 return mPaddingBottom;
20813 * Returns the left padding of this view. If there are inset and enabled
20814 * scrollbars, this value may include the space required to display the
20815 * scrollbars as well.
20817 * @return the left padding in pixels
20819 public int getPaddingLeft() {
20820 if (!isPaddingResolved()) {
20823 return mPaddingLeft;
20827 * Returns the start padding of this view depending on its resolved layout direction.
20828 * If there are inset and enabled scrollbars, this value may include the space
20829 * required to display the scrollbars as well.
20831 * @return the start padding in pixels
20833 public int getPaddingStart() {
20834 if (!isPaddingResolved()) {
20837 return (getLayoutDirection() == LAYOUT_DIRECTION_RTL) ?
20838 mPaddingRight : mPaddingLeft;
20842 * Returns the right padding of this view. If there are inset and enabled
20843 * scrollbars, this value may include the space required to display the
20844 * scrollbars as well.
20846 * @return the right padding in pixels
20848 public int getPaddingRight() {
20849 if (!isPaddingResolved()) {
20852 return mPaddingRight;
20856 * Returns the end padding of this view depending on its resolved layout direction.
20857 * If there are inset and enabled scrollbars, this value may include the space
20858 * required to display the scrollbars as well.
20860 * @return the end padding in pixels
20862 public int getPaddingEnd() {
20863 if (!isPaddingResolved()) {
20866 return (getLayoutDirection() == LAYOUT_DIRECTION_RTL) ?
20867 mPaddingLeft : mPaddingRight;
20871 * Return if the padding has been set through relative values
20872 * {@link #setPaddingRelative(int, int, int, int)} or through
20873 * @attr ref android.R.styleable#View_paddingStart or
20874 * @attr ref android.R.styleable#View_paddingEnd
20876 * @return true if the padding is relative or false if it is not.
20878 public boolean isPaddingRelative() {
20879 return (mUserPaddingStart != UNDEFINED_PADDING || mUserPaddingEnd != UNDEFINED_PADDING);
20882 Insets computeOpticalInsets() {
20883 return (mBackground == null) ? Insets.NONE : mBackground.getOpticalInsets();
20889 public void resetPaddingToInitialValues() {
20890 if (isRtlCompatibilityMode()) {
20891 mPaddingLeft = mUserPaddingLeftInitial;
20892 mPaddingRight = mUserPaddingRightInitial;
20895 if (isLayoutRtl()) {
20896 mPaddingLeft = (mUserPaddingEnd >= 0) ? mUserPaddingEnd : mUserPaddingLeftInitial;
20897 mPaddingRight = (mUserPaddingStart >= 0) ? mUserPaddingStart : mUserPaddingRightInitial;
20899 mPaddingLeft = (mUserPaddingStart >= 0) ? mUserPaddingStart : mUserPaddingLeftInitial;
20900 mPaddingRight = (mUserPaddingEnd >= 0) ? mUserPaddingEnd : mUserPaddingRightInitial;
20907 public Insets getOpticalInsets() {
20908 if (mLayoutInsets == null) {
20909 mLayoutInsets = computeOpticalInsets();
20911 return mLayoutInsets;
20915 * Set this view's optical insets.
20917 * <p>This method should be treated similarly to setMeasuredDimension and not as a general
20918 * property. Views that compute their own optical insets should call it as part of measurement.
20919 * This method does not request layout. If you are setting optical insets outside of
20920 * measure/layout itself you will want to call requestLayout() yourself.
20924 public void setOpticalInsets(Insets insets) {
20925 mLayoutInsets = insets;
20929 * Changes the selection state of this view. A view can be selected or not.
20930 * Note that selection is not the same as focus. Views are typically
20931 * selected in the context of an AdapterView like ListView or GridView;
20932 * the selected view is the view that is highlighted.
20934 * @param selected true if the view must be selected, false otherwise
20936 public void setSelected(boolean selected) {
20937 //noinspection DoubleNegation
20938 if (((mPrivateFlags & PFLAG_SELECTED) != 0) != selected) {
20939 mPrivateFlags = (mPrivateFlags & ~PFLAG_SELECTED) | (selected ? PFLAG_SELECTED : 0);
20940 if (!selected) resetPressedState();
20942 refreshDrawableState();
20943 dispatchSetSelected(selected);
20945 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SELECTED);
20947 notifyViewAccessibilityStateChangedIfNeeded(
20948 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED);
20954 * Dispatch setSelected to all of this View's children.
20956 * @see #setSelected(boolean)
20958 * @param selected The new selected state
20960 protected void dispatchSetSelected(boolean selected) {
20964 * Indicates the selection state of this view.
20966 * @return true if the view is selected, false otherwise
20968 @ViewDebug.ExportedProperty
20969 public boolean isSelected() {
20970 return (mPrivateFlags & PFLAG_SELECTED) != 0;
20974 * Changes the activated state of this view. A view can be activated or not.
20975 * Note that activation is not the same as selection. Selection is
20976 * a transient property, representing the view (hierarchy) the user is
20977 * currently interacting with. Activation is a longer-term state that the
20978 * user can move views in and out of. For example, in a list view with
20979 * single or multiple selection enabled, the views in the current selection
20980 * set are activated. (Um, yeah, we are deeply sorry about the terminology
20981 * here.) The activated state is propagated down to children of the view it
20984 * @param activated true if the view must be activated, false otherwise
20986 public void setActivated(boolean activated) {
20987 //noinspection DoubleNegation
20988 if (((mPrivateFlags & PFLAG_ACTIVATED) != 0) != activated) {
20989 mPrivateFlags = (mPrivateFlags & ~PFLAG_ACTIVATED) | (activated ? PFLAG_ACTIVATED : 0);
20991 refreshDrawableState();
20992 dispatchSetActivated(activated);
20997 * Dispatch setActivated to all of this View's children.
20999 * @see #setActivated(boolean)
21001 * @param activated The new activated state
21003 protected void dispatchSetActivated(boolean activated) {
21007 * Indicates the activation state of this view.
21009 * @return true if the view is activated, false otherwise
21011 @ViewDebug.ExportedProperty
21012 public boolean isActivated() {
21013 return (mPrivateFlags & PFLAG_ACTIVATED) != 0;
21017 * Returns the ViewTreeObserver for this view's hierarchy. The view tree
21018 * observer can be used to get notifications when global events, like
21021 * The returned ViewTreeObserver observer is not guaranteed to remain
21022 * valid for the lifetime of this View. If the caller of this method keeps
21023 * a long-lived reference to ViewTreeObserver, it should always check for
21024 * the return value of {@link ViewTreeObserver#isAlive()}.
21026 * @return The ViewTreeObserver for this view's hierarchy.
21028 public ViewTreeObserver getViewTreeObserver() {
21029 if (mAttachInfo != null) {
21030 return mAttachInfo.mTreeObserver;
21032 if (mFloatingTreeObserver == null) {
21033 mFloatingTreeObserver = new ViewTreeObserver(mContext);
21035 return mFloatingTreeObserver;
21039 * <p>Finds the topmost view in the current view hierarchy.</p>
21041 * @return the topmost view containing this view
21043 public View getRootView() {
21044 if (mAttachInfo != null) {
21045 final View v = mAttachInfo.mRootView;
21051 View parent = this;
21053 while (parent.mParent != null && parent.mParent instanceof View) {
21054 parent = (View) parent.mParent;
21061 * Transforms a motion event from view-local coordinates to on-screen
21064 * @param ev the view-local motion event
21065 * @return false if the transformation could not be applied
21068 public boolean toGlobalMotionEvent(MotionEvent ev) {
21069 final AttachInfo info = mAttachInfo;
21070 if (info == null) {
21074 final Matrix m = info.mTmpMatrix;
21075 m.set(Matrix.IDENTITY_MATRIX);
21076 transformMatrixToGlobal(m);
21082 * Transforms a motion event from on-screen coordinates to view-local
21085 * @param ev the on-screen motion event
21086 * @return false if the transformation could not be applied
21089 public boolean toLocalMotionEvent(MotionEvent ev) {
21090 final AttachInfo info = mAttachInfo;
21091 if (info == null) {
21095 final Matrix m = info.mTmpMatrix;
21096 m.set(Matrix.IDENTITY_MATRIX);
21097 transformMatrixToLocal(m);
21103 * Modifies the input matrix such that it maps view-local coordinates to
21104 * on-screen coordinates.
21106 * @param m input matrix to modify
21109 public void transformMatrixToGlobal(Matrix m) {
21110 final ViewParent parent = mParent;
21111 if (parent instanceof View) {
21112 final View vp = (View) parent;
21113 vp.transformMatrixToGlobal(m);
21114 m.preTranslate(-vp.mScrollX, -vp.mScrollY);
21115 } else if (parent instanceof ViewRootImpl) {
21116 final ViewRootImpl vr = (ViewRootImpl) parent;
21117 vr.transformMatrixToGlobal(m);
21118 m.preTranslate(0, -vr.mCurScrollY);
21121 m.preTranslate(mLeft, mTop);
21123 if (!hasIdentityMatrix()) {
21124 m.preConcat(getMatrix());
21129 * Modifies the input matrix such that it maps on-screen coordinates to
21130 * view-local coordinates.
21132 * @param m input matrix to modify
21135 public void transformMatrixToLocal(Matrix m) {
21136 final ViewParent parent = mParent;
21137 if (parent instanceof View) {
21138 final View vp = (View) parent;
21139 vp.transformMatrixToLocal(m);
21140 m.postTranslate(vp.mScrollX, vp.mScrollY);
21141 } else if (parent instanceof ViewRootImpl) {
21142 final ViewRootImpl vr = (ViewRootImpl) parent;
21143 vr.transformMatrixToLocal(m);
21144 m.postTranslate(0, vr.mCurScrollY);
21147 m.postTranslate(-mLeft, -mTop);
21149 if (!hasIdentityMatrix()) {
21150 m.postConcat(getInverseMatrix());
21157 @ViewDebug.ExportedProperty(category = "layout", indexMapping = {
21158 @ViewDebug.IntToString(from = 0, to = "x"),
21159 @ViewDebug.IntToString(from = 1, to = "y")
21161 public int[] getLocationOnScreen() {
21162 int[] location = new int[2];
21163 getLocationOnScreen(location);
21168 * <p>Computes the coordinates of this view on the screen. The argument
21169 * must be an array of two integers. After the method returns, the array
21170 * contains the x and y location in that order.</p>
21172 * @param outLocation an array of two integers in which to hold the coordinates
21174 public void getLocationOnScreen(@Size(2) int[] outLocation) {
21175 getLocationInWindow(outLocation);
21177 final AttachInfo info = mAttachInfo;
21178 if (info != null) {
21179 outLocation[0] += info.mWindowLeft;
21180 outLocation[1] += info.mWindowTop;
21185 * <p>Computes the coordinates of this view in its window. The argument
21186 * must be an array of two integers. After the method returns, the array
21187 * contains the x and y location in that order.</p>
21189 * @param outLocation an array of two integers in which to hold the coordinates
21191 public void getLocationInWindow(@Size(2) int[] outLocation) {
21192 if (outLocation == null || outLocation.length < 2) {
21193 throw new IllegalArgumentException("outLocation must be an array of two integers");
21196 outLocation[0] = 0;
21197 outLocation[1] = 0;
21199 transformFromViewToWindowSpace(outLocation);
21203 public void transformFromViewToWindowSpace(@Size(2) int[] inOutLocation) {
21204 if (inOutLocation == null || inOutLocation.length < 2) {
21205 throw new IllegalArgumentException("inOutLocation must be an array of two integers");
21208 if (mAttachInfo == null) {
21209 // When the view is not attached to a window, this method does not make sense
21210 inOutLocation[0] = inOutLocation[1] = 0;
21214 float position[] = mAttachInfo.mTmpTransformLocation;
21215 position[0] = inOutLocation[0];
21216 position[1] = inOutLocation[1];
21218 if (!hasIdentityMatrix()) {
21219 getMatrix().mapPoints(position);
21222 position[0] += mLeft;
21223 position[1] += mTop;
21225 ViewParent viewParent = mParent;
21226 while (viewParent instanceof View) {
21227 final View view = (View) viewParent;
21229 position[0] -= view.mScrollX;
21230 position[1] -= view.mScrollY;
21232 if (!view.hasIdentityMatrix()) {
21233 view.getMatrix().mapPoints(position);
21236 position[0] += view.mLeft;
21237 position[1] += view.mTop;
21239 viewParent = view.mParent;
21242 if (viewParent instanceof ViewRootImpl) {
21244 final ViewRootImpl vr = (ViewRootImpl) viewParent;
21245 position[1] -= vr.mCurScrollY;
21248 inOutLocation[0] = Math.round(position[0]);
21249 inOutLocation[1] = Math.round(position[1]);
21253 * @param id the id of the view to be found
21254 * @return the view of the specified id, null if cannot be found
21257 protected <T extends View> T findViewTraversal(@IdRes int id) {
21265 * @param tag the tag of the view to be found
21266 * @return the view of specified tag, null if cannot be found
21269 protected <T extends View> T findViewWithTagTraversal(Object tag) {
21270 if (tag != null && tag.equals(mTag)) {
21277 * @param predicate The predicate to evaluate.
21278 * @param childToSkip If not null, ignores this child during the recursive traversal.
21279 * @return The first view that matches the predicate or null.
21282 protected <T extends View> T findViewByPredicateTraversal(Predicate<View> predicate,
21283 View childToSkip) {
21284 if (predicate.test(this)) {
21291 * Finds the first descendant view with the given ID, the view itself if
21292 * the ID matches {@link #getId()}, or {@code null} if the ID is invalid
21293 * (< 0) or there is no matching view in the hierarchy.
21295 * <strong>Note:</strong> In most cases -- depending on compiler support --
21296 * the resulting view is automatically cast to the target class type. If
21297 * the target class type is unconstrained, an explicit cast may be
21300 * @param id the ID to search for
21301 * @return a view with given ID if found, or {@code null} otherwise
21302 * @see View#findViewById(int)
21305 public final <T extends View> T findViewById(@IdRes int id) {
21309 return findViewTraversal(id);
21313 * Finds a view by its unuque and stable accessibility id.
21315 * @param accessibilityId The searched accessibility id.
21316 * @return The found view.
21318 final <T extends View> T findViewByAccessibilityId(int accessibilityId) {
21319 if (accessibilityId < 0) {
21322 T view = findViewByAccessibilityIdTraversal(accessibilityId);
21323 if (view != null) {
21324 return view.includeForAccessibility() ? view : null;
21330 * Performs the traversal to find a view by its unuque and stable accessibility id.
21332 * <strong>Note:</strong>This method does not stop at the root namespace
21333 * boundary since the user can touch the screen at an arbitrary location
21334 * potentially crossing the root namespace bounday which will send an
21335 * accessibility event to accessibility services and they should be able
21336 * to obtain the event source. Also accessibility ids are guaranteed to be
21337 * unique in the window.
21339 * @param accessibilityId The accessibility id.
21340 * @return The found view.
21343 public <T extends View> T findViewByAccessibilityIdTraversal(int accessibilityId) {
21344 if (getAccessibilityViewId() == accessibilityId) {
21351 * Look for a child view with the given tag. If this view has the given
21352 * tag, return this view.
21354 * @param tag The tag to search for, using "tag.equals(getTag())".
21355 * @return The View that has the given tag in the hierarchy or null
21357 public final <T extends View> T findViewWithTag(Object tag) {
21361 return findViewWithTagTraversal(tag);
21365 * Look for a child view that matches the specified predicate.
21366 * If this view matches the predicate, return this view.
21368 * @param predicate The predicate to evaluate.
21369 * @return The first view that matches the predicate or null.
21372 public final <T extends View> T findViewByPredicate(Predicate<View> predicate) {
21373 return findViewByPredicateTraversal(predicate, null);
21377 * Look for a child view that matches the specified predicate,
21378 * starting with the specified view and its descendents and then
21379 * recusively searching the ancestors and siblings of that view
21380 * until this view is reached.
21382 * This method is useful in cases where the predicate does not match
21383 * a single unique view (perhaps multiple views use the same id)
21384 * and we are trying to find the view that is "closest" in scope to the
21387 * @param start The view to start from.
21388 * @param predicate The predicate to evaluate.
21389 * @return The first view that matches the predicate or null.
21392 public final <T extends View> T findViewByPredicateInsideOut(
21393 View start, Predicate<View> predicate) {
21394 View childToSkip = null;
21396 T view = start.findViewByPredicateTraversal(predicate, childToSkip);
21397 if (view != null || start == this) {
21401 ViewParent parent = start.getParent();
21402 if (parent == null || !(parent instanceof View)) {
21406 childToSkip = start;
21407 start = (View) parent;
21412 * Sets the identifier for this view. The identifier does not have to be
21413 * unique in this view's hierarchy. The identifier should be a positive
21418 * @see #findViewById(int)
21420 * @param id a number used to identify the view
21422 * @attr ref android.R.styleable#View_id
21424 public void setId(@IdRes int id) {
21426 if (mID == View.NO_ID && mLabelForId != View.NO_ID) {
21427 mID = generateViewId();
21434 * @param isRoot true if the view belongs to the root namespace, false
21437 public void setIsRootNamespace(boolean isRoot) {
21439 mPrivateFlags |= PFLAG_IS_ROOT_NAMESPACE;
21441 mPrivateFlags &= ~PFLAG_IS_ROOT_NAMESPACE;
21448 * @return true if the view belongs to the root namespace, false otherwise
21450 public boolean isRootNamespace() {
21451 return (mPrivateFlags&PFLAG_IS_ROOT_NAMESPACE) != 0;
21455 * Returns this view's identifier.
21457 * @return a positive integer used to identify the view or {@link #NO_ID}
21458 * if the view has no ID
21461 * @see #findViewById(int)
21462 * @attr ref android.R.styleable#View_id
21465 @ViewDebug.CapturedViewProperty
21466 public int getId() {
21471 * Returns this view's tag.
21473 * @return the Object stored in this view as a tag, or {@code null} if not
21476 * @see #setTag(Object)
21477 * @see #getTag(int)
21479 @ViewDebug.ExportedProperty
21480 public Object getTag() {
21485 * Sets the tag associated with this view. A tag can be used to mark
21486 * a view in its hierarchy and does not have to be unique within the
21487 * hierarchy. Tags can also be used to store data within a view without
21488 * resorting to another data structure.
21490 * @param tag an Object to tag the view with
21493 * @see #setTag(int, Object)
21495 public void setTag(final Object tag) {
21500 * Returns the tag associated with this view and the specified key.
21502 * @param key The key identifying the tag
21504 * @return the Object stored in this view as a tag, or {@code null} if not
21507 * @see #setTag(int, Object)
21510 public Object getTag(int key) {
21511 if (mKeyedTags != null) return mKeyedTags.get(key);
21516 * Sets a tag associated with this view and a key. A tag can be used
21517 * to mark a view in its hierarchy and does not have to be unique within
21518 * the hierarchy. Tags can also be used to store data within a view
21519 * without resorting to another data structure.
21521 * The specified key should be an id declared in the resources of the
21522 * application to ensure it is unique (see the <a
21523 * href="{@docRoot}guide/topics/resources/more-resources.html#Id">ID resource type</a>).
21524 * Keys identified as belonging to
21525 * the Android framework or not associated with any package will cause
21526 * an {@link IllegalArgumentException} to be thrown.
21528 * @param key The key identifying the tag
21529 * @param tag An Object to tag the view with
21531 * @throws IllegalArgumentException If they specified key is not valid
21533 * @see #setTag(Object)
21534 * @see #getTag(int)
21536 public void setTag(int key, final Object tag) {
21537 // If the package id is 0x00 or 0x01, it's either an undefined package
21538 // or a framework id
21539 if ((key >>> 24) < 2) {
21540 throw new IllegalArgumentException("The key must be an application-specific "
21544 setKeyedTag(key, tag);
21548 * Variation of {@link #setTag(int, Object)} that enforces the key to be a
21553 public void setTagInternal(int key, Object tag) {
21554 if ((key >>> 24) != 0x1) {
21555 throw new IllegalArgumentException("The key must be a framework-specific "
21559 setKeyedTag(key, tag);
21562 private void setKeyedTag(int key, Object tag) {
21563 if (mKeyedTags == null) {
21564 mKeyedTags = new SparseArray<Object>(2);
21567 mKeyedTags.put(key, tag);
21571 * Prints information about this view in the log output, with the tag
21572 * {@link #VIEW_LOG_TAG}.
21576 public void debug() {
21581 * Prints information about this view in the log output, with the tag
21582 * {@link #VIEW_LOG_TAG}. Each line in the output is preceded with an
21583 * indentation defined by the <code>depth</code>.
21585 * @param depth the indentation level
21589 protected void debug(int depth) {
21590 String output = debugIndent(depth - 1);
21592 output += "+ " + this;
21595 output += " (id=" + id + ")";
21597 Object tag = getTag();
21599 output += " (tag=" + tag + ")";
21601 Log.d(VIEW_LOG_TAG, output);
21603 if ((mPrivateFlags & PFLAG_FOCUSED) != 0) {
21604 output = debugIndent(depth) + " FOCUSED";
21605 Log.d(VIEW_LOG_TAG, output);
21608 output = debugIndent(depth);
21609 output += "frame={" + mLeft + ", " + mTop + ", " + mRight
21610 + ", " + mBottom + "} scroll={" + mScrollX + ", " + mScrollY
21612 Log.d(VIEW_LOG_TAG, output);
21614 if (mPaddingLeft != 0 || mPaddingTop != 0 || mPaddingRight != 0
21615 || mPaddingBottom != 0) {
21616 output = debugIndent(depth);
21617 output += "padding={" + mPaddingLeft + ", " + mPaddingTop
21618 + ", " + mPaddingRight + ", " + mPaddingBottom + "}";
21619 Log.d(VIEW_LOG_TAG, output);
21622 output = debugIndent(depth);
21623 output += "mMeasureWidth=" + mMeasuredWidth +
21624 " mMeasureHeight=" + mMeasuredHeight;
21625 Log.d(VIEW_LOG_TAG, output);
21627 output = debugIndent(depth);
21628 if (mLayoutParams == null) {
21629 output += "BAD! no layout params";
21631 output = mLayoutParams.debug(output);
21633 Log.d(VIEW_LOG_TAG, output);
21635 output = debugIndent(depth);
21636 output += "flags={";
21637 output += View.printFlags(mViewFlags);
21639 Log.d(VIEW_LOG_TAG, output);
21641 output = debugIndent(depth);
21642 output += "privateFlags={";
21643 output += View.printPrivateFlags(mPrivateFlags);
21645 Log.d(VIEW_LOG_TAG, output);
21649 * Creates a string of whitespaces used for indentation.
21651 * @param depth the indentation level
21652 * @return a String containing (depth * 2 + 3) * 2 white spaces
21656 protected static String debugIndent(int depth) {
21657 StringBuilder spaces = new StringBuilder((depth * 2 + 3) * 2);
21658 for (int i = 0; i < (depth * 2) + 3; i++) {
21659 spaces.append(' ').append(' ');
21661 return spaces.toString();
21665 * <p>Return the offset of the widget's text baseline from the widget's top
21666 * boundary. If this widget does not support baseline alignment, this
21667 * method returns -1. </p>
21669 * @return the offset of the baseline within the widget's bounds or -1
21670 * if baseline alignment is not supported
21672 @ViewDebug.ExportedProperty(category = "layout")
21673 public int getBaseline() {
21678 * Returns whether the view hierarchy is currently undergoing a layout pass. This
21679 * information is useful to avoid situations such as calling {@link #requestLayout()} during
21682 * @return whether the view hierarchy is currently undergoing a layout pass
21684 public boolean isInLayout() {
21685 ViewRootImpl viewRoot = getViewRootImpl();
21686 return (viewRoot != null && viewRoot.isInLayout());
21690 * Call this when something has changed which has invalidated the
21691 * layout of this view. This will schedule a layout pass of the view
21692 * tree. This should not be called while the view hierarchy is currently in a layout
21693 * pass ({@link #isInLayout()}. If layout is happening, the request may be honored at the
21694 * end of the current layout pass (and then layout will run again) or after the current
21695 * frame is drawn and the next layout occurs.
21697 * <p>Subclasses which override this method should call the superclass method to
21698 * handle possible request-during-layout errors correctly.</p>
21701 public void requestLayout() {
21702 if (mMeasureCache != null) mMeasureCache.clear();
21704 if (mAttachInfo != null && mAttachInfo.mViewRequestingLayout == null) {
21705 // Only trigger request-during-layout logic if this is the view requesting it,
21706 // not the views in its parent hierarchy
21707 ViewRootImpl viewRoot = getViewRootImpl();
21708 if (viewRoot != null && viewRoot.isInLayout()) {
21709 if (!viewRoot.requestLayoutDuringLayout(this)) {
21713 mAttachInfo.mViewRequestingLayout = this;
21716 mPrivateFlags |= PFLAG_FORCE_LAYOUT;
21717 mPrivateFlags |= PFLAG_INVALIDATED;
21719 if (mParent != null && !mParent.isLayoutRequested()) {
21720 mParent.requestLayout();
21722 if (mAttachInfo != null && mAttachInfo.mViewRequestingLayout == this) {
21723 mAttachInfo.mViewRequestingLayout = null;
21728 * Forces this view to be laid out during the next layout pass.
21729 * This method does not call requestLayout() or forceLayout()
21732 public void forceLayout() {
21733 if (mMeasureCache != null) mMeasureCache.clear();
21735 mPrivateFlags |= PFLAG_FORCE_LAYOUT;
21736 mPrivateFlags |= PFLAG_INVALIDATED;
21741 * This is called to find out how big a view should be. The parent
21742 * supplies constraint information in the width and height parameters.
21746 * The actual measurement work of a view is performed in
21747 * {@link #onMeasure(int, int)}, called by this method. Therefore, only
21748 * {@link #onMeasure(int, int)} can and must be overridden by subclasses.
21752 * @param widthMeasureSpec Horizontal space requirements as imposed by the
21754 * @param heightMeasureSpec Vertical space requirements as imposed by the
21757 * @see #onMeasure(int, int)
21759 public final void measure(int widthMeasureSpec, int heightMeasureSpec) {
21760 boolean optical = isLayoutModeOptical(this);
21761 if (optical != isLayoutModeOptical(mParent)) {
21762 Insets insets = getOpticalInsets();
21763 int oWidth = insets.left + insets.right;
21764 int oHeight = insets.top + insets.bottom;
21765 widthMeasureSpec = MeasureSpec.adjust(widthMeasureSpec, optical ? -oWidth : oWidth);
21766 heightMeasureSpec = MeasureSpec.adjust(heightMeasureSpec, optical ? -oHeight : oHeight);
21769 // Suppress sign extension for the low bytes
21770 long key = (long) widthMeasureSpec << 32 | (long) heightMeasureSpec & 0xffffffffL;
21771 if (mMeasureCache == null) mMeasureCache = new LongSparseLongArray(2);
21773 final boolean forceLayout = (mPrivateFlags & PFLAG_FORCE_LAYOUT) == PFLAG_FORCE_LAYOUT;
21775 // Optimize layout by avoiding an extra EXACTLY pass when the view is
21776 // already measured as the correct size. In API 23 and below, this
21777 // extra pass is required to make LinearLayout re-distribute weight.
21778 final boolean specChanged = widthMeasureSpec != mOldWidthMeasureSpec
21779 || heightMeasureSpec != mOldHeightMeasureSpec;
21780 final boolean isSpecExactly = MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.EXACTLY
21781 && MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.EXACTLY;
21782 final boolean matchesSpecSize = getMeasuredWidth() == MeasureSpec.getSize(widthMeasureSpec)
21783 && getMeasuredHeight() == MeasureSpec.getSize(heightMeasureSpec);
21784 final boolean needsLayout = specChanged
21785 && (sAlwaysRemeasureExactly || !isSpecExactly || !matchesSpecSize);
21787 if (forceLayout || needsLayout) {
21788 // first clears the measured dimension flag
21789 mPrivateFlags &= ~PFLAG_MEASURED_DIMENSION_SET;
21791 resolveRtlPropertiesIfNeeded();
21793 int cacheIndex = forceLayout ? -1 : mMeasureCache.indexOfKey(key);
21794 if (cacheIndex < 0 || sIgnoreMeasureCache) {
21795 // measure ourselves, this should set the measured dimension flag back
21796 onMeasure(widthMeasureSpec, heightMeasureSpec);
21797 mPrivateFlags3 &= ~PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT;
21799 long value = mMeasureCache.valueAt(cacheIndex);
21800 // Casting a long to int drops the high 32 bits, no mask needed
21801 setMeasuredDimensionRaw((int) (value >> 32), (int) value);
21802 mPrivateFlags3 |= PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT;
21805 // flag not set, setMeasuredDimension() was not invoked, we raise
21806 // an exception to warn the developer
21807 if ((mPrivateFlags & PFLAG_MEASURED_DIMENSION_SET) != PFLAG_MEASURED_DIMENSION_SET) {
21808 throw new IllegalStateException("View with id " + getId() + ": "
21809 + getClass().getName() + "#onMeasure() did not set the"
21810 + " measured dimension by calling"
21811 + " setMeasuredDimension()");
21814 mPrivateFlags |= PFLAG_LAYOUT_REQUIRED;
21817 mOldWidthMeasureSpec = widthMeasureSpec;
21818 mOldHeightMeasureSpec = heightMeasureSpec;
21820 mMeasureCache.put(key, ((long) mMeasuredWidth) << 32 |
21821 (long) mMeasuredHeight & 0xffffffffL); // suppress sign extension
21826 * Measure the view and its content to determine the measured width and the
21827 * measured height. This method is invoked by {@link #measure(int, int)} and
21828 * should be overridden by subclasses to provide accurate and efficient
21829 * measurement of their contents.
21833 * <strong>CONTRACT:</strong> When overriding this method, you
21834 * <em>must</em> call {@link #setMeasuredDimension(int, int)} to store the
21835 * measured width and height of this view. Failure to do so will trigger an
21836 * <code>IllegalStateException</code>, thrown by
21837 * {@link #measure(int, int)}. Calling the superclass'
21838 * {@link #onMeasure(int, int)} is a valid use.
21842 * The base class implementation of measure defaults to the background size,
21843 * unless a larger size is allowed by the MeasureSpec. Subclasses should
21844 * override {@link #onMeasure(int, int)} to provide better measurements of
21849 * If this method is overridden, it is the subclass's responsibility to make
21850 * sure the measured height and width are at least the view's minimum height
21851 * and width ({@link #getSuggestedMinimumHeight()} and
21852 * {@link #getSuggestedMinimumWidth()}).
21855 * @param widthMeasureSpec horizontal space requirements as imposed by the parent.
21856 * The requirements are encoded with
21857 * {@link android.view.View.MeasureSpec}.
21858 * @param heightMeasureSpec vertical space requirements as imposed by the parent.
21859 * The requirements are encoded with
21860 * {@link android.view.View.MeasureSpec}.
21862 * @see #getMeasuredWidth()
21863 * @see #getMeasuredHeight()
21864 * @see #setMeasuredDimension(int, int)
21865 * @see #getSuggestedMinimumHeight()
21866 * @see #getSuggestedMinimumWidth()
21867 * @see android.view.View.MeasureSpec#getMode(int)
21868 * @see android.view.View.MeasureSpec#getSize(int)
21870 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
21871 setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec),
21872 getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec));
21876 * <p>This method must be called by {@link #onMeasure(int, int)} to store the
21877 * measured width and measured height. Failing to do so will trigger an
21878 * exception at measurement time.</p>
21880 * @param measuredWidth The measured width of this view. May be a complex
21881 * bit mask as defined by {@link #MEASURED_SIZE_MASK} and
21882 * {@link #MEASURED_STATE_TOO_SMALL}.
21883 * @param measuredHeight The measured height of this view. May be a complex
21884 * bit mask as defined by {@link #MEASURED_SIZE_MASK} and
21885 * {@link #MEASURED_STATE_TOO_SMALL}.
21887 protected final void setMeasuredDimension(int measuredWidth, int measuredHeight) {
21888 boolean optical = isLayoutModeOptical(this);
21889 if (optical != isLayoutModeOptical(mParent)) {
21890 Insets insets = getOpticalInsets();
21891 int opticalWidth = insets.left + insets.right;
21892 int opticalHeight = insets.top + insets.bottom;
21894 measuredWidth += optical ? opticalWidth : -opticalWidth;
21895 measuredHeight += optical ? opticalHeight : -opticalHeight;
21897 setMeasuredDimensionRaw(measuredWidth, measuredHeight);
21901 * Sets the measured dimension without extra processing for things like optical bounds.
21902 * Useful for reapplying consistent values that have already been cooked with adjustments
21903 * for optical bounds, etc. such as those from the measurement cache.
21905 * @param measuredWidth The measured width of this view. May be a complex
21906 * bit mask as defined by {@link #MEASURED_SIZE_MASK} and
21907 * {@link #MEASURED_STATE_TOO_SMALL}.
21908 * @param measuredHeight The measured height of this view. May be a complex
21909 * bit mask as defined by {@link #MEASURED_SIZE_MASK} and
21910 * {@link #MEASURED_STATE_TOO_SMALL}.
21912 private void setMeasuredDimensionRaw(int measuredWidth, int measuredHeight) {
21913 mMeasuredWidth = measuredWidth;
21914 mMeasuredHeight = measuredHeight;
21916 mPrivateFlags |= PFLAG_MEASURED_DIMENSION_SET;
21920 * Merge two states as returned by {@link #getMeasuredState()}.
21921 * @param curState The current state as returned from a view or the result
21922 * of combining multiple views.
21923 * @param newState The new view state to combine.
21924 * @return Returns a new integer reflecting the combination of the two
21927 public static int combineMeasuredStates(int curState, int newState) {
21928 return curState | newState;
21932 * Version of {@link #resolveSizeAndState(int, int, int)}
21933 * returning only the {@link #MEASURED_SIZE_MASK} bits of the result.
21935 public static int resolveSize(int size, int measureSpec) {
21936 return resolveSizeAndState(size, measureSpec, 0) & MEASURED_SIZE_MASK;
21940 * Utility to reconcile a desired size and state, with constraints imposed
21941 * by a MeasureSpec. Will take the desired size, unless a different size
21942 * is imposed by the constraints. The returned value is a compound integer,
21943 * with the resolved size in the {@link #MEASURED_SIZE_MASK} bits and
21944 * optionally the bit {@link #MEASURED_STATE_TOO_SMALL} set if the
21945 * resulting size is smaller than the size the view wants to be.
21947 * @param size How big the view wants to be.
21948 * @param measureSpec Constraints imposed by the parent.
21949 * @param childMeasuredState Size information bit mask for the view's
21951 * @return Size information bit mask as defined by
21952 * {@link #MEASURED_SIZE_MASK} and
21953 * {@link #MEASURED_STATE_TOO_SMALL}.
21955 public static int resolveSizeAndState(int size, int measureSpec, int childMeasuredState) {
21956 final int specMode = MeasureSpec.getMode(measureSpec);
21957 final int specSize = MeasureSpec.getSize(measureSpec);
21959 switch (specMode) {
21960 case MeasureSpec.AT_MOST:
21961 if (specSize < size) {
21962 result = specSize | MEASURED_STATE_TOO_SMALL;
21967 case MeasureSpec.EXACTLY:
21970 case MeasureSpec.UNSPECIFIED:
21974 return result | (childMeasuredState & MEASURED_STATE_MASK);
21978 * Utility to return a default size. Uses the supplied size if the
21979 * MeasureSpec imposed no constraints. Will get larger if allowed
21980 * by the MeasureSpec.
21982 * @param size Default size for this view
21983 * @param measureSpec Constraints imposed by the parent
21984 * @return The size this view should be.
21986 public static int getDefaultSize(int size, int measureSpec) {
21988 int specMode = MeasureSpec.getMode(measureSpec);
21989 int specSize = MeasureSpec.getSize(measureSpec);
21991 switch (specMode) {
21992 case MeasureSpec.UNSPECIFIED:
21995 case MeasureSpec.AT_MOST:
21996 case MeasureSpec.EXACTLY:
22004 * Returns the suggested minimum height that the view should use. This
22005 * returns the maximum of the view's minimum height
22006 * and the background's minimum height
22007 * ({@link android.graphics.drawable.Drawable#getMinimumHeight()}).
22009 * When being used in {@link #onMeasure(int, int)}, the caller should still
22010 * ensure the returned height is within the requirements of the parent.
22012 * @return The suggested minimum height of the view.
22014 protected int getSuggestedMinimumHeight() {
22015 return (mBackground == null) ? mMinHeight : max(mMinHeight, mBackground.getMinimumHeight());
22020 * Returns the suggested minimum width that the view should use. This
22021 * returns the maximum of the view's minimum width
22022 * and the background's minimum width
22023 * ({@link android.graphics.drawable.Drawable#getMinimumWidth()}).
22025 * When being used in {@link #onMeasure(int, int)}, the caller should still
22026 * ensure the returned width is within the requirements of the parent.
22028 * @return The suggested minimum width of the view.
22030 protected int getSuggestedMinimumWidth() {
22031 return (mBackground == null) ? mMinWidth : max(mMinWidth, mBackground.getMinimumWidth());
22035 * Returns the minimum height of the view.
22037 * @return the minimum height the view will try to be, in pixels
22039 * @see #setMinimumHeight(int)
22041 * @attr ref android.R.styleable#View_minHeight
22043 public int getMinimumHeight() {
22048 * Sets the minimum height of the view. It is not guaranteed the view will
22049 * be able to achieve this minimum height (for example, if its parent layout
22050 * constrains it with less available height).
22052 * @param minHeight The minimum height the view will try to be, in pixels
22054 * @see #getMinimumHeight()
22056 * @attr ref android.R.styleable#View_minHeight
22058 @RemotableViewMethod
22059 public void setMinimumHeight(int minHeight) {
22060 mMinHeight = minHeight;
22065 * Returns the minimum width of the view.
22067 * @return the minimum width the view will try to be, in pixels
22069 * @see #setMinimumWidth(int)
22071 * @attr ref android.R.styleable#View_minWidth
22073 public int getMinimumWidth() {
22078 * Sets the minimum width of the view. It is not guaranteed the view will
22079 * be able to achieve this minimum width (for example, if its parent layout
22080 * constrains it with less available width).
22082 * @param minWidth The minimum width the view will try to be, in pixels
22084 * @see #getMinimumWidth()
22086 * @attr ref android.R.styleable#View_minWidth
22088 public void setMinimumWidth(int minWidth) {
22089 mMinWidth = minWidth;
22095 * Get the animation currently associated with this view.
22097 * @return The animation that is currently playing or
22098 * scheduled to play for this view.
22100 public Animation getAnimation() {
22101 return mCurrentAnimation;
22105 * Start the specified animation now.
22107 * @param animation the animation to start now
22109 public void startAnimation(Animation animation) {
22110 animation.setStartTime(Animation.START_ON_FIRST_FRAME);
22111 setAnimation(animation);
22112 invalidateParentCaches();
22117 * Cancels any animations for this view.
22119 public void clearAnimation() {
22120 if (mCurrentAnimation != null) {
22121 mCurrentAnimation.detach();
22123 mCurrentAnimation = null;
22124 invalidateParentIfNeeded();
22128 * Sets the next animation to play for this view.
22129 * If you want the animation to play immediately, use
22130 * {@link #startAnimation(android.view.animation.Animation)} instead.
22131 * This method provides allows fine-grained
22132 * control over the start time and invalidation, but you
22133 * must make sure that 1) the animation has a start time set, and
22134 * 2) the view's parent (which controls animations on its children)
22135 * will be invalidated when the animation is supposed to
22138 * @param animation The next animation, or null.
22140 public void setAnimation(Animation animation) {
22141 mCurrentAnimation = animation;
22143 if (animation != null) {
22144 // If the screen is off assume the animation start time is now instead of
22145 // the next frame we draw. Keeping the START_ON_FIRST_FRAME start time
22146 // would cause the animation to start when the screen turns back on
22147 if (mAttachInfo != null && mAttachInfo.mDisplayState == Display.STATE_OFF
22148 && animation.getStartTime() == Animation.START_ON_FIRST_FRAME) {
22149 animation.setStartTime(AnimationUtils.currentAnimationTimeMillis());
22156 * Invoked by a parent ViewGroup to notify the start of the animation
22157 * currently associated with this view. If you override this method,
22158 * always call super.onAnimationStart();
22160 * @see #setAnimation(android.view.animation.Animation)
22161 * @see #getAnimation()
22164 protected void onAnimationStart() {
22165 mPrivateFlags |= PFLAG_ANIMATION_STARTED;
22169 * Invoked by a parent ViewGroup to notify the end of the animation
22170 * currently associated with this view. If you override this method,
22171 * always call super.onAnimationEnd();
22173 * @see #setAnimation(android.view.animation.Animation)
22174 * @see #getAnimation()
22177 protected void onAnimationEnd() {
22178 mPrivateFlags &= ~PFLAG_ANIMATION_STARTED;
22182 * Invoked if there is a Transform that involves alpha. Subclass that can
22183 * draw themselves with the specified alpha should return true, and then
22184 * respect that alpha when their onDraw() is called. If this returns false
22185 * then the view may be redirected to draw into an offscreen buffer to
22186 * fulfill the request, which will look fine, but may be slower than if the
22187 * subclass handles it internally. The default implementation returns false.
22189 * @param alpha The alpha (0..255) to apply to the view's drawing
22190 * @return true if the view can draw with the specified alpha.
22192 protected boolean onSetAlpha(int alpha) {
22197 * This is used by the RootView to perform an optimization when
22198 * the view hierarchy contains one or several SurfaceView.
22199 * SurfaceView is always considered transparent, but its children are not,
22200 * therefore all View objects remove themselves from the global transparent
22201 * region (passed as a parameter to this function).
22203 * @param region The transparent region for this ViewAncestor (window).
22205 * @return Returns true if the effective visibility of the view at this
22206 * point is opaque, regardless of the transparent region; returns false
22207 * if it is possible for underlying windows to be seen behind the view.
22211 public boolean gatherTransparentRegion(Region region) {
22212 final AttachInfo attachInfo = mAttachInfo;
22213 if (region != null && attachInfo != null) {
22214 final int pflags = mPrivateFlags;
22215 if ((pflags & PFLAG_SKIP_DRAW) == 0) {
22216 // The SKIP_DRAW flag IS NOT set, so this view draws. We need to
22217 // remove it from the transparent region.
22218 final int[] location = attachInfo.mTransparentLocation;
22219 getLocationInWindow(location);
22220 // When a view has Z value, then it will be better to leave some area below the view
22221 // for drawing shadow. The shadow outset is proportional to the Z value. Note that
22222 // the bottom part needs more offset than the left, top and right parts due to the
22223 // spot light effects.
22224 int shadowOffset = getZ() > 0 ? (int) getZ() : 0;
22225 region.op(location[0] - shadowOffset, location[1] - shadowOffset,
22226 location[0] + mRight - mLeft + shadowOffset,
22227 location[1] + mBottom - mTop + (shadowOffset * 3), Region.Op.DIFFERENCE);
22229 if (mBackground != null && mBackground.getOpacity() != PixelFormat.TRANSPARENT) {
22230 // The SKIP_DRAW flag IS set and the background drawable exists, we remove
22231 // the background drawable's non-transparent parts from this transparent region.
22232 applyDrawableToTransparentRegion(mBackground, region);
22234 if (mForegroundInfo != null && mForegroundInfo.mDrawable != null
22235 && mForegroundInfo.mDrawable.getOpacity() != PixelFormat.TRANSPARENT) {
22236 // Similarly, we remove the foreground drawable's non-transparent parts.
22237 applyDrawableToTransparentRegion(mForegroundInfo.mDrawable, region);
22239 if (mDefaultFocusHighlight != null
22240 && mDefaultFocusHighlight.getOpacity() != PixelFormat.TRANSPARENT) {
22241 // Similarly, we remove the default focus highlight's non-transparent parts.
22242 applyDrawableToTransparentRegion(mDefaultFocusHighlight, region);
22250 * Play a sound effect for this view.
22252 * <p>The framework will play sound effects for some built in actions, such as
22253 * clicking, but you may wish to play these effects in your widget,
22254 * for instance, for internal navigation.
22256 * <p>The sound effect will only be played if sound effects are enabled by the user, and
22257 * {@link #isSoundEffectsEnabled()} is true.
22259 * @param soundConstant One of the constants defined in {@link SoundEffectConstants}
22261 public void playSoundEffect(int soundConstant) {
22262 if (mAttachInfo == null || mAttachInfo.mRootCallbacks == null || !isSoundEffectsEnabled()) {
22265 mAttachInfo.mRootCallbacks.playSoundEffect(soundConstant);
22271 * <p>Provide haptic feedback to the user for this view.
22273 * <p>The framework will provide haptic feedback for some built in actions,
22274 * such as long presses, but you may wish to provide feedback for your
22277 * <p>The feedback will only be performed if
22278 * {@link #isHapticFeedbackEnabled()} is true.
22280 * @param feedbackConstant One of the constants defined in
22281 * {@link HapticFeedbackConstants}
22283 public boolean performHapticFeedback(int feedbackConstant) {
22284 return performHapticFeedback(feedbackConstant, 0);
22290 * <p>Like {@link #performHapticFeedback(int)}, with additional options.
22292 * @param feedbackConstant One of the constants defined in
22293 * {@link HapticFeedbackConstants}
22294 * @param flags Additional flags as per {@link HapticFeedbackConstants}.
22296 public boolean performHapticFeedback(int feedbackConstant, int flags) {
22297 if (mAttachInfo == null) {
22300 //noinspection SimplifiableIfStatement
22301 if ((flags & HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING) == 0
22302 && !isHapticFeedbackEnabled()) {
22305 return mAttachInfo.mRootCallbacks.performHapticFeedback(feedbackConstant,
22306 (flags & HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING) != 0);
22310 * Request that the visibility of the status bar or other screen/window
22311 * decorations be changed.
22313 * <p>This method is used to put the over device UI into temporary modes
22314 * where the user's attention is focused more on the application content,
22315 * by dimming or hiding surrounding system affordances. This is typically
22316 * used in conjunction with {@link Window#FEATURE_ACTION_BAR_OVERLAY
22317 * Window.FEATURE_ACTION_BAR_OVERLAY}, allowing the applications content
22318 * to be placed behind the action bar (and with these flags other system
22319 * affordances) so that smooth transitions between hiding and showing them
22322 * <p>Two representative examples of the use of system UI visibility is
22323 * implementing a content browsing application (like a magazine reader)
22324 * and a video playing application.
22326 * <p>The first code shows a typical implementation of a View in a content
22327 * browsing application. In this implementation, the application goes
22328 * into a content-oriented mode by hiding the status bar and action bar,
22329 * and putting the navigation elements into lights out mode. The user can
22330 * then interact with content while in this mode. Such an application should
22331 * provide an easy way for the user to toggle out of the mode (such as to
22332 * check information in the status bar or access notifications). In the
22333 * implementation here, this is done simply by tapping on the content.
22335 * {@sample development/samples/ApiDemos/src/com/example/android/apis/view/ContentBrowserActivity.java
22338 * <p>This second code sample shows a typical implementation of a View
22339 * in a video playing application. In this situation, while the video is
22340 * playing the application would like to go into a complete full-screen mode,
22341 * to use as much of the display as possible for the video. When in this state
22342 * the user can not interact with the application; the system intercepts
22343 * touching on the screen to pop the UI out of full screen mode. See
22344 * {@link #fitSystemWindows(Rect)} for a sample layout that goes with this code.
22346 * {@sample development/samples/ApiDemos/src/com/example/android/apis/view/VideoPlayerActivity.java
22349 * @param visibility Bitwise-or of flags {@link #SYSTEM_UI_FLAG_LOW_PROFILE},
22350 * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, {@link #SYSTEM_UI_FLAG_FULLSCREEN},
22351 * {@link #SYSTEM_UI_FLAG_LAYOUT_STABLE}, {@link #SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION},
22352 * {@link #SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN}, {@link #SYSTEM_UI_FLAG_IMMERSIVE},
22353 * and {@link #SYSTEM_UI_FLAG_IMMERSIVE_STICKY}.
22355 public void setSystemUiVisibility(int visibility) {
22356 if (visibility != mSystemUiVisibility) {
22357 mSystemUiVisibility = visibility;
22358 if (mParent != null && mAttachInfo != null && !mAttachInfo.mRecomputeGlobalAttributes) {
22359 mParent.recomputeViewAttributes(this);
22365 * Returns the last {@link #setSystemUiVisibility(int)} that this view has requested.
22366 * @return Bitwise-or of flags {@link #SYSTEM_UI_FLAG_LOW_PROFILE},
22367 * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, {@link #SYSTEM_UI_FLAG_FULLSCREEN},
22368 * {@link #SYSTEM_UI_FLAG_LAYOUT_STABLE}, {@link #SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION},
22369 * {@link #SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN}, {@link #SYSTEM_UI_FLAG_IMMERSIVE},
22370 * and {@link #SYSTEM_UI_FLAG_IMMERSIVE_STICKY}.
22372 public int getSystemUiVisibility() {
22373 return mSystemUiVisibility;
22377 * Returns the current system UI visibility that is currently set for
22378 * the entire window. This is the combination of the
22379 * {@link #setSystemUiVisibility(int)} values supplied by all of the
22380 * views in the window.
22382 public int getWindowSystemUiVisibility() {
22383 return mAttachInfo != null ? mAttachInfo.mSystemUiVisibility : 0;
22387 * Override to find out when the window's requested system UI visibility
22388 * has changed, that is the value returned by {@link #getWindowSystemUiVisibility()}.
22389 * This is different from the callbacks received through
22390 * {@link #setOnSystemUiVisibilityChangeListener(OnSystemUiVisibilityChangeListener)}
22391 * in that this is only telling you about the local request of the window,
22392 * not the actual values applied by the system.
22394 public void onWindowSystemUiVisibilityChanged(int visible) {
22398 * Dispatch callbacks to {@link #onWindowSystemUiVisibilityChanged(int)} down
22399 * the view hierarchy.
22401 public void dispatchWindowSystemUiVisiblityChanged(int visible) {
22402 onWindowSystemUiVisibilityChanged(visible);
22406 * Set a listener to receive callbacks when the visibility of the system bar changes.
22407 * @param l The {@link OnSystemUiVisibilityChangeListener} to receive callbacks.
22409 public void setOnSystemUiVisibilityChangeListener(OnSystemUiVisibilityChangeListener l) {
22410 getListenerInfo().mOnSystemUiVisibilityChangeListener = l;
22411 if (mParent != null && mAttachInfo != null && !mAttachInfo.mRecomputeGlobalAttributes) {
22412 mParent.recomputeViewAttributes(this);
22417 * Dispatch callbacks to {@link #setOnSystemUiVisibilityChangeListener} down
22418 * the view hierarchy.
22420 public void dispatchSystemUiVisibilityChanged(int visibility) {
22421 ListenerInfo li = mListenerInfo;
22422 if (li != null && li.mOnSystemUiVisibilityChangeListener != null) {
22423 li.mOnSystemUiVisibilityChangeListener.onSystemUiVisibilityChange(
22424 visibility & PUBLIC_STATUS_BAR_VISIBILITY_MASK);
22428 boolean updateLocalSystemUiVisibility(int localValue, int localChanges) {
22429 int val = (mSystemUiVisibility&~localChanges) | (localValue&localChanges);
22430 if (val != mSystemUiVisibility) {
22431 setSystemUiVisibility(val);
22438 public void setDisabledSystemUiVisibility(int flags) {
22439 if (mAttachInfo != null) {
22440 if (mAttachInfo.mDisabledSystemUiVisibility != flags) {
22441 mAttachInfo.mDisabledSystemUiVisibility = flags;
22442 if (mParent != null) {
22443 mParent.recomputeViewAttributes(this);
22450 * Creates an image that the system displays during the drag and drop
22451 * operation. This is called a "drag shadow". The default implementation
22452 * for a DragShadowBuilder based on a View returns an image that has exactly the same
22453 * appearance as the given View. The default also positions the center of the drag shadow
22454 * directly under the touch point. If no View is provided (the constructor with no parameters
22455 * is used), and {@link #onProvideShadowMetrics(Point,Point) onProvideShadowMetrics()} and
22456 * {@link #onDrawShadow(Canvas) onDrawShadow()} are not overridden, then the
22457 * default is an invisible drag shadow.
22459 * You are not required to use the View you provide to the constructor as the basis of the
22460 * drag shadow. The {@link #onDrawShadow(Canvas) onDrawShadow()} method allows you to draw
22461 * anything you want as the drag shadow.
22464 * You pass a DragShadowBuilder object to the system when you start the drag. The system
22465 * calls {@link #onProvideShadowMetrics(Point,Point) onProvideShadowMetrics()} to get the
22466 * size and position of the drag shadow. It uses this data to construct a
22467 * {@link android.graphics.Canvas} object, then it calls {@link #onDrawShadow(Canvas) onDrawShadow()}
22468 * so that your application can draw the shadow image in the Canvas.
22471 * <div class="special reference">
22472 * <h3>Developer Guides</h3>
22473 * <p>For a guide to implementing drag and drop features, read the
22474 * <a href="{@docRoot}guide/topics/ui/drag-drop.html">Drag and Drop</a> developer guide.</p>
22477 public static class DragShadowBuilder {
22478 private final WeakReference<View> mView;
22481 * Constructs a shadow image builder based on a View. By default, the resulting drag
22482 * shadow will have the same appearance and dimensions as the View, with the touch point
22483 * over the center of the View.
22484 * @param view A View. Any View in scope can be used.
22486 public DragShadowBuilder(View view) {
22487 mView = new WeakReference<View>(view);
22491 * Construct a shadow builder object with no associated View. This
22492 * constructor variant is only useful when the {@link #onProvideShadowMetrics(Point, Point)}
22493 * and {@link #onDrawShadow(Canvas)} methods are also overridden in order
22494 * to supply the drag shadow's dimensions and appearance without
22495 * reference to any View object. If they are not overridden, then the result is an
22496 * invisible drag shadow.
22498 public DragShadowBuilder() {
22499 mView = new WeakReference<View>(null);
22503 * Returns the View object that had been passed to the
22504 * {@link #View.DragShadowBuilder(View)}
22505 * constructor. If that View parameter was {@code null} or if the
22506 * {@link #View.DragShadowBuilder()}
22507 * constructor was used to instantiate the builder object, this method will return
22510 * @return The View object associate with this builder object.
22512 @SuppressWarnings({"JavadocReference"})
22513 final public View getView() {
22514 return mView.get();
22518 * Provides the metrics for the shadow image. These include the dimensions of
22519 * the shadow image, and the point within that shadow that should
22520 * be centered under the touch location while dragging.
22522 * The default implementation sets the dimensions of the shadow to be the
22523 * same as the dimensions of the View itself and centers the shadow under
22527 * @param outShadowSize A {@link android.graphics.Point} containing the width and height
22528 * of the shadow image. Your application must set {@link android.graphics.Point#x} to the
22529 * desired width and must set {@link android.graphics.Point#y} to the desired height of the
22532 * @param outShadowTouchPoint A {@link android.graphics.Point} for the position within the
22533 * shadow image that should be underneath the touch point during the drag and drop
22534 * operation. Your application must set {@link android.graphics.Point#x} to the
22535 * X coordinate and {@link android.graphics.Point#y} to the Y coordinate of this position.
22537 public void onProvideShadowMetrics(Point outShadowSize, Point outShadowTouchPoint) {
22538 final View view = mView.get();
22539 if (view != null) {
22540 outShadowSize.set(view.getWidth(), view.getHeight());
22541 outShadowTouchPoint.set(outShadowSize.x / 2, outShadowSize.y / 2);
22543 Log.e(View.VIEW_LOG_TAG, "Asked for drag thumb metrics but no view");
22548 * Draws the shadow image. The system creates the {@link android.graphics.Canvas} object
22549 * based on the dimensions it received from the
22550 * {@link #onProvideShadowMetrics(Point, Point)} callback.
22552 * @param canvas A {@link android.graphics.Canvas} object in which to draw the shadow image.
22554 public void onDrawShadow(Canvas canvas) {
22555 final View view = mView.get();
22556 if (view != null) {
22559 Log.e(View.VIEW_LOG_TAG, "Asked to draw drag shadow but no view");
22565 * @deprecated Use {@link #startDragAndDrop(ClipData, DragShadowBuilder, Object, int)
22566 * startDragAndDrop()} for newer platform versions.
22569 public final boolean startDrag(ClipData data, DragShadowBuilder shadowBuilder,
22570 Object myLocalState, int flags) {
22571 return startDragAndDrop(data, shadowBuilder, myLocalState, flags);
22575 * Starts a drag and drop operation. When your application calls this method, it passes a
22576 * {@link android.view.View.DragShadowBuilder} object to the system. The
22577 * system calls this object's {@link DragShadowBuilder#onProvideShadowMetrics(Point, Point)}
22578 * to get metrics for the drag shadow, and then calls the object's
22579 * {@link DragShadowBuilder#onDrawShadow(Canvas)} to draw the drag shadow itself.
22581 * Once the system has the drag shadow, it begins the drag and drop operation by sending
22582 * drag events to all the View objects in your application that are currently visible. It does
22583 * this either by calling the View object's drag listener (an implementation of
22584 * {@link android.view.View.OnDragListener#onDrag(View,DragEvent) onDrag()} or by calling the
22585 * View object's {@link android.view.View#onDragEvent(DragEvent) onDragEvent()} method.
22586 * Both are passed a {@link android.view.DragEvent} object that has a
22587 * {@link android.view.DragEvent#getAction()} value of
22588 * {@link android.view.DragEvent#ACTION_DRAG_STARTED}.
22591 * Your application can invoke {@link #startDragAndDrop(ClipData, DragShadowBuilder, Object,
22592 * int) startDragAndDrop()} on any attached View object. The View object does not need to be
22593 * the one used in {@link android.view.View.DragShadowBuilder}, nor does it need to be related
22594 * to the View the user selected for dragging.
22596 * @param data A {@link android.content.ClipData} object pointing to the data to be
22597 * transferred by the drag and drop operation.
22598 * @param shadowBuilder A {@link android.view.View.DragShadowBuilder} object for building the
22600 * @param myLocalState An {@link java.lang.Object} containing local data about the drag and
22601 * drop operation. When dispatching drag events to views in the same activity this object
22602 * will be available through {@link android.view.DragEvent#getLocalState()}. Views in other
22603 * activities will not have access to this data ({@link android.view.DragEvent#getLocalState()}
22604 * will return null).
22606 * myLocalState is a lightweight mechanism for the sending information from the dragged View
22607 * to the target Views. For example, it can contain flags that differentiate between a
22608 * a copy operation and a move operation.
22610 * @param flags Flags that control the drag and drop operation. This can be set to 0 for no
22611 * flags, or any combination of the following:
22613 * <li>{@link #DRAG_FLAG_GLOBAL}</li>
22614 * <li>{@link #DRAG_FLAG_GLOBAL_PERSISTABLE_URI_PERMISSION}</li>
22615 * <li>{@link #DRAG_FLAG_GLOBAL_PREFIX_URI_PERMISSION}</li>
22616 * <li>{@link #DRAG_FLAG_GLOBAL_URI_READ}</li>
22617 * <li>{@link #DRAG_FLAG_GLOBAL_URI_WRITE}</li>
22618 * <li>{@link #DRAG_FLAG_OPAQUE}</li>
22620 * @return {@code true} if the method completes successfully, or
22621 * {@code false} if it fails anywhere. Returning {@code false} means the system was unable to
22622 * do a drag, and so no drag operation is in progress.
22624 public final boolean startDragAndDrop(ClipData data, DragShadowBuilder shadowBuilder,
22625 Object myLocalState, int flags) {
22626 if (ViewDebug.DEBUG_DRAG) {
22627 Log.d(VIEW_LOG_TAG, "startDragAndDrop: data=" + data + " flags=" + flags);
22629 if (mAttachInfo == null) {
22630 Log.w(VIEW_LOG_TAG, "startDragAndDrop called on a detached view.");
22634 if (data != null) {
22635 data.prepareToLeaveProcess((flags & View.DRAG_FLAG_GLOBAL) != 0);
22638 boolean okay = false;
22640 Point shadowSize = new Point();
22641 Point shadowTouchPoint = new Point();
22642 shadowBuilder.onProvideShadowMetrics(shadowSize, shadowTouchPoint);
22644 if ((shadowSize.x < 0) || (shadowSize.y < 0) ||
22645 (shadowTouchPoint.x < 0) || (shadowTouchPoint.y < 0)) {
22646 throw new IllegalStateException("Drag shadow dimensions must not be negative");
22649 if (ViewDebug.DEBUG_DRAG) {
22650 Log.d(VIEW_LOG_TAG, "drag shadow: width=" + shadowSize.x + " height=" + shadowSize.y
22651 + " shadowX=" + shadowTouchPoint.x + " shadowY=" + shadowTouchPoint.y);
22653 if (mAttachInfo.mDragSurface != null) {
22654 mAttachInfo.mDragSurface.release();
22656 mAttachInfo.mDragSurface = new Surface();
22658 mAttachInfo.mDragToken = mAttachInfo.mSession.prepareDrag(mAttachInfo.mWindow,
22659 flags, shadowSize.x, shadowSize.y, mAttachInfo.mDragSurface);
22660 if (ViewDebug.DEBUG_DRAG) Log.d(VIEW_LOG_TAG, "prepareDrag returned token="
22661 + mAttachInfo.mDragToken + " surface=" + mAttachInfo.mDragSurface);
22662 if (mAttachInfo.mDragToken != null) {
22663 Canvas canvas = mAttachInfo.mDragSurface.lockCanvas(null);
22665 canvas.drawColor(0, PorterDuff.Mode.CLEAR);
22666 shadowBuilder.onDrawShadow(canvas);
22668 mAttachInfo.mDragSurface.unlockCanvasAndPost(canvas);
22671 final ViewRootImpl root = getViewRootImpl();
22673 // Cache the local state object for delivery with DragEvents
22674 root.setLocalDragState(myLocalState);
22676 // repurpose 'shadowSize' for the last touch point
22677 root.getLastTouchPoint(shadowSize);
22679 okay = mAttachInfo.mSession.performDrag(mAttachInfo.mWindow, mAttachInfo.mDragToken,
22680 root.getLastTouchSource(), shadowSize.x, shadowSize.y,
22681 shadowTouchPoint.x, shadowTouchPoint.y, data);
22682 if (ViewDebug.DEBUG_DRAG) Log.d(VIEW_LOG_TAG, "performDrag returned " + okay);
22684 } catch (Exception e) {
22685 Log.e(VIEW_LOG_TAG, "Unable to initiate drag", e);
22686 mAttachInfo.mDragSurface.destroy();
22687 mAttachInfo.mDragSurface = null;
22694 * Cancels an ongoing drag and drop operation.
22696 * A {@link android.view.DragEvent} object with
22697 * {@link android.view.DragEvent#getAction()} value of
22698 * {@link android.view.DragEvent#ACTION_DRAG_ENDED} and
22699 * {@link android.view.DragEvent#getResult()} value of {@code false}
22700 * will be sent to every
22701 * View that received {@link android.view.DragEvent#ACTION_DRAG_STARTED}
22702 * even if they are not currently visible.
22705 * This method can be called on any View in the same window as the View on which
22706 * {@link #startDragAndDrop(ClipData, DragShadowBuilder, Object, int) startDragAndDrop}
22710 public final void cancelDragAndDrop() {
22711 if (ViewDebug.DEBUG_DRAG) {
22712 Log.d(VIEW_LOG_TAG, "cancelDragAndDrop");
22714 if (mAttachInfo == null) {
22715 Log.w(VIEW_LOG_TAG, "cancelDragAndDrop called on a detached view.");
22718 if (mAttachInfo.mDragToken != null) {
22720 mAttachInfo.mSession.cancelDragAndDrop(mAttachInfo.mDragToken);
22721 } catch (Exception e) {
22722 Log.e(VIEW_LOG_TAG, "Unable to cancel drag", e);
22724 mAttachInfo.mDragToken = null;
22726 Log.e(VIEW_LOG_TAG, "No active drag to cancel");
22731 * Updates the drag shadow for the ongoing drag and drop operation.
22733 * @param shadowBuilder A {@link android.view.View.DragShadowBuilder} object for building the
22736 public final void updateDragShadow(DragShadowBuilder shadowBuilder) {
22737 if (ViewDebug.DEBUG_DRAG) {
22738 Log.d(VIEW_LOG_TAG, "updateDragShadow");
22740 if (mAttachInfo == null) {
22741 Log.w(VIEW_LOG_TAG, "updateDragShadow called on a detached view.");
22744 if (mAttachInfo.mDragToken != null) {
22746 Canvas canvas = mAttachInfo.mDragSurface.lockCanvas(null);
22748 canvas.drawColor(0, PorterDuff.Mode.CLEAR);
22749 shadowBuilder.onDrawShadow(canvas);
22751 mAttachInfo.mDragSurface.unlockCanvasAndPost(canvas);
22753 } catch (Exception e) {
22754 Log.e(VIEW_LOG_TAG, "Unable to update drag shadow", e);
22757 Log.e(VIEW_LOG_TAG, "No active drag");
22762 * Starts a move from {startX, startY}, the amount of the movement will be the offset
22763 * between {startX, startY} and the new cursor positon.
22764 * @param startX horizontal coordinate where the move started.
22765 * @param startY vertical coordinate where the move started.
22766 * @return whether moving was started successfully.
22769 public final boolean startMovingTask(float startX, float startY) {
22770 if (ViewDebug.DEBUG_POSITIONING) {
22771 Log.d(VIEW_LOG_TAG, "startMovingTask: {" + startX + "," + startY + "}");
22774 return mAttachInfo.mSession.startMovingTask(mAttachInfo.mWindow, startX, startY);
22775 } catch (RemoteException e) {
22776 Log.e(VIEW_LOG_TAG, "Unable to start moving", e);
22782 * Handles drag events sent by the system following a call to
22783 * {@link android.view.View#startDragAndDrop(ClipData,DragShadowBuilder,Object,int)
22784 * startDragAndDrop()}.
22786 * When the system calls this method, it passes a
22787 * {@link android.view.DragEvent} object. A call to
22788 * {@link android.view.DragEvent#getAction()} returns one of the action type constants defined
22789 * in DragEvent. The method uses these to determine what is happening in the drag and drop
22791 * @param event The {@link android.view.DragEvent} sent by the system.
22792 * The {@link android.view.DragEvent#getAction()} method returns an action type constant defined
22793 * in DragEvent, indicating the type of drag event represented by this object.
22794 * @return {@code true} if the method was successful, otherwise {@code false}.
22796 * The method should return {@code true} in response to an action type of
22797 * {@link android.view.DragEvent#ACTION_DRAG_STARTED} to receive drag events for the current
22801 * The method should also return {@code true} in response to an action type of
22802 * {@link android.view.DragEvent#ACTION_DROP} if it consumed the drop, or
22803 * {@code false} if it didn't.
22806 * For all other events, the return value is ignored.
22809 public boolean onDragEvent(DragEvent event) {
22813 // Dispatches ACTION_DRAG_ENTERED and ACTION_DRAG_EXITED events for pre-Nougat apps.
22814 boolean dispatchDragEnterExitInPreN(DragEvent event) {
22815 return callDragEventHandler(event);
22819 * Detects if this View is enabled and has a drag event listener.
22820 * If both are true, then it calls the drag event listener with the
22821 * {@link android.view.DragEvent} it received. If the drag event listener returns
22822 * {@code true}, then dispatchDragEvent() returns {@code true}.
22824 * For all other cases, the method calls the
22825 * {@link android.view.View#onDragEvent(DragEvent) onDragEvent()} drag event handler
22826 * method and returns its result.
22829 * This ensures that a drag event is always consumed, even if the View does not have a drag
22830 * event listener. However, if the View has a listener and the listener returns true, then
22831 * onDragEvent() is not called.
22834 public boolean dispatchDragEvent(DragEvent event) {
22835 event.mEventHandlerWasCalled = true;
22836 if (event.mAction == DragEvent.ACTION_DRAG_LOCATION ||
22837 event.mAction == DragEvent.ACTION_DROP) {
22838 // About to deliver an event with coordinates to this view. Notify that now this view
22839 // has drag focus. This will send exit/enter events as needed.
22840 getViewRootImpl().setDragFocus(this, event);
22842 return callDragEventHandler(event);
22845 final boolean callDragEventHandler(DragEvent event) {
22846 final boolean result;
22848 ListenerInfo li = mListenerInfo;
22849 //noinspection SimplifiableIfStatement
22850 if (li != null && li.mOnDragListener != null && (mViewFlags & ENABLED_MASK) == ENABLED
22851 && li.mOnDragListener.onDrag(this, event)) {
22854 result = onDragEvent(event);
22857 switch (event.mAction) {
22858 case DragEvent.ACTION_DRAG_ENTERED: {
22859 mPrivateFlags2 |= View.PFLAG2_DRAG_HOVERED;
22860 refreshDrawableState();
22862 case DragEvent.ACTION_DRAG_EXITED: {
22863 mPrivateFlags2 &= ~View.PFLAG2_DRAG_HOVERED;
22864 refreshDrawableState();
22866 case DragEvent.ACTION_DRAG_ENDED: {
22867 mPrivateFlags2 &= ~View.DRAG_MASK;
22868 refreshDrawableState();
22875 boolean canAcceptDrag() {
22876 return (mPrivateFlags2 & PFLAG2_DRAG_CAN_ACCEPT) != 0;
22880 * This needs to be a better API (NOT ON VIEW) before it is exposed. If
22881 * it is ever exposed at all.
22884 public void onCloseSystemDialogs(String reason) {
22888 * Given a Drawable whose bounds have been set to draw into this view,
22889 * update a Region being computed for
22890 * {@link #gatherTransparentRegion(android.graphics.Region)} so
22891 * that any non-transparent parts of the Drawable are removed from the
22892 * given transparent region.
22894 * @param dr The Drawable whose transparency is to be applied to the region.
22895 * @param region A Region holding the current transparency information,
22896 * where any parts of the region that are set are considered to be
22897 * transparent. On return, this region will be modified to have the
22898 * transparency information reduced by the corresponding parts of the
22899 * Drawable that are not transparent.
22902 public void applyDrawableToTransparentRegion(Drawable dr, Region region) {
22904 Log.i("View", "Getting transparent region for: " + this);
22906 final Region r = dr.getTransparentRegion();
22907 final Rect db = dr.getBounds();
22908 final AttachInfo attachInfo = mAttachInfo;
22909 if (r != null && attachInfo != null) {
22910 final int w = getRight()-getLeft();
22911 final int h = getBottom()-getTop();
22913 //Log.i("VIEW", "Drawable left " + db.left + " > view 0");
22914 r.op(0, 0, db.left, h, Region.Op.UNION);
22916 if (db.right < w) {
22917 //Log.i("VIEW", "Drawable right " + db.right + " < view " + w);
22918 r.op(db.right, 0, w, h, Region.Op.UNION);
22921 //Log.i("VIEW", "Drawable top " + db.top + " > view 0");
22922 r.op(0, 0, w, db.top, Region.Op.UNION);
22924 if (db.bottom < h) {
22925 //Log.i("VIEW", "Drawable bottom " + db.bottom + " < view " + h);
22926 r.op(0, db.bottom, w, h, Region.Op.UNION);
22928 final int[] location = attachInfo.mTransparentLocation;
22929 getLocationInWindow(location);
22930 r.translate(location[0], location[1]);
22931 region.op(r, Region.Op.INTERSECT);
22933 region.op(db, Region.Op.DIFFERENCE);
22937 private void checkForLongClick(int delayOffset, float x, float y) {
22938 if ((mViewFlags & LONG_CLICKABLE) == LONG_CLICKABLE || (mViewFlags & TOOLTIP) == TOOLTIP) {
22939 mHasPerformedLongPress = false;
22941 if (mPendingCheckForLongPress == null) {
22942 mPendingCheckForLongPress = new CheckForLongPress();
22944 mPendingCheckForLongPress.setAnchor(x, y);
22945 mPendingCheckForLongPress.rememberWindowAttachCount();
22946 mPendingCheckForLongPress.rememberPressedState();
22947 postDelayed(mPendingCheckForLongPress,
22948 ViewConfiguration.getLongPressTimeout() - delayOffset);
22953 * Inflate a view from an XML resource. This convenience method wraps the {@link
22954 * LayoutInflater} class, which provides a full range of options for view inflation.
22956 * @param context The Context object for your activity or application.
22957 * @param resource The resource ID to inflate
22958 * @param root A view group that will be the parent. Used to properly inflate the
22959 * layout_* parameters.
22960 * @see LayoutInflater
22962 public static View inflate(Context context, @LayoutRes int resource, ViewGroup root) {
22963 LayoutInflater factory = LayoutInflater.from(context);
22964 return factory.inflate(resource, root);
22968 * Scroll the view with standard behavior for scrolling beyond the normal
22969 * content boundaries. Views that call this method should override
22970 * {@link #onOverScrolled(int, int, boolean, boolean)} to respond to the
22971 * results of an over-scroll operation.
22973 * Views can use this method to handle any touch or fling-based scrolling.
22975 * @param deltaX Change in X in pixels
22976 * @param deltaY Change in Y in pixels
22977 * @param scrollX Current X scroll value in pixels before applying deltaX
22978 * @param scrollY Current Y scroll value in pixels before applying deltaY
22979 * @param scrollRangeX Maximum content scroll range along the X axis
22980 * @param scrollRangeY Maximum content scroll range along the Y axis
22981 * @param maxOverScrollX Number of pixels to overscroll by in either direction
22982 * along the X axis.
22983 * @param maxOverScrollY Number of pixels to overscroll by in either direction
22984 * along the Y axis.
22985 * @param isTouchEvent true if this scroll operation is the result of a touch event.
22986 * @return true if scrolling was clamped to an over-scroll boundary along either
22987 * axis, false otherwise.
22989 @SuppressWarnings({"UnusedParameters"})
22990 protected boolean overScrollBy(int deltaX, int deltaY,
22991 int scrollX, int scrollY,
22992 int scrollRangeX, int scrollRangeY,
22993 int maxOverScrollX, int maxOverScrollY,
22994 boolean isTouchEvent) {
22995 final int overScrollMode = mOverScrollMode;
22996 final boolean canScrollHorizontal =
22997 computeHorizontalScrollRange() > computeHorizontalScrollExtent();
22998 final boolean canScrollVertical =
22999 computeVerticalScrollRange() > computeVerticalScrollExtent();
23000 final boolean overScrollHorizontal = overScrollMode == OVER_SCROLL_ALWAYS ||
23001 (overScrollMode == OVER_SCROLL_IF_CONTENT_SCROLLS && canScrollHorizontal);
23002 final boolean overScrollVertical = overScrollMode == OVER_SCROLL_ALWAYS ||
23003 (overScrollMode == OVER_SCROLL_IF_CONTENT_SCROLLS && canScrollVertical);
23005 int newScrollX = scrollX + deltaX;
23006 if (!overScrollHorizontal) {
23007 maxOverScrollX = 0;
23010 int newScrollY = scrollY + deltaY;
23011 if (!overScrollVertical) {
23012 maxOverScrollY = 0;
23015 // Clamp values if at the limits and record
23016 final int left = -maxOverScrollX;
23017 final int right = maxOverScrollX + scrollRangeX;
23018 final int top = -maxOverScrollY;
23019 final int bottom = maxOverScrollY + scrollRangeY;
23021 boolean clampedX = false;
23022 if (newScrollX > right) {
23023 newScrollX = right;
23025 } else if (newScrollX < left) {
23030 boolean clampedY = false;
23031 if (newScrollY > bottom) {
23032 newScrollY = bottom;
23034 } else if (newScrollY < top) {
23039 onOverScrolled(newScrollX, newScrollY, clampedX, clampedY);
23041 return clampedX || clampedY;
23045 * Called by {@link #overScrollBy(int, int, int, int, int, int, int, int, boolean)} to
23046 * respond to the results of an over-scroll operation.
23048 * @param scrollX New X scroll value in pixels
23049 * @param scrollY New Y scroll value in pixels
23050 * @param clampedX True if scrollX was clamped to an over-scroll boundary
23051 * @param clampedY True if scrollY was clamped to an over-scroll boundary
23053 protected void onOverScrolled(int scrollX, int scrollY,
23054 boolean clampedX, boolean clampedY) {
23055 // Intentionally empty.
23059 * Returns the over-scroll mode for this view. The result will be
23060 * one of {@link #OVER_SCROLL_ALWAYS} (default), {@link #OVER_SCROLL_IF_CONTENT_SCROLLS}
23061 * (allow over-scrolling only if the view content is larger than the container),
23062 * or {@link #OVER_SCROLL_NEVER}.
23064 * @return This view's over-scroll mode.
23066 public int getOverScrollMode() {
23067 return mOverScrollMode;
23071 * Set the over-scroll mode for this view. Valid over-scroll modes are
23072 * {@link #OVER_SCROLL_ALWAYS} (default), {@link #OVER_SCROLL_IF_CONTENT_SCROLLS}
23073 * (allow over-scrolling only if the view content is larger than the container),
23074 * or {@link #OVER_SCROLL_NEVER}.
23076 * Setting the over-scroll mode of a view will have an effect only if the
23077 * view is capable of scrolling.
23079 * @param overScrollMode The new over-scroll mode for this view.
23081 public void setOverScrollMode(int overScrollMode) {
23082 if (overScrollMode != OVER_SCROLL_ALWAYS &&
23083 overScrollMode != OVER_SCROLL_IF_CONTENT_SCROLLS &&
23084 overScrollMode != OVER_SCROLL_NEVER) {
23085 throw new IllegalArgumentException("Invalid overscroll mode " + overScrollMode);
23087 mOverScrollMode = overScrollMode;
23091 * Enable or disable nested scrolling for this view.
23093 * <p>If this property is set to true the view will be permitted to initiate nested
23094 * scrolling operations with a compatible parent view in the current hierarchy. If this
23095 * view does not implement nested scrolling this will have no effect. Disabling nested scrolling
23096 * while a nested scroll is in progress has the effect of {@link #stopNestedScroll() stopping}
23097 * the nested scroll.</p>
23099 * @param enabled true to enable nested scrolling, false to disable
23101 * @see #isNestedScrollingEnabled()
23103 public void setNestedScrollingEnabled(boolean enabled) {
23105 mPrivateFlags3 |= PFLAG3_NESTED_SCROLLING_ENABLED;
23107 stopNestedScroll();
23108 mPrivateFlags3 &= ~PFLAG3_NESTED_SCROLLING_ENABLED;
23113 * Returns true if nested scrolling is enabled for this view.
23115 * <p>If nested scrolling is enabled and this View class implementation supports it,
23116 * this view will act as a nested scrolling child view when applicable, forwarding data
23117 * about the scroll operation in progress to a compatible and cooperating nested scrolling
23120 * @return true if nested scrolling is enabled
23122 * @see #setNestedScrollingEnabled(boolean)
23124 public boolean isNestedScrollingEnabled() {
23125 return (mPrivateFlags3 & PFLAG3_NESTED_SCROLLING_ENABLED) ==
23126 PFLAG3_NESTED_SCROLLING_ENABLED;
23130 * Begin a nestable scroll operation along the given axes.
23132 * <p>A view starting a nested scroll promises to abide by the following contract:</p>
23134 * <p>The view will call startNestedScroll upon initiating a scroll operation. In the case
23135 * of a touch scroll this corresponds to the initial {@link MotionEvent#ACTION_DOWN}.
23136 * In the case of touch scrolling the nested scroll will be terminated automatically in
23137 * the same manner as {@link ViewParent#requestDisallowInterceptTouchEvent(boolean)}.
23138 * In the event of programmatic scrolling the caller must explicitly call
23139 * {@link #stopNestedScroll()} to indicate the end of the nested scroll.</p>
23141 * <p>If <code>startNestedScroll</code> returns true, a cooperative parent was found.
23142 * If it returns false the caller may ignore the rest of this contract until the next scroll.
23143 * Calling startNestedScroll while a nested scroll is already in progress will return true.</p>
23145 * <p>At each incremental step of the scroll the caller should invoke
23146 * {@link #dispatchNestedPreScroll(int, int, int[], int[]) dispatchNestedPreScroll}
23147 * once it has calculated the requested scrolling delta. If it returns true the nested scrolling
23148 * parent at least partially consumed the scroll and the caller should adjust the amount it
23151 * <p>After applying the remainder of the scroll delta the caller should invoke
23152 * {@link #dispatchNestedScroll(int, int, int, int, int[]) dispatchNestedScroll}, passing
23153 * both the delta consumed and the delta unconsumed. A nested scrolling parent may treat
23154 * these values differently. See {@link ViewParent#onNestedScroll(View, int, int, int, int)}.
23157 * @param axes Flags consisting of a combination of {@link #SCROLL_AXIS_HORIZONTAL} and/or
23158 * {@link #SCROLL_AXIS_VERTICAL}.
23159 * @return true if a cooperative parent was found and nested scrolling has been enabled for
23160 * the current gesture.
23162 * @see #stopNestedScroll()
23163 * @see #dispatchNestedPreScroll(int, int, int[], int[])
23164 * @see #dispatchNestedScroll(int, int, int, int, int[])
23166 public boolean startNestedScroll(int axes) {
23167 if (hasNestedScrollingParent()) {
23168 // Already in progress
23171 if (isNestedScrollingEnabled()) {
23172 ViewParent p = getParent();
23174 while (p != null) {
23176 if (p.onStartNestedScroll(child, this, axes)) {
23177 mNestedScrollingParent = p;
23178 p.onNestedScrollAccepted(child, this, axes);
23181 } catch (AbstractMethodError e) {
23182 Log.e(VIEW_LOG_TAG, "ViewParent " + p + " does not implement interface " +
23183 "method onStartNestedScroll", e);
23184 // Allow the search upward to continue
23186 if (p instanceof View) {
23196 * Stop a nested scroll in progress.
23198 * <p>Calling this method when a nested scroll is not currently in progress is harmless.</p>
23200 * @see #startNestedScroll(int)
23202 public void stopNestedScroll() {
23203 if (mNestedScrollingParent != null) {
23204 mNestedScrollingParent.onStopNestedScroll(this);
23205 mNestedScrollingParent = null;
23210 * Returns true if this view has a nested scrolling parent.
23212 * <p>The presence of a nested scrolling parent indicates that this view has initiated
23213 * a nested scroll and it was accepted by an ancestor view further up the view hierarchy.</p>
23215 * @return whether this view has a nested scrolling parent
23217 public boolean hasNestedScrollingParent() {
23218 return mNestedScrollingParent != null;
23222 * Dispatch one step of a nested scroll in progress.
23224 * <p>Implementations of views that support nested scrolling should call this to report
23225 * info about a scroll in progress to the current nested scrolling parent. If a nested scroll
23226 * is not currently in progress or nested scrolling is not
23227 * {@link #isNestedScrollingEnabled() enabled} for this view this method does nothing.</p>
23229 * <p>Compatible View implementations should also call
23230 * {@link #dispatchNestedPreScroll(int, int, int[], int[]) dispatchNestedPreScroll} before
23231 * consuming a component of the scroll event themselves.</p>
23233 * @param dxConsumed Horizontal distance in pixels consumed by this view during this scroll step
23234 * @param dyConsumed Vertical distance in pixels consumed by this view during this scroll step
23235 * @param dxUnconsumed Horizontal scroll distance in pixels not consumed by this view
23236 * @param dyUnconsumed Horizontal scroll distance in pixels not consumed by this view
23237 * @param offsetInWindow Optional. If not null, on return this will contain the offset
23238 * in local view coordinates of this view from before this operation
23239 * to after it completes. View implementations may use this to adjust
23240 * expected input coordinate tracking.
23241 * @return true if the event was dispatched, false if it could not be dispatched.
23242 * @see #dispatchNestedPreScroll(int, int, int[], int[])
23244 public boolean dispatchNestedScroll(int dxConsumed, int dyConsumed,
23245 int dxUnconsumed, int dyUnconsumed, @Nullable @Size(2) int[] offsetInWindow) {
23246 if (isNestedScrollingEnabled() && mNestedScrollingParent != null) {
23247 if (dxConsumed != 0 || dyConsumed != 0 || dxUnconsumed != 0 || dyUnconsumed != 0) {
23250 if (offsetInWindow != null) {
23251 getLocationInWindow(offsetInWindow);
23252 startX = offsetInWindow[0];
23253 startY = offsetInWindow[1];
23256 mNestedScrollingParent.onNestedScroll(this, dxConsumed, dyConsumed,
23257 dxUnconsumed, dyUnconsumed);
23259 if (offsetInWindow != null) {
23260 getLocationInWindow(offsetInWindow);
23261 offsetInWindow[0] -= startX;
23262 offsetInWindow[1] -= startY;
23265 } else if (offsetInWindow != null) {
23266 // No motion, no dispatch. Keep offsetInWindow up to date.
23267 offsetInWindow[0] = 0;
23268 offsetInWindow[1] = 0;
23275 * Dispatch one step of a nested scroll in progress before this view consumes any portion of it.
23277 * <p>Nested pre-scroll events are to nested scroll events what touch intercept is to touch.
23278 * <code>dispatchNestedPreScroll</code> offers an opportunity for the parent view in a nested
23279 * scrolling operation to consume some or all of the scroll operation before the child view
23282 * @param dx Horizontal scroll distance in pixels
23283 * @param dy Vertical scroll distance in pixels
23284 * @param consumed Output. If not null, consumed[0] will contain the consumed component of dx
23285 * and consumed[1] the consumed dy.
23286 * @param offsetInWindow Optional. If not null, on return this will contain the offset
23287 * in local view coordinates of this view from before this operation
23288 * to after it completes. View implementations may use this to adjust
23289 * expected input coordinate tracking.
23290 * @return true if the parent consumed some or all of the scroll delta
23291 * @see #dispatchNestedScroll(int, int, int, int, int[])
23293 public boolean dispatchNestedPreScroll(int dx, int dy,
23294 @Nullable @Size(2) int[] consumed, @Nullable @Size(2) int[] offsetInWindow) {
23295 if (isNestedScrollingEnabled() && mNestedScrollingParent != null) {
23296 if (dx != 0 || dy != 0) {
23299 if (offsetInWindow != null) {
23300 getLocationInWindow(offsetInWindow);
23301 startX = offsetInWindow[0];
23302 startY = offsetInWindow[1];
23305 if (consumed == null) {
23306 if (mTempNestedScrollConsumed == null) {
23307 mTempNestedScrollConsumed = new int[2];
23309 consumed = mTempNestedScrollConsumed;
23313 mNestedScrollingParent.onNestedPreScroll(this, dx, dy, consumed);
23315 if (offsetInWindow != null) {
23316 getLocationInWindow(offsetInWindow);
23317 offsetInWindow[0] -= startX;
23318 offsetInWindow[1] -= startY;
23320 return consumed[0] != 0 || consumed[1] != 0;
23321 } else if (offsetInWindow != null) {
23322 offsetInWindow[0] = 0;
23323 offsetInWindow[1] = 0;
23330 * Dispatch a fling to a nested scrolling parent.
23332 * <p>This method should be used to indicate that a nested scrolling child has detected
23333 * suitable conditions for a fling. Generally this means that a touch scroll has ended with a
23334 * {@link VelocityTracker velocity} in the direction of scrolling that meets or exceeds
23335 * the {@link ViewConfiguration#getScaledMinimumFlingVelocity() minimum fling velocity}
23336 * along a scrollable axis.</p>
23338 * <p>If a nested scrolling child view would normally fling but it is at the edge of
23339 * its own content, it can use this method to delegate the fling to its nested scrolling
23340 * parent instead. The parent may optionally consume the fling or observe a child fling.</p>
23342 * @param velocityX Horizontal fling velocity in pixels per second
23343 * @param velocityY Vertical fling velocity in pixels per second
23344 * @param consumed true if the child consumed the fling, false otherwise
23345 * @return true if the nested scrolling parent consumed or otherwise reacted to the fling
23347 public boolean dispatchNestedFling(float velocityX, float velocityY, boolean consumed) {
23348 if (isNestedScrollingEnabled() && mNestedScrollingParent != null) {
23349 return mNestedScrollingParent.onNestedFling(this, velocityX, velocityY, consumed);
23355 * Dispatch a fling to a nested scrolling parent before it is processed by this view.
23357 * <p>Nested pre-fling events are to nested fling events what touch intercept is to touch
23358 * and what nested pre-scroll is to nested scroll. <code>dispatchNestedPreFling</code>
23359 * offsets an opportunity for the parent view in a nested fling to fully consume the fling
23360 * before the child view consumes it. If this method returns <code>true</code>, a nested
23361 * parent view consumed the fling and this view should not scroll as a result.</p>
23363 * <p>For a better user experience, only one view in a nested scrolling chain should consume
23364 * the fling at a time. If a parent view consumed the fling this method will return false.
23365 * Custom view implementations should account for this in two ways:</p>
23368 * <li>If a custom view is paged and needs to settle to a fixed page-point, do not
23369 * call <code>dispatchNestedPreFling</code>; consume the fling and settle to a valid
23370 * position regardless.</li>
23371 * <li>If a nested parent does consume the fling, this view should not scroll at all,
23372 * even to settle back to a valid idle position.</li>
23375 * <p>Views should also not offer fling velocities to nested parent views along an axis
23376 * where scrolling is not currently supported; a {@link android.widget.ScrollView ScrollView}
23377 * should not offer a horizontal fling velocity to its parents since scrolling along that
23378 * axis is not permitted and carrying velocity along that motion does not make sense.</p>
23380 * @param velocityX Horizontal fling velocity in pixels per second
23381 * @param velocityY Vertical fling velocity in pixels per second
23382 * @return true if a nested scrolling parent consumed the fling
23384 public boolean dispatchNestedPreFling(float velocityX, float velocityY) {
23385 if (isNestedScrollingEnabled() && mNestedScrollingParent != null) {
23386 return mNestedScrollingParent.onNestedPreFling(this, velocityX, velocityY);
23392 * Gets a scale factor that determines the distance the view should scroll
23393 * vertically in response to {@link MotionEvent#ACTION_SCROLL}.
23394 * @return The vertical scroll scale factor.
23397 protected float getVerticalScrollFactor() {
23398 if (mVerticalScrollFactor == 0) {
23399 TypedValue outValue = new TypedValue();
23400 if (!mContext.getTheme().resolveAttribute(
23401 com.android.internal.R.attr.listPreferredItemHeight, outValue, true)) {
23402 throw new IllegalStateException(
23403 "Expected theme to define listPreferredItemHeight.");
23405 mVerticalScrollFactor = outValue.getDimension(
23406 mContext.getResources().getDisplayMetrics());
23408 return mVerticalScrollFactor;
23412 * Gets a scale factor that determines the distance the view should scroll
23413 * horizontally in response to {@link MotionEvent#ACTION_SCROLL}.
23414 * @return The horizontal scroll scale factor.
23417 protected float getHorizontalScrollFactor() {
23418 // TODO: Should use something else.
23419 return getVerticalScrollFactor();
23423 * Return the value specifying the text direction or policy that was set with
23424 * {@link #setTextDirection(int)}.
23426 * @return the defined text direction. It can be one of:
23428 * {@link #TEXT_DIRECTION_INHERIT},
23429 * {@link #TEXT_DIRECTION_FIRST_STRONG},
23430 * {@link #TEXT_DIRECTION_ANY_RTL},
23431 * {@link #TEXT_DIRECTION_LTR},
23432 * {@link #TEXT_DIRECTION_RTL},
23433 * {@link #TEXT_DIRECTION_LOCALE},
23434 * {@link #TEXT_DIRECTION_FIRST_STRONG_LTR},
23435 * {@link #TEXT_DIRECTION_FIRST_STRONG_RTL}
23437 * @attr ref android.R.styleable#View_textDirection
23441 @ViewDebug.ExportedProperty(category = "text", mapping = {
23442 @ViewDebug.IntToString(from = TEXT_DIRECTION_INHERIT, to = "INHERIT"),
23443 @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG, to = "FIRST_STRONG"),
23444 @ViewDebug.IntToString(from = TEXT_DIRECTION_ANY_RTL, to = "ANY_RTL"),
23445 @ViewDebug.IntToString(from = TEXT_DIRECTION_LTR, to = "LTR"),
23446 @ViewDebug.IntToString(from = TEXT_DIRECTION_RTL, to = "RTL"),
23447 @ViewDebug.IntToString(from = TEXT_DIRECTION_LOCALE, to = "LOCALE"),
23448 @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG_LTR, to = "FIRST_STRONG_LTR"),
23449 @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG_RTL, to = "FIRST_STRONG_RTL")
23451 public int getRawTextDirection() {
23452 return (mPrivateFlags2 & PFLAG2_TEXT_DIRECTION_MASK) >> PFLAG2_TEXT_DIRECTION_MASK_SHIFT;
23456 * Set the text direction.
23458 * @param textDirection the direction to set. Should be one of:
23460 * {@link #TEXT_DIRECTION_INHERIT},
23461 * {@link #TEXT_DIRECTION_FIRST_STRONG},
23462 * {@link #TEXT_DIRECTION_ANY_RTL},
23463 * {@link #TEXT_DIRECTION_LTR},
23464 * {@link #TEXT_DIRECTION_RTL},
23465 * {@link #TEXT_DIRECTION_LOCALE}
23466 * {@link #TEXT_DIRECTION_FIRST_STRONG_LTR},
23467 * {@link #TEXT_DIRECTION_FIRST_STRONG_RTL},
23469 * Resolution will be done if the value is set to TEXT_DIRECTION_INHERIT. The resolution
23470 * proceeds up the parent chain of the view to get the value. If there is no parent, then it will
23471 * return the default {@link #TEXT_DIRECTION_FIRST_STRONG}.
23473 * @attr ref android.R.styleable#View_textDirection
23475 public void setTextDirection(int textDirection) {
23476 if (getRawTextDirection() != textDirection) {
23477 // Reset the current text direction and the resolved one
23478 mPrivateFlags2 &= ~PFLAG2_TEXT_DIRECTION_MASK;
23479 resetResolvedTextDirection();
23480 // Set the new text direction
23481 mPrivateFlags2 |= ((textDirection << PFLAG2_TEXT_DIRECTION_MASK_SHIFT) & PFLAG2_TEXT_DIRECTION_MASK);
23483 resolveTextDirection();
23485 onRtlPropertiesChanged(getLayoutDirection());
23493 * Return the resolved text direction.
23495 * @return the resolved text direction. Returns one of:
23497 * {@link #TEXT_DIRECTION_FIRST_STRONG},
23498 * {@link #TEXT_DIRECTION_ANY_RTL},
23499 * {@link #TEXT_DIRECTION_LTR},
23500 * {@link #TEXT_DIRECTION_RTL},
23501 * {@link #TEXT_DIRECTION_LOCALE},
23502 * {@link #TEXT_DIRECTION_FIRST_STRONG_LTR},
23503 * {@link #TEXT_DIRECTION_FIRST_STRONG_RTL}
23505 * @attr ref android.R.styleable#View_textDirection
23507 @ViewDebug.ExportedProperty(category = "text", mapping = {
23508 @ViewDebug.IntToString(from = TEXT_DIRECTION_INHERIT, to = "INHERIT"),
23509 @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG, to = "FIRST_STRONG"),
23510 @ViewDebug.IntToString(from = TEXT_DIRECTION_ANY_RTL, to = "ANY_RTL"),
23511 @ViewDebug.IntToString(from = TEXT_DIRECTION_LTR, to = "LTR"),
23512 @ViewDebug.IntToString(from = TEXT_DIRECTION_RTL, to = "RTL"),
23513 @ViewDebug.IntToString(from = TEXT_DIRECTION_LOCALE, to = "LOCALE"),
23514 @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG_LTR, to = "FIRST_STRONG_LTR"),
23515 @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG_RTL, to = "FIRST_STRONG_RTL")
23517 public int getTextDirection() {
23518 return (mPrivateFlags2 & PFLAG2_TEXT_DIRECTION_RESOLVED_MASK) >> PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT;
23522 * Resolve the text direction.
23524 * @return true if resolution has been done, false otherwise.
23528 public boolean resolveTextDirection() {
23529 // Reset any previous text direction resolution
23530 mPrivateFlags2 &= ~(PFLAG2_TEXT_DIRECTION_RESOLVED | PFLAG2_TEXT_DIRECTION_RESOLVED_MASK);
23532 if (hasRtlSupport()) {
23533 // Set resolved text direction flag depending on text direction flag
23534 final int textDirection = getRawTextDirection();
23535 switch(textDirection) {
23536 case TEXT_DIRECTION_INHERIT:
23537 if (!canResolveTextDirection()) {
23538 // We cannot do the resolution if there is no parent, so use the default one
23539 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT;
23540 // Resolution will need to happen again later
23544 // Parent has not yet resolved, so we still return the default
23546 if (!mParent.isTextDirectionResolved()) {
23547 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT;
23548 // Resolution will need to happen again later
23551 } catch (AbstractMethodError e) {
23552 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() +
23553 " does not fully implement ViewParent", e);
23554 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED |
23555 PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT;
23559 // Set current resolved direction to the same value as the parent's one
23560 int parentResolvedDirection;
23562 parentResolvedDirection = mParent.getTextDirection();
23563 } catch (AbstractMethodError e) {
23564 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() +
23565 " does not fully implement ViewParent", e);
23566 parentResolvedDirection = TEXT_DIRECTION_LTR;
23568 switch (parentResolvedDirection) {
23569 case TEXT_DIRECTION_FIRST_STRONG:
23570 case TEXT_DIRECTION_ANY_RTL:
23571 case TEXT_DIRECTION_LTR:
23572 case TEXT_DIRECTION_RTL:
23573 case TEXT_DIRECTION_LOCALE:
23574 case TEXT_DIRECTION_FIRST_STRONG_LTR:
23575 case TEXT_DIRECTION_FIRST_STRONG_RTL:
23577 (parentResolvedDirection << PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT);
23580 // Default resolved direction is "first strong" heuristic
23581 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT;
23584 case TEXT_DIRECTION_FIRST_STRONG:
23585 case TEXT_DIRECTION_ANY_RTL:
23586 case TEXT_DIRECTION_LTR:
23587 case TEXT_DIRECTION_RTL:
23588 case TEXT_DIRECTION_LOCALE:
23589 case TEXT_DIRECTION_FIRST_STRONG_LTR:
23590 case TEXT_DIRECTION_FIRST_STRONG_RTL:
23591 // Resolved direction is the same as text direction
23592 mPrivateFlags2 |= (textDirection << PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT);
23595 // Default resolved direction is "first strong" heuristic
23596 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT;
23599 // Default resolved direction is "first strong" heuristic
23600 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT;
23604 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED;
23609 * Check if text direction resolution can be done.
23611 * @return true if text direction resolution can be done otherwise return false.
23613 public boolean canResolveTextDirection() {
23614 switch (getRawTextDirection()) {
23615 case TEXT_DIRECTION_INHERIT:
23616 if (mParent != null) {
23618 return mParent.canResolveTextDirection();
23619 } catch (AbstractMethodError e) {
23620 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() +
23621 " does not fully implement ViewParent", e);
23632 * Reset resolved text direction. Text direction will be resolved during a call to
23633 * {@link #onMeasure(int, int)}.
23637 public void resetResolvedTextDirection() {
23638 // Reset any previous text direction resolution
23639 mPrivateFlags2 &= ~(PFLAG2_TEXT_DIRECTION_RESOLVED | PFLAG2_TEXT_DIRECTION_RESOLVED_MASK);
23640 // Set to default value
23641 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT;
23645 * @return true if text direction is inherited.
23649 public boolean isTextDirectionInherited() {
23650 return (getRawTextDirection() == TEXT_DIRECTION_INHERIT);
23654 * @return true if text direction is resolved.
23656 public boolean isTextDirectionResolved() {
23657 return (mPrivateFlags2 & PFLAG2_TEXT_DIRECTION_RESOLVED) == PFLAG2_TEXT_DIRECTION_RESOLVED;
23661 * Return the value specifying the text alignment or policy that was set with
23662 * {@link #setTextAlignment(int)}.
23664 * @return the defined text alignment. It can be one of:
23666 * {@link #TEXT_ALIGNMENT_INHERIT},
23667 * {@link #TEXT_ALIGNMENT_GRAVITY},
23668 * {@link #TEXT_ALIGNMENT_CENTER},
23669 * {@link #TEXT_ALIGNMENT_TEXT_START},
23670 * {@link #TEXT_ALIGNMENT_TEXT_END},
23671 * {@link #TEXT_ALIGNMENT_VIEW_START},
23672 * {@link #TEXT_ALIGNMENT_VIEW_END}
23674 * @attr ref android.R.styleable#View_textAlignment
23678 @ViewDebug.ExportedProperty(category = "text", mapping = {
23679 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_INHERIT, to = "INHERIT"),
23680 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_GRAVITY, to = "GRAVITY"),
23681 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_TEXT_START, to = "TEXT_START"),
23682 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_TEXT_END, to = "TEXT_END"),
23683 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_CENTER, to = "CENTER"),
23684 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_VIEW_START, to = "VIEW_START"),
23685 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_VIEW_END, to = "VIEW_END")
23688 public int getRawTextAlignment() {
23689 return (mPrivateFlags2 & PFLAG2_TEXT_ALIGNMENT_MASK) >> PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT;
23693 * Set the text alignment.
23695 * @param textAlignment The text alignment to set. Should be one of
23697 * {@link #TEXT_ALIGNMENT_INHERIT},
23698 * {@link #TEXT_ALIGNMENT_GRAVITY},
23699 * {@link #TEXT_ALIGNMENT_CENTER},
23700 * {@link #TEXT_ALIGNMENT_TEXT_START},
23701 * {@link #TEXT_ALIGNMENT_TEXT_END},
23702 * {@link #TEXT_ALIGNMENT_VIEW_START},
23703 * {@link #TEXT_ALIGNMENT_VIEW_END}
23705 * Resolution will be done if the value is set to TEXT_ALIGNMENT_INHERIT. The resolution
23706 * proceeds up the parent chain of the view to get the value. If there is no parent, then it
23707 * will return the default {@link #TEXT_ALIGNMENT_GRAVITY}.
23709 * @attr ref android.R.styleable#View_textAlignment
23711 public void setTextAlignment(@TextAlignment int textAlignment) {
23712 if (textAlignment != getRawTextAlignment()) {
23713 // Reset the current and resolved text alignment
23714 mPrivateFlags2 &= ~PFLAG2_TEXT_ALIGNMENT_MASK;
23715 resetResolvedTextAlignment();
23716 // Set the new text alignment
23718 ((textAlignment << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT) & PFLAG2_TEXT_ALIGNMENT_MASK);
23720 resolveTextAlignment();
23722 onRtlPropertiesChanged(getLayoutDirection());
23730 * Return the resolved text alignment.
23732 * @return the resolved text alignment. Returns one of:
23734 * {@link #TEXT_ALIGNMENT_GRAVITY},
23735 * {@link #TEXT_ALIGNMENT_CENTER},
23736 * {@link #TEXT_ALIGNMENT_TEXT_START},
23737 * {@link #TEXT_ALIGNMENT_TEXT_END},
23738 * {@link #TEXT_ALIGNMENT_VIEW_START},
23739 * {@link #TEXT_ALIGNMENT_VIEW_END}
23741 * @attr ref android.R.styleable#View_textAlignment
23743 @ViewDebug.ExportedProperty(category = "text", mapping = {
23744 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_INHERIT, to = "INHERIT"),
23745 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_GRAVITY, to = "GRAVITY"),
23746 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_TEXT_START, to = "TEXT_START"),
23747 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_TEXT_END, to = "TEXT_END"),
23748 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_CENTER, to = "CENTER"),
23749 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_VIEW_START, to = "VIEW_START"),
23750 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_VIEW_END, to = "VIEW_END")
23753 public int getTextAlignment() {
23754 return (mPrivateFlags2 & PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK) >>
23755 PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT;
23759 * Resolve the text alignment.
23761 * @return true if resolution has been done, false otherwise.
23765 public boolean resolveTextAlignment() {
23766 // Reset any previous text alignment resolution
23767 mPrivateFlags2 &= ~(PFLAG2_TEXT_ALIGNMENT_RESOLVED | PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK);
23769 if (hasRtlSupport()) {
23770 // Set resolved text alignment flag depending on text alignment flag
23771 final int textAlignment = getRawTextAlignment();
23772 switch (textAlignment) {
23773 case TEXT_ALIGNMENT_INHERIT:
23774 // Check if we can resolve the text alignment
23775 if (!canResolveTextAlignment()) {
23776 // We cannot do the resolution if there is no parent so use the default
23777 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT;
23778 // Resolution will need to happen again later
23782 // Parent has not yet resolved, so we still return the default
23784 if (!mParent.isTextAlignmentResolved()) {
23785 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT;
23786 // Resolution will need to happen again later
23789 } catch (AbstractMethodError e) {
23790 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() +
23791 " does not fully implement ViewParent", e);
23792 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED |
23793 PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT;
23797 int parentResolvedTextAlignment;
23799 parentResolvedTextAlignment = mParent.getTextAlignment();
23800 } catch (AbstractMethodError e) {
23801 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() +
23802 " does not fully implement ViewParent", e);
23803 parentResolvedTextAlignment = TEXT_ALIGNMENT_GRAVITY;
23805 switch (parentResolvedTextAlignment) {
23806 case TEXT_ALIGNMENT_GRAVITY:
23807 case TEXT_ALIGNMENT_TEXT_START:
23808 case TEXT_ALIGNMENT_TEXT_END:
23809 case TEXT_ALIGNMENT_CENTER:
23810 case TEXT_ALIGNMENT_VIEW_START:
23811 case TEXT_ALIGNMENT_VIEW_END:
23812 // Resolved text alignment is the same as the parent resolved
23815 (parentResolvedTextAlignment << PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT);
23818 // Use default resolved text alignment
23819 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT;
23822 case TEXT_ALIGNMENT_GRAVITY:
23823 case TEXT_ALIGNMENT_TEXT_START:
23824 case TEXT_ALIGNMENT_TEXT_END:
23825 case TEXT_ALIGNMENT_CENTER:
23826 case TEXT_ALIGNMENT_VIEW_START:
23827 case TEXT_ALIGNMENT_VIEW_END:
23828 // Resolved text alignment is the same as text alignment
23829 mPrivateFlags2 |= (textAlignment << PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT);
23832 // Use default resolved text alignment
23833 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT;
23836 // Use default resolved text alignment
23837 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT;
23840 // Set the resolved
23841 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED;
23846 * Check if text alignment resolution can be done.
23848 * @return true if text alignment resolution can be done otherwise return false.
23850 public boolean canResolveTextAlignment() {
23851 switch (getRawTextAlignment()) {
23852 case TEXT_DIRECTION_INHERIT:
23853 if (mParent != null) {
23855 return mParent.canResolveTextAlignment();
23856 } catch (AbstractMethodError e) {
23857 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() +
23858 " does not fully implement ViewParent", e);
23869 * Reset resolved text alignment. Text alignment will be resolved during a call to
23870 * {@link #onMeasure(int, int)}.
23874 public void resetResolvedTextAlignment() {
23875 // Reset any previous text alignment resolution
23876 mPrivateFlags2 &= ~(PFLAG2_TEXT_ALIGNMENT_RESOLVED | PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK);
23878 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT;
23882 * @return true if text alignment is inherited.
23886 public boolean isTextAlignmentInherited() {
23887 return (getRawTextAlignment() == TEXT_ALIGNMENT_INHERIT);
23891 * @return true if text alignment is resolved.
23893 public boolean isTextAlignmentResolved() {
23894 return (mPrivateFlags2 & PFLAG2_TEXT_ALIGNMENT_RESOLVED) == PFLAG2_TEXT_ALIGNMENT_RESOLVED;
23898 * Generate a value suitable for use in {@link #setId(int)}.
23899 * This value will not collide with ID values generated at build time by aapt for R.id.
23901 * @return a generated ID value
23903 public static int generateViewId() {
23905 final int result = sNextGeneratedId.get();
23906 // aapt-generated IDs have the high byte nonzero; clamp to the range under that.
23907 int newValue = result + 1;
23908 if (newValue > 0x00FFFFFF) newValue = 1; // Roll over to 1, not 0.
23909 if (sNextGeneratedId.compareAndSet(result, newValue)) {
23915 private static boolean isViewIdGenerated(int id) {
23916 return (id & 0xFF000000) == 0 && (id & 0x00FFFFFF) != 0;
23920 * Gets the Views in the hierarchy affected by entering and exiting Activity Scene transitions.
23921 * @param transitioningViews This View will be added to transitioningViews if it is VISIBLE and
23922 * a normal View or a ViewGroup with
23923 * {@link android.view.ViewGroup#isTransitionGroup()} true.
23926 public void captureTransitioningViews(List<View> transitioningViews) {
23927 if (getVisibility() == View.VISIBLE) {
23928 transitioningViews.add(this);
23933 * Adds all Views that have {@link #getTransitionName()} non-null to namedElements.
23934 * @param namedElements Will contain all Views in the hierarchy having a transitionName.
23937 public void findNamedViews(Map<String, View> namedElements) {
23938 if (getVisibility() == VISIBLE || mGhostView != null) {
23939 String transitionName = getTransitionName();
23940 if (transitionName != null) {
23941 namedElements.put(transitionName, this);
23947 * Returns the pointer icon for the motion event, or null if it doesn't specify the icon.
23948 * The default implementation does not care the location or event types, but some subclasses
23949 * may use it (such as WebViews).
23950 * @param event The MotionEvent from a mouse
23951 * @param pointerIndex The index of the pointer for which to retrieve the {@link PointerIcon}.
23952 * This will be between 0 and {@link MotionEvent#getPointerCount()}.
23955 public PointerIcon onResolvePointerIcon(MotionEvent event, int pointerIndex) {
23956 final float x = event.getX(pointerIndex);
23957 final float y = event.getY(pointerIndex);
23958 if (isDraggingScrollBar() || isOnScrollbarThumb(x, y)) {
23959 return PointerIcon.getSystemIcon(mContext, PointerIcon.TYPE_ARROW);
23961 return mPointerIcon;
23965 * Set the pointer icon for the current view.
23966 * Passing {@code null} will restore the pointer icon to its default value.
23967 * @param pointerIcon A PointerIcon instance which will be shown when the mouse hovers.
23969 public void setPointerIcon(PointerIcon pointerIcon) {
23970 mPointerIcon = pointerIcon;
23971 if (mAttachInfo == null || mAttachInfo.mHandlingPointerEvent) {
23975 mAttachInfo.mSession.updatePointerIcon(mAttachInfo.mWindow);
23976 } catch (RemoteException e) {
23981 * Gets the pointer icon for the current view.
23983 public PointerIcon getPointerIcon() {
23984 return mPointerIcon;
23988 * Checks pointer capture status.
23990 * @return true if the view has pointer capture.
23991 * @see #requestPointerCapture()
23992 * @see #hasPointerCapture()
23994 public boolean hasPointerCapture() {
23995 final ViewRootImpl viewRootImpl = getViewRootImpl();
23996 if (viewRootImpl == null) {
23999 return viewRootImpl.hasPointerCapture();
24003 * Requests pointer capture mode.
24005 * When the window has pointer capture, the mouse pointer icon will disappear and will not
24006 * change its position. Further mouse will be dispatched with the source
24007 * {@link InputDevice#SOURCE_MOUSE_RELATIVE}, and relative position changes will be available
24008 * through {@link MotionEvent#getX} and {@link MotionEvent#getY}. Non-mouse events
24009 * (touchscreens, or stylus) will not be affected.
24011 * If the window already has pointer capture, this call does nothing.
24013 * The capture may be released through {@link #releasePointerCapture()}, or will be lost
24014 * automatically when the window loses focus.
24016 * @see #releasePointerCapture()
24017 * @see #hasPointerCapture()
24019 public void requestPointerCapture() {
24020 final ViewRootImpl viewRootImpl = getViewRootImpl();
24021 if (viewRootImpl != null) {
24022 viewRootImpl.requestPointerCapture(true);
24028 * Releases the pointer capture.
24030 * If the window does not have pointer capture, this call will do nothing.
24031 * @see #requestPointerCapture()
24032 * @see #hasPointerCapture()
24034 public void releasePointerCapture() {
24035 final ViewRootImpl viewRootImpl = getViewRootImpl();
24036 if (viewRootImpl != null) {
24037 viewRootImpl.requestPointerCapture(false);
24042 * Called when the window has just acquired or lost pointer capture.
24044 * @param hasCapture True if the view now has pointerCapture, false otherwise.
24047 public void onPointerCaptureChange(boolean hasCapture) {
24051 * @see #onPointerCaptureChange
24053 public void dispatchPointerCaptureChanged(boolean hasCapture) {
24054 onPointerCaptureChange(hasCapture);
24058 * Implement this method to handle captured pointer events
24060 * @param event The captured pointer event.
24061 * @return True if the event was handled, false otherwise.
24062 * @see #requestPointerCapture()
24064 public boolean onCapturedPointerEvent(MotionEvent event) {
24069 * Interface definition for a callback to be invoked when a captured pointer event
24070 * is being dispatched this view. The callback will be invoked before the event is
24071 * given to the view.
24073 public interface OnCapturedPointerListener {
24075 * Called when a captured pointer event is dispatched to a view.
24076 * @param view The view this event has been dispatched to.
24077 * @param event The captured event.
24078 * @return True if the listener has consumed the event, false otherwise.
24080 boolean onCapturedPointer(View view, MotionEvent event);
24084 * Set a listener to receive callbacks when the pointer capture state of a view changes.
24085 * @param l The {@link OnCapturedPointerListener} to receive callbacks.
24087 public void setOnCapturedPointerListener(OnCapturedPointerListener l) {
24088 getListenerInfo().mOnCapturedPointerListener = l;
24094 * A Property wrapper around the <code>alpha</code> functionality handled by the
24095 * {@link View#setAlpha(float)} and {@link View#getAlpha()} methods.
24097 public static final Property<View, Float> ALPHA = new FloatProperty<View>("alpha") {
24099 public void setValue(View object, float value) {
24100 object.setAlpha(value);
24104 public Float get(View object) {
24105 return object.getAlpha();
24110 * A Property wrapper around the <code>translationX</code> functionality handled by the
24111 * {@link View#setTranslationX(float)} and {@link View#getTranslationX()} methods.
24113 public static final Property<View, Float> TRANSLATION_X = new FloatProperty<View>("translationX") {
24115 public void setValue(View object, float value) {
24116 object.setTranslationX(value);
24120 public Float get(View object) {
24121 return object.getTranslationX();
24126 * A Property wrapper around the <code>translationY</code> functionality handled by the
24127 * {@link View#setTranslationY(float)} and {@link View#getTranslationY()} methods.
24129 public static final Property<View, Float> TRANSLATION_Y = new FloatProperty<View>("translationY") {
24131 public void setValue(View object, float value) {
24132 object.setTranslationY(value);
24136 public Float get(View object) {
24137 return object.getTranslationY();
24142 * A Property wrapper around the <code>translationZ</code> functionality handled by the
24143 * {@link View#setTranslationZ(float)} and {@link View#getTranslationZ()} methods.
24145 public static final Property<View, Float> TRANSLATION_Z = new FloatProperty<View>("translationZ") {
24147 public void setValue(View object, float value) {
24148 object.setTranslationZ(value);
24152 public Float get(View object) {
24153 return object.getTranslationZ();
24158 * A Property wrapper around the <code>x</code> functionality handled by the
24159 * {@link View#setX(float)} and {@link View#getX()} methods.
24161 public static final Property<View, Float> X = new FloatProperty<View>("x") {
24163 public void setValue(View object, float value) {
24164 object.setX(value);
24168 public Float get(View object) {
24169 return object.getX();
24174 * A Property wrapper around the <code>y</code> functionality handled by the
24175 * {@link View#setY(float)} and {@link View#getY()} methods.
24177 public static final Property<View, Float> Y = new FloatProperty<View>("y") {
24179 public void setValue(View object, float value) {
24180 object.setY(value);
24184 public Float get(View object) {
24185 return object.getY();
24190 * A Property wrapper around the <code>z</code> functionality handled by the
24191 * {@link View#setZ(float)} and {@link View#getZ()} methods.
24193 public static final Property<View, Float> Z = new FloatProperty<View>("z") {
24195 public void setValue(View object, float value) {
24196 object.setZ(value);
24200 public Float get(View object) {
24201 return object.getZ();
24206 * A Property wrapper around the <code>rotation</code> functionality handled by the
24207 * {@link View#setRotation(float)} and {@link View#getRotation()} methods.
24209 public static final Property<View, Float> ROTATION = new FloatProperty<View>("rotation") {
24211 public void setValue(View object, float value) {
24212 object.setRotation(value);
24216 public Float get(View object) {
24217 return object.getRotation();
24222 * A Property wrapper around the <code>rotationX</code> functionality handled by the
24223 * {@link View#setRotationX(float)} and {@link View#getRotationX()} methods.
24225 public static final Property<View, Float> ROTATION_X = new FloatProperty<View>("rotationX") {
24227 public void setValue(View object, float value) {
24228 object.setRotationX(value);
24232 public Float get(View object) {
24233 return object.getRotationX();
24238 * A Property wrapper around the <code>rotationY</code> functionality handled by the
24239 * {@link View#setRotationY(float)} and {@link View#getRotationY()} methods.
24241 public static final Property<View, Float> ROTATION_Y = new FloatProperty<View>("rotationY") {
24243 public void setValue(View object, float value) {
24244 object.setRotationY(value);
24248 public Float get(View object) {
24249 return object.getRotationY();
24254 * A Property wrapper around the <code>scaleX</code> functionality handled by the
24255 * {@link View#setScaleX(float)} and {@link View#getScaleX()} methods.
24257 public static final Property<View, Float> SCALE_X = new FloatProperty<View>("scaleX") {
24259 public void setValue(View object, float value) {
24260 object.setScaleX(value);
24264 public Float get(View object) {
24265 return object.getScaleX();
24270 * A Property wrapper around the <code>scaleY</code> functionality handled by the
24271 * {@link View#setScaleY(float)} and {@link View#getScaleY()} methods.
24273 public static final Property<View, Float> SCALE_Y = new FloatProperty<View>("scaleY") {
24275 public void setValue(View object, float value) {
24276 object.setScaleY(value);
24280 public Float get(View object) {
24281 return object.getScaleY();
24286 * A MeasureSpec encapsulates the layout requirements passed from parent to child.
24287 * Each MeasureSpec represents a requirement for either the width or the height.
24288 * A MeasureSpec is comprised of a size and a mode. There are three possible
24291 * <dt>UNSPECIFIED</dt>
24293 * The parent has not imposed any constraint on the child. It can be whatever size
24299 * The parent has determined an exact size for the child. The child is going to be
24300 * given those bounds regardless of how big it wants to be.
24305 * The child can be as large as it wants up to the specified size.
24309 * MeasureSpecs are implemented as ints to reduce object allocation. This class
24310 * is provided to pack and unpack the <size, mode> tuple into the int.
24312 public static class MeasureSpec {
24313 private static final int MODE_SHIFT = 30;
24314 private static final int MODE_MASK = 0x3 << MODE_SHIFT;
24317 @IntDef({UNSPECIFIED, EXACTLY, AT_MOST})
24318 @Retention(RetentionPolicy.SOURCE)
24319 public @interface MeasureSpecMode {}
24322 * Measure specification mode: The parent has not imposed any constraint
24323 * on the child. It can be whatever size it wants.
24325 public static final int UNSPECIFIED = 0 << MODE_SHIFT;
24328 * Measure specification mode: The parent has determined an exact size
24329 * for the child. The child is going to be given those bounds regardless
24330 * of how big it wants to be.
24332 public static final int EXACTLY = 1 << MODE_SHIFT;
24335 * Measure specification mode: The child can be as large as it wants up
24336 * to the specified size.
24338 public static final int AT_MOST = 2 << MODE_SHIFT;
24341 * Creates a measure specification based on the supplied size and mode.
24343 * The mode must always be one of the following:
24345 * <li>{@link android.view.View.MeasureSpec#UNSPECIFIED}</li>
24346 * <li>{@link android.view.View.MeasureSpec#EXACTLY}</li>
24347 * <li>{@link android.view.View.MeasureSpec#AT_MOST}</li>
24350 * <p><strong>Note:</strong> On API level 17 and lower, makeMeasureSpec's
24351 * implementation was such that the order of arguments did not matter
24352 * and overflow in either value could impact the resulting MeasureSpec.
24353 * {@link android.widget.RelativeLayout} was affected by this bug.
24354 * Apps targeting API levels greater than 17 will get the fixed, more strict
24357 * @param size the size of the measure specification
24358 * @param mode the mode of the measure specification
24359 * @return the measure specification based on size and mode
24361 public static int makeMeasureSpec(@IntRange(from = 0, to = (1 << MeasureSpec.MODE_SHIFT) - 1) int size,
24362 @MeasureSpecMode int mode) {
24363 if (sUseBrokenMakeMeasureSpec) {
24364 return size + mode;
24366 return (size & ~MODE_MASK) | (mode & MODE_MASK);
24371 * Like {@link #makeMeasureSpec(int, int)}, but any spec with a mode of UNSPECIFIED
24372 * will automatically get a size of 0. Older apps expect this.
24374 * @hide internal use only for compatibility with system widgets and older apps
24376 public static int makeSafeMeasureSpec(int size, int mode) {
24377 if (sUseZeroUnspecifiedMeasureSpec && mode == UNSPECIFIED) {
24380 return makeMeasureSpec(size, mode);
24384 * Extracts the mode from the supplied measure specification.
24386 * @param measureSpec the measure specification to extract the mode from
24387 * @return {@link android.view.View.MeasureSpec#UNSPECIFIED},
24388 * {@link android.view.View.MeasureSpec#AT_MOST} or
24389 * {@link android.view.View.MeasureSpec#EXACTLY}
24392 public static int getMode(int measureSpec) {
24393 //noinspection ResourceType
24394 return (measureSpec & MODE_MASK);
24398 * Extracts the size from the supplied measure specification.
24400 * @param measureSpec the measure specification to extract the size from
24401 * @return the size in pixels defined in the supplied measure specification
24403 public static int getSize(int measureSpec) {
24404 return (measureSpec & ~MODE_MASK);
24407 static int adjust(int measureSpec, int delta) {
24408 final int mode = getMode(measureSpec);
24409 int size = getSize(measureSpec);
24410 if (mode == UNSPECIFIED) {
24411 // No need to adjust size for UNSPECIFIED mode.
24412 return makeMeasureSpec(size, UNSPECIFIED);
24416 Log.e(VIEW_LOG_TAG, "MeasureSpec.adjust: new size would be negative! (" + size +
24417 ") spec: " + toString(measureSpec) + " delta: " + delta);
24420 return makeMeasureSpec(size, mode);
24424 * Returns a String representation of the specified measure
24427 * @param measureSpec the measure specification to convert to a String
24428 * @return a String with the following format: "MeasureSpec: MODE SIZE"
24430 public static String toString(int measureSpec) {
24431 int mode = getMode(measureSpec);
24432 int size = getSize(measureSpec);
24434 StringBuilder sb = new StringBuilder("MeasureSpec: ");
24436 if (mode == UNSPECIFIED)
24437 sb.append("UNSPECIFIED ");
24438 else if (mode == EXACTLY)
24439 sb.append("EXACTLY ");
24440 else if (mode == AT_MOST)
24441 sb.append("AT_MOST ");
24443 sb.append(mode).append(" ");
24446 return sb.toString();
24450 private final class CheckForLongPress implements Runnable {
24451 private int mOriginalWindowAttachCount;
24454 private boolean mOriginalPressedState;
24457 public void run() {
24458 if ((mOriginalPressedState == isPressed()) && (mParent != null)
24459 && mOriginalWindowAttachCount == mWindowAttachCount) {
24460 if (performLongClick(mX, mY)) {
24461 mHasPerformedLongPress = true;
24466 public void setAnchor(float x, float y) {
24471 public void rememberWindowAttachCount() {
24472 mOriginalWindowAttachCount = mWindowAttachCount;
24475 public void rememberPressedState() {
24476 mOriginalPressedState = isPressed();
24480 private final class CheckForTap implements Runnable {
24485 public void run() {
24486 mPrivateFlags &= ~PFLAG_PREPRESSED;
24487 setPressed(true, x, y);
24488 checkForLongClick(ViewConfiguration.getTapTimeout(), x, y);
24492 private final class PerformClick implements Runnable {
24494 public void run() {
24500 * This method returns a ViewPropertyAnimator object, which can be used to animate
24501 * specific properties on this View.
24503 * @return ViewPropertyAnimator The ViewPropertyAnimator associated with this View.
24505 public ViewPropertyAnimator animate() {
24506 if (mAnimator == null) {
24507 mAnimator = new ViewPropertyAnimator(this);
24513 * Sets the name of the View to be used to identify Views in Transitions.
24514 * Names should be unique in the View hierarchy.
24516 * @param transitionName The name of the View to uniquely identify it for Transitions.
24518 public final void setTransitionName(String transitionName) {
24519 mTransitionName = transitionName;
24523 * Returns the name of the View to be used to identify Views in Transitions.
24524 * Names should be unique in the View hierarchy.
24526 * <p>This returns null if the View has not been given a name.</p>
24528 * @return The name used of the View to be used to identify Views in Transitions or null
24529 * if no name has been given.
24531 @ViewDebug.ExportedProperty
24532 public String getTransitionName() {
24533 return mTransitionName;
24539 public void requestKeyboardShortcuts(List<KeyboardShortcutGroup> data, int deviceId) {
24544 * Interface definition for a callback to be invoked when a hardware key event is
24545 * dispatched to this view. The callback will be invoked before the key event is
24546 * given to the view. This is only useful for hardware keyboards; a software input
24547 * method has no obligation to trigger this listener.
24549 public interface OnKeyListener {
24551 * Called when a hardware key is dispatched to a view. This allows listeners to
24552 * get a chance to respond before the target view.
24553 * <p>Key presses in software keyboards will generally NOT trigger this method,
24554 * although some may elect to do so in some situations. Do not assume a
24555 * software input method has to be key-based; even if it is, it may use key presses
24556 * in a different way than you expect, so there is no way to reliably catch soft
24557 * input key presses.
24559 * @param v The view the key has been dispatched to.
24560 * @param keyCode The code for the physical key that was pressed
24561 * @param event The KeyEvent object containing full information about
24563 * @return True if the listener has consumed the event, false otherwise.
24565 boolean onKey(View v, int keyCode, KeyEvent event);
24569 * Interface definition for a callback to be invoked when a touch event is
24570 * dispatched to this view. The callback will be invoked before the touch
24571 * event is given to the view.
24573 public interface OnTouchListener {
24575 * Called when a touch event is dispatched to a view. This allows listeners to
24576 * get a chance to respond before the target view.
24578 * @param v The view the touch event has been dispatched to.
24579 * @param event The MotionEvent object containing full information about
24581 * @return True if the listener has consumed the event, false otherwise.
24583 boolean onTouch(View v, MotionEvent event);
24587 * Interface definition for a callback to be invoked when a hover event is
24588 * dispatched to this view. The callback will be invoked before the hover
24589 * event is given to the view.
24591 public interface OnHoverListener {
24593 * Called when a hover event is dispatched to a view. This allows listeners to
24594 * get a chance to respond before the target view.
24596 * @param v The view the hover event has been dispatched to.
24597 * @param event The MotionEvent object containing full information about
24599 * @return True if the listener has consumed the event, false otherwise.
24601 boolean onHover(View v, MotionEvent event);
24605 * Interface definition for a callback to be invoked when a generic motion event is
24606 * dispatched to this view. The callback will be invoked before the generic motion
24607 * event is given to the view.
24609 public interface OnGenericMotionListener {
24611 * Called when a generic motion event is dispatched to a view. This allows listeners to
24612 * get a chance to respond before the target view.
24614 * @param v The view the generic motion event has been dispatched to.
24615 * @param event The MotionEvent object containing full information about
24617 * @return True if the listener has consumed the event, false otherwise.
24619 boolean onGenericMotion(View v, MotionEvent event);
24623 * Interface definition for a callback to be invoked when a view has been clicked and held.
24625 public interface OnLongClickListener {
24627 * Called when a view has been clicked and held.
24629 * @param v The view that was clicked and held.
24631 * @return true if the callback consumed the long click, false otherwise.
24633 boolean onLongClick(View v);
24637 * Interface definition for a callback to be invoked when a drag is being dispatched
24638 * to this view. The callback will be invoked before the hosting view's own
24639 * onDrag(event) method. If the listener wants to fall back to the hosting view's
24640 * onDrag(event) behavior, it should return 'false' from this callback.
24642 * <div class="special reference">
24643 * <h3>Developer Guides</h3>
24644 * <p>For a guide to implementing drag and drop features, read the
24645 * <a href="{@docRoot}guide/topics/ui/drag-drop.html">Drag and Drop</a> developer guide.</p>
24648 public interface OnDragListener {
24650 * Called when a drag event is dispatched to a view. This allows listeners
24651 * to get a chance to override base View behavior.
24653 * @param v The View that received the drag event.
24654 * @param event The {@link android.view.DragEvent} object for the drag event.
24655 * @return {@code true} if the drag event was handled successfully, or {@code false}
24656 * if the drag event was not handled. Note that {@code false} will trigger the View
24657 * to call its {@link #onDragEvent(DragEvent) onDragEvent()} handler.
24659 boolean onDrag(View v, DragEvent event);
24663 * Interface definition for a callback to be invoked when the focus state of
24666 public interface OnFocusChangeListener {
24668 * Called when the focus state of a view has changed.
24670 * @param v The view whose state has changed.
24671 * @param hasFocus The new focus state of v.
24673 void onFocusChange(View v, boolean hasFocus);
24677 * Interface definition for a callback to be invoked when a view is clicked.
24679 public interface OnClickListener {
24681 * Called when a view has been clicked.
24683 * @param v The view that was clicked.
24685 void onClick(View v);
24689 * Interface definition for a callback to be invoked when a view is context clicked.
24691 public interface OnContextClickListener {
24693 * Called when a view is context clicked.
24695 * @param v The view that has been context clicked.
24696 * @return true if the callback consumed the context click, false otherwise.
24698 boolean onContextClick(View v);
24702 * Interface definition for a callback to be invoked when the context menu
24703 * for this view is being built.
24705 public interface OnCreateContextMenuListener {
24707 * Called when the context menu for this view is being built. It is not
24708 * safe to hold onto the menu after this method returns.
24710 * @param menu The context menu that is being built
24711 * @param v The view for which the context menu is being built
24712 * @param menuInfo Extra information about the item for which the
24713 * context menu should be shown. This information will vary
24714 * depending on the class of v.
24716 void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo);
24720 * Interface definition for a callback to be invoked when the status bar changes
24721 * visibility. This reports <strong>global</strong> changes to the system UI
24722 * state, not what the application is requesting.
24724 * @see View#setOnSystemUiVisibilityChangeListener(android.view.View.OnSystemUiVisibilityChangeListener)
24726 public interface OnSystemUiVisibilityChangeListener {
24728 * Called when the status bar changes visibility because of a call to
24729 * {@link View#setSystemUiVisibility(int)}.
24731 * @param visibility Bitwise-or of flags {@link #SYSTEM_UI_FLAG_LOW_PROFILE},
24732 * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, and {@link #SYSTEM_UI_FLAG_FULLSCREEN}.
24733 * This tells you the <strong>global</strong> state of these UI visibility
24734 * flags, not what your app is currently applying.
24736 public void onSystemUiVisibilityChange(int visibility);
24740 * Interface definition for a callback to be invoked when this view is attached
24741 * or detached from its window.
24743 public interface OnAttachStateChangeListener {
24745 * Called when the view is attached to a window.
24746 * @param v The view that was attached
24748 public void onViewAttachedToWindow(View v);
24750 * Called when the view is detached from a window.
24751 * @param v The view that was detached
24753 public void onViewDetachedFromWindow(View v);
24757 * Listener for applying window insets on a view in a custom way.
24759 * <p>Apps may choose to implement this interface if they want to apply custom policy
24760 * to the way that window insets are treated for a view. If an OnApplyWindowInsetsListener
24762 * {@link OnApplyWindowInsetsListener#onApplyWindowInsets(View, WindowInsets) onApplyWindowInsets}
24763 * method will be called instead of the View's own
24764 * {@link #onApplyWindowInsets(WindowInsets) onApplyWindowInsets} method. The listener
24765 * may optionally call the parameter View's <code>onApplyWindowInsets</code> method to apply
24766 * the View's normal behavior as part of its own.</p>
24768 public interface OnApplyWindowInsetsListener {
24770 * When {@link View#setOnApplyWindowInsetsListener(View.OnApplyWindowInsetsListener) set}
24771 * on a View, this listener method will be called instead of the view's own
24772 * {@link View#onApplyWindowInsets(WindowInsets) onApplyWindowInsets} method.
24774 * @param v The view applying window insets
24775 * @param insets The insets to apply
24776 * @return The insets supplied, minus any insets that were consumed
24778 public WindowInsets onApplyWindowInsets(View v, WindowInsets insets);
24781 private final class UnsetPressedState implements Runnable {
24783 public void run() {
24789 * When a view becomes invisible checks if autofill considers the view invisible too. This
24790 * happens after the regular removal operation to make sure the operation is finished by the
24791 * time this is called.
24793 private static class VisibilityChangeForAutofillHandler extends Handler {
24794 private final AutofillManager mAfm;
24795 private final View mView;
24797 private VisibilityChangeForAutofillHandler(@NonNull AutofillManager afm,
24798 @NonNull View view) {
24804 public void handleMessage(Message msg) {
24805 mAfm.notifyViewVisibilityChange(mView, mView.isShown());
24810 * Base class for derived classes that want to save and restore their own
24811 * state in {@link android.view.View#onSaveInstanceState()}.
24813 public static class BaseSavedState extends AbsSavedState {
24814 static final int START_ACTIVITY_REQUESTED_WHO_SAVED = 0b1;
24815 static final int IS_AUTOFILLED = 0b10;
24816 static final int ACCESSIBILITY_ID = 0b100;
24818 // Flags that describe what data in this state is valid
24820 String mStartActivityRequestWhoSaved;
24821 boolean mIsAutofilled;
24822 int mAccessibilityViewId;
24825 * Constructor used when reading from a parcel. Reads the state of the superclass.
24827 * @param source parcel to read from
24829 public BaseSavedState(Parcel source) {
24830 this(source, null);
24834 * Constructor used when reading from a parcel using a given class loader.
24835 * Reads the state of the superclass.
24837 * @param source parcel to read from
24838 * @param loader ClassLoader to use for reading
24840 public BaseSavedState(Parcel source, ClassLoader loader) {
24841 super(source, loader);
24842 mSavedData = source.readInt();
24843 mStartActivityRequestWhoSaved = source.readString();
24844 mIsAutofilled = source.readBoolean();
24845 mAccessibilityViewId = source.readInt();
24849 * Constructor called by derived classes when creating their SavedState objects
24851 * @param superState The state of the superclass of this view
24853 public BaseSavedState(Parcelable superState) {
24858 public void writeToParcel(Parcel out, int flags) {
24859 super.writeToParcel(out, flags);
24861 out.writeInt(mSavedData);
24862 out.writeString(mStartActivityRequestWhoSaved);
24863 out.writeBoolean(mIsAutofilled);
24864 out.writeInt(mAccessibilityViewId);
24867 public static final Parcelable.Creator<BaseSavedState> CREATOR
24868 = new Parcelable.ClassLoaderCreator<BaseSavedState>() {
24870 public BaseSavedState createFromParcel(Parcel in) {
24871 return new BaseSavedState(in);
24875 public BaseSavedState createFromParcel(Parcel in, ClassLoader loader) {
24876 return new BaseSavedState(in, loader);
24880 public BaseSavedState[] newArray(int size) {
24881 return new BaseSavedState[size];
24887 * A set of information given to a view when it is attached to its parent
24890 final static class AttachInfo {
24891 interface Callbacks {
24892 void playSoundEffect(int effectId);
24893 boolean performHapticFeedback(int effectId, boolean always);
24897 * InvalidateInfo is used to post invalidate(int, int, int, int) messages
24898 * to a Handler. This class contains the target (View) to invalidate and
24899 * the coordinates of the dirty rectangle.
24901 * For performance purposes, this class also implements a pool of up to
24902 * POOL_LIMIT objects that get reused. This reduces memory allocations
24903 * whenever possible.
24905 static class InvalidateInfo {
24906 private static final int POOL_LIMIT = 10;
24908 private static final SynchronizedPool<InvalidateInfo> sPool =
24909 new SynchronizedPool<InvalidateInfo>(POOL_LIMIT);
24918 public static InvalidateInfo obtain() {
24919 InvalidateInfo instance = sPool.acquire();
24920 return (instance != null) ? instance : new InvalidateInfo();
24923 public void recycle() {
24925 sPool.release(this);
24929 final IWindowSession mSession;
24931 final IWindow mWindow;
24933 final IBinder mWindowToken;
24937 final Callbacks mRootCallbacks;
24939 IWindowId mIWindowId;
24940 WindowId mWindowId;
24943 * The top view of the hierarchy.
24947 IBinder mPanelParentWindowToken;
24949 boolean mHardwareAccelerated;
24950 boolean mHardwareAccelerationRequested;
24951 ThreadedRenderer mThreadedRenderer;
24952 List<RenderNode> mPendingAnimatingRenderNodes;
24955 * The state of the display to which the window is attached, as reported
24956 * by {@link Display#getState()}. Note that the display state constants
24957 * declared by {@link Display} do not exactly line up with the screen state
24958 * constants declared by {@link View} (there are more display states than
24961 int mDisplayState = Display.STATE_UNKNOWN;
24964 * Scale factor used by the compatibility mode
24966 float mApplicationScale;
24969 * Indicates whether the application is in compatibility mode
24971 boolean mScalingRequired;
24974 * Left position of this view's window
24979 * Top position of this view's window
24984 * Indicates whether views need to use 32-bit drawing caches
24986 boolean mUse32BitDrawingCache;
24989 * For windows that are full-screen but using insets to layout inside
24990 * of the screen areas, these are the current insets to appear inside
24991 * the overscan area of the display.
24993 final Rect mOverscanInsets = new Rect();
24996 * For windows that are full-screen but using insets to layout inside
24997 * of the screen decorations, these are the current insets for the
24998 * content of the window.
25000 final Rect mContentInsets = new Rect();
25003 * For windows that are full-screen but using insets to layout inside
25004 * of the screen decorations, these are the current insets for the
25005 * actual visible parts of the window.
25007 final Rect mVisibleInsets = new Rect();
25010 * For windows that are full-screen but using insets to layout inside
25011 * of the screen decorations, these are the current insets for the
25012 * stable system windows.
25014 final Rect mStableInsets = new Rect();
25017 * For windows that include areas that are not covered by real surface these are the outsets
25018 * for real surface.
25020 final Rect mOutsets = new Rect();
25023 * In multi-window we force show the navigation bar. Because we don't want that the surface
25024 * size changes in this mode, we instead have a flag whether the navigation bar size should
25025 * always be consumed, so the app is treated like there is no virtual navigation bar at all.
25027 boolean mAlwaysConsumeNavBar;
25030 * The internal insets given by this window. This value is
25031 * supplied by the client (through
25032 * {@link ViewTreeObserver.OnComputeInternalInsetsListener}) and will
25033 * be given to the window manager when changed to be used in laying
25034 * out windows behind it.
25036 final ViewTreeObserver.InternalInsetsInfo mGivenInternalInsets
25037 = new ViewTreeObserver.InternalInsetsInfo();
25040 * Set to true when mGivenInternalInsets is non-empty.
25042 boolean mHasNonEmptyGivenInternalInsets;
25045 * All views in the window's hierarchy that serve as scroll containers,
25046 * used to determine if the window can be resized or must be panned
25047 * to adjust for a soft input area.
25049 final ArrayList<View> mScrollContainers = new ArrayList<View>();
25051 final KeyEvent.DispatcherState mKeyDispatchState
25052 = new KeyEvent.DispatcherState();
25055 * Indicates whether the view's window currently has the focus.
25057 boolean mHasWindowFocus;
25060 * The current visibility of the window.
25062 int mWindowVisibility;
25065 * Indicates the time at which drawing started to occur.
25070 * Indicates whether or not ignoring the DIRTY_MASK flags.
25072 boolean mIgnoreDirtyState;
25075 * This flag tracks when the mIgnoreDirtyState flag is set during draw(),
25076 * to avoid clearing that flag prematurely.
25078 boolean mSetIgnoreDirtyState = false;
25081 * Indicates whether the view's window is currently in touch mode.
25083 boolean mInTouchMode;
25086 * Indicates whether the view has requested unbuffered input dispatching for the current
25089 boolean mUnbufferedDispatchRequested;
25092 * Indicates that ViewAncestor should trigger a global layout change
25093 * the next time it performs a traversal
25095 boolean mRecomputeGlobalAttributes;
25098 * Always report new attributes at next traversal.
25100 boolean mForceReportNewAttributes;
25103 * Set during a traveral if any views want to keep the screen on.
25105 boolean mKeepScreenOn;
25108 * Set during a traveral if the light center needs to be updated.
25110 boolean mNeedsUpdateLightCenter;
25113 * Bitwise-or of all of the values that views have passed to setSystemUiVisibility().
25115 int mSystemUiVisibility;
25118 * Hack to force certain system UI visibility flags to be cleared.
25120 int mDisabledSystemUiVisibility;
25123 * Last global system UI visibility reported by the window manager.
25125 int mGlobalSystemUiVisibility = -1;
25128 * True if a view in this hierarchy has an OnSystemUiVisibilityChangeListener
25131 boolean mHasSystemUiListeners;
25134 * Set if the window has requested to extend into the overscan region
25135 * via WindowManager.LayoutParams.FLAG_LAYOUT_IN_OVERSCAN.
25137 boolean mOverscanRequested;
25140 * Set if the visibility of any views has changed.
25142 boolean mViewVisibilityChanged;
25145 * Set to true if a view has been scrolled.
25147 boolean mViewScrollChanged;
25150 * Set to true if high contrast mode enabled
25152 boolean mHighContrastText;
25155 * Set to true if a pointer event is currently being handled.
25157 boolean mHandlingPointerEvent;
25160 * Global to the view hierarchy used as a temporary for dealing with
25161 * x/y points in the transparent region computations.
25163 final int[] mTransparentLocation = new int[2];
25166 * Global to the view hierarchy used as a temporary for dealing with
25167 * x/y points in the ViewGroup.invalidateChild implementation.
25169 final int[] mInvalidateChildLocation = new int[2];
25172 * Global to the view hierarchy used as a temporary for dealing with
25173 * computing absolute on-screen location.
25175 final int[] mTmpLocation = new int[2];
25178 * Global to the view hierarchy used as a temporary for dealing with
25179 * x/y location when view is transformed.
25181 final float[] mTmpTransformLocation = new float[2];
25184 * The view tree observer used to dispatch global events like
25185 * layout, pre-draw, touch mode change, etc.
25187 final ViewTreeObserver mTreeObserver;
25190 * A Canvas used by the view hierarchy to perform bitmap caching.
25195 * The view root impl.
25197 final ViewRootImpl mViewRootImpl;
25200 * A Handler supplied by a view's {@link android.view.ViewRootImpl}. This
25201 * handler can be used to pump events in the UI events queue.
25203 final Handler mHandler;
25206 * Temporary for use in computing invalidate rectangles while
25207 * calling up the hierarchy.
25209 final Rect mTmpInvalRect = new Rect();
25212 * Temporary for use in computing hit areas with transformed views
25214 final RectF mTmpTransformRect = new RectF();
25217 * Temporary for use in computing hit areas with transformed views
25219 final RectF mTmpTransformRect1 = new RectF();
25222 * Temporary list of rectanges.
25224 final List<RectF> mTmpRectList = new ArrayList<>();
25227 * Temporary for use in transforming invalidation rect
25229 final Matrix mTmpMatrix = new Matrix();
25232 * Temporary for use in transforming invalidation rect
25234 final Transformation mTmpTransformation = new Transformation();
25237 * Temporary for use in querying outlines from OutlineProviders
25239 final Outline mTmpOutline = new Outline();
25242 * Temporary list for use in collecting focusable descendents of a view.
25244 final ArrayList<View> mTempArrayList = new ArrayList<View>(24);
25247 * The id of the window for accessibility purposes.
25249 int mAccessibilityWindowId = AccessibilityWindowInfo.UNDEFINED_WINDOW_ID;
25252 * Flags related to accessibility processing.
25254 * @see AccessibilityNodeInfo#FLAG_INCLUDE_NOT_IMPORTANT_VIEWS
25255 * @see AccessibilityNodeInfo#FLAG_REPORT_VIEW_IDS
25257 int mAccessibilityFetchFlags;
25260 * The drawable for highlighting accessibility focus.
25262 Drawable mAccessibilityFocusDrawable;
25265 * The drawable for highlighting autofilled views.
25267 * @see #isAutofilled()
25269 Drawable mAutofilledDrawable;
25272 * Show where the margins, bounds and layout bounds are for each view.
25274 boolean mDebugLayout = SystemProperties.getBoolean(DEBUG_LAYOUT_PROPERTY, false);
25277 * Point used to compute visible regions.
25279 final Point mPoint = new Point();
25282 * Used to track which View originated a requestLayout() call, used when
25283 * requestLayout() is called during layout.
25285 View mViewRequestingLayout;
25288 * Used to track views that need (at least) a partial relayout at their current size
25289 * during the next traversal.
25291 List<View> mPartialLayoutViews = new ArrayList<>();
25294 * Swapped with mPartialLayoutViews during layout to avoid concurrent
25295 * modification. Lazily assigned during ViewRootImpl layout.
25297 List<View> mEmptyPartialLayoutViews;
25300 * Used to track the identity of the current drag operation.
25302 IBinder mDragToken;
25305 * The drag shadow surface for the current drag operation.
25307 public Surface mDragSurface;
25311 * The view that currently has a tooltip displayed.
25316 * Creates a new set of attachment information with the specified
25317 * events handler and thread.
25319 * @param handler the events handler the view must use
25321 AttachInfo(IWindowSession session, IWindow window, Display display,
25322 ViewRootImpl viewRootImpl, Handler handler, Callbacks effectPlayer,
25324 mSession = session;
25326 mWindowToken = window.asBinder();
25327 mDisplay = display;
25328 mViewRootImpl = viewRootImpl;
25329 mHandler = handler;
25330 mRootCallbacks = effectPlayer;
25331 mTreeObserver = new ViewTreeObserver(context);
25336 * <p>ScrollabilityCache holds various fields used by a View when scrolling
25337 * is supported. This avoids keeping too many unused fields in most
25338 * instances of View.</p>
25340 private static class ScrollabilityCache implements Runnable {
25343 * Scrollbars are not visible
25345 public static final int OFF = 0;
25348 * Scrollbars are visible
25350 public static final int ON = 1;
25353 * Scrollbars are fading away
25355 public static final int FADING = 2;
25357 public boolean fadeScrollBars;
25359 public int fadingEdgeLength;
25360 public int scrollBarDefaultDelayBeforeFade;
25361 public int scrollBarFadeDuration;
25363 public int scrollBarSize;
25364 public int scrollBarMinTouchTarget;
25365 public ScrollBarDrawable scrollBar;
25366 public float[] interpolatorValues;
25369 public final Paint paint;
25370 public final Matrix matrix;
25371 public Shader shader;
25373 public final Interpolator scrollBarInterpolator = new Interpolator(1, 2);
25375 private static final float[] OPAQUE = { 255 };
25376 private static final float[] TRANSPARENT = { 0.0f };
25379 * When fading should start. This time moves into the future every time
25380 * a new scroll happens. Measured based on SystemClock.uptimeMillis()
25382 public long fadeStartTime;
25386 * The current state of the scrollbars: ON, OFF, or FADING
25388 public int state = OFF;
25390 private int mLastColor;
25392 public final Rect mScrollBarBounds = new Rect();
25393 public final Rect mScrollBarTouchBounds = new Rect();
25395 public static final int NOT_DRAGGING = 0;
25396 public static final int DRAGGING_VERTICAL_SCROLL_BAR = 1;
25397 public static final int DRAGGING_HORIZONTAL_SCROLL_BAR = 2;
25398 public int mScrollBarDraggingState = NOT_DRAGGING;
25400 public float mScrollBarDraggingPos = 0;
25402 public ScrollabilityCache(ViewConfiguration configuration, View host) {
25403 fadingEdgeLength = configuration.getScaledFadingEdgeLength();
25404 scrollBarSize = configuration.getScaledScrollBarSize();
25405 scrollBarMinTouchTarget = configuration.getScaledMinScrollbarTouchTarget();
25406 scrollBarDefaultDelayBeforeFade = ViewConfiguration.getScrollDefaultDelay();
25407 scrollBarFadeDuration = ViewConfiguration.getScrollBarFadeDuration();
25409 paint = new Paint();
25410 matrix = new Matrix();
25411 // use use a height of 1, and then wack the matrix each time we
25412 // actually use it.
25413 shader = new LinearGradient(0, 0, 0, 1, 0xFF000000, 0, Shader.TileMode.CLAMP);
25414 paint.setShader(shader);
25415 paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT));
25420 public void setFadeColor(int color) {
25421 if (color != mLastColor) {
25422 mLastColor = color;
25425 shader = new LinearGradient(0, 0, 0, 1, color | 0xFF000000,
25426 color & 0x00FFFFFF, Shader.TileMode.CLAMP);
25427 paint.setShader(shader);
25428 // Restore the default transfer mode (src_over)
25429 paint.setXfermode(null);
25431 shader = new LinearGradient(0, 0, 0, 1, 0xFF000000, 0, Shader.TileMode.CLAMP);
25432 paint.setShader(shader);
25433 paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT));
25438 public void run() {
25439 long now = AnimationUtils.currentAnimationTimeMillis();
25440 if (now >= fadeStartTime) {
25442 // the animation fades the scrollbars out by changing
25443 // the opacity (alpha) from fully opaque to fully
25445 int nextFrame = (int) now;
25446 int framesCount = 0;
25448 Interpolator interpolator = scrollBarInterpolator;
25451 interpolator.setKeyFrame(framesCount++, nextFrame, OPAQUE);
25454 nextFrame += scrollBarFadeDuration;
25455 interpolator.setKeyFrame(framesCount, nextFrame, TRANSPARENT);
25459 // Kick off the fade animation
25460 host.invalidate(true);
25466 * Resuable callback for sending
25467 * {@link AccessibilityEvent#TYPE_VIEW_SCROLLED} accessibility event.
25469 private class SendViewScrolledAccessibilityEvent implements Runnable {
25470 public volatile boolean mIsPending;
25472 public void run() {
25473 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SCROLLED);
25474 mIsPending = false;
25480 * This class represents a delegate that can be registered in a {@link View}
25481 * to enhance accessibility support via composition rather via inheritance.
25482 * It is specifically targeted to widget developers that extend basic View
25483 * classes i.e. classes in package android.view, that would like their
25484 * applications to be backwards compatible.
25486 * <div class="special reference">
25487 * <h3>Developer Guides</h3>
25488 * <p>For more information about making applications accessible, read the
25489 * <a href="{@docRoot}guide/topics/ui/accessibility/index.html">Accessibility</a>
25490 * developer guide.</p>
25493 * A scenario in which a developer would like to use an accessibility delegate
25494 * is overriding a method introduced in a later API version than the minimal API
25495 * version supported by the application. For example, the method
25496 * {@link View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)} is not available
25497 * in API version 4 when the accessibility APIs were first introduced. If a
25498 * developer would like his application to run on API version 4 devices (assuming
25499 * all other APIs used by the application are version 4 or lower) and take advantage
25500 * of this method, instead of overriding the method which would break the application's
25501 * backwards compatibility, he can override the corresponding method in this
25502 * delegate and register the delegate in the target View if the API version of
25503 * the system is high enough, i.e. the API version is the same as or higher than the API
25504 * version that introduced
25505 * {@link View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)}.
25508 * Here is an example implementation:
25511 * if (Build.VERSION.SDK_INT >= 14) {
25512 * // If the API version is equal of higher than the version in
25513 * // which onInitializeAccessibilityNodeInfo was introduced we
25514 * // register a delegate with a customized implementation.
25515 * View view = findViewById(R.id.view_id);
25516 * view.setAccessibilityDelegate(new AccessibilityDelegate() {
25517 * public void onInitializeAccessibilityNodeInfo(View host,
25518 * AccessibilityNodeInfo info) {
25519 * // Let the default implementation populate the info.
25520 * super.onInitializeAccessibilityNodeInfo(host, info);
25521 * // Set some other information.
25522 * info.setEnabled(host.isEnabled());
25526 * </code></pre></p>
25528 * This delegate contains methods that correspond to the accessibility methods
25529 * in View. If a delegate has been specified the implementation in View hands
25530 * off handling to the corresponding method in this delegate. The default
25531 * implementation the delegate methods behaves exactly as the corresponding
25532 * method in View for the case of no accessibility delegate been set. Hence,
25533 * to customize the behavior of a View method, clients can override only the
25534 * corresponding delegate method without altering the behavior of the rest
25535 * accessibility related methods of the host view.
25538 * <strong>Note:</strong> On platform versions prior to
25539 * {@link android.os.Build.VERSION_CODES#M API 23}, delegate methods on
25540 * views in the {@code android.widget.*} package are called <i>before</i>
25541 * host methods. This prevents certain properties such as class name from
25542 * being modified by overriding
25543 * {@link AccessibilityDelegate#onInitializeAccessibilityNodeInfo(View, AccessibilityNodeInfo)},
25544 * as any changes will be overwritten by the host class.
25546 * Starting in {@link android.os.Build.VERSION_CODES#M API 23}, delegate
25547 * methods are called <i>after</i> host methods, which all properties to be
25548 * modified without being overwritten by the host class.
25550 public static class AccessibilityDelegate {
25553 * Sends an accessibility event of the given type. If accessibility is not
25554 * enabled this method has no effect.
25556 * The default implementation behaves as {@link View#sendAccessibilityEvent(int)
25557 * View#sendAccessibilityEvent(int)} for the case of no accessibility delegate
25561 * @param host The View hosting the delegate.
25562 * @param eventType The type of the event to send.
25564 * @see View#sendAccessibilityEvent(int) View#sendAccessibilityEvent(int)
25566 public void sendAccessibilityEvent(View host, int eventType) {
25567 host.sendAccessibilityEventInternal(eventType);
25571 * Performs the specified accessibility action on the view. For
25572 * possible accessibility actions look at {@link AccessibilityNodeInfo}.
25574 * The default implementation behaves as
25575 * {@link View#performAccessibilityAction(int, Bundle)
25576 * View#performAccessibilityAction(int, Bundle)} for the case of
25577 * no accessibility delegate been set.
25580 * @param action The action to perform.
25581 * @return Whether the action was performed.
25583 * @see View#performAccessibilityAction(int, Bundle)
25584 * View#performAccessibilityAction(int, Bundle)
25586 public boolean performAccessibilityAction(View host, int action, Bundle args) {
25587 return host.performAccessibilityActionInternal(action, args);
25591 * Sends an accessibility event. This method behaves exactly as
25592 * {@link #sendAccessibilityEvent(View, int)} but takes as an argument an
25593 * empty {@link AccessibilityEvent} and does not perform a check whether
25594 * accessibility is enabled.
25596 * The default implementation behaves as
25597 * {@link View#sendAccessibilityEventUnchecked(AccessibilityEvent)
25598 * View#sendAccessibilityEventUnchecked(AccessibilityEvent)} for
25599 * the case of no accessibility delegate been set.
25602 * @param host The View hosting the delegate.
25603 * @param event The event to send.
25605 * @see View#sendAccessibilityEventUnchecked(AccessibilityEvent)
25606 * View#sendAccessibilityEventUnchecked(AccessibilityEvent)
25608 public void sendAccessibilityEventUnchecked(View host, AccessibilityEvent event) {
25609 host.sendAccessibilityEventUncheckedInternal(event);
25613 * Dispatches an {@link AccessibilityEvent} to the host {@link View} first and then
25614 * to its children for adding their text content to the event.
25616 * The default implementation behaves as
25617 * {@link View#dispatchPopulateAccessibilityEvent(AccessibilityEvent)
25618 * View#dispatchPopulateAccessibilityEvent(AccessibilityEvent)} for
25619 * the case of no accessibility delegate been set.
25622 * @param host The View hosting the delegate.
25623 * @param event The event.
25624 * @return True if the event population was completed.
25626 * @see View#dispatchPopulateAccessibilityEvent(AccessibilityEvent)
25627 * View#dispatchPopulateAccessibilityEvent(AccessibilityEvent)
25629 public boolean dispatchPopulateAccessibilityEvent(View host, AccessibilityEvent event) {
25630 return host.dispatchPopulateAccessibilityEventInternal(event);
25634 * Gives a chance to the host View to populate the accessibility event with its
25637 * The default implementation behaves as
25638 * {@link View#onPopulateAccessibilityEvent(AccessibilityEvent)
25639 * View#onPopulateAccessibilityEvent(AccessibilityEvent)} for
25640 * the case of no accessibility delegate been set.
25643 * @param host The View hosting the delegate.
25644 * @param event The accessibility event which to populate.
25646 * @see View#onPopulateAccessibilityEvent(AccessibilityEvent)
25647 * View#onPopulateAccessibilityEvent(AccessibilityEvent)
25649 public void onPopulateAccessibilityEvent(View host, AccessibilityEvent event) {
25650 host.onPopulateAccessibilityEventInternal(event);
25654 * Initializes an {@link AccessibilityEvent} with information about the
25655 * the host View which is the event source.
25657 * The default implementation behaves as
25658 * {@link View#onInitializeAccessibilityEvent(AccessibilityEvent)
25659 * View#onInitializeAccessibilityEvent(AccessibilityEvent)} for
25660 * the case of no accessibility delegate been set.
25663 * @param host The View hosting the delegate.
25664 * @param event The event to initialize.
25666 * @see View#onInitializeAccessibilityEvent(AccessibilityEvent)
25667 * View#onInitializeAccessibilityEvent(AccessibilityEvent)
25669 public void onInitializeAccessibilityEvent(View host, AccessibilityEvent event) {
25670 host.onInitializeAccessibilityEventInternal(event);
25674 * Initializes an {@link AccessibilityNodeInfo} with information about the host view.
25676 * The default implementation behaves as
25677 * {@link View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)
25678 * View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)} for
25679 * the case of no accessibility delegate been set.
25682 * @param host The View hosting the delegate.
25683 * @param info The instance to initialize.
25685 * @see View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)
25686 * View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)
25688 public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) {
25689 host.onInitializeAccessibilityNodeInfoInternal(info);
25693 * Adds extra data to an {@link AccessibilityNodeInfo} based on an explicit request for the
25696 * This method only needs to be implemented if the View offers to provide additional data.
25699 * The default implementation behaves as
25700 * {@link View#addExtraDataToAccessibilityNodeInfo(AccessibilityNodeInfo, int) for
25701 * the case where no accessibility delegate is set.
25704 * @param host The View hosting the delegate. Never {@code null}.
25705 * @param info The info to which to add the extra data. Never {@code null}.
25706 * @param extraDataKey A key specifying the type of extra data to add to the info. The
25707 * extra data should be added to the {@link Bundle} returned by
25708 * the info's {@link AccessibilityNodeInfo#getExtras} method. Never
25710 * @param arguments A {@link Bundle} holding any arguments relevant for this request.
25711 * May be {@code null} if the if the service provided no arguments.
25713 * @see AccessibilityNodeInfo#setExtraAvailableData
25715 public void addExtraDataToAccessibilityNodeInfo(@NonNull View host,
25716 @NonNull AccessibilityNodeInfo info, @NonNull String extraDataKey,
25717 @Nullable Bundle arguments) {
25718 host.addExtraDataToAccessibilityNodeInfo(info, extraDataKey, arguments);
25722 * Called when a child of the host View has requested sending an
25723 * {@link AccessibilityEvent} and gives an opportunity to the parent (the host)
25724 * to augment the event.
25726 * The default implementation behaves as
25727 * {@link ViewGroup#onRequestSendAccessibilityEvent(View, AccessibilityEvent)
25728 * ViewGroup#onRequestSendAccessibilityEvent(View, AccessibilityEvent)} for
25729 * the case of no accessibility delegate been set.
25732 * @param host The View hosting the delegate.
25733 * @param child The child which requests sending the event.
25734 * @param event The event to be sent.
25735 * @return True if the event should be sent
25737 * @see ViewGroup#onRequestSendAccessibilityEvent(View, AccessibilityEvent)
25738 * ViewGroup#onRequestSendAccessibilityEvent(View, AccessibilityEvent)
25740 public boolean onRequestSendAccessibilityEvent(ViewGroup host, View child,
25741 AccessibilityEvent event) {
25742 return host.onRequestSendAccessibilityEventInternal(child, event);
25746 * Gets the provider for managing a virtual view hierarchy rooted at this View
25747 * and reported to {@link android.accessibilityservice.AccessibilityService}s
25748 * that explore the window content.
25750 * The default implementation behaves as
25751 * {@link View#getAccessibilityNodeProvider() View#getAccessibilityNodeProvider()} for
25752 * the case of no accessibility delegate been set.
25755 * @return The provider.
25757 * @see AccessibilityNodeProvider
25759 public AccessibilityNodeProvider getAccessibilityNodeProvider(View host) {
25764 * Returns an {@link AccessibilityNodeInfo} representing the host view from the
25765 * point of view of an {@link android.accessibilityservice.AccessibilityService}.
25766 * This method is responsible for obtaining an accessibility node info from a
25767 * pool of reusable instances and calling
25768 * {@link #onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)} on the host
25769 * view to initialize the former.
25771 * <strong>Note:</strong> The client is responsible for recycling the obtained
25772 * instance by calling {@link AccessibilityNodeInfo#recycle()} to minimize object
25776 * The default implementation behaves as
25777 * {@link View#createAccessibilityNodeInfo() View#createAccessibilityNodeInfo()} for
25778 * the case of no accessibility delegate been set.
25780 * @return A populated {@link AccessibilityNodeInfo}.
25782 * @see AccessibilityNodeInfo
25786 public AccessibilityNodeInfo createAccessibilityNodeInfo(View host) {
25787 return host.createAccessibilityNodeInfoInternal();
25791 private static class MatchIdPredicate implements Predicate<View> {
25795 public boolean test(View view) {
25796 return (view.mID == mId);
25800 private static class MatchLabelForPredicate implements Predicate<View> {
25801 private int mLabeledId;
25804 public boolean test(View view) {
25805 return (view.mLabelForId == mLabeledId);
25809 private class SendViewStateChangedAccessibilityEvent implements Runnable {
25810 private int mChangeTypes = 0;
25811 private boolean mPosted;
25812 private boolean mPostedWithDelay;
25813 private long mLastEventTimeMillis;
25816 public void run() {
25818 mPostedWithDelay = false;
25819 mLastEventTimeMillis = SystemClock.uptimeMillis();
25820 if (AccessibilityManager.getInstance(mContext).isEnabled()) {
25821 final AccessibilityEvent event = AccessibilityEvent.obtain();
25822 event.setEventType(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED);
25823 event.setContentChangeTypes(mChangeTypes);
25824 sendAccessibilityEventUnchecked(event);
25829 public void runOrPost(int changeType) {
25830 mChangeTypes |= changeType;
25832 // If this is a live region or the child of a live region, collect
25833 // all events from this frame and send them on the next frame.
25834 if (inLiveRegion()) {
25835 // If we're already posted with a delay, remove that.
25836 if (mPostedWithDelay) {
25837 removeCallbacks(this);
25838 mPostedWithDelay = false;
25840 // Only post if we're not already posted.
25852 final long timeSinceLastMillis = SystemClock.uptimeMillis() - mLastEventTimeMillis;
25853 final long minEventIntevalMillis =
25854 ViewConfiguration.getSendRecurringAccessibilityEventsInterval();
25855 if (timeSinceLastMillis >= minEventIntevalMillis) {
25856 removeCallbacks(this);
25859 postDelayed(this, minEventIntevalMillis - timeSinceLastMillis);
25860 mPostedWithDelay = true;
25865 private boolean inLiveRegion() {
25866 if (getAccessibilityLiveRegion() != View.ACCESSIBILITY_LIVE_REGION_NONE) {
25870 ViewParent parent = getParent();
25871 while (parent instanceof View) {
25872 if (((View) parent).getAccessibilityLiveRegion()
25873 != View.ACCESSIBILITY_LIVE_REGION_NONE) {
25876 parent = parent.getParent();
25883 * Dump all private flags in readable format, useful for documentation and
25886 private static void dumpFlags() {
25887 final HashMap<String, String> found = Maps.newHashMap();
25889 for (Field field : View.class.getDeclaredFields()) {
25890 final int modifiers = field.getModifiers();
25891 if (Modifier.isStatic(modifiers) && Modifier.isFinal(modifiers)) {
25892 if (field.getType().equals(int.class)) {
25893 final int value = field.getInt(null);
25894 dumpFlag(found, field.getName(), value);
25895 } else if (field.getType().equals(int[].class)) {
25896 final int[] values = (int[]) field.get(null);
25897 for (int i = 0; i < values.length; i++) {
25898 dumpFlag(found, field.getName() + "[" + i + "]", values[i]);
25903 } catch (IllegalAccessException e) {
25904 throw new RuntimeException(e);
25907 final ArrayList<String> keys = Lists.newArrayList();
25908 keys.addAll(found.keySet());
25909 Collections.sort(keys);
25910 for (String key : keys) {
25911 Log.d(VIEW_LOG_TAG, found.get(key));
25915 private static void dumpFlag(HashMap<String, String> found, String name, int value) {
25916 // Sort flags by prefix, then by bits, always keeping unique keys
25917 final String bits = String.format("%32s", Integer.toBinaryString(value)).replace('0', ' ');
25918 final int prefix = name.indexOf('_');
25919 final String key = (prefix > 0 ? name.substring(0, prefix) : name) + bits + name;
25920 final String output = bits + " " + name;
25921 found.put(key, output);
25925 public void encode(@NonNull ViewHierarchyEncoder stream) {
25926 stream.beginObject(this);
25927 encodeProperties(stream);
25928 stream.endObject();
25933 protected void encodeProperties(@NonNull ViewHierarchyEncoder stream) {
25934 Object resolveId = ViewDebug.resolveId(getContext(), mID);
25935 if (resolveId instanceof String) {
25936 stream.addProperty("id", (String) resolveId);
25938 stream.addProperty("id", mID);
25941 stream.addProperty("misc:transformation.alpha",
25942 mTransformationInfo != null ? mTransformationInfo.mAlpha : 0);
25943 stream.addProperty("misc:transitionName", getTransitionName());
25946 stream.addProperty("layout:left", mLeft);
25947 stream.addProperty("layout:right", mRight);
25948 stream.addProperty("layout:top", mTop);
25949 stream.addProperty("layout:bottom", mBottom);
25950 stream.addProperty("layout:width", getWidth());
25951 stream.addProperty("layout:height", getHeight());
25952 stream.addProperty("layout:layoutDirection", getLayoutDirection());
25953 stream.addProperty("layout:layoutRtl", isLayoutRtl());
25954 stream.addProperty("layout:hasTransientState", hasTransientState());
25955 stream.addProperty("layout:baseline", getBaseline());
25958 ViewGroup.LayoutParams layoutParams = getLayoutParams();
25959 if (layoutParams != null) {
25960 stream.addPropertyKey("layoutParams");
25961 layoutParams.encode(stream);
25965 stream.addProperty("scrolling:scrollX", mScrollX);
25966 stream.addProperty("scrolling:scrollY", mScrollY);
25969 stream.addProperty("padding:paddingLeft", mPaddingLeft);
25970 stream.addProperty("padding:paddingRight", mPaddingRight);
25971 stream.addProperty("padding:paddingTop", mPaddingTop);
25972 stream.addProperty("padding:paddingBottom", mPaddingBottom);
25973 stream.addProperty("padding:userPaddingRight", mUserPaddingRight);
25974 stream.addProperty("padding:userPaddingLeft", mUserPaddingLeft);
25975 stream.addProperty("padding:userPaddingBottom", mUserPaddingBottom);
25976 stream.addProperty("padding:userPaddingStart", mUserPaddingStart);
25977 stream.addProperty("padding:userPaddingEnd", mUserPaddingEnd);
25980 stream.addProperty("measurement:minHeight", mMinHeight);
25981 stream.addProperty("measurement:minWidth", mMinWidth);
25982 stream.addProperty("measurement:measuredWidth", mMeasuredWidth);
25983 stream.addProperty("measurement:measuredHeight", mMeasuredHeight);
25986 stream.addProperty("drawing:elevation", getElevation());
25987 stream.addProperty("drawing:translationX", getTranslationX());
25988 stream.addProperty("drawing:translationY", getTranslationY());
25989 stream.addProperty("drawing:translationZ", getTranslationZ());
25990 stream.addProperty("drawing:rotation", getRotation());
25991 stream.addProperty("drawing:rotationX", getRotationX());
25992 stream.addProperty("drawing:rotationY", getRotationY());
25993 stream.addProperty("drawing:scaleX", getScaleX());
25994 stream.addProperty("drawing:scaleY", getScaleY());
25995 stream.addProperty("drawing:pivotX", getPivotX());
25996 stream.addProperty("drawing:pivotY", getPivotY());
25997 stream.addProperty("drawing:opaque", isOpaque());
25998 stream.addProperty("drawing:alpha", getAlpha());
25999 stream.addProperty("drawing:transitionAlpha", getTransitionAlpha());
26000 stream.addProperty("drawing:shadow", hasShadow());
26001 stream.addProperty("drawing:solidColor", getSolidColor());
26002 stream.addProperty("drawing:layerType", mLayerType);
26003 stream.addProperty("drawing:willNotDraw", willNotDraw());
26004 stream.addProperty("drawing:hardwareAccelerated", isHardwareAccelerated());
26005 stream.addProperty("drawing:willNotCacheDrawing", willNotCacheDrawing());
26006 stream.addProperty("drawing:drawingCacheEnabled", isDrawingCacheEnabled());
26007 stream.addProperty("drawing:overlappingRendering", hasOverlappingRendering());
26010 stream.addProperty("focus:hasFocus", hasFocus());
26011 stream.addProperty("focus:isFocused", isFocused());
26012 stream.addProperty("focus:focusable", getFocusable());
26013 stream.addProperty("focus:isFocusable", isFocusable());
26014 stream.addProperty("focus:isFocusableInTouchMode", isFocusableInTouchMode());
26016 stream.addProperty("misc:clickable", isClickable());
26017 stream.addProperty("misc:pressed", isPressed());
26018 stream.addProperty("misc:selected", isSelected());
26019 stream.addProperty("misc:touchMode", isInTouchMode());
26020 stream.addProperty("misc:hovered", isHovered());
26021 stream.addProperty("misc:activated", isActivated());
26023 stream.addProperty("misc:visibility", getVisibility());
26024 stream.addProperty("misc:fitsSystemWindows", getFitsSystemWindows());
26025 stream.addProperty("misc:filterTouchesWhenObscured", getFilterTouchesWhenObscured());
26027 stream.addProperty("misc:enabled", isEnabled());
26028 stream.addProperty("misc:soundEffectsEnabled", isSoundEffectsEnabled());
26029 stream.addProperty("misc:hapticFeedbackEnabled", isHapticFeedbackEnabled());
26031 // theme attributes
26032 Resources.Theme theme = getContext().getTheme();
26033 if (theme != null) {
26034 stream.addPropertyKey("theme");
26035 theme.encode(stream);
26038 // view attribute information
26039 int n = mAttributes != null ? mAttributes.length : 0;
26040 stream.addProperty("meta:__attrCount__", n/2);
26041 for (int i = 0; i < n; i += 2) {
26042 stream.addProperty("meta:__attr__" + mAttributes[i], mAttributes[i+1]);
26045 stream.addProperty("misc:scrollBarStyle", getScrollBarStyle());
26048 stream.addProperty("text:textDirection", getTextDirection());
26049 stream.addProperty("text:textAlignment", getTextAlignment());
26052 CharSequence contentDescription = getContentDescription();
26053 stream.addProperty("accessibility:contentDescription",
26054 contentDescription == null ? "" : contentDescription.toString());
26055 stream.addProperty("accessibility:labelFor", getLabelFor());
26056 stream.addProperty("accessibility:importantForAccessibility", getImportantForAccessibility());
26060 * Determine if this view is rendered on a round wearable device and is the main view
26063 boolean shouldDrawRoundScrollbar() {
26064 if (!mResources.getConfiguration().isScreenRound() || mAttachInfo == null) {
26068 final View rootView = getRootView();
26069 final WindowInsets insets = getRootWindowInsets();
26071 int height = getHeight();
26072 int width = getWidth();
26073 int displayHeight = rootView.getHeight();
26074 int displayWidth = rootView.getWidth();
26076 if (height != displayHeight || width != displayWidth) {
26080 getLocationInWindow(mAttachInfo.mTmpLocation);
26081 return mAttachInfo.mTmpLocation[0] == insets.getStableInsetLeft()
26082 && mAttachInfo.mTmpLocation[1] == insets.getStableInsetTop();
26086 * Sets the tooltip text which will be displayed in a small popup next to the view.
26088 * The tooltip will be displayed:
26090 * <li>On long click, unless it is handled otherwise (by OnLongClickListener or a context
26092 * <li>On hover, after a brief delay since the pointer has stopped moving </li>
26095 * <strong>Note:</strong> Do not override this method, as it will have no
26096 * effect on the text displayed in the tooltip.
26098 * @param tooltipText the tooltip text, or null if no tooltip is required
26099 * @see #getTooltipText()
26100 * @attr ref android.R.styleable#View_tooltipText
26102 public void setTooltipText(@Nullable CharSequence tooltipText) {
26103 if (TextUtils.isEmpty(tooltipText)) {
26104 setFlags(0, TOOLTIP);
26106 mTooltipInfo = null;
26108 setFlags(TOOLTIP, TOOLTIP);
26109 if (mTooltipInfo == null) {
26110 mTooltipInfo = new TooltipInfo();
26111 mTooltipInfo.mShowTooltipRunnable = this::showHoverTooltip;
26112 mTooltipInfo.mHideTooltipRunnable = this::hideTooltip;
26114 mTooltipInfo.mTooltipText = tooltipText;
26115 if (mTooltipInfo.mTooltipPopup != null && mTooltipInfo.mTooltipPopup.isShowing()) {
26116 mTooltipInfo.mTooltipPopup.updateContent(mTooltipInfo.mTooltipText);
26122 * @hide Binary compatibility stub. To be removed when we finalize O APIs.
26124 public void setTooltip(@Nullable CharSequence tooltipText) {
26125 setTooltipText(tooltipText);
26129 * Returns the view's tooltip text.
26131 * <strong>Note:</strong> Do not override this method, as it will have no
26132 * effect on the text displayed in the tooltip. You must call
26133 * {@link #setTooltipText(CharSequence)} to modify the tooltip text.
26135 * @return the tooltip text
26136 * @see #setTooltipText(CharSequence)
26137 * @attr ref android.R.styleable#View_tooltipText
26140 public CharSequence getTooltipText() {
26141 return mTooltipInfo != null ? mTooltipInfo.mTooltipText : null;
26145 * @hide Binary compatibility stub. To be removed when we finalize O APIs.
26148 public CharSequence getTooltip() {
26149 return getTooltipText();
26152 private boolean showTooltip(int x, int y, boolean fromLongClick) {
26153 if (mAttachInfo == null || mTooltipInfo == null) {
26156 if ((mViewFlags & ENABLED_MASK) != ENABLED) {
26159 if (TextUtils.isEmpty(mTooltipInfo.mTooltipText)) {
26163 mTooltipInfo.mTooltipFromLongClick = fromLongClick;
26164 mTooltipInfo.mTooltipPopup = new TooltipPopup(getContext());
26165 final boolean fromTouch = (mPrivateFlags3 & PFLAG3_FINGER_DOWN) == PFLAG3_FINGER_DOWN;
26166 mTooltipInfo.mTooltipPopup.show(this, x, y, fromTouch, mTooltipInfo.mTooltipText);
26167 mAttachInfo.mTooltipHost = this;
26171 void hideTooltip() {
26172 if (mTooltipInfo == null) {
26175 removeCallbacks(mTooltipInfo.mShowTooltipRunnable);
26176 if (mTooltipInfo.mTooltipPopup == null) {
26179 mTooltipInfo.mTooltipPopup.hide();
26180 mTooltipInfo.mTooltipPopup = null;
26181 mTooltipInfo.mTooltipFromLongClick = false;
26182 if (mAttachInfo != null) {
26183 mAttachInfo.mTooltipHost = null;
26187 private boolean showLongClickTooltip(int x, int y) {
26188 removeCallbacks(mTooltipInfo.mShowTooltipRunnable);
26189 removeCallbacks(mTooltipInfo.mHideTooltipRunnable);
26190 return showTooltip(x, y, true);
26193 private void showHoverTooltip() {
26194 showTooltip(mTooltipInfo.mAnchorX, mTooltipInfo.mAnchorY, false);
26197 boolean dispatchTooltipHoverEvent(MotionEvent event) {
26198 if (mTooltipInfo == null) {
26201 switch(event.getAction()) {
26202 case MotionEvent.ACTION_HOVER_MOVE:
26203 if ((mViewFlags & TOOLTIP) != TOOLTIP || (mViewFlags & ENABLED_MASK) != ENABLED) {
26206 if (!mTooltipInfo.mTooltipFromLongClick) {
26207 if (mTooltipInfo.mTooltipPopup == null) {
26208 // Schedule showing the tooltip after a timeout.
26209 mTooltipInfo.mAnchorX = (int) event.getX();
26210 mTooltipInfo.mAnchorY = (int) event.getY();
26211 removeCallbacks(mTooltipInfo.mShowTooltipRunnable);
26212 postDelayed(mTooltipInfo.mShowTooltipRunnable,
26213 ViewConfiguration.getHoverTooltipShowTimeout());
26216 // Hide hover-triggered tooltip after a period of inactivity.
26217 // Match the timeout used by NativeInputManager to hide the mouse pointer
26218 // (depends on SYSTEM_UI_FLAG_LOW_PROFILE being set).
26220 if ((getWindowSystemUiVisibility() & SYSTEM_UI_FLAG_LOW_PROFILE)
26221 == SYSTEM_UI_FLAG_LOW_PROFILE) {
26222 timeout = ViewConfiguration.getHoverTooltipHideShortTimeout();
26224 timeout = ViewConfiguration.getHoverTooltipHideTimeout();
26226 removeCallbacks(mTooltipInfo.mHideTooltipRunnable);
26227 postDelayed(mTooltipInfo.mHideTooltipRunnable, timeout);
26231 case MotionEvent.ACTION_HOVER_EXIT:
26232 if (!mTooltipInfo.mTooltipFromLongClick) {
26240 void handleTooltipKey(KeyEvent event) {
26241 switch (event.getAction()) {
26242 case KeyEvent.ACTION_DOWN:
26243 if (event.getRepeatCount() == 0) {
26248 case KeyEvent.ACTION_UP:
26254 private void handleTooltipUp() {
26255 if (mTooltipInfo == null || mTooltipInfo.mTooltipPopup == null) {
26258 removeCallbacks(mTooltipInfo.mHideTooltipRunnable);
26259 postDelayed(mTooltipInfo.mHideTooltipRunnable,
26260 ViewConfiguration.getLongPressTooltipHideTimeout());
26263 private int getFocusableAttribute(TypedArray attributes) {
26264 TypedValue val = new TypedValue();
26265 if (attributes.getValue(com.android.internal.R.styleable.View_focusable, val)) {
26266 if (val.type == TypedValue.TYPE_INT_BOOLEAN) {
26267 return (val.data == 0 ? NOT_FOCUSABLE : FOCUSABLE);
26272 return FOCUSABLE_AUTO;
26277 * @return The content view of the tooltip popup currently being shown, or null if the tooltip
26282 public View getTooltipView() {
26283 if (mTooltipInfo == null || mTooltipInfo.mTooltipPopup == null) {
26286 return mTooltipInfo.mTooltipPopup.getContentView();