summaryrefslogtreecommitdiffstats
path: root/core/java/android/view/View.java
diff options
context:
space:
mode:
authorJean-Baptiste Queru <jbq@google.com>2009-07-21 11:16:54 -0700
committerJean-Baptiste Queru <jbq@google.com>2009-07-21 11:16:54 -0700
commitcf4550c3198d6b3d92cdc52707fe70d7cc0caa9f (patch)
tree6510f35ad004f1a4640b48264c290926e8596d7a /core/java/android/view/View.java
parent4cf03d381b2dff908857fceff0bec445f8d44f36 (diff)
downloadframeworks_base-cf4550c3198d6b3d92cdc52707fe70d7cc0caa9f.zip
frameworks_base-cf4550c3198d6b3d92cdc52707fe70d7cc0caa9f.tar.gz
frameworks_base-cf4550c3198d6b3d92cdc52707fe70d7cc0caa9f.tar.bz2
donut snapshot
Diffstat (limited to 'core/java/android/view/View.java')
-rw-r--r--core/java/android/view/View.java484
1 files changed, 402 insertions, 82 deletions
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 9e709cf..ff8868b 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -16,6 +16,9 @@
package android.view;
+import com.android.internal.R;
+import com.android.internal.view.menu.MenuBuilder;
+
import android.content.Context;
import android.content.res.Resources;
import android.content.res.TypedArray;
@@ -25,12 +28,12 @@ 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.Region;
import android.graphics.Shader;
-import android.graphics.Point;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.os.Handler;
@@ -42,47 +45,47 @@ import android.os.RemoteException;
import android.os.SystemClock;
import android.os.SystemProperties;
import android.util.AttributeSet;
+import android.util.Config;
import android.util.EventLog;
import android.util.Log;
-import android.util.SparseArray;
-import android.util.Poolable;
import android.util.Pool;
-import android.util.Pools;
+import android.util.Poolable;
import android.util.PoolableManager;
-import android.util.Config;
+import android.util.Pools;
+import android.util.SparseArray;
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.inputmethod.EditorInfo;
import android.view.inputmethod.InputConnection;
import android.view.inputmethod.InputMethodManager;
-import android.view.inputmethod.EditorInfo;
import android.widget.ScrollBarDrawable;
-import com.android.internal.R;
-import com.android.internal.view.menu.MenuBuilder;
-
+import java.lang.ref.SoftReference;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.WeakHashMap;
-import java.lang.ref.SoftReference;
-import java.lang.reflect.Method;
-import java.lang.reflect.InvocationTargetException;
/**
* <p>
* 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 <em>widgets</em>, which are
- * used to create interactive UI components (buttons, text fields, etc.). The
+ * used to create interactive UI components (buttons, text fields, etc.). The
* {@link android.view.ViewGroup} subclass is the base class for <em>layouts</em>, which
* are invisible containers that hold other Views (or other ViewGroups) and define
* their layout properties.
* </p>
*
* <div class="special">
- * <p>For an introduction to using this class to develop your
- * application's user interface, read the Developer Guide documentation on
+ * <p>For an introduction to using this class to develop your
+ * application's user interface, read the Developer Guide documentation on
* <strong><a href="{@docRoot}guide/topics/ui/index.html">User Interface</a></strong>. Special topics
- * include:
+ * include:
* <br/><a href="{@docRoot}guide/topics/ui/declaring-layout.html">Declaring Layout</a>
* <br/><a href="{@docRoot}guide/topics/ui/menus.html">Creating Menus</a>
* <br/><a href="{@docRoot}guide/topics/ui/layout-objects.html">Common Layout Objects</a>
@@ -93,7 +96,7 @@ import java.lang.reflect.InvocationTargetException;
* <br/><a href="{@docRoot}guide/topics/ui/how-android-draws.html">How Android Draws Views</a>.
* </p>
* </div>
- *
+ *
* <a name="Using"></a>
* <h3>Using Views</h3>
* <p>
@@ -419,7 +422,7 @@ import java.lang.reflect.InvocationTargetException;
* </p>
*
* <p>
- * Note that the framework will not draw views that are not in the invalid region.
+ * Note that the framework will not draw views that are not in the invalid region.
* </p>
*
* <p>
@@ -535,25 +538,52 @@ import java.lang.reflect.InvocationTargetException;
* take care of redrawing the appropriate views until the animation completes.
* </p>
*
+ * @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_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_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_scrollX
* @attr ref android.R.styleable#View_scrollY
- * @attr ref android.R.styleable#View_scrollbarTrackHorizontal
- * @attr ref android.R.styleable#View_scrollbarThumbHorizontal
* @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_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_visibility
*
* @see android.view.ViewGroup
*/
-public class View implements Drawable.Callback, KeyEvent.Callback {
+public class View implements Drawable.Callback, KeyEvent.Callback, AccessibilityEventSource {
private static final boolean DBG = false;
/**
@@ -851,6 +881,18 @@ public class View implements Drawable.Callback, KeyEvent.Callback {
public static final int HAPTIC_FEEDBACK_ENABLED = 0x10000000;
/**
+ * 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.
*/
@@ -1428,6 +1470,27 @@ public class View implements Drawable.Callback, KeyEvent.Callback {
static final int DIRTY_MASK = 0x00600000;
/**
+ * Indicates whether the background is opaque.
+ *
+ * @hide
+ */
+ static final int OPAQUE_BACKGROUND = 0x00800000;
+
+ /**
+ * Indicates whether the scrollbars are opaque.
+ *
+ * @hide
+ */
+ static final int OPAQUE_SCROLLBARS = 0x01000000;
+
+ /**
+ * Indicates whether the view is opaque.
+ *
+ * @hide
+ */
+ static final int OPAQUE_MASK = 0x01800000;
+
+ /**
* The parent this view is attached to.
* {@hide}
*
@@ -1449,7 +1512,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback {
@ViewDebug.FlagToString(mask = LAYOUT_REQUIRED, equals = LAYOUT_REQUIRED,
name = "LAYOUT_REQUIRED"),
@ViewDebug.FlagToString(mask = DRAWING_CACHE_VALID, equals = DRAWING_CACHE_VALID,
- name = "DRAWING_CACHE_VALID", outputIf = false),
+ name = "DRAWING_CACHE_INVALID", outputIf = false),
@ViewDebug.FlagToString(mask = DRAWN, equals = DRAWN, name = "DRAWN", outputIf = true),
@ViewDebug.FlagToString(mask = DRAWN, equals = DRAWN, name = "NOT_DRAWN", outputIf = false),
@ViewDebug.FlagToString(mask = DIRTY_MASK, equals = DIRTY_OPAQUE, name = "DIRTY_OPAQUE"),
@@ -1551,6 +1614,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback {
protected int mPaddingBottom;
/**
+ * Briefly describes the view and is primarily used for accessibility support.
+ */
+ private CharSequence mContentDescription;
+
+ /**
* Cache the paddingRight set by the user to append to the scrollbar's size.
*/
@ViewDebug.ExportedProperty
@@ -1622,6 +1690,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback {
private int[] mDrawableState = null;
private SoftReference<Bitmap> mDrawingCache;
+ private SoftReference<Bitmap> mUnscaledDrawingCache;
/**
* When this view has focus and the next focus is {@link #FOCUS_LEFT},
@@ -1701,7 +1770,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback {
public View(Context context) {
mContext = context;
mResources = context != null ? context.getResources() : null;
- mViewFlags = SOUND_EFFECTS_ENABLED|HAPTIC_FEEDBACK_ENABLED;
+ mViewFlags = SOUND_EFFECTS_ENABLED | HAPTIC_FEEDBACK_ENABLED;
++sInstanceCount;
}
@@ -1762,7 +1831,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback {
int viewFlagMasks = 0;
boolean setScrollContainer = false;
-
+
int x = 0;
int y = 0;
@@ -1858,16 +1927,21 @@ public class View implements Drawable.Callback, KeyEvent.Callback {
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) {
@@ -1922,6 +1996,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback {
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() {
@@ -1990,7 +2069,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback {
if (!setScrollContainer && (viewFlagValues&SCROLLBARS_VERTICAL) != 0) {
setScrollContainer(true);
}
-
+
+ computeOpaqueFlags();
+
a.recycle();
}
@@ -2255,6 +2336,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback {
* otherwise is returned.
*/
public boolean performClick() {
+ sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);
+
if (mOnClickListener != null) {
playSoundEffect(SoundEffectConstants.CLICK);
mOnClickListener.onClick(this);
@@ -2272,6 +2355,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback {
* otherwise is returned.
*/
public boolean performLongClick() {
+ sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_LONG_CLICKED);
+
boolean handled = false;
if (mOnLongClickListener != null) {
handled = mOnLongClickListener.onLongClick(View.this);
@@ -2387,7 +2472,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback {
if (!(parent instanceof View)) {
break;
}
-
+
child = (View) parent;
parent = child.getParent();
}
@@ -2479,7 +2564,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback {
* 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
@@ -2492,6 +2577,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback {
* from (in addition to direction). Will be <code>null</code> 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()) {
@@ -2506,7 +2595,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback {
&& mAttachInfo.mHasWindowFocus) {
imm.focusIn(this);
}
-
+
invalidate();
if (mOnFocusChangeListener != null) {
mOnFocusChangeListener.onFocusChange(this, gainFocus);
@@ -2514,6 +2603,79 @@ public class View implements Drawable.Callback, KeyEvent.Callback {
}
/**
+ * {@inheritDoc}
+ */
+ public void sendAccessibilityEvent(int eventType) {
+ if (AccessibilityManager.getInstance(mContext).isEnabled()) {
+ sendAccessibilityEventUnchecked(AccessibilityEvent.obtain(eventType));
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void sendAccessibilityEventUnchecked(AccessibilityEvent event) {
+ event.setClassName(getClass().getName());
+ event.setPackageName(getContext().getPackageName());
+ event.setEnabled(isEnabled());
+ event.setContentDescription(mContentDescription);
+
+ if (event.getEventType() == AccessibilityEvent.TYPE_VIEW_FOCUSED && mAttachInfo != null) {
+ ArrayList<View> focusablesTempList = mAttachInfo.mFocusablesTempList;
+ getRootView().addFocusables(focusablesTempList, View.FOCUS_FORWARD, FOCUSABLES_ALL);
+ event.setItemCount(focusablesTempList.size());
+ event.setCurrentItemIndex(focusablesTempList.indexOf(this));
+ focusablesTempList.clear();
+ }
+
+ dispatchPopulateAccessibilityEvent(event);
+
+ AccessibilityManager.getInstance(mContext).sendAccessibilityEvent(event);
+ }
+
+ /**
+ * Dispatches an {@link AccessibilityEvent} to the {@link View} children
+ * to be populated.
+ *
+ * @param event The event.
+ *
+ * @return True if the event population was completed.
+ */
+ public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
+ return false;
+ }
+
+ /**
+ * Gets the {@link View} description. It briefly describes the view and is
+ * primarily used for accessibility support. Set this property to enable
+ * better accessibility support for your application. This is especially
+ * true for views that do not have textual representation (For example,
+ * ImageButton).
+ *
+ * @return The content descriptiopn.
+ *
+ * @attr ref android.R.styleable#View_contentDescription
+ */
+ public CharSequence getContentDescription() {
+ return mContentDescription;
+ }
+
+ /**
+ * Sets the {@link View} description. It briefly describes the view and is
+ * primarily used for accessibility support. Set this property to enable
+ * better accessibility support for your application. This is especially
+ * true for views that do not have textual representation (For example,
+ * ImageButton).
+ *
+ * @param contentDescription The content description.
+ *
+ * @attr ref android.R.styleable#View_contentDescription
+ */
+ public void setContentDescription(CharSequence contentDescription) {
+ mContentDescription = contentDescription;
+ }
+
+ /**
* Invoked whenever this view loses focus, either by losing window focus or by losing
* focus within its window. This method can be used to clear any state tied to the
* focus. For instance, if a button is held pressed with the trackball and the window
@@ -2522,7 +2684,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback {
* Subclasses of View overriding this method should always call super.onFocusLost().
*
* @see #onFocusChanged(boolean, int, android.graphics.Rect)
- * @see #onWindowFocusChanged(boolean)
+ * @see #onWindowFocusChanged(boolean)
*
* @hide pending API council approval
*/
@@ -3222,11 +3384,37 @@ public class View implements Drawable.Callback, KeyEvent.Callback {
* @param direction The direction of the focus
*/
public void addFocusables(ArrayList<View> views, int direction) {
- if (!isFocusable()) return;
+ addFocusables(views, direction, FOCUSABLES_TOUCH_MODE);
+ }
- if (isInTouchMode() && !isFocusableInTouchMode()) return;
+ /**
+ * Adds any focusable views that are descendants of this view (possibly
+ * including this view if it is focusable itself) to views. This method
+ * adds all focusable views regardless if we are in touch mode or
+ * only views focusable in touch mode if we are in touch mode depending on
+ * the focusable mode paramater.
+ *
+ * @param views Focusable views found so far or null if all we are interested is
+ * the number of focusables.
+ * @param direction The direction of the focus.
+ * @param focusableMode The type of focusables to be added.
+ *
+ * @see #FOCUSABLES_ALL
+ * @see #FOCUSABLES_TOUCH_MODE
+ */
+ public void addFocusables(ArrayList<View> views, int direction, int focusableMode) {
+ if (!isFocusable()) {
+ return;
+ }
- views.add(this);
+ if ((focusableMode & FOCUSABLES_TOUCH_MODE) == FOCUSABLES_TOUCH_MODE &&
+ isInTouchMode() && !isFocusableInTouchMode()) {
+ return;
+ }
+
+ if (views != null) {
+ views.add(this);
+ }
}
/**
@@ -3398,14 +3586,14 @@ public class View implements Drawable.Callback, KeyEvent.Callback {
*/
public void onStartTemporaryDetach() {
}
-
+
/**
* 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
@@ -3790,25 +3978,25 @@ public class View implements Drawable.Callback, KeyEvent.Callback {
* 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.
- *
+ *
* <p>The default implementation always returns false. This does
* <em>not</em> 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.
- *
+ *
* <p>When implementing this, you probably also want to implement
* {@link #onCheckIsTextEditor()} to indicate you will return a
* non-null InputConnection.
@@ -3832,7 +4020,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback {
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.
@@ -4563,14 +4751,42 @@ public class View implements Drawable.Callback, KeyEvent.Callback {
* whether an instance is opaque. Opaque Views are treated in a special way by
* the View hierarchy, possibly allowing it to perform optimizations during
* invalidate/draw passes.
- *
+ *
* @return True if this View is guaranteed to be fully opaque, false otherwise.
*
* @hide Pending API council approval
*/
@ViewDebug.ExportedProperty
public boolean isOpaque() {
- return mBGDrawable != null && mBGDrawable.getOpacity() == PixelFormat.OPAQUE;
+ return (mPrivateFlags & OPAQUE_MASK) == OPAQUE_MASK;
+ }
+
+ private void computeOpaqueFlags() {
+ // Opaque if:
+ // - Has a background
+ // - Background is opaque
+ // - Doesn't have scrollbars or scrollbars are inside overlay
+
+ if (mBGDrawable != null && mBGDrawable.getOpacity() == PixelFormat.OPAQUE) {
+ mPrivateFlags |= OPAQUE_BACKGROUND;
+ } else {
+ mPrivateFlags &= ~OPAQUE_BACKGROUND;
+ }
+
+ final int flags = mViewFlags;
+ if (((flags & SCROLLBARS_VERTICAL) == 0 && (flags & SCROLLBARS_HORIZONTAL) == 0) ||
+ (flags & SCROLLBARS_STYLE_MASK) == SCROLLBARS_INSIDE_OVERLAY) {
+ mPrivateFlags |= OPAQUE_SCROLLBARS;
+ } else {
+ mPrivateFlags &= ~OPAQUE_SCROLLBARS;
+ }
+ }
+
+ /**
+ * @hide
+ */
+ protected boolean hasOpaqueScrollbars() {
+ return (mPrivateFlags & OPAQUE_SCROLLBARS) == OPAQUE_SCROLLBARS;
}
/**
@@ -4897,6 +5113,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback {
public void setHorizontalScrollBarEnabled(boolean horizontalScrollBarEnabled) {
if (isHorizontalScrollBarEnabled() != horizontalScrollBarEnabled) {
mViewFlags ^= SCROLLBARS_HORIZONTAL;
+ computeOpaqueFlags();
recomputePadding();
}
}
@@ -4926,6 +5143,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback {
public void setVerticalScrollBarEnabled(boolean verticalScrollBarEnabled) {
if (isVerticalScrollBarEnabled() != verticalScrollBarEnabled) {
mViewFlags ^= SCROLLBARS_VERTICAL;
+ computeOpaqueFlags();
recomputePadding();
}
}
@@ -4954,6 +5172,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback {
public void setScrollBarStyle(int style) {
if (style != (mViewFlags & SCROLLBARS_STYLE_MASK)) {
mViewFlags = (mViewFlags & ~SCROLLBARS_STYLE_MASK) | (style & SCROLLBARS_STYLE_MASK);
+ computeOpaqueFlags();
recomputePadding();
}
}
@@ -5132,9 +5351,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback {
}
}
}
-
+
/**
- * Override this if the vertical scrollbar needs to be hidden in a subclass, like when
+ * Override this if the vertical scrollbar needs to be hidden in a subclass, like when
* FastScroller is visible.
* @return whether to temporarily hide the vertical scrollbar
* @hide
@@ -5570,28 +5789,52 @@ public class View implements Drawable.Callback, KeyEvent.Callback {
}
/**
+ * <p>Calling this method is equivalent to calling <code>getDrawingCache(false)</code>.</p>
+ *
+ * @return A non-scaled bitmap representing this view or null if cache is disabled.
+ *
+ * @see #getDrawingCache(boolean)
+ */
+ public Bitmap getDrawingCache() {
+ return getDrawingCache(false);
+ }
+
+ /**
* <p>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.</p>
+ *
+ * <p>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.</p>
+ *
+ * @param autoScale Indicates whether the generated bitmap should be scaled based on
+ * the current density of the screen when the application is in compatibility
+ * mode.
*
- * @return a bitmap representing this view or null if cache is disabled
- *
+ * @return A bitmap representing this view or null if cache is disabled.
+ *
* @see #setDrawingCacheEnabled(boolean)
* @see #isDrawingCacheEnabled()
- * @see #buildDrawingCache()
+ * @see #buildDrawingCache(boolean)
* @see #destroyDrawingCache()
*/
- public Bitmap getDrawingCache() {
+ public Bitmap getDrawingCache(boolean autoScale) {
if ((mViewFlags & WILL_NOT_CACHE_DRAWING) == WILL_NOT_CACHE_DRAWING) {
return null;
}
if ((mViewFlags & DRAWING_CACHE_ENABLED) == DRAWING_CACHE_ENABLED) {
- buildDrawingCache();
+ buildDrawingCache(autoScale);
}
- return mDrawingCache == null ? null : mDrawingCache.get();
+ return autoScale ? (mDrawingCache == null ? null : mDrawingCache.get()) :
+ (mUnscaledDrawingCache == null ? null : mUnscaledDrawingCache.get());
}
/**
@@ -5610,6 +5853,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback {
if (bitmap != null) bitmap.recycle();
mDrawingCache = null;
}
+ if (mUnscaledDrawingCache != null) {
+ final Bitmap bitmap = mUnscaledDrawingCache.get();
+ if (bitmap != null) bitmap.recycle();
+ mUnscaledDrawingCache = null;
+ }
}
/**
@@ -5637,18 +5885,36 @@ public class View implements Drawable.Callback, KeyEvent.Callback {
}
/**
+ * <p>Calling this method is equivalent to calling <code>buildDrawingCache(false)</code>.</p>
+ *
+ * @see #buildDrawingCache(boolean)
+ */
+ public void buildDrawingCache() {
+ buildDrawingCache(false);
+ }
+
+ /**
* <p>Forces the drawing cache to be built if the drawing cache is invalid.</p>
*
* <p>If you call {@link #buildDrawingCache()} manually without calling
* {@link #setDrawingCacheEnabled(boolean) setDrawingCacheEnabled(true)}, you
* should cleanup the cache by calling {@link #destroyDrawingCache()} afterwards.</p>
+ *
+ * <p>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.</p>
*
* @see #getDrawingCache()
* @see #destroyDrawingCache()
*/
- public void buildDrawingCache() {
- if ((mPrivateFlags & DRAWING_CACHE_VALID) == 0 || mDrawingCache == null ||
- mDrawingCache.get() == null) {
+ public void buildDrawingCache(boolean autoScale) {
+ if ((mPrivateFlags & DRAWING_CACHE_VALID) == 0 || (autoScale ?
+ (mDrawingCache == null || mDrawingCache.get() == null) :
+ (mUnscaledDrawingCache == null || mUnscaledDrawingCache.get() == null))) {
if (ViewDebug.TRACE_HIERARCHY) {
ViewDebug.trace(this, ViewDebug.HierarchyTraceType.BUILD_CACHE);
@@ -5657,8 +5923,16 @@ public class View implements Drawable.Callback, KeyEvent.Callback {
EventLog.writeEvent(60002, hashCode());
}
- final int width = mRight - mLeft;
- final int height = mBottom - mTop;
+ int width = mRight - mLeft;
+ int height = mBottom - mTop;
+
+ final AttachInfo attachInfo = mAttachInfo;
+ final boolean scalingRequired = attachInfo != null && attachInfo.mScalingRequired;
+
+ if (autoScale && scalingRequired) {
+ width = (int) ((width * attachInfo.mApplicationScale) + 0.5f);
+ height = (int) ((height * attachInfo.mApplicationScale) + 0.5f);
+ }
final int drawingCacheBackgroundColor = mDrawingCacheBackgroundColor;
final boolean opaque = drawingCacheBackgroundColor != 0 ||
@@ -5672,7 +5946,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback {
}
boolean clear = true;
- Bitmap bitmap = mDrawingCache == null ? null : mDrawingCache.get();
+ Bitmap bitmap = autoScale ? (mDrawingCache == null ? null : mDrawingCache.get()) :
+ (mUnscaledDrawingCache == null ? null : mUnscaledDrawingCache.get());
if (bitmap == null || bitmap.getWidth() != width || bitmap.getHeight() != height) {
@@ -5701,12 +5976,20 @@ public class View implements Drawable.Callback, KeyEvent.Callback {
try {
bitmap = Bitmap.createBitmap(width, height, quality);
- mDrawingCache = new SoftReference<Bitmap>(bitmap);
+ if (autoScale) {
+ mDrawingCache = new SoftReference<Bitmap>(bitmap);
+ } else {
+ mUnscaledDrawingCache = new SoftReference<Bitmap>(bitmap);
+ }
} catch (OutOfMemoryError e) {
// If there is not enough memory to create the bitmap cache, just
// ignore the issue as bitmap caches are not required to draw the
// view hierarchy
- mDrawingCache = null;
+ if (autoScale) {
+ mDrawingCache = null;
+ } else {
+ mUnscaledDrawingCache = null;
+ }
return;
}
@@ -5714,7 +5997,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback {
}
Canvas canvas;
- final AttachInfo attachInfo = mAttachInfo;
if (attachInfo != null) {
canvas = attachInfo.mCanvas;
if (canvas == null) {
@@ -5737,15 +6019,22 @@ public class View implements Drawable.Callback, KeyEvent.Callback {
computeScroll();
final int restoreCount = canvas.save();
+
+ if (autoScale && scalingRequired) {
+ final float scale = attachInfo.mApplicationScale;
+ canvas.scale(scale, scale);
+ }
+
canvas.translate(-mScrollX, -mScrollY);
- mPrivateFlags = (mPrivateFlags & ~DIRTY_MASK) | DRAWN;
+ mPrivateFlags |= DRAWN;
// Fast path for layouts with no backgrounds
if ((mPrivateFlags & SKIP_DRAW) == SKIP_DRAW) {
if (ViewDebug.TRACE_HIERARCHY) {
ViewDebug.trace(this, ViewDebug.HierarchyTraceType.DRAW);
}
+ mPrivateFlags &= ~DIRTY_MASK;
dispatchDraw(canvas);
} else {
draw(canvas);
@@ -5792,7 +6081,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback {
canvas = new Canvas(bitmap);
}
- if ((backgroundColor&0xff000000) != 0) {
+ if ((backgroundColor & 0xff000000) != 0) {
bitmap.eraseColor(backgroundColor);
}
@@ -5800,6 +6089,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback {
final int restoreCount = canvas.save();
canvas.translate(-mScrollX, -mScrollY);
+ // Temporarily remove the dirty mask
+ int flags = mPrivateFlags;
+ mPrivateFlags &= ~DIRTY_MASK;
+
// Fast path for layouts with no backgrounds
if ((mPrivateFlags & SKIP_DRAW) == SKIP_DRAW) {
dispatchDraw(canvas);
@@ -5807,13 +6100,15 @@ public class View implements Drawable.Callback, KeyEvent.Callback {
draw(canvas);
}
+ mPrivateFlags = flags;
+
canvas.restoreToCount(restoreCount);
if (attachInfo != null) {
// Restore the cached Canvas for our siblings
attachInfo.mCanvas = canvas;
}
-
+
return bitmap;
}
@@ -5927,8 +6222,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback {
ViewDebug.trace(this, ViewDebug.HierarchyTraceType.DRAW);
}
- final boolean dirtyOpaque = (mPrivateFlags & DIRTY_MASK) == DIRTY_OPAQUE;
- mPrivateFlags = (mPrivateFlags & ~DIRTY_MASK) | DRAWN;
+ final int privateFlags = mPrivateFlags;
+ final boolean dirtyOpaque = (privateFlags & DIRTY_MASK) == DIRTY_OPAQUE &&
+ (mAttachInfo == null || !mAttachInfo.mIgnoreDirtyState);
+ mPrivateFlags = (privateFlags & ~DIRTY_MASK) | DRAWN;
/*
* Draw traversal performs several drawing steps which must be executed
@@ -6306,7 +6603,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback {
boolean changed = false;
if (DBG) {
- System.out.println(this + " View.setFrame(" + left + "," + top + ","
+ Log.d("View", this + " View.setFrame(" + left + "," + top + ","
+ right + "," + bottom + ")");
}
@@ -6709,6 +7006,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback {
requestLayout = true;
}
+ computeOpaqueFlags();
+
if (requestLayout) {
requestLayout();
}
@@ -6749,7 +7048,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback {
mUserPaddingBottom = bottom;
final int viewFlags = mViewFlags;
-
+
// Common case is there are no scroll bars.
if ((viewFlags & (SCROLLBARS_VERTICAL|SCROLLBARS_HORIZONTAL)) != 0) {
// TODO: Deal with RTL languages to adjust left padding instead of right.
@@ -6762,7 +7061,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback {
? 0 : getHorizontalScrollbarHeight();
}
}
-
+
if (mPaddingLeft != left) {
changed = true;
mPaddingLeft = left;
@@ -6899,7 +7198,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback {
return v;
}
}
-
+
View parent = this;
while (parent.mParent != null && parent.mParent instanceof View) {
@@ -6920,8 +7219,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback {
getLocationInWindow(location);
final AttachInfo info = mAttachInfo;
- location[0] += info.mWindowLeft;
- location[1] += info.mWindowTop;
+ if (info != null) {
+ location[0] += info.mWindowLeft;
+ location[1] += info.mWindowTop;
+ }
}
/**
@@ -6947,7 +7248,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback {
location[1] += view.mTop - view.mScrollY;
viewParent = view.mParent;
}
-
+
if (viewParent instanceof ViewRoot) {
// *cough*
final ViewRoot vr = (ViewRoot)viewParent;
@@ -7098,7 +7399,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback {
* @return the Object stored in this view as a tag
*
* @see #setTag(int, Object)
- * @see #getTag()
+ * @see #getTag()
*/
public Object getTag(int key) {
SparseArray<Object> tags = null;
@@ -7154,7 +7455,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback {
+ "resource id.");
}
- setTagInternal(this, key, tag);
+ setTagInternal(this, key, tag);
}
private static void setTagInternal(View view, int key, Object tag) {
@@ -7189,7 +7490,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback {
/**
* Method that subclasses should implement to check their consistency. The type of
* consistency check is indicated by the bit field passed as a parameter.
- *
+ *
* @param consistency The type of consistency. See ViewDebug for more information.
*
* @throws IllegalStateException if the view is in an inconsistent state.
@@ -7744,7 +8045,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback {
/**
* BZZZTT!!1!
- *
+ *
* <p>Provide haptic feedback to the user for this view.
*
* <p>The framework will provide haptic feedback for some built in actions,
@@ -7763,7 +8064,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback {
/**
* BZZZTT!!1!
- *
+ *
* <p>Like {@link #performHapticFeedback(int)}, with additional options.
*
* @param feedbackConstant One of the constants defined in
@@ -8158,7 +8459,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback {
* window.
*/
static class AttachInfo {
-
interface Callbacks {
void playSoundEffect(int effectId);
boolean performHapticFeedback(int effectId, boolean always);
@@ -8227,11 +8527,21 @@ public class View implements Drawable.Callback, KeyEvent.Callback {
* The top view of the hierarchy.
*/
View mRootView;
-
+
IBinder mPanelParentWindowToken;
Surface mSurface;
/**
+ * Scale factor used by the compatibility mode
+ */
+ float mApplicationScale;
+
+ /**
+ * Indicates whether the application is in compatibility mode
+ */
+ boolean mScalingRequired;
+
+ /**
* Left position of this view's window
*/
int mWindowLeft;
@@ -8288,6 +8598,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback {
long mDrawingTime;
/**
+ * Indicates whether or not ignoring the DIRTY_MASK flags.
+ */
+ boolean mIgnoreDirtyState;
+
+ /**
* Indicates whether the view's window is currently in touch mode.
*/
boolean mInTouchMode;
@@ -8365,7 +8680,12 @@ public class View implements Drawable.Callback, KeyEvent.Callback {
* calling up the hierarchy.
*/
final Rect mTmpInvalRect = new Rect();
-
+
+ /**
+ * Temporary list for use in collecting focusable descendents of a view.
+ */
+ final ArrayList<View> mFocusablesTempList = new ArrayList<View>(24);
+
/**
* Creates a new set of attachment information with the specified
* events handler and thread.
@@ -8408,18 +8728,18 @@ public class View implements Drawable.Callback, KeyEvent.Callback {
// use use a height of 1, and then wack the matrix each time we
// actually use it.
shader = new LinearGradient(0, 0, 0, 1, 0xFF000000, 0, Shader.TileMode.CLAMP);
-
+
paint.setShader(shader);
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT));
}
-
+
public void setFadeColor(int color) {
if (color != 0 && color != mLastColor) {
mLastColor = color;
color |= 0xFF000000;
-
+
shader = new LinearGradient(0, 0, 0, 1, color, 0, Shader.TileMode.CLAMP);
-
+
paint.setShader(shader);
// Restore the default transfer mode (src_over)
paint.setXfermode(null);