/* * Copyright (C) 2006 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.view; import com.android.internal.R; import com.android.internal.util.Predicate; import com.android.internal.view.menu.MenuBuilder; import android.content.ClipData; import android.content.Context; import android.content.res.Configuration; import android.content.res.Resources; import android.content.res.TypedArray; import android.graphics.Bitmap; import android.graphics.Camera; import android.graphics.Canvas; import android.graphics.Interpolator; import android.graphics.LinearGradient; import android.graphics.Matrix; import android.graphics.Paint; import android.graphics.PixelFormat; import android.graphics.Point; import android.graphics.PorterDuff; import android.graphics.PorterDuffXfermode; import android.graphics.Rect; import android.graphics.RectF; import android.graphics.Region; import android.graphics.Shader; import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; import android.os.Handler; import android.os.IBinder; import android.os.Message; import android.os.Parcel; import android.os.Parcelable; import android.os.RemoteException; import android.os.SystemClock; import android.os.SystemProperties; import android.util.AttributeSet; import android.util.Log; import android.util.Pool; import android.util.Poolable; import android.util.PoolableManager; import android.util.Pools; import android.util.SparseArray; import android.util.TypedValue; import android.view.ContextMenu.ContextMenuInfo; import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityEventSource; import android.view.accessibility.AccessibilityManager; import android.view.animation.Animation; import android.view.animation.AnimationUtils; import android.view.inputmethod.EditorInfo; import android.view.inputmethod.InputConnection; import android.view.inputmethod.InputMethodManager; import android.widget.ScrollBarDrawable; import java.lang.ref.WeakReference; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Arrays; import java.util.WeakHashMap; import java.util.concurrent.CopyOnWriteArrayList; /** *
* This class represents the basic building block for user interface components. A View * occupies a rectangular area on the screen and is responsible for drawing and * event handling. View is the base class for widgets, which are * used to create interactive UI components (buttons, text fields, etc.). The * {@link android.view.ViewGroup} subclass is the base class for layouts, which * are invisible containers that hold other Views (or other ViewGroups) and define * their layout properties. *
* *For an introduction to using this class to develop your
* application's user interface, read the Developer Guide documentation on
* User Interface. Special topics
* include:
*
Declaring Layout
*
Creating Menus
*
Common Layout Objects
*
Binding to Data with AdapterView
*
Handling UI Events
*
Applying Styles and Themes
*
Building Custom Components
*
How Android Draws Views.
*
* All of the views in a window are arranged in a single tree. You can add views * either from code or by specifying a tree of views in one or more XML layout * files. There are many specialized subclasses of views that act as controls or * are capable of displaying text, images, or other content. *
** Once you have created a tree of views, there are typically a few types of * common operations you may wish to perform: *
* Note: The Android framework is responsible for measuring, laying out and * drawing views. You should not call methods that perform these actions on * views yourself unless you are actually implementing a * {@link android.view.ViewGroup}. *
* * ** To implement a custom view, you will usually begin by providing overrides for * some of the standard methods that the framework calls on all views. You do * not need to override all of these methods. In fact, you can start by just * overriding {@link #onDraw(android.graphics.Canvas)}. *
Category | Methods | Description |
---|---|---|
Creation | *Constructors | *There is a form of the constructor that are called when the view * is created from code and a form that is called when the view is * inflated from a layout file. The second form should parse and apply * any attributes defined in the layout file. * | *
{@link #onFinishInflate()} |
* Called after a view and all of its children has been inflated * from XML. | *|
Layout | *{@link #onMeasure} |
* Called to determine the size requirements for this view and all * of its children. * | *
{@link #onLayout} |
* Called when this view should assign a size and position to all * of its children. * | *|
{@link #onSizeChanged} |
* Called when the size of this view has changed. * | *|
Drawing | *{@link #onDraw} |
* Called when the view should render its content. * | *
Event processing | *{@link #onKeyDown} |
* Called when a new key event occurs. * | *
{@link #onKeyUp} |
* Called when a key up event occurs. * | *|
{@link #onTrackballEvent} |
* Called when a trackball motion event occurs. * | *|
{@link #onTouchEvent} |
* Called when a touch screen motion event occurs. * | *|
Focus | *{@link #onFocusChanged} |
* Called when the view gains or loses focus. * | *
{@link #onWindowFocusChanged} |
* Called when the window containing the view gains or loses focus. * | *|
Attaching | *{@link #onAttachedToWindow()} |
* Called when the view is attached to a window. * | *
{@link #onDetachedFromWindow} |
* Called when the view is detached from its window. * | *|
{@link #onWindowVisibilityChanged} |
* Called when the visibility of the window containing the view * has changed. * | *
* <Button * android:id="@+id/my_button" * android:layout_width="wrap_content" * android:layout_height="wrap_content" * android:text="@string/my_button_text"/> *
* Button myButton = (Button) findViewById(R.id.my_button); *
* View IDs need not be unique throughout the tree, but it is good practice to * ensure that they are at least unique within the part of the tree you are * searching. *
* * ** The geometry of a view is that of a rectangle. A view has a location, * expressed as a pair of left and top coordinates, and * two dimensions, expressed as a width and a height. The unit for location * and dimensions is the pixel. *
* ** It is possible to retrieve the location of a view by invoking the methods * {@link #getLeft()} and {@link #getTop()}. The former returns the left, or X, * coordinate of the rectangle representing the view. The latter returns the * top, or Y, coordinate of the rectangle representing the view. These methods * both return the location of the view relative to its parent. For instance, * when getLeft() returns 20, that means the view is located 20 pixels to the * right of the left edge of its direct parent. *
* *
* In addition, several convenience methods are offered to avoid unnecessary
* computations, namely {@link #getRight()} and {@link #getBottom()}.
* These methods return the coordinates of the right and bottom edges of the
* rectangle representing the view. For instance, calling {@link #getRight()}
* is similar to the following computation: getLeft() + getWidth()
* (see Size for more information about the width.)
*
* The size of a view is expressed with a width and a height. A view actually * possess two pairs of width and height values. *
* ** The first pair is known as measured width and * measured height. These dimensions define how big a view wants to be * within its parent (see Layout for more details.) The * measured dimensions can be obtained by calling {@link #getMeasuredWidth()} * and {@link #getMeasuredHeight()}. *
* ** The second pair is simply known as width and height, or * sometimes drawing width and drawing height. These * dimensions define the actual size of the view on screen, at drawing time and * after layout. These values may, but do not have to, be different from the * measured width and height. The width and height can be obtained by calling * {@link #getWidth()} and {@link #getHeight()}. *
* ** To measure its dimensions, a view takes into account its padding. The padding * is expressed in pixels for the left, top, right and bottom parts of the view. * Padding can be used to offset the content of the view by a specific amount of * pixels. For instance, a left padding of 2 will push the view's content by * 2 pixels to the right of the left edge. Padding can be set using the * {@link #setPadding(int, int, int, int)} method and queried by calling * {@link #getPaddingLeft()}, {@link #getPaddingTop()}, * {@link #getPaddingRight()} and {@link #getPaddingBottom()}. *
* ** Even though a view can define a padding, it does not provide any support for * margins. However, view groups provide such a support. Refer to * {@link android.view.ViewGroup} and * {@link android.view.ViewGroup.MarginLayoutParams} for further information. *
* * ** Layout is a two pass process: a measure pass and a layout pass. The measuring * pass is implemented in {@link #measure(int, int)} and is a top-down traversal * of the view tree. Each view pushes dimension specifications down the tree * during the recursion. At the end of the measure pass, every view has stored * its measurements. The second pass happens in * {@link #layout(int,int,int,int)} and is also top-down. During * this pass each parent is responsible for positioning all of its children * using the sizes computed in the measure pass. *
* ** When a view's measure() method returns, its {@link #getMeasuredWidth()} and * {@link #getMeasuredHeight()} values must be set, along with those for all of * that view's descendants. A view's measured width and measured height values * must respect the constraints imposed by the view's parents. This guarantees * that at the end of the measure pass, all parents accept all of their * children's measurements. A parent view may call measure() more than once on * its children. For example, the parent may measure each child once with * unspecified dimensions to find out how big they want to be, then call * measure() on them again with actual numbers if the sum of all the children's * unconstrained sizes is too big or too small. *
* ** The measure pass uses two classes to communicate dimensions. The * {@link MeasureSpec} class is used by views to tell their parents how they * want to be measured and positioned. The base LayoutParams class just * describes how big the view wants to be for both width and height. For each * dimension, it can specify one of: *
* MeasureSpecs are used to push requirements down the tree from parent to * child. A MeasureSpec can be in one of three modes: *
* To intiate a layout, call {@link #requestLayout}. This method is typically * called by a view on itself when it believes that is can no longer fit within * its current bounds. *
* * *
* Drawing is handled by walking the tree and rendering each view that
* intersects the the invalid region. Because the tree is traversed in-order,
* this means that parents will draw before (i.e., behind) their children, with
* siblings drawn in the order they appear in the tree.
* If you set a background drawable for a View, then the View will draw it for you
* before calling back to its onDraw()
method.
*
* Note that the framework will not draw views that are not in the invalid region. *
* ** To force a view to draw, call {@link #invalidate()}. *
* * ** The basic cycle of a view is as follows: *
Note: The entire view tree is single threaded. You must always be on * the UI thread when calling any method on any view. * If you are doing work on other threads and want to update the state of a view * from that thread, you should use a {@link Handler}. *
* * ** The framework will handle routine focus movement in response to user input. * This includes changing the focus as views are removed or hidden, or as new * views become available. Views indicate their willingness to take focus * through the {@link #isFocusable} method. To change whether a view can take * focus, call {@link #setFocusable(boolean)}. When in touch mode (see notes below) * views indicate whether they still would like focus via {@link #isFocusableInTouchMode} * and can change this via {@link #setFocusableInTouchMode(boolean)}. *
** Focus movement is based on an algorithm which finds the nearest neighbor in a * given direction. In rare cases, the default algorithm may not match the * intended behavior of the developer. In these situations, you can provide * explicit overrides by using these XML attributes in the layout file: *
* nextFocusDown * nextFocusLeft * nextFocusRight * nextFocusUp ** * * *
* To get a particular view to take focus, call {@link #requestFocus()}. *
* * ** When a user is navigating a user interface via directional keys such as a D-pad, it is * necessary to give focus to actionable items such as buttons so the user can see * what will take input. If the device has touch capabilities, however, and the user * begins interacting with the interface by touching it, it is no longer necessary to * always highlight, or give focus to, a particular view. This motivates a mode * for interaction named 'touch mode'. *
** For a touch capable device, once the user touches the screen, the device * will enter touch mode. From this point onward, only views for which * {@link #isFocusableInTouchMode} is true will be focusable, such as text editing widgets. * Other views that are touchable, like buttons, will not take focus when touched; they will * only fire the on click listeners. *
** Any time a user hits a directional key, such as a D-pad direction, the view device will * exit touch mode, and find a view to take focus, so that the user may resume interacting * with the user interface without touching the screen again. *
** The touch mode state is maintained across {@link android.app.Activity}s. Call * {@link #isInTouchMode} to see whether the device is currently in touch mode. *
* * ** The framework provides basic support for views that wish to internally * scroll their content. This includes keeping track of the X and Y scroll * offset as well as mechanisms for drawing scrollbars. See * {@link #scrollBy(int, int)}, {@link #scrollTo(int, int)}, and * {@link #awakenScrollBars()} for more details. *
* * ** Unlike IDs, tags are not used to identify views. Tags are essentially an * extra piece of information that can be associated with a view. They are most * often used as a convenience to store data related to views in the views * themselves rather than by putting them in a separate structure. *
* * ** You can attach an {@link Animation} object to a view using * {@link #setAnimation(Animation)} or * {@link #startAnimation(Animation)}. The animation can alter the scale, * rotation, translation and alpha of a view over time. If the animation is * attached to a view that has children, the animation will affect the entire * subtree rooted by that node. When an animation is started, the framework will * take care of redrawing the appropriate views until the animation completes. *
** Starting with Android 3.0, the preferred way of animating views is to use the * {@link android.animation} package APIs. *
* * ** Sometimes it is essential that an application be able to verify that an action * is being performed with the full knowledge and consent of the user, such as * granting a permission request, making a purchase or clicking on an advertisement. * Unfortunately, a malicious application could try to spoof the user into * performing these actions, unaware, by concealing the intended purpose of the view. * As a remedy, the framework offers a touch filtering mechanism that can be used to * improve the security of views that provide access to sensitive functionality. *
* To enable touch filtering, call {@link #setFilterTouchesWhenObscured} or set the * android:filterTouchesWhenObscured layout attribute to true. When enabled, the framework * will discard touches that are received whenever the view's window is obscured by * another visible window. As a result, the view will not receive touches whenever a * toast, dialog or other window appears above the view's window. *
* For more fine-grained control over security, consider overriding the * {@link #onFilterTouchEventForSecurity} method to implement your own security policy. * See also {@link MotionEvent#FLAG_WINDOW_IS_OBSCURED}. *
* * @attr ref android.R.styleable#View_alpha * @attr ref android.R.styleable#View_background * @attr ref android.R.styleable#View_clickable * @attr ref android.R.styleable#View_contentDescription * @attr ref android.R.styleable#View_drawingCacheQuality * @attr ref android.R.styleable#View_duplicateParentState * @attr ref android.R.styleable#View_id * @attr ref android.R.styleable#View_fadingEdge * @attr ref android.R.styleable#View_fadingEdgeLength * @attr ref android.R.styleable#View_filterTouchesWhenObscured * @attr ref android.R.styleable#View_fitsSystemWindows * @attr ref android.R.styleable#View_isScrollContainer * @attr ref android.R.styleable#View_focusable * @attr ref android.R.styleable#View_focusableInTouchMode * @attr ref android.R.styleable#View_hapticFeedbackEnabled * @attr ref android.R.styleable#View_keepScreenOn * @attr ref android.R.styleable#View_layerType * @attr ref android.R.styleable#View_longClickable * @attr ref android.R.styleable#View_minHeight * @attr ref android.R.styleable#View_minWidth * @attr ref android.R.styleable#View_nextFocusDown * @attr ref android.R.styleable#View_nextFocusLeft * @attr ref android.R.styleable#View_nextFocusRight * @attr ref android.R.styleable#View_nextFocusUp * @attr ref android.R.styleable#View_onClick * @attr ref android.R.styleable#View_padding * @attr ref android.R.styleable#View_paddingBottom * @attr ref android.R.styleable#View_paddingLeft * @attr ref android.R.styleable#View_paddingRight * @attr ref android.R.styleable#View_paddingTop * @attr ref android.R.styleable#View_saveEnabled * @attr ref android.R.styleable#View_rotation * @attr ref android.R.styleable#View_rotationX * @attr ref android.R.styleable#View_rotationY * @attr ref android.R.styleable#View_scaleX * @attr ref android.R.styleable#View_scaleY * @attr ref android.R.styleable#View_scrollX * @attr ref android.R.styleable#View_scrollY * @attr ref android.R.styleable#View_scrollbarSize * @attr ref android.R.styleable#View_scrollbarStyle * @attr ref android.R.styleable#View_scrollbars * @attr ref android.R.styleable#View_scrollbarDefaultDelayBeforeFade * @attr ref android.R.styleable#View_scrollbarFadeDuration * @attr ref android.R.styleable#View_scrollbarTrackHorizontal * @attr ref android.R.styleable#View_scrollbarThumbHorizontal * @attr ref android.R.styleable#View_scrollbarThumbVertical * @attr ref android.R.styleable#View_scrollbarTrackVertical * @attr ref android.R.styleable#View_scrollbarAlwaysDrawHorizontalTrack * @attr ref android.R.styleable#View_scrollbarAlwaysDrawVerticalTrack * @attr ref android.R.styleable#View_soundEffectsEnabled * @attr ref android.R.styleable#View_tag * @attr ref android.R.styleable#View_transformPivotX * @attr ref android.R.styleable#View_transformPivotY * @attr ref android.R.styleable#View_translationX * @attr ref android.R.styleable#View_translationY * @attr ref android.R.styleable#View_visibility * * @see android.view.ViewGroup */ public class View implements Drawable.Callback, KeyEvent.Callback, AccessibilityEventSource { private static final boolean DBG = false; /** * The logging tag used by this class with android.util.Log. */ protected static final String VIEW_LOG_TAG = "View"; /** * Used to mark a View that has no ID. */ public static final int NO_ID = -1; /** * This view does not want keystrokes. Use with TAKES_FOCUS_MASK when * calling setFlags. */ private static final int NOT_FOCUSABLE = 0x00000000; /** * This view wants keystrokes. Use with TAKES_FOCUS_MASK when calling * setFlags. */ private static final int FOCUSABLE = 0x00000001; /** * Mask for use with setFlags indicating bits used for focus. */ private static final int FOCUSABLE_MASK = 0x00000001; /** * This view will adjust its padding to fit sytem windows (e.g. status bar) */ private static final int FITS_SYSTEM_WINDOWS = 0x00000002; /** * This view is visible. Use with {@link #setVisibility}. */ public static final int VISIBLE = 0x00000000; /** * This view is invisible, but it still takes up space for layout purposes. * Use with {@link #setVisibility}. */ public static final int INVISIBLE = 0x00000004; /** * This view is invisible, and it doesn't take any space for layout * purposes. Use with {@link #setVisibility}. */ public static final int GONE = 0x00000008; /** * Mask for use with setFlags indicating bits used for visibility. * {@hide} */ static final int VISIBILITY_MASK = 0x0000000C; private static final int[] VISIBILITY_FLAGS = {VISIBLE, INVISIBLE, GONE}; /** * This view is enabled. Intrepretation varies by subclass. * Use with ENABLED_MASK when calling setFlags. * {@hide} */ static final int ENABLED = 0x00000000; /** * This view is disabled. Intrepretation varies by subclass. * Use with ENABLED_MASK when calling setFlags. * {@hide} */ static final int DISABLED = 0x00000020; /** * Mask for use with setFlags indicating bits used for indicating whether * this view is enabled * {@hide} */ static final int ENABLED_MASK = 0x00000020; /** * This view won't draw. {@link #onDraw} won't be called and further * optimizations * will be performed. It is okay to have this flag set and a background. * Use with DRAW_MASK when calling setFlags. * {@hide} */ static final int WILL_NOT_DRAW = 0x00000080; /** * Mask for use with setFlags indicating bits used for indicating whether * this view is will draw * {@hide} */ static final int DRAW_MASK = 0x00000080; /** *This view doesn't show scrollbars.
* {@hide} */ static final int SCROLLBARS_NONE = 0x00000000; /** *This view shows horizontal scrollbars.
* {@hide} */ static final int SCROLLBARS_HORIZONTAL = 0x00000100; /** *This view shows vertical scrollbars.
* {@hide} */ static final int SCROLLBARS_VERTICAL = 0x00000200; /** *Mask for use with setFlags indicating bits used for indicating which * scrollbars are enabled.
* {@hide} */ static final int SCROLLBARS_MASK = 0x00000300; /** * Indicates that the view should filter touches when its window is obscured. * Refer to the class comments for more information about this security feature. * {@hide} */ static final int FILTER_TOUCHES_WHEN_OBSCURED = 0x00000400; // note flag value 0x00000800 is now available for next flags... /** *This view doesn't show fading edges.
* {@hide} */ static final int FADING_EDGE_NONE = 0x00000000; /** *This view shows horizontal fading edges.
* {@hide} */ static final int FADING_EDGE_HORIZONTAL = 0x00001000; /** *This view shows vertical fading edges.
* {@hide} */ static final int FADING_EDGE_VERTICAL = 0x00002000; /** *Mask for use with setFlags indicating bits used for indicating which * fading edges are enabled.
* {@hide} */ static final int FADING_EDGE_MASK = 0x00003000; /** *Indicates this view can be clicked. When clickable, a View reacts * to clicks by notifying the OnClickListener.
* {@hide} */ static final int CLICKABLE = 0x00004000; /** *
Indicates this view is caching its drawing into a bitmap.
* {@hide} */ static final int DRAWING_CACHE_ENABLED = 0x00008000; /** *Indicates that no icicle should be saved for this view.
* {@hide} */ static final int SAVE_DISABLED = 0x000010000; /** *
Mask for use with setFlags indicating bits used for the saveEnabled * property.
* {@hide} */ static final int SAVE_DISABLED_MASK = 0x000010000; /** *Indicates that no drawing cache should ever be created for this view.
* {@hide} */ static final int WILL_NOT_CACHE_DRAWING = 0x000020000; /** *
Indicates this view can take / keep focus when int touch mode.
* {@hide} */ static final int FOCUSABLE_IN_TOUCH_MODE = 0x00040000; /** *Enables low quality mode for the drawing cache.
*/ public static final int DRAWING_CACHE_QUALITY_LOW = 0x00080000; /** *Enables high quality mode for the drawing cache.
*/ public static final int DRAWING_CACHE_QUALITY_HIGH = 0x00100000; /** *Enables automatic quality mode for the drawing cache.
*/ public static final int DRAWING_CACHE_QUALITY_AUTO = 0x00000000; private static final int[] DRAWING_CACHE_QUALITY_FLAGS = { DRAWING_CACHE_QUALITY_AUTO, DRAWING_CACHE_QUALITY_LOW, DRAWING_CACHE_QUALITY_HIGH }; /** *Mask for use with setFlags indicating bits used for the cache * quality property.
* {@hide} */ static final int DRAWING_CACHE_QUALITY_MASK = 0x00180000; /** ** Indicates this view can be long clicked. When long clickable, a View * reacts to long clicks by notifying the OnLongClickListener or showing a * context menu. *
* {@hide} */ static final int LONG_CLICKABLE = 0x00200000; /** *Indicates that this view gets its drawable states from its direct parent * and ignores its original internal states.
* * @hide */ static final int DUPLICATE_PARENT_STATE = 0x00400000; /** * The scrollbar style to display the scrollbars inside the content area, * without increasing the padding. The scrollbars will be overlaid with * translucency on the view's content. */ public static final int SCROLLBARS_INSIDE_OVERLAY = 0; /** * The scrollbar style to display the scrollbars inside the padded area, * increasing the padding of the view. The scrollbars will not overlap the * content area of the view. */ public static final int SCROLLBARS_INSIDE_INSET = 0x01000000; /** * The scrollbar style to display the scrollbars at the edge of the view, * without increasing the padding. The scrollbars will be overlaid with * translucency. */ public static final int SCROLLBARS_OUTSIDE_OVERLAY = 0x02000000; /** * The scrollbar style to display the scrollbars at the edge of the view, * increasing the padding of the view. The scrollbars will only overlap the * background, if any. */ public static final int SCROLLBARS_OUTSIDE_INSET = 0x03000000; /** * Mask to check if the scrollbar style is overlay or inset. * {@hide} */ static final int SCROLLBARS_INSET_MASK = 0x01000000; /** * Mask to check if the scrollbar style is inside or outside. * {@hide} */ static final int SCROLLBARS_OUTSIDE_MASK = 0x02000000; /** * Mask for scrollbar style. * {@hide} */ static final int SCROLLBARS_STYLE_MASK = 0x03000000; /** * View flag indicating that the screen should remain on while the * window containing this view is visible to the user. This effectively * takes care of automatically setting the WindowManager's * {@link WindowManager.LayoutParams#FLAG_KEEP_SCREEN_ON}. */ public static final int KEEP_SCREEN_ON = 0x04000000; /** * View flag indicating whether this view should have sound effects enabled * for events such as clicking and touching. */ public static final int SOUND_EFFECTS_ENABLED = 0x08000000; /** * View flag indicating whether this view should have haptic feedback * enabled for events such as long presses. */ public static final int HAPTIC_FEEDBACK_ENABLED = 0x10000000; /** *Indicates that the view hierarchy should stop saving state when * it reaches this view. If state saving is initiated immediately at * the view, it will be allowed. * {@hide} */ static final int PARENT_SAVE_DISABLED = 0x20000000; /** *
Mask for use with setFlags indicating bits used for PARENT_SAVE_DISABLED.
* {@hide} */ static final int PARENT_SAVE_DISABLED_MASK = 0x20000000; /** * View flag indicating whether {@link #addFocusables(ArrayList, int, int)} * should add all focusable Views regardless if they are focusable in touch mode. */ public static final int FOCUSABLES_ALL = 0x00000000; /** * View flag indicating whether {@link #addFocusables(ArrayList, int, int)} * should add only Views focusable in touch mode. */ public static final int FOCUSABLES_TOUCH_MODE = 0x00000001; /** * Use with {@link #focusSearch}. Move focus to the previous selectable * item. */ public static final int FOCUS_BACKWARD = 0x00000001; /** * Use with {@link #focusSearch}. Move focus to the next selectable * item. */ public static final int FOCUS_FORWARD = 0x00000002; /** * Use with {@link #focusSearch}. Move focus to the left. */ public static final int FOCUS_LEFT = 0x00000011; /** * Use with {@link #focusSearch}. Move focus up. */ public static final int FOCUS_UP = 0x00000021; /** * Use with {@link #focusSearch}. Move focus to the right. */ public static final int FOCUS_RIGHT = 0x00000042; /** * Use with {@link #focusSearch}. Move focus down. */ public static final int FOCUS_DOWN = 0x00000082; /** * Bits of {@link #getMeasuredWidthAndState()} and * {@link #getMeasuredWidthAndState()} that provide the actual measured size. */ public static final int MEASURED_SIZE_MASK = 0x00ffffff; /** * Bits of {@link #getMeasuredWidthAndState()} and * {@link #getMeasuredWidthAndState()} that provide the additional state bits. */ public static final int MEASURED_STATE_MASK = 0xff000000; /** * Bit shift of {@link #MEASURED_STATE_MASK} to get to the height bits * for functions that combine both width and height into a single int, * such as {@link #getMeasuredState()} and the childState argument of * {@link #resolveSizeAndState(int, int, int)}. */ public static final int MEASURED_HEIGHT_STATE_SHIFT = 16; /** * Bit of {@link #getMeasuredWidthAndState()} and * {@link #getMeasuredWidthAndState()} that indicates the measured size * is smaller that the space the view would like to have. */ public static final int MEASURED_STATE_TOO_SMALL = 0x01000000; /** * Base View state sets */ // Singles /** * Indicates the view has no states set. States are used with * {@link android.graphics.drawable.Drawable} to change the drawing of the * view depending on its state. * * @see android.graphics.drawable.Drawable * @see #getDrawableState() */ protected static final int[] EMPTY_STATE_SET; /** * Indicates the view is enabled. States are used with * {@link android.graphics.drawable.Drawable} to change the drawing of the * view depending on its state. * * @see android.graphics.drawable.Drawable * @see #getDrawableState() */ protected static final int[] ENABLED_STATE_SET; /** * Indicates the view is focused. States are used with * {@link android.graphics.drawable.Drawable} to change the drawing of the * view depending on its state. * * @see android.graphics.drawable.Drawable * @see #getDrawableState() */ protected static final int[] FOCUSED_STATE_SET; /** * Indicates the view is selected. States are used with * {@link android.graphics.drawable.Drawable} to change the drawing of the * view depending on its state. * * @see android.graphics.drawable.Drawable * @see #getDrawableState() */ protected static final int[] SELECTED_STATE_SET; /** * Indicates the view is pressed. States are used with * {@link android.graphics.drawable.Drawable} to change the drawing of the * view depending on its state. * * @see android.graphics.drawable.Drawable * @see #getDrawableState() * @hide */ protected static final int[] PRESSED_STATE_SET; /** * Indicates the view's window has focus. States are used with * {@link android.graphics.drawable.Drawable} to change the drawing of the * view depending on its state. * * @see android.graphics.drawable.Drawable * @see #getDrawableState() */ protected static final int[] WINDOW_FOCUSED_STATE_SET; // Doubles /** * Indicates the view is enabled and has the focus. * * @see #ENABLED_STATE_SET * @see #FOCUSED_STATE_SET */ protected static final int[] ENABLED_FOCUSED_STATE_SET; /** * Indicates the view is enabled and selected. * * @see #ENABLED_STATE_SET * @see #SELECTED_STATE_SET */ protected static final int[] ENABLED_SELECTED_STATE_SET; /** * Indicates the view is enabled and that its window has focus. * * @see #ENABLED_STATE_SET * @see #WINDOW_FOCUSED_STATE_SET */ protected static final int[] ENABLED_WINDOW_FOCUSED_STATE_SET; /** * Indicates the view is focused and selected. * * @see #FOCUSED_STATE_SET * @see #SELECTED_STATE_SET */ protected static final int[] FOCUSED_SELECTED_STATE_SET; /** * Indicates the view has the focus and that its window has the focus. * * @see #FOCUSED_STATE_SET * @see #WINDOW_FOCUSED_STATE_SET */ protected static final int[] FOCUSED_WINDOW_FOCUSED_STATE_SET; /** * Indicates the view is selected and that its window has the focus. * * @see #SELECTED_STATE_SET * @see #WINDOW_FOCUSED_STATE_SET */ protected static final int[] SELECTED_WINDOW_FOCUSED_STATE_SET; // Triples /** * Indicates the view is enabled, focused and selected. * * @see #ENABLED_STATE_SET * @see #FOCUSED_STATE_SET * @see #SELECTED_STATE_SET */ protected static final int[] ENABLED_FOCUSED_SELECTED_STATE_SET; /** * Indicates the view is enabled, focused and its window has the focus. * * @see #ENABLED_STATE_SET * @see #FOCUSED_STATE_SET * @see #WINDOW_FOCUSED_STATE_SET */ protected static final int[] ENABLED_FOCUSED_WINDOW_FOCUSED_STATE_SET; /** * Indicates the view is enabled, selected and its window has the focus. * * @see #ENABLED_STATE_SET * @see #SELECTED_STATE_SET * @see #WINDOW_FOCUSED_STATE_SET */ protected static final int[] ENABLED_SELECTED_WINDOW_FOCUSED_STATE_SET; /** * Indicates the view is focused, selected and its window has the focus. * * @see #FOCUSED_STATE_SET * @see #SELECTED_STATE_SET * @see #WINDOW_FOCUSED_STATE_SET */ protected static final int[] FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET; /** * Indicates the view is enabled, focused, selected and its window * has the focus. * * @see #ENABLED_STATE_SET * @see #FOCUSED_STATE_SET * @see #SELECTED_STATE_SET * @see #WINDOW_FOCUSED_STATE_SET */ protected static final int[] ENABLED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET; /** * Indicates the view is pressed and its window has the focus. * * @see #PRESSED_STATE_SET * @see #WINDOW_FOCUSED_STATE_SET */ protected static final int[] PRESSED_WINDOW_FOCUSED_STATE_SET; /** * Indicates the view is pressed and selected. * * @see #PRESSED_STATE_SET * @see #SELECTED_STATE_SET */ protected static final int[] PRESSED_SELECTED_STATE_SET; /** * Indicates the view is pressed, selected and its window has the focus. * * @see #PRESSED_STATE_SET * @see #SELECTED_STATE_SET * @see #WINDOW_FOCUSED_STATE_SET */ protected static final int[] PRESSED_SELECTED_WINDOW_FOCUSED_STATE_SET; /** * Indicates the view is pressed and focused. * * @see #PRESSED_STATE_SET * @see #FOCUSED_STATE_SET */ protected static final int[] PRESSED_FOCUSED_STATE_SET; /** * Indicates the view is pressed, focused and its window has the focus. * * @see #PRESSED_STATE_SET * @see #FOCUSED_STATE_SET * @see #WINDOW_FOCUSED_STATE_SET */ protected static final int[] PRESSED_FOCUSED_WINDOW_FOCUSED_STATE_SET; /** * Indicates the view is pressed, focused and selected. * * @see #PRESSED_STATE_SET * @see #SELECTED_STATE_SET * @see #FOCUSED_STATE_SET */ protected static final int[] PRESSED_FOCUSED_SELECTED_STATE_SET; /** * Indicates the view is pressed, focused, selected and its window has the focus. * * @see #PRESSED_STATE_SET * @see #FOCUSED_STATE_SET * @see #SELECTED_STATE_SET * @see #WINDOW_FOCUSED_STATE_SET */ protected static final int[] PRESSED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET; /** * Indicates the view is pressed and enabled. * * @see #PRESSED_STATE_SET * @see #ENABLED_STATE_SET */ protected static final int[] PRESSED_ENABLED_STATE_SET; /** * Indicates the view is pressed, enabled and its window has the focus. * * @see #PRESSED_STATE_SET * @see #ENABLED_STATE_SET * @see #WINDOW_FOCUSED_STATE_SET */ protected static final int[] PRESSED_ENABLED_WINDOW_FOCUSED_STATE_SET; /** * Indicates the view is pressed, enabled and selected. * * @see #PRESSED_STATE_SET * @see #ENABLED_STATE_SET * @see #SELECTED_STATE_SET */ protected static final int[] PRESSED_ENABLED_SELECTED_STATE_SET; /** * Indicates the view is pressed, enabled, selected and its window has the * focus. * * @see #PRESSED_STATE_SET * @see #ENABLED_STATE_SET * @see #SELECTED_STATE_SET * @see #WINDOW_FOCUSED_STATE_SET */ protected static final int[] PRESSED_ENABLED_SELECTED_WINDOW_FOCUSED_STATE_SET; /** * Indicates the view is pressed, enabled and focused. * * @see #PRESSED_STATE_SET * @see #ENABLED_STATE_SET * @see #FOCUSED_STATE_SET */ protected static final int[] PRESSED_ENABLED_FOCUSED_STATE_SET; /** * Indicates the view is pressed, enabled, focused and its window has the * focus. * * @see #PRESSED_STATE_SET * @see #ENABLED_STATE_SET * @see #FOCUSED_STATE_SET * @see #WINDOW_FOCUSED_STATE_SET */ protected static final int[] PRESSED_ENABLED_FOCUSED_WINDOW_FOCUSED_STATE_SET; /** * Indicates the view is pressed, enabled, focused and selected. * * @see #PRESSED_STATE_SET * @see #ENABLED_STATE_SET * @see #SELECTED_STATE_SET * @see #FOCUSED_STATE_SET */ protected static final int[] PRESSED_ENABLED_FOCUSED_SELECTED_STATE_SET; /** * Indicates the view is pressed, enabled, focused, selected and its window * has the focus. * * @see #PRESSED_STATE_SET * @see #ENABLED_STATE_SET * @see #SELECTED_STATE_SET * @see #FOCUSED_STATE_SET * @see #WINDOW_FOCUSED_STATE_SET */ protected static final int[] PRESSED_ENABLED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET; /** * The order here is very important to {@link #getDrawableState()} */ private static final int[][] VIEW_STATE_SETS; static final int VIEW_STATE_WINDOW_FOCUSED = 1; static final int VIEW_STATE_SELECTED = 1 << 1; static final int VIEW_STATE_FOCUSED = 1 << 2; static final int VIEW_STATE_ENABLED = 1 << 3; static final int VIEW_STATE_PRESSED = 1 << 4; static final int VIEW_STATE_ACTIVATED = 1 << 5; static final int VIEW_STATE_ACCELERATED = 1 << 6; static final int VIEW_STATE_HOVERED = 1 << 7; static final int VIEW_STATE_DRAG_CAN_ACCEPT = 1 << 8; static final int VIEW_STATE_DRAG_HOVERED = 1 << 9; static final int[] VIEW_STATE_IDS = new int[] { R.attr.state_window_focused, VIEW_STATE_WINDOW_FOCUSED, R.attr.state_selected, VIEW_STATE_SELECTED, R.attr.state_focused, VIEW_STATE_FOCUSED, R.attr.state_enabled, VIEW_STATE_ENABLED, R.attr.state_pressed, VIEW_STATE_PRESSED, R.attr.state_activated, VIEW_STATE_ACTIVATED, R.attr.state_accelerated, VIEW_STATE_ACCELERATED, R.attr.state_hovered, VIEW_STATE_HOVERED, R.attr.state_drag_can_accept, VIEW_STATE_DRAG_CAN_ACCEPT, R.attr.state_drag_hovered, VIEW_STATE_DRAG_HOVERED, }; static { if ((VIEW_STATE_IDS.length/2) != R.styleable.ViewDrawableStates.length) { throw new IllegalStateException( "VIEW_STATE_IDs array length does not match ViewDrawableStates style array"); } int[] orderedIds = new int[VIEW_STATE_IDS.length]; for (int i = 0; i < R.styleable.ViewDrawableStates.length; i++) { int viewState = R.styleable.ViewDrawableStates[i]; for (int j = 0; jIndicates that the view has a software layer. A software layer is backed * by a bitmap and causes the view to be rendered using Android's software * rendering pipeline, even if hardware acceleration is enabled.
* *Software layers have various usages:
*When the application is not using hardware acceleration, a software layer * is useful to apply a specific color filter and/or blending mode and/or * translucency to a view and all its children.
*When the application is using hardware acceleration, a software layer * is useful to render drawing primitives not supported by the hardware * accelerated pipeline. It can also be used to cache a complex view tree * into a texture and reduce the complexity of drawing operations. For instance, * when animating a complex view tree with a translation, a software layer can * be used to render the view tree only once.
*Software layers should be avoided when the affected view tree updates * often. Every update will require to re-render the software layer, which can * potentially be slow (particularly when hardware acceleration is turned on * since the layer will have to be uploaded into a hardware texture after every * update.)
* * @see #getLayerType() * @see #setLayerType(int, android.graphics.Paint) * @see #LAYER_TYPE_NONE * @see #LAYER_TYPE_HARDWARE */ public static final int LAYER_TYPE_SOFTWARE = 1; /** *Indicates that the view has a hardware layer. A hardware layer is backed * by a hardware specific texture (generally Frame Buffer Objects or FBO on * OpenGL hardware) and causes the view to be rendered using Android's hardware * rendering pipeline, but only if hardware acceleration is turned on for the * view hierarchy. When hardware acceleration is turned off, hardware layers * behave exactly as {@link #LAYER_TYPE_SOFTWARE software layers}.
* *A hardware layer is useful to apply a specific color filter and/or * blending mode and/or translucency to a view and all its children.
*A hardware layer can be used to cache a complex view tree into a * texture and reduce the complexity of drawing operations. For instance, * when animating a complex view tree with a translation, a hardware layer can * be used to render the view tree only once.
*A hardware layer can also be used to increase the rendering quality when * rotation transformations are applied on a view. It can also be used to * prevent potential clipping issues when applying 3D transforms on a view.
* * @see #getLayerType() * @see #setLayerType(int, android.graphics.Paint) * @see #LAYER_TYPE_NONE * @see #LAYER_TYPE_SOFTWARE */ public static final int LAYER_TYPE_HARDWARE = 2; @ViewDebug.ExportedProperty(category = "drawing", mapping = { @ViewDebug.IntToString(from = LAYER_TYPE_NONE, to = "NONE"), @ViewDebug.IntToString(from = LAYER_TYPE_SOFTWARE, to = "SOFTWARE"), @ViewDebug.IntToString(from = LAYER_TYPE_HARDWARE, to = "HARDWARE") }) int mLayerType = LAYER_TYPE_NONE; Paint mLayerPaint; Rect mLocalDirtyRect; /** * Consistency verifier for debugging purposes. * @hide */ protected final InputEventConsistencyVerifier mInputEventConsistencyVerifier = InputEventConsistencyVerifier.isInstrumentationEnabled() ? new InputEventConsistencyVerifier(this, 0) : null; /** * Simple constructor to use when creating a view from code. * * @param context The Context the view is running in, through which it can * access the current theme, resources, etc. */ public View(Context context) { mContext = context; mResources = context != null ? context.getResources() : null; mViewFlags = SOUND_EFFECTS_ENABLED | HAPTIC_FEEDBACK_ENABLED; mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop(); setOverScrollMode(OVER_SCROLL_IF_CONTENT_SCROLLS); } /** * Constructor that is called when inflating a view from XML. This is called * when a view is being constructed from an XML file, supplying attributes * that were specified in the XML file. This version uses a default style of * 0, so the only attribute values applied are those in the Context's Theme * and the given AttributeSet. * *
* The method onFinishInflate() will be called after all children have been
* added.
*
* @param context The Context the view is running in, through which it can
* access the current theme, resources, etc.
* @param attrs The attributes of the XML tag that is inflating the view.
* @see #View(Context, AttributeSet, int)
*/
public View(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
/**
* Perform inflation from XML and apply a class-specific base style. This
* constructor of View allows subclasses to use their own base style when
* they are inflating. For example, a Button class's constructor would call
* this version of the super class constructor and supply
* R.attr.buttonStyle
for defStyle; this allows
* the theme's button style to modify all of the base view attributes (in
* particular its background) as well as the Button class's attributes.
*
* @param context The Context the view is running in, through which it can
* access the current theme, resources, etc.
* @param attrs The attributes of the XML tag that is inflating the view.
* @param defStyle The default style to apply to this view. If 0, no style
* will be applied (beyond what is included in the theme). This may
* either be an attribute resource, whose value will be retrieved
* from the current theme, or an explicit style resource.
* @see #View(Context, AttributeSet)
*/
public View(Context context, AttributeSet attrs, int defStyle) {
this(context);
TypedArray a = context.obtainStyledAttributes(attrs, com.android.internal.R.styleable.View,
defStyle, 0);
Drawable background = null;
int leftPadding = -1;
int topPadding = -1;
int rightPadding = -1;
int bottomPadding = -1;
int padding = -1;
int viewFlagValues = 0;
int viewFlagMasks = 0;
boolean setScrollContainer = false;
int x = 0;
int y = 0;
float tx = 0;
float ty = 0;
float rotation = 0;
float rotationX = 0;
float rotationY = 0;
float sx = 1f;
float sy = 1f;
boolean transformSet = false;
int scrollbarStyle = SCROLLBARS_INSIDE_OVERLAY;
int overScrollMode = mOverScrollMode;
final int N = a.getIndexCount();
for (int i = 0; i < N; i++) {
int attr = a.getIndex(i);
switch (attr) {
case com.android.internal.R.styleable.View_background:
background = a.getDrawable(attr);
break;
case com.android.internal.R.styleable.View_padding:
padding = a.getDimensionPixelSize(attr, -1);
break;
case com.android.internal.R.styleable.View_paddingLeft:
leftPadding = a.getDimensionPixelSize(attr, -1);
break;
case com.android.internal.R.styleable.View_paddingTop:
topPadding = a.getDimensionPixelSize(attr, -1);
break;
case com.android.internal.R.styleable.View_paddingRight:
rightPadding = a.getDimensionPixelSize(attr, -1);
break;
case com.android.internal.R.styleable.View_paddingBottom:
bottomPadding = a.getDimensionPixelSize(attr, -1);
break;
case com.android.internal.R.styleable.View_scrollX:
x = a.getDimensionPixelOffset(attr, 0);
break;
case com.android.internal.R.styleable.View_scrollY:
y = a.getDimensionPixelOffset(attr, 0);
break;
case com.android.internal.R.styleable.View_alpha:
setAlpha(a.getFloat(attr, 1f));
break;
case com.android.internal.R.styleable.View_transformPivotX:
setPivotX(a.getDimensionPixelOffset(attr, 0));
break;
case com.android.internal.R.styleable.View_transformPivotY:
setPivotY(a.getDimensionPixelOffset(attr, 0));
break;
case com.android.internal.R.styleable.View_translationX:
tx = a.getDimensionPixelOffset(attr, 0);
transformSet = true;
break;
case com.android.internal.R.styleable.View_translationY:
ty = a.getDimensionPixelOffset(attr, 0);
transformSet = true;
break;
case com.android.internal.R.styleable.View_rotation:
rotation = a.getFloat(attr, 0);
transformSet = true;
break;
case com.android.internal.R.styleable.View_rotationX:
rotationX = a.getFloat(attr, 0);
transformSet = true;
break;
case com.android.internal.R.styleable.View_rotationY:
rotationY = a.getFloat(attr, 0);
transformSet = true;
break;
case com.android.internal.R.styleable.View_scaleX:
sx = a.getFloat(attr, 1f);
transformSet = true;
break;
case com.android.internal.R.styleable.View_scaleY:
sy = a.getFloat(attr, 1f);
transformSet = true;
break;
case com.android.internal.R.styleable.View_id:
mID = a.getResourceId(attr, NO_ID);
break;
case com.android.internal.R.styleable.View_tag:
mTag = a.getText(attr);
break;
case com.android.internal.R.styleable.View_fitsSystemWindows:
if (a.getBoolean(attr, false)) {
viewFlagValues |= FITS_SYSTEM_WINDOWS;
viewFlagMasks |= FITS_SYSTEM_WINDOWS;
}
break;
case com.android.internal.R.styleable.View_focusable:
if (a.getBoolean(attr, false)) {
viewFlagValues |= FOCUSABLE;
viewFlagMasks |= FOCUSABLE_MASK;
}
break;
case com.android.internal.R.styleable.View_focusableInTouchMode:
if (a.getBoolean(attr, false)) {
viewFlagValues |= FOCUSABLE_IN_TOUCH_MODE | FOCUSABLE;
viewFlagMasks |= FOCUSABLE_IN_TOUCH_MODE | FOCUSABLE_MASK;
}
break;
case com.android.internal.R.styleable.View_clickable:
if (a.getBoolean(attr, false)) {
viewFlagValues |= CLICKABLE;
viewFlagMasks |= CLICKABLE;
}
break;
case com.android.internal.R.styleable.View_longClickable:
if (a.getBoolean(attr, false)) {
viewFlagValues |= LONG_CLICKABLE;
viewFlagMasks |= LONG_CLICKABLE;
}
break;
case com.android.internal.R.styleable.View_saveEnabled:
if (!a.getBoolean(attr, true)) {
viewFlagValues |= SAVE_DISABLED;
viewFlagMasks |= SAVE_DISABLED_MASK;
}
break;
case com.android.internal.R.styleable.View_duplicateParentState:
if (a.getBoolean(attr, false)) {
viewFlagValues |= DUPLICATE_PARENT_STATE;
viewFlagMasks |= DUPLICATE_PARENT_STATE;
}
break;
case com.android.internal.R.styleable.View_visibility:
final int visibility = a.getInt(attr, 0);
if (visibility != 0) {
viewFlagValues |= VISIBILITY_FLAGS[visibility];
viewFlagMasks |= VISIBILITY_MASK;
}
break;
case com.android.internal.R.styleable.View_drawingCacheQuality:
final int cacheQuality = a.getInt(attr, 0);
if (cacheQuality != 0) {
viewFlagValues |= DRAWING_CACHE_QUALITY_FLAGS[cacheQuality];
viewFlagMasks |= DRAWING_CACHE_QUALITY_MASK;
}
break;
case com.android.internal.R.styleable.View_contentDescription:
mContentDescription = a.getString(attr);
break;
case com.android.internal.R.styleable.View_soundEffectsEnabled:
if (!a.getBoolean(attr, true)) {
viewFlagValues &= ~SOUND_EFFECTS_ENABLED;
viewFlagMasks |= SOUND_EFFECTS_ENABLED;
}
break;
case com.android.internal.R.styleable.View_hapticFeedbackEnabled:
if (!a.getBoolean(attr, true)) {
viewFlagValues &= ~HAPTIC_FEEDBACK_ENABLED;
viewFlagMasks |= HAPTIC_FEEDBACK_ENABLED;
}
break;
case R.styleable.View_scrollbars:
final int scrollbars = a.getInt(attr, SCROLLBARS_NONE);
if (scrollbars != SCROLLBARS_NONE) {
viewFlagValues |= scrollbars;
viewFlagMasks |= SCROLLBARS_MASK;
initializeScrollbars(a);
}
break;
case R.styleable.View_fadingEdge:
final int fadingEdge = a.getInt(attr, FADING_EDGE_NONE);
if (fadingEdge != FADING_EDGE_NONE) {
viewFlagValues |= fadingEdge;
viewFlagMasks |= FADING_EDGE_MASK;
initializeFadingEdge(a);
}
break;
case R.styleable.View_scrollbarStyle:
scrollbarStyle = a.getInt(attr, SCROLLBARS_INSIDE_OVERLAY);
if (scrollbarStyle != SCROLLBARS_INSIDE_OVERLAY) {
viewFlagValues |= scrollbarStyle & SCROLLBARS_STYLE_MASK;
viewFlagMasks |= SCROLLBARS_STYLE_MASK;
}
break;
case R.styleable.View_isScrollContainer:
setScrollContainer = true;
if (a.getBoolean(attr, false)) {
setScrollContainer(true);
}
break;
case com.android.internal.R.styleable.View_keepScreenOn:
if (a.getBoolean(attr, false)) {
viewFlagValues |= KEEP_SCREEN_ON;
viewFlagMasks |= KEEP_SCREEN_ON;
}
break;
case R.styleable.View_filterTouchesWhenObscured:
if (a.getBoolean(attr, false)) {
viewFlagValues |= FILTER_TOUCHES_WHEN_OBSCURED;
viewFlagMasks |= FILTER_TOUCHES_WHEN_OBSCURED;
}
break;
case R.styleable.View_nextFocusLeft:
mNextFocusLeftId = a.getResourceId(attr, View.NO_ID);
break;
case R.styleable.View_nextFocusRight:
mNextFocusRightId = a.getResourceId(attr, View.NO_ID);
break;
case R.styleable.View_nextFocusUp:
mNextFocusUpId = a.getResourceId(attr, View.NO_ID);
break;
case R.styleable.View_nextFocusDown:
mNextFocusDownId = a.getResourceId(attr, View.NO_ID);
break;
case R.styleable.View_nextFocusForward:
mNextFocusForwardId = a.getResourceId(attr, View.NO_ID);
break;
case R.styleable.View_minWidth:
mMinWidth = a.getDimensionPixelSize(attr, 0);
break;
case R.styleable.View_minHeight:
mMinHeight = a.getDimensionPixelSize(attr, 0);
break;
case R.styleable.View_onClick:
if (context.isRestricted()) {
throw new IllegalStateException("The android:onClick attribute cannot "
+ "be used within a restricted context");
}
final String handlerName = a.getString(attr);
if (handlerName != null) {
setOnClickListener(new OnClickListener() {
private Method mHandler;
public void onClick(View v) {
if (mHandler == null) {
try {
mHandler = getContext().getClass().getMethod(handlerName,
View.class);
} catch (NoSuchMethodException e) {
int id = getId();
String idText = id == NO_ID ? "" : " with id '"
+ getContext().getResources().getResourceEntryName(
id) + "'";
throw new IllegalStateException("Could not find a method " +
handlerName + "(View) in the activity "
+ getContext().getClass() + " for onClick handler"
+ " on view " + View.this.getClass() + idText, e);
}
}
try {
mHandler.invoke(getContext(), View.this);
} catch (IllegalAccessException e) {
throw new IllegalStateException("Could not execute non "
+ "public method of the activity", e);
} catch (InvocationTargetException e) {
throw new IllegalStateException("Could not execute "
+ "method of the activity", e);
}
}
});
}
break;
case R.styleable.View_overScrollMode:
overScrollMode = a.getInt(attr, OVER_SCROLL_IF_CONTENT_SCROLLS);
break;
case R.styleable.View_verticalScrollbarPosition:
mVerticalScrollbarPosition = a.getInt(attr, SCROLLBAR_POSITION_DEFAULT);
break;
case R.styleable.View_layerType:
setLayerType(a.getInt(attr, LAYER_TYPE_NONE), null);
break;
}
}
setOverScrollMode(overScrollMode);
if (background != null) {
setBackgroundDrawable(background);
}
if (padding >= 0) {
leftPadding = padding;
topPadding = padding;
rightPadding = padding;
bottomPadding = padding;
}
// If the user specified the padding (either with android:padding or
// android:paddingLeft/Top/Right/Bottom), use this padding, otherwise
// use the default padding or the padding from the background drawable
// (stored at this point in mPadding*)
setPadding(leftPadding >= 0 ? leftPadding : mPaddingLeft,
topPadding >= 0 ? topPadding : mPaddingTop,
rightPadding >= 0 ? rightPadding : mPaddingRight,
bottomPadding >= 0 ? bottomPadding : mPaddingBottom);
if (viewFlagMasks != 0) {
setFlags(viewFlagValues, viewFlagMasks);
}
// Needs to be called after mViewFlags is set
if (scrollbarStyle != SCROLLBARS_INSIDE_OVERLAY) {
recomputePadding();
}
if (x != 0 || y != 0) {
scrollTo(x, y);
}
if (transformSet) {
setTranslationX(tx);
setTranslationY(ty);
setRotation(rotation);
setRotationX(rotationX);
setRotationY(rotationY);
setScaleX(sx);
setScaleY(sy);
}
if (!setScrollContainer && (viewFlagValues&SCROLLBARS_VERTICAL) != 0) {
setScrollContainer(true);
}
computeOpaqueFlags();
a.recycle();
}
/**
* Non-public constructor for use in testing
*/
View() {
}
/**
*
* Initializes the fading edges from a given set of styled attributes. This * method should be called by subclasses that need fading edges and when an * instance of these subclasses is created programmatically rather than * being inflated from XML. This method is automatically called when the XML * is inflated. *
* * @param a the styled attributes set to initialize the fading edges from */ protected void initializeFadingEdge(TypedArray a) { initScrollCache(); mScrollCache.fadingEdgeLength = a.getDimensionPixelSize( R.styleable.View_fadingEdgeLength, ViewConfiguration.get(mContext).getScaledFadingEdgeLength()); } /** * Returns the size of the vertical faded edges used to indicate that more * content in this view is visible. * * @return The size in pixels of the vertical faded edge or 0 if vertical * faded edges are not enabled for this view. * @attr ref android.R.styleable#View_fadingEdgeLength */ public int getVerticalFadingEdgeLength() { if (isVerticalFadingEdgeEnabled()) { ScrollabilityCache cache = mScrollCache; if (cache != null) { return cache.fadingEdgeLength; } } return 0; } /** * Set the size of the faded edge used to indicate that more content in this * view is available. Will not change whether the fading edge is enabled; use * {@link #setVerticalFadingEdgeEnabled} or {@link #setHorizontalFadingEdgeEnabled} * to enable the fading edge for the vertical or horizontal fading edges. * * @param length The size in pixels of the faded edge used to indicate that more * content in this view is visible. */ public void setFadingEdgeLength(int length) { initScrollCache(); mScrollCache.fadingEdgeLength = length; } /** * Returns the size of the horizontal faded edges used to indicate that more * content in this view is visible. * * @return The size in pixels of the horizontal faded edge or 0 if horizontal * faded edges are not enabled for this view. * @attr ref android.R.styleable#View_fadingEdgeLength */ public int getHorizontalFadingEdgeLength() { if (isHorizontalFadingEdgeEnabled()) { ScrollabilityCache cache = mScrollCache; if (cache != null) { return cache.fadingEdgeLength; } } return 0; } /** * Returns the width of the vertical scrollbar. * * @return The width in pixels of the vertical scrollbar or 0 if there * is no vertical scrollbar. */ public int getVerticalScrollbarWidth() { ScrollabilityCache cache = mScrollCache; if (cache != null) { ScrollBarDrawable scrollBar = cache.scrollBar; if (scrollBar != null) { int size = scrollBar.getSize(true); if (size <= 0) { size = cache.scrollBarSize; } return size; } return 0; } return 0; } /** * Returns the height of the horizontal scrollbar. * * @return The height in pixels of the horizontal scrollbar or 0 if * there is no horizontal scrollbar. */ protected int getHorizontalScrollbarHeight() { ScrollabilityCache cache = mScrollCache; if (cache != null) { ScrollBarDrawable scrollBar = cache.scrollBar; if (scrollBar != null) { int size = scrollBar.getSize(false); if (size <= 0) { size = cache.scrollBarSize; } return size; } return 0; } return 0; } /** ** Initializes the scrollbars from a given set of styled attributes. This * method should be called by subclasses that need scrollbars and when an * instance of these subclasses is created programmatically rather than * being inflated from XML. This method is automatically called when the XML * is inflated. *
* * @param a the styled attributes set to initialize the scrollbars from */ protected void initializeScrollbars(TypedArray a) { initScrollCache(); final ScrollabilityCache scrollabilityCache = mScrollCache; if (scrollabilityCache.scrollBar == null) { scrollabilityCache.scrollBar = new ScrollBarDrawable(); } final boolean fadeScrollbars = a.getBoolean(R.styleable.View_fadeScrollbars, true); if (!fadeScrollbars) { scrollabilityCache.state = ScrollabilityCache.ON; } scrollabilityCache.fadeScrollBars = fadeScrollbars; scrollabilityCache.scrollBarFadeDuration = a.getInt( R.styleable.View_scrollbarFadeDuration, ViewConfiguration .getScrollBarFadeDuration()); scrollabilityCache.scrollBarDefaultDelayBeforeFade = a.getInt( R.styleable.View_scrollbarDefaultDelayBeforeFade, ViewConfiguration.getScrollDefaultDelay()); scrollabilityCache.scrollBarSize = a.getDimensionPixelSize( com.android.internal.R.styleable.View_scrollbarSize, ViewConfiguration.get(mContext).getScaledScrollBarSize()); Drawable track = a.getDrawable(R.styleable.View_scrollbarTrackHorizontal); scrollabilityCache.scrollBar.setHorizontalTrackDrawable(track); Drawable thumb = a.getDrawable(R.styleable.View_scrollbarThumbHorizontal); if (thumb != null) { scrollabilityCache.scrollBar.setHorizontalThumbDrawable(thumb); } boolean alwaysDraw = a.getBoolean(R.styleable.View_scrollbarAlwaysDrawHorizontalTrack, false); if (alwaysDraw) { scrollabilityCache.scrollBar.setAlwaysDrawHorizontalTrack(true); } track = a.getDrawable(R.styleable.View_scrollbarTrackVertical); scrollabilityCache.scrollBar.setVerticalTrackDrawable(track); thumb = a.getDrawable(R.styleable.View_scrollbarThumbVertical); if (thumb != null) { scrollabilityCache.scrollBar.setVerticalThumbDrawable(thumb); } alwaysDraw = a.getBoolean(R.styleable.View_scrollbarAlwaysDrawVerticalTrack, false); if (alwaysDraw) { scrollabilityCache.scrollBar.setAlwaysDrawVerticalTrack(true); } // Re-apply user/background padding so that scrollbar(s) get added recomputePadding(); } /** ** Initalizes the scrollability cache if necessary. *
*/ private void initScrollCache() { if (mScrollCache == null) { mScrollCache = new ScrollabilityCache(ViewConfiguration.get(mContext), this); } } /** * Set the position of the vertical scroll bar. Should be one of * {@link #SCROLLBAR_POSITION_DEFAULT}, {@link #SCROLLBAR_POSITION_LEFT} or * {@link #SCROLLBAR_POSITION_RIGHT}. * * @param position Where the vertical scroll bar should be positioned. */ public void setVerticalScrollbarPosition(int position) { if (mVerticalScrollbarPosition != position) { mVerticalScrollbarPosition = position; computeOpaqueFlags(); recomputePadding(); } } /** * @return The position where the vertical scroll bar will show, if applicable. * @see #setVerticalScrollbarPosition(int) */ public int getVerticalScrollbarPosition() { return mVerticalScrollbarPosition; } /** * Register a callback to be invoked when focus of this view changed. * * @param l The callback that will run. */ public void setOnFocusChangeListener(OnFocusChangeListener l) { mOnFocusChangeListener = l; } /** * Add a listener that will be called when the bounds of the view change due to * layout processing. * * @param listener The listener that will be called when layout bounds change. */ public void addOnLayoutChangeListener(OnLayoutChangeListener listener) { if (mOnLayoutChangeListeners == null) { mOnLayoutChangeListeners = new ArrayListA View should call this if it maintains some notion of which part * of its content is interesting. For example, a text editing view * should call this when its cursor moves. * * @param rectangle The rectangle. * @return Whether any parent scrolled. */ public boolean requestRectangleOnScreen(Rect rectangle) { return requestRectangleOnScreen(rectangle, false); } /** * Request that a rectangle of this view be visible on the screen, * scrolling if necessary just enough. * *
A View should call this if it maintains some notion of which part * of its content is interesting. For example, a text editing view * should call this when its cursor moves. * *
When You may wish to disable sound effects for a view if you already play sounds,
* for instance, a dial key that plays dtmf tones.
*
* @param soundEffectsEnabled whether sound effects are enabled for this view.
* @see #isSoundEffectsEnabled()
* @see #playSoundEffect(int)
* @attr ref android.R.styleable#View_soundEffectsEnabled
*/
public void setSoundEffectsEnabled(boolean soundEffectsEnabled) {
setFlags(soundEffectsEnabled ? SOUND_EFFECTS_ENABLED: 0, SOUND_EFFECTS_ENABLED);
}
/**
* @return whether this view should have sound effects enabled for events such as
* clicking and touching.
*
* @see #setSoundEffectsEnabled(boolean)
* @see #playSoundEffect(int)
* @attr ref android.R.styleable#View_soundEffectsEnabled
*/
@ViewDebug.ExportedProperty
public boolean isSoundEffectsEnabled() {
return SOUND_EFFECTS_ENABLED == (mViewFlags & SOUND_EFFECTS_ENABLED);
}
/**
* Set whether this view should have haptic feedback for events such as
* long presses.
*
* You may wish to disable haptic feedback if your view already controls
* its own haptic feedback.
*
* @param hapticFeedbackEnabled whether haptic feedback enabled for this view.
* @see #isHapticFeedbackEnabled()
* @see #performHapticFeedback(int)
* @attr ref android.R.styleable#View_hapticFeedbackEnabled
*/
public void setHapticFeedbackEnabled(boolean hapticFeedbackEnabled) {
setFlags(hapticFeedbackEnabled ? HAPTIC_FEEDBACK_ENABLED: 0, HAPTIC_FEEDBACK_ENABLED);
}
/**
* @return whether this view should have haptic feedback enabled for events
* long presses.
*
* @see #setHapticFeedbackEnabled(boolean)
* @see #performHapticFeedback(int)
* @attr ref android.R.styleable#View_hapticFeedbackEnabled
*/
@ViewDebug.ExportedProperty
public boolean isHapticFeedbackEnabled() {
return HAPTIC_FEEDBACK_ENABLED == (mViewFlags & HAPTIC_FEEDBACK_ENABLED);
}
/**
* If this view doesn't do any drawing on its own, set this flag to
* allow further optimizations. By default, this flag is not set on
* View, but could be set on some View subclasses such as ViewGroup.
*
* Typically, if you override {@link #onDraw} you should clear this flag.
*
* @param willNotDraw whether or not this View draw on its own
*/
public void setWillNotDraw(boolean willNotDraw) {
setFlags(willNotDraw ? WILL_NOT_DRAW : 0, DRAW_MASK);
}
/**
* Returns whether or not this View draws on its own.
*
* @return true if this view has nothing to draw, false otherwise
*/
@ViewDebug.ExportedProperty(category = "drawing")
public boolean willNotDraw() {
return (mViewFlags & DRAW_MASK) == WILL_NOT_DRAW;
}
/**
* When a View's drawing cache is enabled, drawing is redirected to an
* offscreen bitmap. Some views, like an ImageView, must be able to
* bypass this mechanism if they already draw a single bitmap, to avoid
* unnecessary usage of the memory.
*
* @param willNotCacheDrawing true if this view does not cache its
* drawing, false otherwise
*/
public void setWillNotCacheDrawing(boolean willNotCacheDrawing) {
setFlags(willNotCacheDrawing ? WILL_NOT_CACHE_DRAWING : 0, WILL_NOT_CACHE_DRAWING);
}
/**
* Returns whether or not this View can cache its drawing or not.
*
* @return true if this view does not cache its drawing, false otherwise
*/
@ViewDebug.ExportedProperty(category = "drawing")
public boolean willNotCacheDrawing() {
return (mViewFlags & WILL_NOT_CACHE_DRAWING) == WILL_NOT_CACHE_DRAWING;
}
/**
* Indicates whether this view reacts to click events or not.
*
* @return true if the view is clickable, false otherwise
*
* @see #setClickable(boolean)
* @attr ref android.R.styleable#View_clickable
*/
@ViewDebug.ExportedProperty
public boolean isClickable() {
return (mViewFlags & CLICKABLE) == CLICKABLE;
}
/**
* Enables or disables click events for this view. When a view
* is clickable it will change its state to "pressed" on every click.
* Subclasses should set the view clickable to visually react to
* user's clicks.
*
* @param clickable true to make the view clickable, false otherwise
*
* @see #isClickable()
* @attr ref android.R.styleable#View_clickable
*/
public void setClickable(boolean clickable) {
setFlags(clickable ? CLICKABLE : 0, CLICKABLE);
}
/**
* Indicates whether this view reacts to long click events or not.
*
* @return true if the view is long clickable, false otherwise
*
* @see #setLongClickable(boolean)
* @attr ref android.R.styleable#View_longClickable
*/
public boolean isLongClickable() {
return (mViewFlags & LONG_CLICKABLE) == LONG_CLICKABLE;
}
/**
* Enables or disables long click events for this view. When a view is long
* clickable it reacts to the user holding down the button for a longer
* duration than a tap. This event can either launch the listener or a
* context menu.
*
* @param longClickable true to make the view long clickable, false otherwise
* @see #isLongClickable()
* @attr ref android.R.styleable#View_longClickable
*/
public void setLongClickable(boolean longClickable) {
setFlags(longClickable ? LONG_CLICKABLE : 0, LONG_CLICKABLE);
}
/**
* Sets the pressed state for this view.
*
* @see #isClickable()
* @see #setClickable(boolean)
*
* @param pressed Pass true to set the View's internal state to "pressed", or false to reverts
* the View's internal state from a previously set "pressed" state.
*/
public void setPressed(boolean pressed) {
if (pressed) {
mPrivateFlags |= PRESSED;
} else {
mPrivateFlags &= ~PRESSED;
}
refreshDrawableState();
dispatchSetPressed(pressed);
}
/**
* Dispatch setPressed to all of this View's children.
*
* @see #setPressed(boolean)
*
* @param pressed The new pressed state
*/
protected void dispatchSetPressed(boolean pressed) {
}
/**
* Indicates whether the view is currently in pressed state. Unless
* {@link #setPressed(boolean)} is explicitly called, only clickable views can enter
* the pressed state.
*
* @see #setPressed
* @see #isClickable()
* @see #setClickable(boolean)
*
* @return true if the view is currently pressed, false otherwise
*/
public boolean isPressed() {
return (mPrivateFlags & PRESSED) == PRESSED;
}
/**
* Indicates whether this view will save its state (that is,
* whether its {@link #onSaveInstanceState} method will be called).
*
* @return Returns true if the view state saving is enabled, else false.
*
* @see #setSaveEnabled(boolean)
* @attr ref android.R.styleable#View_saveEnabled
*/
public boolean isSaveEnabled() {
return (mViewFlags & SAVE_DISABLED_MASK) != SAVE_DISABLED;
}
/**
* Controls whether the saving of this view's state is
* enabled (that is, whether its {@link #onSaveInstanceState} method
* will be called). Note that even if freezing is enabled, the
* view still must have an id assigned to it (via {@link #setId setId()})
* for its state to be saved. This flag can only disable the
* saving of this view; any child views may still have their state saved.
*
* @param enabled Set to false to disable state saving, or true
* (the default) to allow it.
*
* @see #isSaveEnabled()
* @see #setId(int)
* @see #onSaveInstanceState()
* @attr ref android.R.styleable#View_saveEnabled
*/
public void setSaveEnabled(boolean enabled) {
setFlags(enabled ? 0 : SAVE_DISABLED, SAVE_DISABLED_MASK);
}
/**
* Gets whether the framework should discard touches when the view's
* window is obscured by another visible window.
* Refer to the {@link View} security documentation for more details.
*
* @return True if touch filtering is enabled.
*
* @see #setFilterTouchesWhenObscured(boolean)
* @attr ref android.R.styleable#View_filterTouchesWhenObscured
*/
@ViewDebug.ExportedProperty
public boolean getFilterTouchesWhenObscured() {
return (mViewFlags & FILTER_TOUCHES_WHEN_OBSCURED) != 0;
}
/**
* Sets whether the framework should discard touches when the view's
* window is obscured by another visible window.
* Refer to the {@link View} security documentation for more details.
*
* @param enabled True if touch filtering should be enabled.
*
* @see #getFilterTouchesWhenObscured
* @attr ref android.R.styleable#View_filterTouchesWhenObscured
*/
public void setFilterTouchesWhenObscured(boolean enabled) {
setFlags(enabled ? 0 : FILTER_TOUCHES_WHEN_OBSCURED,
FILTER_TOUCHES_WHEN_OBSCURED);
}
/**
* Indicates whether the entire hierarchy under this view will save its
* state when a state saving traversal occurs from its parent. The default
* is true; if false, these views will not be saved unless
* {@link #saveHierarchyState(SparseArray)} is called directly on this view.
*
* @return Returns true if the view state saving from parent is enabled, else false.
*
* @see #setSaveFromParentEnabled(boolean)
*/
public boolean isSaveFromParentEnabled() {
return (mViewFlags & PARENT_SAVE_DISABLED_MASK) != PARENT_SAVE_DISABLED;
}
/**
* Controls whether the entire hierarchy under this view will save its
* state when a state saving traversal occurs from its parent. The default
* is true; if false, these views will not be saved unless
* {@link #saveHierarchyState(SparseArray)} is called directly on this view.
*
* @param enabled Set to false to disable state saving, or true
* (the default) to allow it.
*
* @see #isSaveFromParentEnabled()
* @see #setId(int)
* @see #onSaveInstanceState()
*/
public void setSaveFromParentEnabled(boolean enabled) {
setFlags(enabled ? 0 : PARENT_SAVE_DISABLED, PARENT_SAVE_DISABLED_MASK);
}
/**
* Returns whether this View is able to take focus.
*
* @return True if this view can take focus, or false otherwise.
* @attr ref android.R.styleable#View_focusable
*/
@ViewDebug.ExportedProperty(category = "focus")
public final boolean isFocusable() {
return FOCUSABLE == (mViewFlags & FOCUSABLE_MASK);
}
/**
* When a view is focusable, it may not want to take focus when in touch mode.
* For example, a button would like focus when the user is navigating via a D-pad
* so that the user can click on it, but once the user starts touching the screen,
* the button shouldn't take focus
* @return Whether the view is focusable in touch mode.
* @attr ref android.R.styleable#View_focusableInTouchMode
*/
@ViewDebug.ExportedProperty
public final boolean isFocusableInTouchMode() {
return FOCUSABLE_IN_TOUCH_MODE == (mViewFlags & FOCUSABLE_IN_TOUCH_MODE);
}
/**
* Find the nearest view in the specified direction that can take focus.
* This does not actually give focus to that view.
*
* @param direction One of FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, and FOCUS_RIGHT
*
* @return The nearest focusable in the specified direction, or null if none
* can be found.
*/
public View focusSearch(int direction) {
if (mParent != null) {
return mParent.focusSearch(this, direction);
} else {
return null;
}
}
/**
* This method is the last chance for the focused view and its ancestors to
* respond to an arrow key. This is called when the focused view did not
* consume the key internally, nor could the view system find a new view in
* the requested direction to give focus to.
*
* @param focused The currently focused view.
* @param direction The direction focus wants to move. One of FOCUS_UP,
* FOCUS_DOWN, FOCUS_LEFT, and FOCUS_RIGHT.
* @return True if the this view consumed this unhandled move.
*/
public boolean dispatchUnhandledMove(View focused, int direction) {
return false;
}
/**
* If a user manually specified the next view id for a particular direction,
* use the root to look up the view.
* @param root The root view of the hierarchy containing this view.
* @param direction One of FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, FOCUS_RIGHT, FOCUS_FORWARD,
* or FOCUS_BACKWARD.
* @return The user specified next view, or null if there is none.
*/
View findUserSetNextFocus(View root, int direction) {
switch (direction) {
case FOCUS_LEFT:
if (mNextFocusLeftId == View.NO_ID) return null;
return findViewShouldExist(root, mNextFocusLeftId);
case FOCUS_RIGHT:
if (mNextFocusRightId == View.NO_ID) return null;
return findViewShouldExist(root, mNextFocusRightId);
case FOCUS_UP:
if (mNextFocusUpId == View.NO_ID) return null;
return findViewShouldExist(root, mNextFocusUpId);
case FOCUS_DOWN:
if (mNextFocusDownId == View.NO_ID) return null;
return findViewShouldExist(root, mNextFocusDownId);
case FOCUS_FORWARD:
if (mNextFocusForwardId == View.NO_ID) return null;
return findViewShouldExist(root, mNextFocusForwardId);
case FOCUS_BACKWARD: {
final int id = mID;
return root.findViewByPredicate(new Predicate
* Generic motion events with source class {@link InputDevice#SOURCE_CLASS_POINTER}
* are delivered to the view under the pointer. All other generic motion events are
* delivered to the focused view. Hover events are handled specially and are delivered
* to {@link #onHoverEvent}.
*
* Do not call this method directly. Call {@link #dispatchGenericMotionEvent} instead.
*
* Do not call this method directly. Call {@link #dispatchGenericMotionEvent} instead.
*
* Do not call this method directly. Call {@link #dispatchGenericMotionEvent} instead.
*
* Dispatches touch related pointer events to {@link #onTouchEvent} and all
* other events to {@link #onGenericMotionEvent}. This separation of concerns
* reinforces the invariant that {@link #onTouchEvent} is really about touches
* and should not be expected to handle other pointing device features.
* This function requires an IPC back to the window manager to retrieve
* the requested information, so should not be used in performance critical
* code like drawing.
*
* @param outRect Filled in with the visible display frame. If the view
* is not attached to a window, this is simply the raw display size.
*/
public void getWindowVisibleDisplayFrame(Rect outRect) {
if (mAttachInfo != null) {
try {
mAttachInfo.mSession.getDisplayFrame(mAttachInfo.mWindow, outRect);
} catch (RemoteException e) {
return;
}
// XXX This is really broken, and probably all needs to be done
// in the window manager, and we need to know more about whether
// we want the area behind or in front of the IME.
final Rect insets = mAttachInfo.mVisibleInsets;
outRect.left += insets.left;
outRect.top += insets.top;
outRect.right -= insets.right;
outRect.bottom -= insets.bottom;
return;
}
Display d = WindowManagerImpl.getDefault().getDefaultDisplay();
d.getRectSize(outRect);
}
/**
* Dispatch a notification about a resource configuration change down
* the view hierarchy.
* ViewGroups should override to route to their children.
*
* @param newConfig The new resource configuration.
*
* @see #onConfigurationChanged
*/
public void dispatchConfigurationChanged(Configuration newConfig) {
onConfigurationChanged(newConfig);
}
/**
* Called when the current configuration of the resources being used
* by the application have changed. You can use this to decide when
* to reload resources that can changed based on orientation and other
* configuration characterstics. You only need to use this if you are
* not relying on the normal {@link android.app.Activity} mechanism of
* recreating the activity instance upon a configuration change.
*
* @param newConfig The new resource configuration.
*/
protected void onConfigurationChanged(Configuration newConfig) {
}
/**
* Private function to aggregate all per-view attributes in to the view
* root.
*/
void dispatchCollectViewAttributes(int visibility) {
performCollectViewAttributes(visibility);
}
void performCollectViewAttributes(int visibility) {
if ((visibility & VISIBILITY_MASK) == VISIBLE && mAttachInfo != null) {
if ((mViewFlags & KEEP_SCREEN_ON) == KEEP_SCREEN_ON) {
mAttachInfo.mKeepScreenOn = true;
}
mAttachInfo.mSystemUiVisibility |= mSystemUiVisibility;
if (mOnSystemUiVisibilityChangeListener != null) {
mAttachInfo.mHasSystemUiListeners = true;
}
}
}
void needGlobalAttributesUpdate(boolean force) {
final AttachInfo ai = mAttachInfo;
if (ai != null) {
if (force || ai.mKeepScreenOn || (ai.mSystemUiVisibility != 0)
|| ai.mHasSystemUiListeners) {
ai.mRecomputeGlobalAttributes = true;
}
}
}
/**
* Returns whether the device is currently in touch mode. Touch mode is entered
* once the user begins interacting with the device by touch, and affects various
* things like whether focus is always visible to the user.
*
* @return Whether the device is in touch mode.
*/
@ViewDebug.ExportedProperty
public boolean isInTouchMode() {
if (mAttachInfo != null) {
return mAttachInfo.mInTouchMode;
} else {
return ViewRoot.isInTouchMode();
}
}
/**
* Returns the context the view is running in, through which it can
* access the current theme, resources, etc.
*
* @return The view's Context.
*/
@ViewDebug.CapturedViewProperty
public final Context getContext() {
return mContext;
}
/**
* Handle a key event before it is processed by any input method
* associated with the view hierarchy. This can be used to intercept
* key events in special situations before the IME consumes them; a
* typical example would be handling the BACK key to update the application's
* UI instead of allowing the IME to see it and close itself.
*
* @param keyCode The value in event.getKeyCode().
* @param event Description of the key event.
* @return If you handled the event, return true. If you want to allow the
* event to be handled by the next receiver, return false.
*/
public boolean onKeyPreIme(int keyCode, KeyEvent event) {
return false;
}
/**
* Default implementation of {@link KeyEvent.Callback#onKeyDown(int, KeyEvent)
* KeyEvent.Callback.onKeyDown()}: perform press of the view
* when {@link KeyEvent#KEYCODE_DPAD_CENTER} or {@link KeyEvent#KEYCODE_ENTER}
* is released, if the view is enabled and clickable.
*
* @param keyCode A key code that represents the button pressed, from
* {@link android.view.KeyEvent}.
* @param event The KeyEvent object that defines the button action.
*/
public boolean onKeyDown(int keyCode, KeyEvent event) {
boolean result = false;
switch (keyCode) {
case KeyEvent.KEYCODE_DPAD_CENTER:
case KeyEvent.KEYCODE_ENTER: {
if ((mViewFlags & ENABLED_MASK) == DISABLED) {
return true;
}
// Long clickable items don't necessarily have to be clickable
if (((mViewFlags & CLICKABLE) == CLICKABLE ||
(mViewFlags & LONG_CLICKABLE) == LONG_CLICKABLE) &&
(event.getRepeatCount() == 0)) {
setPressed(true);
if ((mViewFlags & LONG_CLICKABLE) == LONG_CLICKABLE) {
postCheckForLongClick(0);
}
return true;
}
break;
}
}
return result;
}
/**
* Default implementation of {@link KeyEvent.Callback#onKeyLongPress(int, KeyEvent)
* KeyEvent.Callback.onKeyLongPress()}: always returns false (doesn't handle
* the event).
*/
public boolean onKeyLongPress(int keyCode, KeyEvent event) {
return false;
}
/**
* Default implementation of {@link KeyEvent.Callback#onKeyUp(int, KeyEvent)
* KeyEvent.Callback.onKeyUp()}: perform clicking of the view
* when {@link KeyEvent#KEYCODE_DPAD_CENTER} or
* {@link KeyEvent#KEYCODE_ENTER} is released.
*
* @param keyCode A key code that represents the button pressed, from
* {@link android.view.KeyEvent}.
* @param event The KeyEvent object that defines the button action.
*/
public boolean onKeyUp(int keyCode, KeyEvent event) {
boolean result = false;
switch (keyCode) {
case KeyEvent.KEYCODE_DPAD_CENTER:
case KeyEvent.KEYCODE_ENTER: {
if ((mViewFlags & ENABLED_MASK) == DISABLED) {
return true;
}
if ((mViewFlags & CLICKABLE) == CLICKABLE && isPressed()) {
setPressed(false);
if (!mHasPerformedLongPress) {
// This is a tap, so remove the longpress check
removeLongPressCallback();
result = performClick();
}
}
break;
}
}
return result;
}
/**
* Default implementation of {@link KeyEvent.Callback#onKeyMultiple(int, int, KeyEvent)
* KeyEvent.Callback.onKeyMultiple()}: always returns false (doesn't handle
* the event).
*
* @param keyCode A key code that represents the button pressed, from
* {@link android.view.KeyEvent}.
* @param repeatCount The number of times the action was made.
* @param event The KeyEvent object that defines the button action.
*/
public boolean onKeyMultiple(int keyCode, int repeatCount, KeyEvent event) {
return false;
}
/**
* Called on the focused view when a key shortcut event is not handled.
* Override this method to implement local key shortcuts for the View.
* Key shortcuts can also be implemented by setting the
* {@link MenuItem#setShortcut(char, char) shortcut} property of menu items.
*
* @param keyCode The value in event.getKeyCode().
* @param event Description of the key event.
* @return If you handled the event, return true. If you want to allow the
* event to be handled by the next receiver, return false.
*/
public boolean onKeyShortcut(int keyCode, KeyEvent event) {
return false;
}
/**
* Check whether the called view is a text editor, in which case it
* would make sense to automatically display a soft input window for
* it. Subclasses should override this if they implement
* {@link #onCreateInputConnection(EditorInfo)} to return true if
* a call on that method would return a non-null InputConnection, and
* they are really a first-class editor that the user would normally
* start typing on when the go into a window containing your view.
*
* The default implementation always returns false. This does
* not mean that its {@link #onCreateInputConnection(EditorInfo)}
* will not be called or the user can not otherwise perform edits on your
* view; it is just a hint to the system that this is not the primary
* purpose of this view.
*
* @return Returns true if this view is a text editor, else false.
*/
public boolean onCheckIsTextEditor() {
return false;
}
/**
* Create a new InputConnection for an InputMethod to interact
* with the view. The default implementation returns null, since it doesn't
* support input methods. You can override this to implement such support.
* This is only needed for views that take focus and text input.
*
* When implementing this, you probably also want to implement
* {@link #onCheckIsTextEditor()} to indicate you will return a
* non-null InputConnection.
*
* @param outAttrs Fill in with attribute information about the connection.
*/
public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
return null;
}
/**
* Called by the {@link android.view.inputmethod.InputMethodManager}
* when a view who is not the current
* input connection target is trying to make a call on the manager. The
* default implementation returns false; you can override this to return
* true for certain views if you are performing InputConnection proxying
* to them.
* @param view The View that is making the InputMethodManager call.
* @return Return true to allow the call, false to reject.
*/
public boolean checkInputConnectionProxy(View view) {
return false;
}
/**
* Show the context menu for this view. It is not safe to hold on to the
* menu after returning from this method.
*
* You should normally not overload this method. Overload
* {@link #onCreateContextMenu(ContextMenu)} or define an
* {@link OnCreateContextMenuListener} to add items to the context menu.
*
* @param menu The context menu to populate
*/
public void createContextMenu(ContextMenu menu) {
ContextMenuInfo menuInfo = getContextMenuInfo();
// Sets the current menu info so all items added to menu will have
// my extra info set.
((MenuBuilder)menu).setCurrentMenuInfo(menuInfo);
onCreateContextMenu(menu);
if (mOnCreateContextMenuListener != null) {
mOnCreateContextMenuListener.onCreateContextMenu(menu, this, menuInfo);
}
// Clear the extra information so subsequent items that aren't mine don't
// have my extra info.
((MenuBuilder)menu).setCurrentMenuInfo(null);
if (mParent != null) {
mParent.createContextMenu(menu);
}
}
/**
* Views should implement this if they have extra information to associate
* with the context menu. The return result is supplied as a parameter to
* the {@link OnCreateContextMenuListener#onCreateContextMenu(ContextMenu, View, ContextMenuInfo)}
* callback.
*
* @return Extra information about the item for which the context menu
* should be shown. This information will vary across different
* subclasses of View.
*/
protected ContextMenuInfo getContextMenuInfo() {
return null;
}
/**
* Views should implement this if the view itself is going to add items to
* the context menu.
*
* @param menu the context menu to populate
*/
protected void onCreateContextMenu(ContextMenu menu) {
}
/**
* Implement this method to handle trackball motion events. The
* relative movement of the trackball since the last event
* can be retrieve with {@link MotionEvent#getX MotionEvent.getX()} and
* {@link MotionEvent#getY MotionEvent.getY()}. These are normalized so
* that a movement of 1 corresponds to the user pressing one DPAD key (so
* they will often be fractional values, representing the more fine-grained
* movement information available from a trackball).
*
* @param event The motion event.
* @return True if the event was handled, false otherwise.
*/
public boolean onTrackballEvent(MotionEvent event) {
return false;
}
/**
* Implement this method to handle generic motion events.
*
* Generic motion events describe joystick movements, mouse hovers, track pad
* touches, scroll wheel movements and other input events. The
* {@link MotionEvent#getSource() source} of the motion event specifies
* the class of input that was received. Implementations of this method
* must examine the bits in the source before processing the event.
* The following code example shows how this is done.
*
* Generic motion events with source class {@link InputDevice#SOURCE_CLASS_POINTER}
* are delivered to the view under the pointer. All other generic motion events are
* delivered to the focused view.
*
* Hover events are pointer events with action {@link MotionEvent#ACTION_HOVER_ENTER},
* {@link MotionEvent#ACTION_HOVER_MOVE}, or {@link MotionEvent#ACTION_HOVER_EXIT}.
*
* The view receives hover enter as the pointer enters the bounds of the view and hover
* exit as the pointer exits the bound of the view or just before the pointer goes down
* (which implies that {@link #onTouchEvent} will be called soon).
*
* If the view would like to handle the hover event itself and prevent its children
* from receiving hover, it should return true from this method. If this method returns
* true and a child has already received a hover enter event, the child will
* automatically receive a hover exit event.
*
* The default implementation sets the hovered state of the view if the view is
* clickable.
* Sets the distance along the Z axis (orthogonal to the X/Y plane on which
* views are drawn) from the camera to this view. The camera's distance
* affects 3D transformations, for instance rotations around the X and Y
* axis. If the rotationX or rotationY properties are changed and this view is
* large (more than half the size of the screen), it is recommended to always
* use a camera distance that's greater than the height (X axis rotation) or
* the width (Y axis rotation) of this view. The distance of the camera from the view plane can have an affect on the
* perspective distortion of the view when it is rotated around the x or y axis.
* For example, a large distance will result in a large viewing angle, and there
* will not be much perspective distortion of the view as it rotates. A short
* distance may cause much more perspective distortion upon rotation, and can
* also result in some drawing artifacts if the rotated view ends up partially
* behind the camera (which is why the recommendation is to use a distance at
* least as far as the size of the view, if the view is to be rotated.) The distance is expressed in "depth pixels." The default distance depends
* on the screen density. For instance, on a medium density display, the
* default distance is 1280. On a high density display, the default distance
* is 1920. If you want to specify a distance that leads to visually consistent
* results across various densities, use the following formula: The density scale factor of a high density display is 1.5,
* and 1920 = 1280 * 1.5. By default, this is 1.0f.
*
* @see #getPivotX()
* @see #getPivotY()
* @return The scaling factor.
*/
public float getScaleX() {
return mScaleX;
}
/**
* Sets the amount that the view is scaled in x around the pivot point, as a proportion of
* the view's unscaled width. A value of 1 means that no scaling is applied.
*
* @param scaleX The scaling factor.
* @see #getPivotX()
* @see #getPivotY()
*
* @attr ref android.R.styleable#View_scaleX
*/
public void setScaleX(float scaleX) {
if (mScaleX != scaleX) {
invalidateParentCaches();
// Double-invalidation is necessary to capture view's old and new areas
invalidate(false);
mScaleX = scaleX;
mMatrixDirty = true;
mPrivateFlags |= DRAWN; // force another invalidation with the new orientation
invalidate(false);
}
}
/**
* The amount that the view is scaled in y around the pivot point, as a proportion of
* the view's unscaled height. A value of 1, the default, means that no scaling is applied.
*
* By default, this is 1.0f.
*
* @see #getPivotX()
* @see #getPivotY()
* @return The scaling factor.
*/
public float getScaleY() {
return mScaleY;
}
/**
* Sets the amount that the view is scaled in Y around the pivot point, as a proportion of
* the view's unscaled width. A value of 1 means that no scaling is applied.
*
* @param scaleY The scaling factor.
* @see #getPivotX()
* @see #getPivotY()
*
* @attr ref android.R.styleable#View_scaleY
*/
public void setScaleY(float scaleY) {
if (mScaleY != scaleY) {
invalidateParentCaches();
// Double-invalidation is necessary to capture view's old and new areas
invalidate(false);
mScaleY = scaleY;
mMatrixDirty = true;
mPrivateFlags |= DRAWN; // force another invalidation with the new orientation
invalidate(false);
}
}
/**
* The x location of the point around which the view is {@link #setRotation(float) rotated}
* and {@link #setScaleX(float) scaled}.
*
* @see #getRotation()
* @see #getScaleX()
* @see #getScaleY()
* @see #getPivotY()
* @return The x location of the pivot point.
*/
public float getPivotX() {
return mPivotX;
}
/**
* Sets the x location of the point around which the view is
* {@link #setRotation(float) rotated} and {@link #setScaleX(float) scaled}.
* By default, the pivot point is centered on the object.
* Setting this property disables this behavior and causes the view to use only the
* explicitly set pivotX and pivotY values.
*
* @param pivotX The x location of the pivot point.
* @see #getRotation()
* @see #getScaleX()
* @see #getScaleY()
* @see #getPivotY()
*
* @attr ref android.R.styleable#View_transformPivotX
*/
public void setPivotX(float pivotX) {
mPrivateFlags |= PIVOT_EXPLICITLY_SET;
if (mPivotX != pivotX) {
invalidateParentCaches();
// Double-invalidation is necessary to capture view's old and new areas
invalidate(false);
mPivotX = pivotX;
mMatrixDirty = true;
mPrivateFlags |= DRAWN; // force another invalidation with the new orientation
invalidate(false);
}
}
/**
* The y location of the point around which the view is {@link #setRotation(float) rotated}
* and {@link #setScaleY(float) scaled}.
*
* @see #getRotation()
* @see #getScaleX()
* @see #getScaleY()
* @see #getPivotY()
* @return The y location of the pivot point.
*/
public float getPivotY() {
return mPivotY;
}
/**
* Sets the y location of the point around which the view is {@link #setRotation(float) rotated}
* and {@link #setScaleY(float) scaled}. By default, the pivot point is centered on the object.
* Setting this property disables this behavior and causes the view to use only the
* explicitly set pivotX and pivotY values.
*
* @param pivotY The y location of the pivot point.
* @see #getRotation()
* @see #getScaleX()
* @see #getScaleY()
* @see #getPivotY()
*
* @attr ref android.R.styleable#View_transformPivotY
*/
public void setPivotY(float pivotY) {
mPrivateFlags |= PIVOT_EXPLICITLY_SET;
if (mPivotY != pivotY) {
invalidateParentCaches();
// Double-invalidation is necessary to capture view's old and new areas
invalidate(false);
mPivotY = pivotY;
mMatrixDirty = true;
mPrivateFlags |= DRAWN; // force another invalidation with the new orientation
invalidate(false);
}
}
/**
* The opacity of the view. This is a value from 0 to 1, where 0 means the view is
* completely transparent and 1 means the view is completely opaque.
*
* By default this is 1.0f.
* @return The opacity of the view.
*/
public float getAlpha() {
return mAlpha;
}
/**
* Sets the opacity of the view. This is a value from 0 to 1, where 0 means the view is
* completely transparent and 1 means the view is completely opaque. If this view overrides {@link #onSetAlpha(int)} to return true, then this view is
* responsible for applying the opacity itself. Otherwise, calling this method is
* equivalent to calling {@link #setLayerType(int, android.graphics.Paint)} and
* setting a hardware layer. Trigger the scrollbars to draw. When invoked this method starts an
* animation to fade the scrollbars out after a default delay. If a subclass
* provides animated scrolling, the start delay should equal the duration
* of the scrolling animation. The animation starts only if at least one of the scrollbars is
* enabled, as specified by {@link #isHorizontalScrollBarEnabled()} and
* {@link #isVerticalScrollBarEnabled()}. When the animation is started,
* this method returns true, and false otherwise. If the animation is
* started, this method calls {@link #invalidate()}; in that case the
* caller should not call {@link #invalidate()}. This method should be invoked every time a subclass directly updates
* the scroll parameters. This method is automatically invoked by {@link #scrollBy(int, int)}
* and {@link #scrollTo(int, int)}.
* Trigger the scrollbars to draw. When invoked this method starts an
* animation to fade the scrollbars out after a fixed delay. If a subclass
* provides animated scrolling, the start delay should equal the duration of
* the scrolling animation.
*
* The animation starts only if at least one of the scrollbars is enabled,
* as specified by {@link #isHorizontalScrollBarEnabled()} and
* {@link #isVerticalScrollBarEnabled()}. When the animation is started,
* this method returns true, and false otherwise. If the animation is
* started, this method calls {@link #invalidate()}; in that case the caller
* should not call {@link #invalidate()}.
*
* This method should be invoked everytime a subclass directly updates the
* scroll parameters.
*
* Trigger the scrollbars to draw. When invoked this method starts an
* animation to fade the scrollbars out after a fixed delay. If a subclass
* provides animated scrolling, the start delay should equal the duration of
* the scrolling animation.
*
* The animation starts only if at least one of the scrollbars is enabled,
* as specified by {@link #isHorizontalScrollBarEnabled()} and
* {@link #isVerticalScrollBarEnabled()}. When the animation is started,
* this method returns true, and false otherwise. If the animation is
* started, this method calls {@link #invalidate()} if the invalidate parameter
* is set to true; in that case the caller
* should not call {@link #invalidate()}.
*
* This method should be invoked everytime a subclass directly updates the
* scroll parameters.
* Indicate whether the horizontal edges are faded when the view is
* scrolled horizontally. Define whether the horizontal edges should be faded when this view
* is scrolled horizontally. Indicate whether the vertical edges are faded when the view is
* scrolled horizontally. Define whether the vertical edges should be faded when this view
* is scrolled vertically. Indicate whether the horizontal scrollbar should be drawn or not. The
* scrollbar is not drawn by default. Define whether the horizontal scrollbar should be drawn or not. The
* scrollbar is not drawn by default. Indicate whether the vertical scrollbar should be drawn or not. The
* scrollbar is not drawn by default. Define whether the vertical scrollbar should be drawn or not. The
* scrollbar is not drawn by default. Specify the style of the scrollbars. The scrollbars can be overlaid or
* inset. When inset, they add to the padding of the view. And the scrollbars
* can be drawn inside the padding area or on the edge of the view. For example,
* if a view has a background drawable and you want to draw the scrollbars
* inside the padding specified by the drawable, you can use
* SCROLLBARS_INSIDE_OVERLAY or SCROLLBARS_INSIDE_INSET. If you want them to
* appear at the edge of the view, ignoring the padding, then you can use
* SCROLLBARS_OUTSIDE_OVERLAY or SCROLLBARS_OUTSIDE_INSET. Returns the current scrollbar style. Compute the horizontal range that the horizontal scrollbar
* represents. The range is expressed in arbitrary units that must be the same as the
* units used by {@link #computeHorizontalScrollExtent()} and
* {@link #computeHorizontalScrollOffset()}. The default range is the drawing width of this view. Compute the horizontal offset of the horizontal scrollbar's thumb
* within the horizontal range. This value is used to compute the position
* of the thumb within the scrollbar's track. The range is expressed in arbitrary units that must be the same as the
* units used by {@link #computeHorizontalScrollRange()} and
* {@link #computeHorizontalScrollExtent()}. The default offset is the scroll offset of this view. Compute the horizontal extent of the horizontal scrollbar's thumb
* within the horizontal range. This value is used to compute the length
* of the thumb within the scrollbar's track. The range is expressed in arbitrary units that must be the same as the
* units used by {@link #computeHorizontalScrollRange()} and
* {@link #computeHorizontalScrollOffset()}. The default extent is the drawing width of this view. Compute the vertical range that the vertical scrollbar represents. The range is expressed in arbitrary units that must be the same as the
* units used by {@link #computeVerticalScrollExtent()} and
* {@link #computeVerticalScrollOffset()}. The default range is the drawing height of this view. Compute the vertical offset of the vertical scrollbar's thumb
* within the horizontal range. This value is used to compute the position
* of the thumb within the scrollbar's track. The range is expressed in arbitrary units that must be the same as the
* units used by {@link #computeVerticalScrollRange()} and
* {@link #computeVerticalScrollExtent()}. The default offset is the scroll offset of this view. Compute the vertical extent of the horizontal scrollbar's thumb
* within the vertical range. This value is used to compute the length
* of the thumb within the scrollbar's track. The range is expressed in arbitrary units that must be the same as the
* units used by {@link #computeVerticalScrollRange()} and
* {@link #computeVerticalScrollOffset()}. The default extent is the drawing height of this view. Request the drawing of the horizontal and the vertical scrollbar. The
* scrollbars are painted only if they have been awakened first. Draw the horizontal scrollbar if
* {@link #isHorizontalScrollBarEnabled()} returns true. Draw the vertical scrollbar if {@link #isVerticalScrollBarEnabled()}
* returns true.
* Some examples of things you may store here: the current cursor position
* in a text view (but usually not the text itself since that is stored in a
* content provider or other persistent storage), the currently selected
* item in a list view.
*
* @return Returns a Parcelable object containing the view's current dynamic
* state, or null if there is nothing interesting to save. The
* default implementation returns null.
* @see #onRestoreInstanceState
* @see #saveHierarchyState
* @see #dispatchSaveInstanceState
* @see #setSaveEnabled(boolean)
*/
protected Parcelable onSaveInstanceState() {
mPrivateFlags |= SAVE_STATE_CALLED;
return BaseSavedState.EMPTY_STATE;
}
/**
* Restore this view hierarchy's frozen state from the given container.
*
* @param container The SparseArray which holds previously frozen states.
*
* @see #saveHierarchyState
* @see #dispatchRestoreInstanceState
* @see #onRestoreInstanceState
*/
public void restoreHierarchyState(SparseArray Return the time at which the drawing of the view hierarchy started. Enables or disables the duplication of the parent's state into this view. When
* duplication is enabled, this view gets its drawable state from its parent rather
* than from its own internal properties. Note: in the current implementation, setting this property to true after the
* view was added to a ViewGroup might have no effect at all. This property should
* always be used from XML or set to true before adding this view to a ViewGroup. Note: if this view's parent addStateFromChildren property is enabled and this
* property is enabled, an exception will be thrown. Note: if the child view uses and updates additionnal states which are unknown to the
* parent, these states should not be affected by this method. Indicates whether this duplicates its drawable state from its parent. Specifies the type of layer backing this view. The layer can be
* {@link #LAYER_TYPE_NONE disabled}, {@link #LAYER_TYPE_SOFTWARE software} or
* {@link #LAYER_TYPE_HARDWARE hardware}. A layer is associated with an optional {@link android.graphics.Paint}
* instance that controls how the layer is composed on screen. The following
* properties of the paint are taken into account when composing the layer: If this view has an alpha value set to < 1.0 by calling
* {@link #setAlpha(float)}, the alpha value of the layer's paint is replaced by
* this view's alpha value. Calling {@link #setAlpha(float)} is therefore
* equivalent to setting a hardware layer on this view and providing a paint with
* the desired alpha value.
*
* Refer to the documentation of {@link #LAYER_TYPE_NONE disabled},
* {@link #LAYER_TYPE_SOFTWARE software} and {@link #LAYER_TYPE_HARDWARE hardware}
* for more information on when and how to use layers. Returns a hardware layer that can be used to draw this view again
* without executing its draw method. Enables or disables the drawing cache. When the drawing cache is enabled, the next call
* to {@link #getDrawingCache()} or {@link #buildDrawingCache()} will draw the view in a
* bitmap. Calling {@link #draw(android.graphics.Canvas)} will not draw from the cache when
* the cache is enabled. To benefit from the cache, you must request the drawing cache by
* calling {@link #getDrawingCache()} and draw it on screen if the returned bitmap is not
* null. Enabling the drawing cache is similar to
* {@link #setLayerType(int, android.graphics.Paint) setting a layer} when hardware
* acceleration is turned off. When hardware acceleration is turned on, enabling the
* drawing cache has no effect on rendering because the system uses a different mechanism
* for acceleration which ignores the flag. If you want to use a Bitmap for the view, even
* when hardware acceleration is enabled, see {@link #setLayerType(int, android.graphics.Paint)}
* for information on how to enable software and hardware layers. This API can be used to manually generate
* a bitmap copy of this view, by setting the flag to Indicates whether the drawing cache is enabled for this view. Returns a display list that can be used to draw this view again
* without executing its draw method. Calling this method is equivalent to calling Returns the bitmap in which this view drawing is cached. The returned bitmap
* is null when caching is disabled. If caching is enabled and the cache is not ready,
* this method will create it. Calling {@link #draw(android.graphics.Canvas)} will not
* draw from the cache when the cache is enabled. To benefit from the cache, you must
* request the drawing cache by calling this method and draw it on screen if the
* returned bitmap is not null. Note about auto scaling in compatibility mode: When auto scaling is not enabled,
* this method will create a bitmap of the same size as this view. Because this bitmap
* will be drawn scaled by the parent ViewGroup, the result on screen might show
* scaling artifacts. To avoid such artifacts, you should call this method by setting
* the auto scaling to true. Doing so, however, will generate a bitmap of a different
* size than the view. This implies that your application must be able to handle this
* size. Frees the resources used by the drawing cache. If you call
* {@link #buildDrawingCache()} manually without calling
* {@link #setDrawingCacheEnabled(boolean) setDrawingCacheEnabled(true)}, you
* should cleanup the cache with this method afterwards. Calling this method is equivalent to calling Forces the drawing cache to be built if the drawing cache is invalid. If you call {@link #buildDrawingCache()} manually without calling
* {@link #setDrawingCacheEnabled(boolean) setDrawingCacheEnabled(true)}, you
* should cleanup the cache by calling {@link #destroyDrawingCache()} afterwards. Note about auto scaling in compatibility mode: When auto scaling is not enabled,
* this method will create a bitmap of the same size as this view. Because this bitmap
* will be drawn scaled by the parent ViewGroup, the result on screen might show
* scaling artifacts. To avoid such artifacts, you should call this method by setting
* the auto scaling to true. Doing so, however, will generate a bitmap of a different
* size than the view. This implies that your application must be able to handle this
* size. You should avoid calling this method when hardware acceleration is enabled. If
* you do not need the drawing cache bitmap, calling this method will increase memory
* usage and cause the view to be rendered in software once, thus negatively impacting
* performance. Indicates whether this view is attached to an hardware accelerated
* window or not. Even if this method returns true, it does not mean that every call
* to {@link #draw(android.graphics.Canvas)} will be made with an hardware
* accelerated {@link android.graphics.Canvas}. For instance, if this view
* is drawn onto an offscren {@link android.graphics.Bitmap} and its
* window is hardware accelerated,
* {@link android.graphics.Canvas#isHardwareAccelerated()} will likely
* return false, and this method will return true. Indicates whether or not this view's layout will be requested during
* the next hierarchy layout pass. This is the second phase of the layout mechanism.
* (The first is measuring). In this phase, each parent calls
* layout on all of its children to position them.
* This is typically done using the child measurements
* that were stored in the measure pass(). Derived classes should not override this method.
* Derived classes with children should override
* onLayout. In that method, they should
* call layout on each of their children. Even if the subclass overrides onFinishInflate, they should always be
* sure to call the super method, so that we get called.
*/
protected void onFinishInflate() {
}
/**
* Returns the resources associated with this view.
*
* @return Resources object.
*/
public Resources getResources() {
return mResources;
}
/**
* Invalidates the specified Drawable.
*
* @param drawable the drawable to invalidate
*/
public void invalidateDrawable(Drawable drawable) {
if (verifyDrawable(drawable)) {
final Rect dirty = drawable.getBounds();
final int scrollX = mScrollX;
final int scrollY = mScrollY;
invalidate(dirty.left + scrollX, dirty.top + scrollY,
dirty.right + scrollX, dirty.bottom + scrollY);
}
}
/**
* Schedules an action on a drawable to occur at a specified time.
*
* @param who the recipient of the action
* @param what the action to run on the drawable
* @param when the time at which the action must occur. Uses the
* {@link SystemClock#uptimeMillis} timebase.
*/
public void scheduleDrawable(Drawable who, Runnable what, long when) {
if (verifyDrawable(who) && what != null && mAttachInfo != null) {
mAttachInfo.mHandler.postAtTime(what, who, when);
}
}
/**
* Cancels a scheduled action on a drawable.
*
* @param who the recipient of the action
* @param what the action to cancel
*/
public void unscheduleDrawable(Drawable who, Runnable what) {
if (verifyDrawable(who) && what != null && mAttachInfo != null) {
mAttachInfo.mHandler.removeCallbacks(what, who);
}
}
/**
* Unschedule any events associated with the given Drawable. This can be
* used when selecting a new Drawable into a view, so that the previous
* one is completely unscheduled.
*
* @param who The Drawable to unschedule.
*
* @see #drawableStateChanged
*/
public void unscheduleDrawable(Drawable who) {
if (mAttachInfo != null) {
mAttachInfo.mHandler.removeCallbacksAndMessages(who);
}
}
/**
* If your view subclass is displaying its own Drawable objects, it should
* override this function and return true for any Drawable it is
* displaying. This allows animations for those drawables to be
* scheduled.
*
* Be sure to call through to the super class when overriding this
* function.
*
* @param who The Drawable to verify. Return true if it is one you are
* displaying, else return the result of calling through to the
* super class.
*
* @return boolean If true than the Drawable is being displayed in the
* view; else false and it is not allowed to animate.
*
* @see #unscheduleDrawable
* @see #drawableStateChanged
*/
protected boolean verifyDrawable(Drawable who) {
return who == mBGDrawable;
}
/**
* This function is called whenever the state of the view changes in such
* a way that it impacts the state of drawables being shown.
*
* Be sure to call through to the superclass when overriding this
* function.
*
* @see Drawable#setState
*/
protected void drawableStateChanged() {
Drawable d = mBGDrawable;
if (d != null && d.isStateful()) {
d.setState(getDrawableState());
}
}
/**
* Call this to force a view to update its drawable state. This will cause
* drawableStateChanged to be called on this view. Views that are interested
* in the new state should call getDrawableState.
*
* @see #drawableStateChanged
* @see #getDrawableState
*/
public void refreshDrawableState() {
mPrivateFlags |= DRAWABLE_STATE_DIRTY;
drawableStateChanged();
ViewParent parent = mParent;
if (parent != null) {
parent.childDrawableStateChanged(this);
}
}
/**
* Return an array of resource IDs of the drawable states representing the
* current state of the view.
*
* @return The current drawable state
*
* @see Drawable#setState
* @see #drawableStateChanged
* @see #onCreateDrawableState
*/
public final int[] getDrawableState() {
if ((mDrawableState != null) && ((mPrivateFlags & DRAWABLE_STATE_DIRTY) == 0)) {
return mDrawableState;
} else {
mDrawableState = onCreateDrawableState(0);
mPrivateFlags &= ~DRAWABLE_STATE_DIRTY;
return mDrawableState;
}
}
/**
* Generate the new {@link android.graphics.drawable.Drawable} state for
* this view. This is called by the view
* system when the cached Drawable state is determined to be invalid. To
* retrieve the current state, you should use {@link #getDrawableState}.
*
* @param extraSpace if non-zero, this is the number of extra entries you
* would like in the returned array in which you can place your own
* states.
*
* @return Returns an array holding the current {@link Drawable} state of
* the view.
*
* @see #mergeDrawableStates
*/
protected int[] onCreateDrawableState(int extraSpace) {
if ((mViewFlags & DUPLICATE_PARENT_STATE) == DUPLICATE_PARENT_STATE &&
mParent instanceof View) {
return ((View) mParent).onCreateDrawableState(extraSpace);
}
int[] drawableState;
int privateFlags = mPrivateFlags;
int viewStateIndex = 0;
if ((privateFlags & PRESSED) != 0) viewStateIndex |= VIEW_STATE_PRESSED;
if ((mViewFlags & ENABLED_MASK) == ENABLED) viewStateIndex |= VIEW_STATE_ENABLED;
if (isFocused()) viewStateIndex |= VIEW_STATE_FOCUSED;
if ((privateFlags & SELECTED) != 0) viewStateIndex |= VIEW_STATE_SELECTED;
if (hasWindowFocus()) viewStateIndex |= VIEW_STATE_WINDOW_FOCUSED;
if ((privateFlags & ACTIVATED) != 0) viewStateIndex |= VIEW_STATE_ACTIVATED;
if (mAttachInfo != null && mAttachInfo.mHardwareAccelerationRequested &&
HardwareRenderer.isAvailable()) {
// This is set if HW acceleration is requested, even if the current
// process doesn't allow it. This is just to allow app preview
// windows to better match their app.
viewStateIndex |= VIEW_STATE_ACCELERATED;
}
if ((privateFlags & HOVERED) != 0) viewStateIndex |= VIEW_STATE_HOVERED;
final int privateFlags2 = mPrivateFlags2;
if ((privateFlags2 & DRAG_CAN_ACCEPT) != 0) viewStateIndex |= VIEW_STATE_DRAG_CAN_ACCEPT;
if ((privateFlags2 & DRAG_HOVERED) != 0) viewStateIndex |= VIEW_STATE_DRAG_HOVERED;
drawableState = VIEW_STATE_SETS[viewStateIndex];
//noinspection ConstantIfStatement
if (false) {
Log.i("View", "drawableStateIndex=" + viewStateIndex);
Log.i("View", toString()
+ " pressed=" + ((privateFlags & PRESSED) != 0)
+ " en=" + ((mViewFlags & ENABLED_MASK) == ENABLED)
+ " fo=" + hasFocus()
+ " sl=" + ((privateFlags & SELECTED) != 0)
+ " wf=" + hasWindowFocus()
+ ": " + Arrays.toString(drawableState));
}
if (extraSpace == 0) {
return drawableState;
}
final int[] fullState;
if (drawableState != null) {
fullState = new int[drawableState.length + extraSpace];
System.arraycopy(drawableState, 0, fullState, 0, drawableState.length);
} else {
fullState = new int[extraSpace];
}
return fullState;
}
/**
* Merge your own state values in additionalState into the base
* state values baseState that were returned by
* {@link #onCreateDrawableState}.
*
* @param baseState The base state values returned by
* {@link #onCreateDrawableState}, which will be modified to also hold your
* own additional state values.
*
* @param additionalState The additional state values you would like
* added to baseState; this array is not modified.
*
* @return As a convenience, the baseState array you originally
* passed into the function is returned.
*
* @see #onCreateDrawableState
*/
protected static int[] mergeDrawableStates(int[] baseState, int[] additionalState) {
final int N = baseState.length;
int i = N - 1;
while (i >= 0 && baseState[i] == 0) {
i--;
}
System.arraycopy(additionalState, 0, baseState, i + 1, additionalState.length);
return baseState;
}
/**
* Call {@link Drawable#jumpToCurrentState() Drawable.jumpToCurrentState()}
* on all Drawable objects associated with this view.
*/
public void jumpDrawablesToCurrentState() {
if (mBGDrawable != null) {
mBGDrawable.jumpToCurrentState();
}
}
/**
* Sets the background color for this view.
* @param color the color of the background
*/
@RemotableViewMethod
public void setBackgroundColor(int color) {
if (mBGDrawable instanceof ColorDrawable) {
((ColorDrawable) mBGDrawable).setColor(color);
} else {
setBackgroundDrawable(new ColorDrawable(color));
}
}
/**
* Set the background to a given resource. The resource should refer to
* a Drawable object or 0 to remove the background.
* @param resid The identifier of the resource.
* @attr ref android.R.styleable#View_background
*/
@RemotableViewMethod
public void setBackgroundResource(int resid) {
if (resid != 0 && resid == mBackgroundResource) {
return;
}
Drawable d= null;
if (resid != 0) {
d = mResources.getDrawable(resid);
}
setBackgroundDrawable(d);
mBackgroundResource = resid;
}
/**
* Set the background to a given Drawable, or remove the background. If the
* background has padding, this View's padding is set to the background's
* padding. However, when a background is removed, this View's padding isn't
* touched. If setting the padding is desired, please use
* {@link #setPadding(int, int, int, int)}.
*
* @param d The Drawable to use as the background, or null to remove the
* background
*/
public void setBackgroundDrawable(Drawable d) {
boolean requestLayout = false;
mBackgroundResource = 0;
/*
* Regardless of whether we're setting a new background or not, we want
* to clear the previous drawable.
*/
if (mBGDrawable != null) {
mBGDrawable.setCallback(null);
unscheduleDrawable(mBGDrawable);
}
if (d != null) {
Rect padding = sThreadLocal.get();
if (padding == null) {
padding = new Rect();
sThreadLocal.set(padding);
}
if (d.getPadding(padding)) {
setPadding(padding.left, padding.top, padding.right, padding.bottom);
}
// Compare the minimum sizes of the old Drawable and the new. If there isn't an old or
// if it has a different minimum size, we should layout again
if (mBGDrawable == null || mBGDrawable.getMinimumHeight() != d.getMinimumHeight() ||
mBGDrawable.getMinimumWidth() != d.getMinimumWidth()) {
requestLayout = true;
}
d.setCallback(this);
if (d.isStateful()) {
d.setState(getDrawableState());
}
d.setVisible(getVisibility() == VISIBLE, false);
mBGDrawable = d;
if ((mPrivateFlags & SKIP_DRAW) != 0) {
mPrivateFlags &= ~SKIP_DRAW;
mPrivateFlags |= ONLY_DRAWS_BACKGROUND;
requestLayout = true;
}
} else {
/* Remove the background */
mBGDrawable = null;
if ((mPrivateFlags & ONLY_DRAWS_BACKGROUND) != 0) {
/*
* This view ONLY drew the background before and we're removing
* the background, so now it won't draw anything
* (hence we SKIP_DRAW)
*/
mPrivateFlags &= ~ONLY_DRAWS_BACKGROUND;
mPrivateFlags |= SKIP_DRAW;
}
/*
* When the background is set, we try to apply its padding to this
* View. When the background is removed, we don't touch this View's
* padding. This is noted in the Javadocs. Hence, we don't need to
* requestLayout(), the invalidate() below is sufficient.
*/
// The old background's minimum size could have affected this
// View's layout, so let's requestLayout
requestLayout = true;
}
computeOpaqueFlags();
if (requestLayout) {
requestLayout();
}
mBackgroundSizeChanged = true;
invalidate(true);
}
/**
* Gets the background drawable
* @return The drawable used as the background for this view, if any.
*/
public Drawable getBackground() {
return mBGDrawable;
}
/**
* Sets the padding. The view may add on the space required to display
* the scrollbars, depending on the style and visibility of the scrollbars.
* So the values returned from {@link #getPaddingLeft}, {@link #getPaddingTop},
* {@link #getPaddingRight} and {@link #getPaddingBottom} may be different
* from the values set in this call.
*
* @attr ref android.R.styleable#View_padding
* @attr ref android.R.styleable#View_paddingBottom
* @attr ref android.R.styleable#View_paddingLeft
* @attr ref android.R.styleable#View_paddingRight
* @attr ref android.R.styleable#View_paddingTop
* @param left the left padding in pixels
* @param top the top padding in pixels
* @param right the right padding in pixels
* @param bottom the bottom padding in pixels
*/
public void setPadding(int left, int top, int right, int bottom) {
boolean changed = false;
mUserPaddingLeft = left;
mUserPaddingRight = right;
mUserPaddingBottom = bottom;
final int viewFlags = mViewFlags;
// Common case is there are no scroll bars.
if ((viewFlags & (SCROLLBARS_VERTICAL|SCROLLBARS_HORIZONTAL)) != 0) {
if ((viewFlags & SCROLLBARS_VERTICAL) != 0) {
// TODO Determine what to do with SCROLLBAR_POSITION_DEFAULT based on RTL settings.
final int offset = (viewFlags & SCROLLBARS_INSET_MASK) == 0
? 0 : getVerticalScrollbarWidth();
switch (mVerticalScrollbarPosition) {
case SCROLLBAR_POSITION_DEFAULT:
case SCROLLBAR_POSITION_RIGHT:
right += offset;
break;
case SCROLLBAR_POSITION_LEFT:
left += offset;
break;
}
}
if ((viewFlags & SCROLLBARS_HORIZONTAL) != 0) {
bottom += (viewFlags & SCROLLBARS_INSET_MASK) == 0
? 0 : getHorizontalScrollbarHeight();
}
}
if (mPaddingLeft != left) {
changed = true;
mPaddingLeft = left;
}
if (mPaddingTop != top) {
changed = true;
mPaddingTop = top;
}
if (mPaddingRight != right) {
changed = true;
mPaddingRight = right;
}
if (mPaddingBottom != bottom) {
changed = true;
mPaddingBottom = bottom;
}
if (changed) {
requestLayout();
}
}
/**
* Returns the top padding of this view.
*
* @return the top padding in pixels
*/
public int getPaddingTop() {
return mPaddingTop;
}
/**
* Returns the bottom padding of this view. If there are inset and enabled
* scrollbars, this value may include the space required to display the
* scrollbars as well.
*
* @return the bottom padding in pixels
*/
public int getPaddingBottom() {
return mPaddingBottom;
}
/**
* Returns the left padding of this view. If there are inset and enabled
* scrollbars, this value may include the space required to display the
* scrollbars as well.
*
* @return the left padding in pixels
*/
public int getPaddingLeft() {
return mPaddingLeft;
}
/**
* Returns the right padding of this view. If there are inset and enabled
* scrollbars, this value may include the space required to display the
* scrollbars as well.
*
* @return the right padding in pixels
*/
public int getPaddingRight() {
return mPaddingRight;
}
/**
* Changes the selection state of this view. A view can be selected or not.
* Note that selection is not the same as focus. Views are typically
* selected in the context of an AdapterView like ListView or GridView;
* the selected view is the view that is highlighted.
*
* @param selected true if the view must be selected, false otherwise
*/
public void setSelected(boolean selected) {
if (((mPrivateFlags & SELECTED) != 0) != selected) {
mPrivateFlags = (mPrivateFlags & ~SELECTED) | (selected ? SELECTED : 0);
if (!selected) resetPressedState();
invalidate(true);
refreshDrawableState();
dispatchSetSelected(selected);
}
}
/**
* Dispatch setSelected to all of this View's children.
*
* @see #setSelected(boolean)
*
* @param selected The new selected state
*/
protected void dispatchSetSelected(boolean selected) {
}
/**
* Indicates the selection state of this view.
*
* @return true if the view is selected, false otherwise
*/
@ViewDebug.ExportedProperty
public boolean isSelected() {
return (mPrivateFlags & SELECTED) != 0;
}
/**
* Changes the activated state of this view. A view can be activated or not.
* Note that activation is not the same as selection. Selection is
* a transient property, representing the view (hierarchy) the user is
* currently interacting with. Activation is a longer-term state that the
* user can move views in and out of. For example, in a list view with
* single or multiple selection enabled, the views in the current selection
* set are activated. (Um, yeah, we are deeply sorry about the terminology
* here.) The activated state is propagated down to children of the view it
* is set on.
*
* @param activated true if the view must be activated, false otherwise
*/
public void setActivated(boolean activated) {
if (((mPrivateFlags & ACTIVATED) != 0) != activated) {
mPrivateFlags = (mPrivateFlags & ~ACTIVATED) | (activated ? ACTIVATED : 0);
invalidate(true);
refreshDrawableState();
dispatchSetActivated(activated);
}
}
/**
* Dispatch setActivated to all of this View's children.
*
* @see #setActivated(boolean)
*
* @param activated The new activated state
*/
protected void dispatchSetActivated(boolean activated) {
}
/**
* Indicates the activation state of this view.
*
* @return true if the view is activated, false otherwise
*/
@ViewDebug.ExportedProperty
public boolean isActivated() {
return (mPrivateFlags & ACTIVATED) != 0;
}
/**
* Returns the ViewTreeObserver for this view's hierarchy. The view tree
* observer can be used to get notifications when global events, like
* layout, happen.
*
* The returned ViewTreeObserver observer is not guaranteed to remain
* valid for the lifetime of this View. If the caller of this method keeps
* a long-lived reference to ViewTreeObserver, it should always check for
* the return value of {@link ViewTreeObserver#isAlive()}.
*
* @return The ViewTreeObserver for this view's hierarchy.
*/
public ViewTreeObserver getViewTreeObserver() {
if (mAttachInfo != null) {
return mAttachInfo.mTreeObserver;
}
if (mFloatingTreeObserver == null) {
mFloatingTreeObserver = new ViewTreeObserver();
}
return mFloatingTreeObserver;
}
/**
* Finds the topmost view in the current view hierarchy. Computes the coordinates of this view on the screen. The argument
* must be an array of two integers. After the method returns, the array
* contains the x and y location in that order. Computes the coordinates of this view in its window. The argument
* must be an array of two integers. After the method returns, the array
* contains the x and y location in that order.immediate
is set to true, scrolling will not be
* animated.
*
* @param rectangle The rectangle.
* @param immediate True to forbid animated scrolling, false otherwise
* @return Whether any parent scrolled.
*/
public boolean requestRectangleOnScreen(Rect rectangle, boolean immediate) {
View child = this;
ViewParent parent = mParent;
boolean scrolled = false;
while (parent != null) {
scrolled |= parent.requestChildRectangleOnScreen(child,
rectangle, immediate);
// offset rect so next call has the rectangle in the
// coordinate system of its direct child.
rectangle.offset(child.getLeft(), child.getTop());
rectangle.offset(-child.getScrollX(), -child.getScrollY());
if (!(parent instanceof View)) {
break;
}
child = (View) parent;
parent = child.getParent();
}
return scrolled;
}
/**
* Called when this view wants to give up focus. This will cause
* {@link #onFocusChanged} to be called.
*/
public void clearFocus() {
if (DBG) {
System.out.println(this + " clearFocus()");
}
if ((mPrivateFlags & FOCUSED) != 0) {
mPrivateFlags &= ~FOCUSED;
if (mParent != null) {
mParent.clearChildFocus(this);
}
onFocusChanged(false, 0, null);
refreshDrawableState();
}
}
/**
* Called to clear the focus of a view that is about to be removed.
* Doesn't call clearChildFocus, which prevents this view from taking
* focus again before it has been removed from the parent
*/
void clearFocusForRemoval() {
if ((mPrivateFlags & FOCUSED) != 0) {
mPrivateFlags &= ~FOCUSED;
onFocusChanged(false, 0, null);
refreshDrawableState();
}
}
/**
* Called internally by the view system when a new view is getting focus.
* This is what clears the old focus.
*/
void unFocus() {
if (DBG) {
System.out.println(this + " unFocus()");
}
if ((mPrivateFlags & FOCUSED) != 0) {
mPrivateFlags &= ~FOCUSED;
onFocusChanged(false, 0, null);
refreshDrawableState();
}
}
/**
* Returns true if this view has focus iteself, or is the ancestor of the
* view that has focus.
*
* @return True if this view has or contains focus, false otherwise.
*/
@ViewDebug.ExportedProperty(category = "focus")
public boolean hasFocus() {
return (mPrivateFlags & FOCUSED) != 0;
}
/**
* Returns true if this view is focusable or if it contains a reachable View
* for which {@link #hasFocusable()} returns true. A "reachable hasFocusable()"
* is a View whose parents do not block descendants focus.
*
* Only {@link #VISIBLE} views are considered focusable.
*
* @return True if the view is focusable or if the view contains a focusable
* View, false otherwise.
*
* @see ViewGroup#FOCUS_BLOCK_DESCENDANTS
*/
public boolean hasFocusable() {
return (mViewFlags & VISIBILITY_MASK) == VISIBLE && isFocusable();
}
/**
* Called by the view system when the focus state of this view changes.
* When the focus change event is caused by directional navigation, direction
* and previouslyFocusedRect provide insight into where the focus is coming from.
* When overriding, be sure to call up through to the super class so that
* the standard focus handling will occur.
*
* @param gainFocus True if the View has focus; false otherwise.
* @param direction The direction focus has moved when requestFocus()
* is called to give this view focus. Values are
* {@link #FOCUS_UP}, {@link #FOCUS_DOWN}, {@link #FOCUS_LEFT},
* {@link #FOCUS_RIGHT}, {@link #FOCUS_FORWARD}, or {@link #FOCUS_BACKWARD}.
* It may not always apply, in which case use the default.
* @param previouslyFocusedRect The rectangle, in this view's coordinate
* system, of the previously focused view. If applicable, this will be
* passed in as finer grained information about where the focus is coming
* from (in addition to direction). Will be null
otherwise.
*/
protected void onFocusChanged(boolean gainFocus, int direction, Rect previouslyFocusedRect) {
if (gainFocus) {
sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED);
}
InputMethodManager imm = InputMethodManager.peekInstance();
if (!gainFocus) {
if (isPressed()) {
setPressed(false);
}
if (imm != null && mAttachInfo != null
&& mAttachInfo.mHasWindowFocus) {
imm.focusOut(this);
}
onFocusLost();
} else if (imm != null && mAttachInfo != null
&& mAttachInfo.mHasWindowFocus) {
imm.focusIn(this);
}
invalidate(true);
if (mOnFocusChangeListener != null) {
mOnFocusChangeListener.onFocusChange(this, gainFocus);
}
if (mAttachInfo != null) {
mAttachInfo.mKeyDispatchState.reset(this);
}
}
/**
* {@inheritDoc}
*/
public void sendAccessibilityEvent(int eventType) {
if (AccessibilityManager.getInstance(mContext).isEnabled()) {
sendAccessibilityEventUnchecked(AccessibilityEvent.obtain(eventType));
}
}
/**
* {@inheritDoc}
*/
public void sendAccessibilityEventUnchecked(AccessibilityEvent event) {
if (!isShown()) {
return;
}
// Populate these here since they are related to the View that
// sends the event and should not be modified while dispatching
// to descendants.
event.setClassName(getClass().getName());
event.setPackageName(getContext().getPackageName());
event.setEnabled(isEnabled());
event.setContentDescription(mContentDescription);
if (event.getEventType() == AccessibilityEvent.TYPE_VIEW_FOCUSED && mAttachInfo != null) {
ArrayListnull
.
*
* @return Whether this view or one of its descendants actually took focus.
*/
public final boolean requestFocus() {
return requestFocus(View.FOCUS_DOWN);
}
/**
* Call this to try to give focus to a specific view or to one of its
* descendants and give it a hint about what direction focus is heading.
*
* A view will not actually take focus if it is not focusable ({@link #isFocusable} returns
* false), or if it is focusable and it is not focusable in touch mode
* ({@link #isFocusableInTouchMode}) while the device is in touch mode.
*
* See also {@link #focusSearch}, which is what you call to say that you
* have focus, and you want your parent to look for the next one.
*
* This is equivalent to calling {@link #requestFocus(int, Rect)} with
* null
set for the previously focused rectangle.
*
* @param direction One of FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, and FOCUS_RIGHT
* @return Whether this view or one of its descendants actually took focus.
*/
public final boolean requestFocus(int direction) {
return requestFocus(direction, null);
}
/**
* Call this to try to give focus to a specific view or to one of its descendants
* and give it hints about the direction and a specific rectangle that the focus
* is coming from. The rectangle can help give larger views a finer grained hint
* about where focus is coming from, and therefore, where to show selection, or
* forward focus change internally.
*
* A view will not actually take focus if it is not focusable ({@link #isFocusable} returns
* false), or if it is focusable and it is not focusable in touch mode
* ({@link #isFocusableInTouchMode}) while the device is in touch mode.
*
* A View will not take focus if it is not visible.
*
* A View will not take focus if one of its parents has
* {@link android.view.ViewGroup#getDescendantFocusability()} equal to
* {@link ViewGroup#FOCUS_BLOCK_DESCENDANTS}.
*
* See also {@link #focusSearch}, which is what you call to say that you
* have focus, and you want your parent to look for the next one.
*
* You may wish to override this method if your custom {@link View} has an internal
* {@link View} that it wishes to forward the request to.
*
* @param direction One of FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, and FOCUS_RIGHT
* @param previouslyFocusedRect The rectangle (in this View's coordinate system)
* to give a finer grained hint about where focus is coming from. May be null
* if there is no hint.
* @return Whether this view or one of its descendants actually took focus.
*/
public boolean requestFocus(int direction, Rect previouslyFocusedRect) {
// need to be focusable
if ((mViewFlags & FOCUSABLE_MASK) != FOCUSABLE ||
(mViewFlags & VISIBILITY_MASK) != VISIBLE) {
return false;
}
// need to be focusable in touch mode if in touch mode
if (isInTouchMode() &&
(FOCUSABLE_IN_TOUCH_MODE != (mViewFlags & FOCUSABLE_IN_TOUCH_MODE))) {
return false;
}
// need to not have any parents blocking us
if (hasAncestorThatBlocksDescendantFocus()) {
return false;
}
handleFocusGainInternal(direction, previouslyFocusedRect);
return true;
}
/** Gets the ViewRoot, or null if not attached. */
/*package*/ ViewRoot getViewRoot() {
View root = getRootView();
return root != null ? (ViewRoot)root.getParent() : null;
}
/**
* Call this to try to give focus to a specific view or to one of its descendants. This is a
* special variant of {@link #requestFocus() } that will allow views that are not focuable in
* touch mode to request focus when they are touched.
*
* @return Whether this view or one of its descendants actually took focus.
*
* @see #isInTouchMode()
*
*/
public final boolean requestFocusFromTouch() {
// Leave touch mode if we need to
if (isInTouchMode()) {
ViewRoot viewRoot = getViewRoot();
if (viewRoot != null) {
viewRoot.ensureTouchMode(false);
}
}
return requestFocus(View.FOCUS_DOWN);
}
/**
* @return Whether any ancestor of this view blocks descendant focus.
*/
private boolean hasAncestorThatBlocksDescendantFocus() {
ViewParent ancestor = mParent;
while (ancestor instanceof ViewGroup) {
final ViewGroup vgAncestor = (ViewGroup) ancestor;
if (vgAncestor.getDescendantFocusability() == ViewGroup.FOCUS_BLOCK_DESCENDANTS) {
return true;
} else {
ancestor = vgAncestor.getParent();
}
}
return false;
}
/**
* @hide
*/
public void dispatchStartTemporaryDetach() {
onStartTemporaryDetach();
}
/**
* This is called when a container is going to temporarily detach a child, with
* {@link ViewGroup#detachViewFromParent(View) ViewGroup.detachViewFromParent}.
* It will either be followed by {@link #onFinishTemporaryDetach()} or
* {@link #onDetachedFromWindow()} when the container is done.
*/
public void onStartTemporaryDetach() {
removeUnsetPressCallback();
mPrivateFlags |= CANCEL_NEXT_UP_EVENT;
}
/**
* @hide
*/
public void dispatchFinishTemporaryDetach() {
onFinishTemporaryDetach();
}
/**
* Called after {@link #onStartTemporaryDetach} when the container is done
* changing the view.
*/
public void onFinishTemporaryDetach() {
}
/**
* capture information of this view for later analysis: developement only
* check dynamic switch to make sure we only dump view
* when ViewDebug.SYSTEM_PROPERTY_CAPTURE_VIEW) is set
*/
private static void captureViewInfo(String subTag, View v) {
if (v == null || SystemProperties.getInt(ViewDebug.SYSTEM_PROPERTY_CAPTURE_VIEW, 0) == 0) {
return;
}
ViewDebug.dumpCapturedView(subTag, v);
}
/**
* Return the global {@link KeyEvent.DispatcherState KeyEvent.DispatcherState}
* for this view's window. Returns null if the view is not currently attached
* to the window. Normally you will not need to use this directly, but
* just use the standard high-level event callbacks like {@link #onKeyDown}.
*/
public KeyEvent.DispatcherState getKeyDispatcherState() {
return mAttachInfo != null ? mAttachInfo.mKeyDispatchState : null;
}
/**
* Dispatch a key event before it is processed by any input method
* associated with the view hierarchy. This can be used to intercept
* key events in special situations before the IME consumes them; a
* typical example would be handling the BACK key to update the application's
* UI instead of allowing the IME to see it and close itself.
*
* @param event The key event to be dispatched.
* @return True if the event was handled, false otherwise.
*/
public boolean dispatchKeyEventPreIme(KeyEvent event) {
return onKeyPreIme(event.getKeyCode(), event);
}
/**
* Dispatch a key event to the next view on the focus path. This path runs
* from the top of the view tree down to the currently focused view. If this
* view has focus, it will dispatch to itself. Otherwise it will dispatch
* the next node down the focus path. This method also fires any key
* listeners.
*
* @param event The key event to be dispatched.
* @return True if the event was handled, false otherwise.
*/
public boolean dispatchKeyEvent(KeyEvent event) {
if (mInputEventConsistencyVerifier != null) {
mInputEventConsistencyVerifier.onKeyEvent(event, 0);
}
//noinspection SimplifiableIfStatement,deprecation
if (false) {
captureViewInfo("captureViewKeyEvent", this);
}
// Give any attached key listener a first crack at the event.
//noinspection SimplifiableIfStatement
if (mOnKeyListener != null && (mViewFlags & ENABLED_MASK) == ENABLED
&& mOnKeyListener.onKey(this, event.getKeyCode(), event)) {
return true;
}
if (event.dispatch(this, mAttachInfo != null
? mAttachInfo.mKeyDispatchState : null, this)) {
return true;
}
if (mInputEventConsistencyVerifier != null) {
mInputEventConsistencyVerifier.onUnhandledEvent(event, 0);
}
return false;
}
/**
* Dispatches a key shortcut event.
*
* @param event The key event to be dispatched.
* @return True if the event was handled by the view, false otherwise.
*/
public boolean dispatchKeyShortcutEvent(KeyEvent event) {
return onKeyShortcut(event.getKeyCode(), event);
}
/**
* Pass the touch screen motion event down to the target view, or this
* view if it is the target.
*
* @param event The motion event to be dispatched.
* @return True if the event was handled by the view, false otherwise.
*/
public boolean dispatchTouchEvent(MotionEvent event) {
if (mInputEventConsistencyVerifier != null) {
mInputEventConsistencyVerifier.onTouchEvent(event, 0);
}
if (onFilterTouchEventForSecurity(event)) {
//noinspection SimplifiableIfStatement
if (mOnTouchListener != null && (mViewFlags & ENABLED_MASK) == ENABLED &&
mOnTouchListener.onTouch(this, event)) {
return true;
}
if (onTouchEvent(event)) {
return true;
}
}
if (mInputEventConsistencyVerifier != null) {
mInputEventConsistencyVerifier.onUnhandledEvent(event, 0);
}
return false;
}
/**
* Filter the touch event to apply security policies.
*
* @param event The motion event to be filtered.
* @return True if the event should be dispatched, false if the event should be dropped.
*
* @see #getFilterTouchesWhenObscured
*/
public boolean onFilterTouchEventForSecurity(MotionEvent event) {
//noinspection RedundantIfStatement
if ((mViewFlags & FILTER_TOUCHES_WHEN_OBSCURED) != 0
&& (event.getFlags() & MotionEvent.FLAG_WINDOW_IS_OBSCURED) != 0) {
// Window is obscured, drop this touch.
return false;
}
return true;
}
/**
* Pass a trackball motion event down to the focused view.
*
* @param event The motion event to be dispatched.
* @return True if the event was handled by the view, false otherwise.
*/
public boolean dispatchTrackballEvent(MotionEvent event) {
if (mInputEventConsistencyVerifier != null) {
mInputEventConsistencyVerifier.onTrackballEvent(event, 0);
}
//Log.i("view", "view=" + this + ", " + event.toString());
if (onTrackballEvent(event)) {
return true;
}
if (mInputEventConsistencyVerifier != null) {
mInputEventConsistencyVerifier.onUnhandledEvent(event, 0);
}
return false;
}
/**
* Dispatch a generic motion event.
*
* public boolean onGenericMotionEvent(MotionEvent event) {
* if ((event.getSource() & InputDevice.SOURCE_CLASS_JOYSTICK) != 0) {
* if (event.getAction() == MotionEvent.ACTION_MOVE) {
* // process the joystick movement...
* return true;
* }
* }
* if ((event.getSource() & InputDevice.SOURCE_CLASS_POINTER) != 0) {
* switch (event.getAction()) {
* case MotionEvent.ACTION_HOVER_MOVE:
* // process the mouse hover movement...
* return true;
* case MotionEvent.ACTION_SCROLL:
* // process the scroll wheel movement...
* return true;
* }
* }
* return super.onGenericMotionEvent(event);
* }
*
*
* @param event The generic motion event being processed.
* @return True if the event was handled, false otherwise.
*/
public boolean onGenericMotionEvent(MotionEvent event) {
return false;
}
/**
* Implement this method to handle hover events.
*
* float scale = context.getResources().getDisplayMetrics().density;
* view.setCameraDistance(distance * scale);
*
*
*
*
*
* true
and calling
* {@link #getDrawingCache()}.getDrawingCache(false)
.buildDrawingCache(false)
.