container) {
- if (mID != NO_ID && (mViewFlags & SAVE_DISABLED_MASK) == 0) {
- mPrivateFlags &= ~SAVE_STATE_CALLED;
- Parcelable state = onSaveInstanceState();
- if ((mPrivateFlags & SAVE_STATE_CALLED) == 0) {
- throw new IllegalStateException(
- "Derived class did not call super.onSaveInstanceState()");
- }
- if (state != null) {
- // Log.i("View", "Freezing #" + Integer.toHexString(mID)
- // + ": " + state);
- container.put(mID, state);
- }
- }
- }
- /**
- * Hook allowing a view to generate a representation of its internal state
- * that can later be used to create a new instance with that same state.
- * This state should only contain information that is not persistent or can
- * not be reconstructed later. For example, you will never store your
- * current position on screen because that will be computed again when a
- * new instance of the view is placed in its view hierarchy.
- *
- * 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(android.os.Parcelable)
- * @see #saveHierarchyState(android.util.SparseArray)
- * @see #dispatchSaveInstanceState(android.util.SparseArray)
- * @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(android.util.SparseArray)
- * @see #dispatchRestoreInstanceState(android.util.SparseArray)
- * @see #onRestoreInstanceState(android.os.Parcelable)
- */
- public void restoreHierarchyState(SparseArray container) {
- dispatchRestoreInstanceState(container);
- }
- /**
- * Called by {@link #restoreHierarchyState(android.util.SparseArray)} to retrieve the
- * state for this view and its children. May be overridden to modify how restoring
- * happens to a view's children; for example, some views may want to not store state
- * for their children.
- *
- * @param container The SparseArray which holds previously saved state.
- *
- * @see #dispatchSaveInstanceState(android.util.SparseArray)
- * @see #restoreHierarchyState(android.util.SparseArray)
- * @see #onRestoreInstanceState(android.os.Parcelable)
- */
- protected void dispatchRestoreInstanceState(SparseArray container) {
- if (mID != NO_ID) {
- Parcelable state = container.get(mID);
- if (state != null) {
- // Log.i("View", "Restoreing #" + Integer.toHexString(mID)
- // + ": " + state);
- mPrivateFlags &= ~SAVE_STATE_CALLED;
- onRestoreInstanceState(state);
- if ((mPrivateFlags & SAVE_STATE_CALLED) == 0) {
- throw new IllegalStateException(
- "Derived class did not call super.onRestoreInstanceState()");
- }
- }
- }
- }
- /**
- * Hook allowing a view to re-apply a representation of its internal state that had previously
- * been generated by {@link #onSaveInstanceState}. This function will never be called with a
- * null state.
- *
- * @param state The frozen state that had previously been returned by
- * {@link #onSaveInstanceState}.
- *
- * @see #onSaveInstanceState()
- * @see #restoreHierarchyState(android.util.SparseArray)
- * @see #dispatchRestoreInstanceState(android.util.SparseArray)
- */
- protected void onRestoreInstanceState(Parcelable state) {
- mPrivateFlags |= SAVE_STATE_CALLED;
- if (state != BaseSavedState.EMPTY_STATE && state != null) {
- throw new IllegalArgumentException("Wrong state class, expecting View State but "
- + "received " + state.getClass().toString() + " instead. This usually happens "
- + "when two views of different type have the same id in the same hierarchy. "
- + "This view's id is " + ViewDebug.resolveId(mContext, getId()) + ". Make sure "
- + "other views do not use the same id.");
- }
- }
- /**
- * Return the time at which the drawing of the view hierarchy started.
- *
- * @return the drawing start time in milliseconds
- */
- public long getDrawingTime() {
- return mAttachInfo != null ? mAttachInfo.mDrawingTime : 0;
- }
- /**
- * 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.
- *
- * @param enabled True to enable duplication of the parent's drawable state, false
- * to disable it.
- *
- * @see #getDrawableState()
- * @see #isDuplicateParentStateEnabled()
- */
- public void setDuplicateParentStateEnabled(boolean enabled) {
- setFlags(enabled ? DUPLICATE_PARENT_STATE : 0, DUPLICATE_PARENT_STATE);
- }
- /**
- * Indicates whether this duplicates its drawable state from its parent.
- *
- * @return True if this view's drawable state is duplicated from the parent,
- * false otherwise
- *
- * @see #getDrawableState()
- * @see #setDuplicateParentStateEnabled(boolean)
- */
- public boolean isDuplicateParentStateEnabled() {
- return (mViewFlags & DUPLICATE_PARENT_STATE) == DUPLICATE_PARENT_STATE;
- }
- /**
- * 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:
- *
- * {@link android.graphics.Paint#getAlpha() Translucency (alpha)}
- * {@link android.graphics.Paint#getXfermode() Blending mode}
- * {@link android.graphics.Paint#getColorFilter() Color filter}
- *
- *
- * 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.
- *
- * @param layerType The ype of layer to use with this view, must be one of
- * {@link #LAYER_TYPE_NONE}, {@link #LAYER_TYPE_SOFTWARE} or
- * {@link #LAYER_TYPE_HARDWARE}
- * @param paint The paint used to compose the layer. This argument is optional
- * and can be null. It is ignored when the layer type is
- * {@link #LAYER_TYPE_NONE}
- *
- * @see #getLayerType()
- * @see #LAYER_TYPE_NONE
- * @see #LAYER_TYPE_SOFTWARE
- * @see #LAYER_TYPE_HARDWARE
- * @see #setAlpha(float)
- *
- * @attr ref android.R.styleable#View_layerType
- */
- public void setLayerType(int layerType, Paint paint) {
- if (layerType < LAYER_TYPE_NONE || layerType > LAYER_TYPE_HARDWARE) {
- throw new IllegalArgumentException("Layer type can only be one of: LAYER_TYPE_NONE, "
- + "LAYER_TYPE_SOFTWARE or LAYER_TYPE_HARDWARE");
- }
- if (layerType == mLayerType) {
- if (layerType != LAYER_TYPE_NONE && paint != mLayerPaint) {
- mLayerPaint = paint == null ? new Paint() : paint;
- invalidateParentCaches();
- invalidate(true);
- }
- return;
- }
- // Destroy any previous software drawing cache if needed
- switch (mLayerType) {
- case LAYER_TYPE_HARDWARE:
- destroyLayer();
- // fall through - non-accelerated views may use software layer mechanism instead
- case LAYER_TYPE_SOFTWARE:
- destroyDrawingCache();
- break;
- default:
- break;
- }
- mLayerType = layerType;
- final boolean layerDisabled = mLayerType == LAYER_TYPE_NONE;
- mLayerPaint = layerDisabled ? null : (paint == null ? new Paint() : paint);
- mLocalDirtyRect = layerDisabled ? null : new Rect();
- invalidateParentCaches();
- invalidate(true);
- }
- /**
- * Indicates whether this view has a static layer. A view with layer type
- * {@link #LAYER_TYPE_NONE} is a static layer. Other types of layers are
- * dynamic.
- */
- boolean hasStaticLayer() {
- return mLayerType == LAYER_TYPE_NONE;
- }
- /**
- * Indicates what type of layer is currently associated with this view. By default
- * a view does not have a layer, and the layer type is {@link #LAYER_TYPE_NONE}.
- * Refer to the documentation of {@link #setLayerType(int, android.graphics.Paint)}
- * for more information on the different types of layers.
- *
- * @return {@link #LAYER_TYPE_NONE}, {@link #LAYER_TYPE_SOFTWARE} or
- * {@link #LAYER_TYPE_HARDWARE}
- *
- * @see #setLayerType(int, android.graphics.Paint)
- * @see #buildLayer()
- * @see #LAYER_TYPE_NONE
- * @see #LAYER_TYPE_SOFTWARE
- * @see #LAYER_TYPE_HARDWARE
- */
- public int getLayerType() {
- return mLayerType;
- }
- /**
- * Forces this view's layer to be created and this view to be rendered
- * into its layer. If this view's layer type is set to {@link #LAYER_TYPE_NONE},
- * invoking this method will have no effect.
- *
- * This method can for instance be used to render a view into its layer before
- * starting an animation. If this view is complex, rendering into the layer
- * before starting the animation will avoid skipping frames.
- *
- * @throws IllegalStateException If this view is not attached to a window
- *
- * @see #setLayerType(int, android.graphics.Paint)
- */
- public void buildLayer() {
- if (mLayerType == LAYER_TYPE_NONE) return;
- if (mAttachInfo == null) {
- throw new IllegalStateException("This view must be attached to a window first");
- }
- switch (mLayerType) {
- case LAYER_TYPE_HARDWARE:
- if (mAttachInfo.mHardwareRenderer != null &&
- mAttachInfo.mHardwareRenderer.isEnabled() &&
- mAttachInfo.mHardwareRenderer.validate()) {
- getHardwareLayer();
- }
- break;
- case LAYER_TYPE_SOFTWARE:
- buildDrawingCache(true);
- break;
- }
- }
-
- // Make sure the HardwareRenderer.validate() was invoked before calling this method
- void flushLayer() {
- if (mLayerType == LAYER_TYPE_HARDWARE && mHardwareLayer != null) {
- mHardwareLayer.flush();
- }
- }
- /**
- * Returns a hardware layer that can be used to draw this view again
- * without executing its draw method.
- *
- * @return A HardwareLayer ready to render, or null if an error occurred.
- */
- HardwareLayer getHardwareLayer() {
- if (mAttachInfo == null || mAttachInfo.mHardwareRenderer == null ||
- !mAttachInfo.mHardwareRenderer.isEnabled()) {
- return null;
- }
-
- if (!mAttachInfo.mHardwareRenderer.validate()) return null;
- final int width = mRight - mLeft;
- final int height = mBottom - mTop;
- if (width == 0 || height == 0) {
- return null;
- }
- if ((mPrivateFlags & DRAWING_CACHE_VALID) == 0 || mHardwareLayer == null) {
- if (mHardwareLayer == null) {
- mHardwareLayer = mAttachInfo.mHardwareRenderer.createHardwareLayer(
- width, height, isOpaque());
- mLocalDirtyRect.setEmpty();
- } else if (mHardwareLayer.getWidth() != width || mHardwareLayer.getHeight() != height) {
- mHardwareLayer.resize(width, height);
- mLocalDirtyRect.setEmpty();
- }
- // The layer is not valid if the underlying GPU resources cannot be allocated
- if (!mHardwareLayer.isValid()) {
- return null;
- }
- HardwareCanvas currentCanvas = mAttachInfo.mHardwareCanvas;
- final HardwareCanvas canvas = mHardwareLayer.start(currentCanvas);
- // Make sure all the GPU resources have been properly allocated
- if (canvas == null) {
- mHardwareLayer.end(currentCanvas);
- return null;
- }
- mAttachInfo.mHardwareCanvas = canvas;
- try {
- canvas.setViewport(width, height);
- canvas.onPreDraw(mLocalDirtyRect);
- mLocalDirtyRect.setEmpty();
- final int restoreCount = canvas.save();
- computeScroll();
- canvas.translate(-mScrollX, -mScrollY);
- mPrivateFlags |= DRAWN | DRAWING_CACHE_VALID;
- // Fast path for layouts with no backgrounds
- if ((mPrivateFlags & SKIP_DRAW) == SKIP_DRAW) {
- mPrivateFlags &= ~DIRTY_MASK;
- dispatchDraw(canvas);
- } else {
- draw(canvas);
- }
- canvas.restoreToCount(restoreCount);
- } finally {
- canvas.onPostDraw();
- mHardwareLayer.end(currentCanvas);
- mAttachInfo.mHardwareCanvas = currentCanvas;
- }
- }
- return mHardwareLayer;
- }
- /**
- * Destroys this View's hardware layer if possible.
- *
- * @return True if the layer was destroyed, false otherwise.
- *
- * @see #setLayerType(int, android.graphics.Paint)
- * @see #LAYER_TYPE_HARDWARE
- */
- boolean destroyLayer() {
- if (mHardwareLayer != null) {
- AttachInfo info = mAttachInfo;
- if (info != null && info.mHardwareRenderer != null &&
- info.mHardwareRenderer.isEnabled() && info.mHardwareRenderer.validate()) {
- mHardwareLayer.destroy();
- mHardwareLayer = null;
- invalidate(true);
- invalidateParentCaches();
- }
- return true;
- }
- return false;
- }
- /**
- * Destroys all hardware rendering resources. This method is invoked
- * when the system needs to reclaim resources. Upon execution of this
- * method, you should free any OpenGL resources created by the view.
- *
- * Note: you must call
- * super.destroyHardwareResources()
when overriding
- * this method.
- *
- * @hide
- */
- protected void destroyHardwareResources() {
- destroyLayer();
- }
- /**
- * 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 true
and calling
- * {@link #getDrawingCache()}.
- *
- * @param enabled true to enable the drawing cache, false otherwise
- *
- * @see #isDrawingCacheEnabled()
- * @see #getDrawingCache()
- * @see #buildDrawingCache()
- * @see #setLayerType(int, android.graphics.Paint)
- */
- public void setDrawingCacheEnabled(boolean enabled) {
- mCachingFailed = false;
- setFlags(enabled ? DRAWING_CACHE_ENABLED : 0, DRAWING_CACHE_ENABLED);
- }
- /**
- * Indicates whether the drawing cache is enabled for this view.
- *
- * @return true if the drawing cache is enabled
- *
- * @see #setDrawingCacheEnabled(boolean)
- * @see #getDrawingCache()
- */
- @ViewDebug.ExportedProperty(category = "drawing")
- public boolean isDrawingCacheEnabled() {
- return (mViewFlags & DRAWING_CACHE_ENABLED) == DRAWING_CACHE_ENABLED;
- }
- /**
- * Debugging utility which recursively outputs the dirty state of a view and its
- * descendants.
- *
- * @hide
- */
- @SuppressWarnings({"UnusedDeclaration"})
- public void outputDirtyFlags(String indent, boolean clear, int clearMask) {
- Log.d("View", indent + this + " DIRTY(" + (mPrivateFlags & View.DIRTY_MASK) +
- ") DRAWN(" + (mPrivateFlags & DRAWN) + ")" + " CACHE_VALID(" +
- (mPrivateFlags & View.DRAWING_CACHE_VALID) +
- ") INVALIDATED(" + (mPrivateFlags & INVALIDATED) + ")");
- if (clear) {
- mPrivateFlags &= clearMask;
- }
- if (this instanceof ViewGroup) {
- ViewGroup parent = (ViewGroup) this;
- final int count = parent.getChildCount();
- for (int i = 0; i < count; i++) {
- final View child = parent.getChildAt(i);
- child.outputDirtyFlags(indent + " ", clear, clearMask);
- }
- }
- }
- /**
- * This method is used by ViewGroup to cause its children to restore or recreate their
- * display lists. It is called by getDisplayList() when the parent ViewGroup does not need
- * to recreate its own display list, which would happen if it went through the normal
- * draw/dispatchDraw mechanisms.
- *
- * @hide
- */
- protected void dispatchGetDisplayList() {}
- /**
- * A view that is not attached or hardware accelerated cannot create a display list.
- * This method checks these conditions and returns the appropriate result.
- *
- * @return true if view has the ability to create a display list, false otherwise.
- *
- * @hide
- */
- public boolean canHaveDisplayList() {
- return !(mAttachInfo == null || mAttachInfo.mHardwareRenderer == null);
- }
- /**
- * @return The HardwareRenderer associated with that view or null if hardware rendering
- * is not supported or this this has not been attached to a window.
- *
- * @hide
- */
- public HardwareRenderer getHardwareRenderer() {
- if (mAttachInfo != null) {
- return mAttachInfo.mHardwareRenderer;
- }
- return null;
- }
- /**
- * Returns a display list that can be used to draw this view again
- * without executing its draw method.
- *
- * @return A DisplayList ready to replay, or null if caching is not enabled.
- *
- * @hide
- */
- public DisplayList getDisplayList() {
- if (!canHaveDisplayList()) {
- return null;
- }
- if (((mPrivateFlags & DRAWING_CACHE_VALID) == 0 ||
- mDisplayList == null || !mDisplayList.isValid() ||
- mRecreateDisplayList)) {
- // Don't need to recreate the display list, just need to tell our
- // children to restore/recreate theirs
- if (mDisplayList != null && mDisplayList.isValid() &&
- !mRecreateDisplayList) {
- mPrivateFlags |= DRAWN | DRAWING_CACHE_VALID;
- mPrivateFlags &= ~DIRTY_MASK;
- dispatchGetDisplayList();
- return mDisplayList;
- }
- // If we got here, we're recreating it. Mark it as such to ensure that
- // we copy in child display lists into ours in drawChild()
- mRecreateDisplayList = true;
- if (mDisplayList == null) {
- final String name = getClass().getSimpleName();
- mDisplayList = mAttachInfo.mHardwareRenderer.createDisplayList(name);
- // If we're creating a new display list, make sure our parent gets invalidated
- // since they will need to recreate their display list to account for this
- // new child display list.
- invalidateParentCaches();
- }
- final HardwareCanvas canvas = mDisplayList.start();
- int restoreCount = 0;
- try {
- int width = mRight - mLeft;
- int height = mBottom - mTop;
- canvas.setViewport(width, height);
- // The dirty rect should always be null for a display list
- canvas.onPreDraw(null);
- computeScroll();
- restoreCount = canvas.save();
- canvas.translate(-mScrollX, -mScrollY);
- mPrivateFlags |= DRAWN | DRAWING_CACHE_VALID;
- mPrivateFlags &= ~DIRTY_MASK;
- // Fast path for layouts with no backgrounds
- if ((mPrivateFlags & SKIP_DRAW) == SKIP_DRAW) {
- dispatchDraw(canvas);
- } else {
- draw(canvas);
- }
- } finally {
- canvas.restoreToCount(restoreCount);
- canvas.onPostDraw();
- mDisplayList.end();
- }
- } else {
- mPrivateFlags |= DRAWN | DRAWING_CACHE_VALID;
- mPrivateFlags &= ~DIRTY_MASK;
- }
- return mDisplayList;
- }
- /**
- * Calling this method is equivalent to calling getDrawingCache(false)
.
- *
- * @return A non-scaled bitmap representing this view or null if cache is disabled.
- *
- * @see #getDrawingCache(boolean)
- */
- public Bitmap getDrawingCache() {
- return getDrawingCache(false);
- }
- /**
- * 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.
- *
- * @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.
- *
- * @see #setDrawingCacheEnabled(boolean)
- * @see #isDrawingCacheEnabled()
- * @see #buildDrawingCache(boolean)
- * @see #destroyDrawingCache()
- */
- 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(autoScale);
- }
- return autoScale ? mDrawingCache : mUnscaledDrawingCache;
- }
- /**
- * 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.
- *
- * @see #setDrawingCacheEnabled(boolean)
- * @see #buildDrawingCache()
- * @see #getDrawingCache()
- */
- public void destroyDrawingCache() {
- if (mDrawingCache != null) {
- mDrawingCache.recycle();
- mDrawingCache = null;
- }
- if (mUnscaledDrawingCache != null) {
- mUnscaledDrawingCache.recycle();
- mUnscaledDrawingCache = null;
- }
- }
- /**
- * Setting a solid background color for the drawing cache's bitmaps will improve
- * performance and memory usage. Note, though that this should only be used if this
- * view will always be drawn on top of a solid color.
- *
- * @param color The background color to use for the drawing cache's bitmap
- *
- * @see #setDrawingCacheEnabled(boolean)
- * @see #buildDrawingCache()
- * @see #getDrawingCache()
- */
- public void setDrawingCacheBackgroundColor(int color) {
- if (color != mDrawingCacheBackgroundColor) {
- mDrawingCacheBackgroundColor = color;
- mPrivateFlags &= ~DRAWING_CACHE_VALID;
- }
- }
- /**
- * @see #setDrawingCacheBackgroundColor(int)
- *
- * @return The background color to used for the drawing cache's bitmap
- */
- public int getDrawingCacheBackgroundColor() {
- return mDrawingCacheBackgroundColor;
- }
- /**
- * Calling this method is equivalent to calling buildDrawingCache(false)
.
- *
- * @see #buildDrawingCache(boolean)
- */
- public void buildDrawingCache() {
- buildDrawingCache(false);
- }
- /**
- * 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.
- *
- * @see #getDrawingCache()
- * @see #destroyDrawingCache()
- */
- public void buildDrawingCache(boolean autoScale) {
- if ((mPrivateFlags & DRAWING_CACHE_VALID) == 0 || (autoScale ?
- mDrawingCache == null : mUnscaledDrawingCache == null)) {
- mCachingFailed = false;
- if (ViewDebug.TRACE_HIERARCHY) {
- ViewDebug.trace(this, ViewDebug.HierarchyTraceType.BUILD_CACHE);
- }
- 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 || isOpaque();
- final boolean use32BitCache = attachInfo != null && attachInfo.mUse32BitDrawingCache;
- if (width <= 0 || height <= 0 ||
- // Projected bitmap size in bytes
- (width * height * (opaque && !use32BitCache ? 2 : 4) >
- ViewConfiguration.get(mContext).getScaledMaximumDrawingCacheSize())) {
- destroyDrawingCache();
- mCachingFailed = true;
- return;
- }
- boolean clear = true;
- Bitmap bitmap = autoScale ? mDrawingCache : mUnscaledDrawingCache;
- if (bitmap == null || bitmap.getWidth() != width || bitmap.getHeight() != height) {
- Bitmap.Config quality;
- if (!opaque) {
- // Never pick ARGB_4444 because it looks awful
- // Keep the DRAWING_CACHE_QUALITY_LOW flag just in case
- switch (mViewFlags & DRAWING_CACHE_QUALITY_MASK) {
- case DRAWING_CACHE_QUALITY_AUTO:
- quality = Bitmap.Config.ARGB_8888;
- break;
- case DRAWING_CACHE_QUALITY_LOW:
- quality = Bitmap.Config.ARGB_8888;
- break;
- case DRAWING_CACHE_QUALITY_HIGH:
- quality = Bitmap.Config.ARGB_8888;
- break;
- default:
- quality = Bitmap.Config.ARGB_8888;
- break;
- }
- } else {
- // Optimization for translucent windows
- // If the window is translucent, use a 32 bits bitmap to benefit from memcpy()
- quality = use32BitCache ? Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565;
- }
- // Try to cleanup memory
- if (bitmap != null) bitmap.recycle();
- try {
- bitmap = Bitmap.createBitmap(width, height, quality);
- bitmap.setDensity(getResources().getDisplayMetrics().densityDpi);
- if (autoScale) {
- mDrawingCache = bitmap;
- } else {
- mUnscaledDrawingCache = bitmap;
- }
- if (opaque && use32BitCache) bitmap.setHasAlpha(false);
- } 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
- if (autoScale) {
- mDrawingCache = null;
- } else {
- mUnscaledDrawingCache = null;
- }
- mCachingFailed = true;
- return;
- }
- clear = drawingCacheBackgroundColor != 0;
- }
- Canvas canvas;
- if (attachInfo != null) {
- canvas = attachInfo.mCanvas;
- if (canvas == null) {
- canvas = new Canvas();
- }
- canvas.setBitmap(bitmap);
- // Temporarily clobber the cached Canvas in case one of our children
- // is also using a drawing cache. Without this, the children would
- // steal the canvas by attaching their own bitmap to it and bad, bad
- // thing would happen (invisible views, corrupted drawings, etc.)
- attachInfo.mCanvas = null;
- } else {
- // This case should hopefully never or seldom happen
- canvas = new Canvas(bitmap);
- }
- if (clear) {
- bitmap.eraseColor(drawingCacheBackgroundColor);
- }
- computeScroll();
- final int restoreCount = canvas.save();
- if (autoScale && scalingRequired) {
- final float scale = attachInfo.mApplicationScale;
- canvas.scale(scale, scale);
- }
- canvas.translate(-mScrollX, -mScrollY);
- mPrivateFlags |= DRAWN;
- if (mAttachInfo == null || !mAttachInfo.mHardwareAccelerated ||
- mLayerType != LAYER_TYPE_NONE) {
- mPrivateFlags |= DRAWING_CACHE_VALID;
- }
- // 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);
- }
- canvas.restoreToCount(restoreCount);
- canvas.setBitmap(null);
- if (attachInfo != null) {
- // Restore the cached Canvas for our siblings
- attachInfo.mCanvas = canvas;
- }
- }
- }
- /**
- * Create a snapshot of the view into a bitmap. We should probably make
- * some form of this public, but should think about the API.
- */
- Bitmap createSnapshot(Bitmap.Config quality, int backgroundColor, boolean skipChildren) {
- int width = mRight - mLeft;
- int height = mBottom - mTop;
- final AttachInfo attachInfo = mAttachInfo;
- final float scale = attachInfo != null ? attachInfo.mApplicationScale : 1.0f;
- width = (int) ((width * scale) + 0.5f);
- height = (int) ((height * scale) + 0.5f);
- Bitmap bitmap = Bitmap.createBitmap(width > 0 ? width : 1, height > 0 ? height : 1, quality);
- if (bitmap == null) {
- throw new OutOfMemoryError();
- }
- Resources resources = getResources();
- if (resources != null) {
- bitmap.setDensity(resources.getDisplayMetrics().densityDpi);
- }
- Canvas canvas;
- if (attachInfo != null) {
- canvas = attachInfo.mCanvas;
- if (canvas == null) {
- canvas = new Canvas();
- }
- canvas.setBitmap(bitmap);
- // Temporarily clobber the cached Canvas in case one of our children
- // is also using a drawing cache. Without this, the children would
- // steal the canvas by attaching their own bitmap to it and bad, bad
- // things would happen (invisible views, corrupted drawings, etc.)
- attachInfo.mCanvas = null;
- } else {
- // This case should hopefully never or seldom happen
- canvas = new Canvas(bitmap);
- }
- if ((backgroundColor & 0xff000000) != 0) {
- bitmap.eraseColor(backgroundColor);
- }
- computeScroll();
- final int restoreCount = canvas.save();
- canvas.scale(scale, scale);
- 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);
- } else {
- draw(canvas);
- }
- mPrivateFlags = flags;
- canvas.restoreToCount(restoreCount);
- canvas.setBitmap(null);
- if (attachInfo != null) {
- // Restore the cached Canvas for our siblings
- attachInfo.mCanvas = canvas;
- }
- return bitmap;
- }
- /**
- * Indicates whether this View is currently in edit mode. A View is usually
- * in edit mode when displayed within a developer tool. For instance, if
- * this View is being drawn by a visual user interface builder, this method
- * should return true.
- *
- * Subclasses should check the return value of this method to provide
- * different behaviors if their normal behavior might interfere with the
- * host environment. For instance: the class spawns a thread in its
- * constructor, the drawing code relies on device-specific features, etc.
- *
- * This method is usually checked in the drawing code of custom widgets.
- *
- * @return True if this View is in edit mode, false otherwise.
- */
- public boolean isInEditMode() {
- return false;
- }
- /**
- * If the View draws content inside its padding and enables fading edges,
- * it needs to support padding offsets. Padding offsets are added to the
- * fading edges to extend the length of the fade so that it covers pixels
- * drawn inside the padding.
- *
- * Subclasses of this class should override this method if they need
- * to draw content inside the padding.
- *
- * @return True if padding offset must be applied, false otherwise.
- *
- * @see #getLeftPaddingOffset()
- * @see #getRightPaddingOffset()
- * @see #getTopPaddingOffset()
- * @see #getBottomPaddingOffset()
- *
- * @since CURRENT
- */
- protected boolean isPaddingOffsetRequired() {
- return false;
- }
- /**
- * Amount by which to extend the left fading region. Called only when
- * {@link #isPaddingOffsetRequired()} returns true.
- *
- * @return The left padding offset in pixels.
- *
- * @see #isPaddingOffsetRequired()
- *
- * @since CURRENT
- */
- protected int getLeftPaddingOffset() {
- return 0;
- }
- /**
- * Amount by which to extend the right fading region. Called only when
- * {@link #isPaddingOffsetRequired()} returns true.
- *
- * @return The right padding offset in pixels.
- *
- * @see #isPaddingOffsetRequired()
- *
- * @since CURRENT
- */
- protected int getRightPaddingOffset() {
- return 0;
- }
- /**
- * Amount by which to extend the top fading region. Called only when
- * {@link #isPaddingOffsetRequired()} returns true.
- *
- * @return The top padding offset in pixels.
- *
- * @see #isPaddingOffsetRequired()
- *
- * @since CURRENT
- */
- protected int getTopPaddingOffset() {
- return 0;
- }
- /**
- * Amount by which to extend the bottom fading region. Called only when
- * {@link #isPaddingOffsetRequired()} returns true.
- *
- * @return The bottom padding offset in pixels.
- *
- * @see #isPaddingOffsetRequired()
- *
- * @since CURRENT
- */
- protected int getBottomPaddingOffset() {
- return 0;
- }
- /**
- * @hide
- * @param offsetRequired
- */
- protected int getFadeTop(boolean offsetRequired) {
- int top = mPaddingTop;
- if (offsetRequired) top += getTopPaddingOffset();
- return top;
- }
-
- /**
- * @hide
- * @param offsetRequired
- */
- protected int getFadeHeight(boolean offsetRequired) {
- int padding = mPaddingTop;
- if (offsetRequired) padding += getTopPaddingOffset();
- return mBottom - mTop - mPaddingBottom - padding;
- }
-
- /**
- * 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.
- *
- * @return True if the view is attached to a window and the window is
- * hardware accelerated; false in any other case.
- */
- public boolean isHardwareAccelerated() {
- return mAttachInfo != null && mAttachInfo.mHardwareAccelerated;
- }
- /**
- * Utility function, called by draw(canvas, parent, drawingTime) to handle the less common
- * case of an active Animation being run on the view.
- */
- private boolean drawAnimation(ViewGroup parent, long drawingTime,
- Animation a, boolean scalingRequired) {
- Transformation invalidationTransform;
- final int flags = parent.mGroupFlags;
- final boolean initialized = a.isInitialized();
- if (!initialized) {
- a.initialize(mRight - mLeft, mBottom - mTop, getWidth(), getHeight());
- a.initializeInvalidateRegion(0, 0, mRight - mLeft, mBottom - mTop);
- onAnimationStart();
- }
- boolean more = a.getTransformation(drawingTime, parent.mChildTransformation, 1f);
- if (scalingRequired && mAttachInfo.mApplicationScale != 1f) {
- if (parent.mInvalidationTransformation == null) {
- parent.mInvalidationTransformation = new Transformation();
- }
- invalidationTransform = parent.mInvalidationTransformation;
- a.getTransformation(drawingTime, invalidationTransform, 1f);
- } else {
- invalidationTransform = parent.mChildTransformation;
- }
- if (more) {
- if (!a.willChangeBounds()) {
- if ((flags & (parent.FLAG_OPTIMIZE_INVALIDATE | parent.FLAG_ANIMATION_DONE)) ==
- parent.FLAG_OPTIMIZE_INVALIDATE) {
- parent.mGroupFlags |= parent.FLAG_INVALIDATE_REQUIRED;
- } else if ((flags & parent.FLAG_INVALIDATE_REQUIRED) == 0) {
- // The child need to draw an animation, potentially offscreen, so
- // make sure we do not cancel invalidate requests
- parent.mPrivateFlags |= DRAW_ANIMATION;
- parent.invalidate(mLeft, mTop, mRight, mBottom);
- }
- } else {
- if (parent.mInvalidateRegion == null) {
- parent.mInvalidateRegion = new RectF();
- }
- final RectF region = parent.mInvalidateRegion;
- a.getInvalidateRegion(0, 0, mRight - mLeft, mBottom - mTop, region,
- invalidationTransform);
- // The child need to draw an animation, potentially offscreen, so
- // make sure we do not cancel invalidate requests
- parent.mPrivateFlags |= DRAW_ANIMATION;
- final int left = mLeft + (int) region.left;
- final int top = mTop + (int) region.top;
- parent.invalidate(left, top, left + (int) (region.width() + .5f),
- top + (int) (region.height() + .5f));
- }
- }
- return more;
- }
- /**
- * This method is called by ViewGroup.drawChild() to have each child view draw itself.
- * This draw() method is an implementation detail and is not intended to be overridden or
- * to be called from anywhere else other than ViewGroup.drawChild().
- */
- boolean draw(Canvas canvas, ViewGroup parent, long drawingTime) {
- boolean more = false;
- final boolean childHasIdentityMatrix = hasIdentityMatrix();
- final int flags = parent.mGroupFlags;
- if ((flags & parent.FLAG_CLEAR_TRANSFORMATION) == parent.FLAG_CLEAR_TRANSFORMATION) {
- parent.mChildTransformation.clear();
- parent.mGroupFlags &= ~parent.FLAG_CLEAR_TRANSFORMATION;
- }
- Transformation transformToApply = null;
- boolean concatMatrix = false;
- boolean scalingRequired = false;
- boolean caching;
- int layerType = parent.mDrawLayers ? getLayerType() : LAYER_TYPE_NONE;
- final boolean hardwareAccelerated = canvas.isHardwareAccelerated();
- if ((flags & parent.FLAG_CHILDREN_DRAWN_WITH_CACHE) == parent.FLAG_CHILDREN_DRAWN_WITH_CACHE ||
- (flags & parent.FLAG_ALWAYS_DRAWN_WITH_CACHE) == parent.FLAG_ALWAYS_DRAWN_WITH_CACHE) {
- caching = true;
- if (mAttachInfo != null) scalingRequired = mAttachInfo.mScalingRequired;
- } else {
- caching = (layerType != LAYER_TYPE_NONE) || hardwareAccelerated;
- }
- final Animation a = getAnimation();
- if (a != null) {
- more = drawAnimation(parent, drawingTime, a, scalingRequired);
- concatMatrix = a.willChangeTransformationMatrix();
- transformToApply = parent.mChildTransformation;
- } else if ((flags & parent.FLAG_SUPPORT_STATIC_TRANSFORMATIONS) ==
- parent.FLAG_SUPPORT_STATIC_TRANSFORMATIONS) {
- final boolean hasTransform =
- parent.getChildStaticTransformation(this, parent.mChildTransformation);
- if (hasTransform) {
- final int transformType = parent.mChildTransformation.getTransformationType();
- transformToApply = transformType != Transformation.TYPE_IDENTITY ?
- parent.mChildTransformation : null;
- concatMatrix = (transformType & Transformation.TYPE_MATRIX) != 0;
- }
- }
- concatMatrix |= !childHasIdentityMatrix;
- // Sets the flag as early as possible to allow draw() implementations
- // to call invalidate() successfully when doing animations
- mPrivateFlags |= DRAWN;
- if (!concatMatrix && canvas.quickReject(mLeft, mTop, mRight, mBottom, Canvas.EdgeType.BW) &&
- (mPrivateFlags & DRAW_ANIMATION) == 0) {
- return more;
- }
- if (hardwareAccelerated) {
- // Clear INVALIDATED flag to allow invalidation to occur during rendering, but
- // retain the flag's value temporarily in the mRecreateDisplayList flag
- mRecreateDisplayList = (mPrivateFlags & INVALIDATED) == INVALIDATED;
- mPrivateFlags &= ~INVALIDATED;
- }
- computeScroll();
- final int sx = mScrollX;
- final int sy = mScrollY;
- DisplayList displayList = null;
- Bitmap cache = null;
- boolean hasDisplayList = false;
- if (caching) {
- if (!hardwareAccelerated) {
- if (layerType != LAYER_TYPE_NONE) {
- layerType = LAYER_TYPE_SOFTWARE;
- buildDrawingCache(true);
- }
- cache = getDrawingCache(true);
- } else {
- switch (layerType) {
- case LAYER_TYPE_SOFTWARE:
- buildDrawingCache(true);
- cache = getDrawingCache(true);
- break;
- case LAYER_TYPE_NONE:
- // Delay getting the display list until animation-driven alpha values are
- // set up and possibly passed on to the view
- hasDisplayList = canHaveDisplayList();
- break;
- }
- }
- }
- final boolean hasNoCache = cache == null || hasDisplayList;
- final boolean offsetForScroll = cache == null && !hasDisplayList &&
- layerType != LAYER_TYPE_HARDWARE;
- final int restoreTo = canvas.save();
- if (offsetForScroll) {
- canvas.translate(mLeft - sx, mTop - sy);
- } else {
- canvas.translate(mLeft, mTop);
- if (scalingRequired) {
- // mAttachInfo cannot be null, otherwise scalingRequired == false
- final float scale = 1.0f / mAttachInfo.mApplicationScale;
- canvas.scale(scale, scale);
- }
- }
- float alpha = getAlpha();
- if (transformToApply != null || alpha < 1.0f || !hasIdentityMatrix()) {
- if (transformToApply != null || !childHasIdentityMatrix) {
- int transX = 0;
- int transY = 0;
- if (offsetForScroll) {
- transX = -sx;
- transY = -sy;
- }
- if (transformToApply != null) {
- if (concatMatrix) {
- // Undo the scroll translation, apply the transformation matrix,
- // then redo the scroll translate to get the correct result.
- canvas.translate(-transX, -transY);
- canvas.concat(transformToApply.getMatrix());
- canvas.translate(transX, transY);
- parent.mGroupFlags |= parent.FLAG_CLEAR_TRANSFORMATION;
- }
- float transformAlpha = transformToApply.getAlpha();
- if (transformAlpha < 1.0f) {
- alpha *= transformToApply.getAlpha();
- parent.mGroupFlags |= parent.FLAG_CLEAR_TRANSFORMATION;
- }
- }
- if (!childHasIdentityMatrix) {
- canvas.translate(-transX, -transY);
- canvas.concat(getMatrix());
- canvas.translate(transX, transY);
- }
- }
- if (alpha < 1.0f) {
- parent.mGroupFlags |= parent.FLAG_CLEAR_TRANSFORMATION;
- if (hasNoCache) {
- final int multipliedAlpha = (int) (255 * alpha);
- if (!onSetAlpha(multipliedAlpha)) {
- int layerFlags = Canvas.HAS_ALPHA_LAYER_SAVE_FLAG;
- if ((flags & parent.FLAG_CLIP_CHILDREN) == parent.FLAG_CLIP_CHILDREN ||
- layerType != LAYER_TYPE_NONE) {
- layerFlags |= Canvas.CLIP_TO_LAYER_SAVE_FLAG;
- }
- if (layerType == LAYER_TYPE_NONE) {
- final int scrollX = hasDisplayList ? 0 : sx;
- final int scrollY = hasDisplayList ? 0 : sy;
- canvas.saveLayerAlpha(scrollX, scrollY, scrollX + mRight - mLeft,
- scrollY + mBottom - mTop, multipliedAlpha, layerFlags);
- }
- } else {
- // Alpha is handled by the child directly, clobber the layer's alpha
- mPrivateFlags |= ALPHA_SET;
- }
- }
- }
- } else if ((mPrivateFlags & ALPHA_SET) == ALPHA_SET) {
- onSetAlpha(255);
- mPrivateFlags &= ~ALPHA_SET;
- }
- if ((flags & parent.FLAG_CLIP_CHILDREN) == parent.FLAG_CLIP_CHILDREN) {
- if (offsetForScroll) {
- canvas.clipRect(sx, sy, sx + (mRight - mLeft), sy + (mBottom - mTop));
- } else {
- if (!scalingRequired || cache == null) {
- canvas.clipRect(0, 0, mRight - mLeft, mBottom - mTop);
- } else {
- canvas.clipRect(0, 0, cache.getWidth(), cache.getHeight());
- }
- }
- }
- if (hasDisplayList) {
- displayList = getDisplayList();
- if (!displayList.isValid()) {
- // Uncommon, but possible. If a view is removed from the hierarchy during the call
- // to getDisplayList(), the display list will be marked invalid and we should not
- // try to use it again.
- displayList = null;
- hasDisplayList = false;
- }
- }
- if (hasNoCache) {
- boolean layerRendered = false;
- if (layerType == LAYER_TYPE_HARDWARE) {
- final HardwareLayer layer = getHardwareLayer();
- if (layer != null && layer.isValid()) {
- mLayerPaint.setAlpha((int) (alpha * 255));
- ((HardwareCanvas) canvas).drawHardwareLayer(layer, 0, 0, mLayerPaint);
- layerRendered = true;
- } else {
- final int scrollX = hasDisplayList ? 0 : sx;
- final int scrollY = hasDisplayList ? 0 : sy;
- canvas.saveLayer(scrollX, scrollY,
- scrollX + mRight - mLeft, scrollY + mBottom - mTop, mLayerPaint,
- Canvas.HAS_ALPHA_LAYER_SAVE_FLAG | Canvas.CLIP_TO_LAYER_SAVE_FLAG);
- }
- }
- if (!layerRendered) {
- if (!hasDisplayList) {
- // Fast path for layouts with no backgrounds
- if ((mPrivateFlags & SKIP_DRAW) == SKIP_DRAW) {
- if (ViewDebug.TRACE_HIERARCHY) {
- ViewDebug.trace(parent, ViewDebug.HierarchyTraceType.DRAW);
- }
- mPrivateFlags &= ~DIRTY_MASK;
- dispatchDraw(canvas);
- } else {
- draw(canvas);
- }
- } else {
- mPrivateFlags &= ~DIRTY_MASK;
- ((HardwareCanvas) canvas).drawDisplayList(displayList,
- mRight - mLeft, mBottom - mTop, null);
- }
- }
- } else if (cache != null) {
- mPrivateFlags &= ~DIRTY_MASK;
- Paint cachePaint;
- if (layerType == LAYER_TYPE_NONE) {
- cachePaint = parent.mCachePaint;
- if (cachePaint == null) {
- cachePaint = new Paint();
- cachePaint.setDither(false);
- parent.mCachePaint = cachePaint;
- }
- if (alpha < 1.0f) {
- cachePaint.setAlpha((int) (alpha * 255));
- parent.mGroupFlags |= parent.FLAG_ALPHA_LOWER_THAN_ONE;
- } else if ((flags & parent.FLAG_ALPHA_LOWER_THAN_ONE) ==
- parent.FLAG_ALPHA_LOWER_THAN_ONE) {
- cachePaint.setAlpha(255);
- parent.mGroupFlags &= ~parent.FLAG_ALPHA_LOWER_THAN_ONE;
- }
- } else {
- cachePaint = mLayerPaint;
- cachePaint.setAlpha((int) (alpha * 255));
- }
- canvas.drawBitmap(cache, 0.0f, 0.0f, cachePaint);
- }
- canvas.restoreToCount(restoreTo);
- if (a != null && !more) {
- if (!hardwareAccelerated && !a.getFillAfter()) {
- onSetAlpha(255);
- }
- parent.finishAnimatingView(this, a);
- }
- if (more && hardwareAccelerated) {
- // invalidation is the trigger to recreate display lists, so if we're using
- // display lists to render, force an invalidate to allow the animation to
- // continue drawing another frame
- parent.invalidate(true);
- if (a.hasAlpha() && (mPrivateFlags & ALPHA_SET) == ALPHA_SET) {
- // alpha animations should cause the child to recreate its display list
- invalidate(true);
- }
- }
- mRecreateDisplayList = false;
- return more;
- }
- /**
- * Manually render this view (and all of its children) to the given Canvas.
- * The view must have already done a full layout before this function is
- * called. When implementing a view, implement
- * {@link #onDraw(android.graphics.Canvas)} instead of overriding this method.
- * If you do need to override this method, call the superclass version.
- *
- * @param canvas The Canvas to which the View is rendered.
- */
- public void draw(Canvas canvas) {
- if (ViewDebug.TRACE_HIERARCHY) {
- ViewDebug.trace(this, ViewDebug.HierarchyTraceType.DRAW);
- }
- 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
- * in the appropriate order:
- *
- * 1. Draw the background
- * 2. If necessary, save the canvas' layers to prepare for fading
- * 3. Draw view's content
- * 4. Draw children
- * 5. If necessary, draw the fading edges and restore layers
- * 6. Draw decorations (scrollbars for instance)
- */
- // Step 1, draw the background, if needed
- int saveCount;
- if (!dirtyOpaque) {
- final Drawable background = mBGDrawable;
- if (background != null) {
- final int scrollX = mScrollX;
- final int scrollY = mScrollY;
- if (mBackgroundSizeChanged) {
- background.setBounds(0, 0, mRight - mLeft, mBottom - mTop);
- mBackgroundSizeChanged = false;
- }
- if ((scrollX | scrollY) == 0) {
- background.draw(canvas);
- } else {
- canvas.translate(scrollX, scrollY);
- background.draw(canvas);
- canvas.translate(-scrollX, -scrollY);
- }
- }
- }
- // skip step 2 & 5 if possible (common case)
- final int viewFlags = mViewFlags;
- boolean horizontalEdges = (viewFlags & FADING_EDGE_HORIZONTAL) != 0;
- boolean verticalEdges = (viewFlags & FADING_EDGE_VERTICAL) != 0;
- if (!verticalEdges && !horizontalEdges) {
- // Step 3, draw the content
- if (!dirtyOpaque) onDraw(canvas);
- // Step 4, draw the children
- dispatchDraw(canvas);
- // Step 6, draw decorations (scrollbars)
- onDrawScrollBars(canvas);
- // we're done...
- return;
- }
- /*
- * Here we do the full fledged routine...
- * (this is an uncommon case where speed matters less,
- * this is why we repeat some of the tests that have been
- * done above)
- */
- boolean drawTop = false;
- boolean drawBottom = false;
- boolean drawLeft = false;
- boolean drawRight = false;
- float topFadeStrength = 0.0f;
- float bottomFadeStrength = 0.0f;
- float leftFadeStrength = 0.0f;
- float rightFadeStrength = 0.0f;
- // Step 2, save the canvas' layers
- int paddingLeft = mPaddingLeft;
- final boolean offsetRequired = isPaddingOffsetRequired();
- if (offsetRequired) {
- paddingLeft += getLeftPaddingOffset();
- }
- int left = mScrollX + paddingLeft;
- int right = left + mRight - mLeft - mPaddingRight - paddingLeft;
- int top = mScrollY + getFadeTop(offsetRequired);
- int bottom = top + getFadeHeight(offsetRequired);
- if (offsetRequired) {
- right += getRightPaddingOffset();
- bottom += getBottomPaddingOffset();
- }
- final ScrollabilityCache scrollabilityCache = mScrollCache;
- final float fadeHeight = scrollabilityCache.fadingEdgeLength;
- int length = (int) fadeHeight;
- // clip the fade length if top and bottom fades overlap
- // overlapping fades produce odd-looking artifacts
- if (verticalEdges && (top + length > bottom - length)) {
- length = (bottom - top) / 2;
- }
- // also clip horizontal fades if necessary
- if (horizontalEdges && (left + length > right - length)) {
- length = (right - left) / 2;
- }
- if (verticalEdges) {
- topFadeStrength = Math.max(0.0f, Math.min(1.0f, getTopFadingEdgeStrength()));
- drawTop = topFadeStrength * fadeHeight > 1.0f;
- bottomFadeStrength = Math.max(0.0f, Math.min(1.0f, getBottomFadingEdgeStrength()));
- drawBottom = bottomFadeStrength * fadeHeight > 1.0f;
- }
- if (horizontalEdges) {
- leftFadeStrength = Math.max(0.0f, Math.min(1.0f, getLeftFadingEdgeStrength()));
- drawLeft = leftFadeStrength * fadeHeight > 1.0f;
- rightFadeStrength = Math.max(0.0f, Math.min(1.0f, getRightFadingEdgeStrength()));
- drawRight = rightFadeStrength * fadeHeight > 1.0f;
- }
- saveCount = canvas.getSaveCount();
- int solidColor = getSolidColor();
- if (solidColor == 0) {
- final int flags = Canvas.HAS_ALPHA_LAYER_SAVE_FLAG;
- if (drawTop) {
- canvas.saveLayer(left, top, right, top + length, null, flags);
- }
- if (drawBottom) {
- canvas.saveLayer(left, bottom - length, right, bottom, null, flags);
- }
- if (drawLeft) {
- canvas.saveLayer(left, top, left + length, bottom, null, flags);
- }
- if (drawRight) {
- canvas.saveLayer(right - length, top, right, bottom, null, flags);
- }
- } else {
- scrollabilityCache.setFadeColor(solidColor);
- }
- // Step 3, draw the content
- if (!dirtyOpaque) onDraw(canvas);
- // Step 4, draw the children
- dispatchDraw(canvas);
- // Step 5, draw the fade effect and restore layers
- final Paint p = scrollabilityCache.paint;
- final Matrix matrix = scrollabilityCache.matrix;
- final Shader fade = scrollabilityCache.shader;
- if (drawTop) {
- matrix.setScale(1, fadeHeight * topFadeStrength);
- matrix.postTranslate(left, top);
- fade.setLocalMatrix(matrix);
- canvas.drawRect(left, top, right, top + length, p);
- }
- if (drawBottom) {
- matrix.setScale(1, fadeHeight * bottomFadeStrength);
- matrix.postRotate(180);
- matrix.postTranslate(left, bottom);
- fade.setLocalMatrix(matrix);
- canvas.drawRect(left, bottom - length, right, bottom, p);
- }
- if (drawLeft) {
- matrix.setScale(1, fadeHeight * leftFadeStrength);
- matrix.postRotate(-90);
- matrix.postTranslate(left, top);
- fade.setLocalMatrix(matrix);
- canvas.drawRect(left, top, left + length, bottom, p);
- }
- if (drawRight) {
- matrix.setScale(1, fadeHeight * rightFadeStrength);
- matrix.postRotate(90);
- matrix.postTranslate(right, top);
- fade.setLocalMatrix(matrix);
- canvas.drawRect(right - length, top, right, bottom, p);
- }
- canvas.restoreToCount(saveCount);
- // Step 6, draw decorations (scrollbars)
- onDrawScrollBars(canvas);
- }
- /**
- * Override this if your view is known to always be drawn on top of a solid color background,
- * and needs to draw fading edges. Returning a non-zero color enables the view system to
- * optimize the drawing of the fading edges. If you do return a non-zero color, the alpha
- * should be set to 0xFF.
- *
- * @see #setVerticalFadingEdgeEnabled(boolean)
- * @see #setHorizontalFadingEdgeEnabled(boolean)
- *
- * @return The known solid color background for this view, or 0 if the color may vary
- */
- @ViewDebug.ExportedProperty(category = "drawing")
- public int getSolidColor() {
- return 0;
- }
- /**
- * Build a human readable string representation of the specified view flags.
- *
- * @param flags the view flags to convert to a string
- * @return a String representing the supplied flags
- */
- private static String printFlags(int flags) {
- String output = "";
- int numFlags = 0;
- if ((flags & FOCUSABLE_MASK) == FOCUSABLE) {
- output += "TAKES_FOCUS";
- numFlags++;
- }
- switch (flags & VISIBILITY_MASK) {
- case INVISIBLE:
- if (numFlags > 0) {
- output += " ";
- }
- output += "INVISIBLE";
- // USELESS HERE numFlags++;
- break;
- case GONE:
- if (numFlags > 0) {
- output += " ";
- }
- output += "GONE";
- // USELESS HERE numFlags++;
- break;
- default:
- break;
- }
- return output;
- }
- /**
- * Build a human readable string representation of the specified private
- * view flags.
- *
- * @param privateFlags the private view flags to convert to a string
- * @return a String representing the supplied flags
- */
- private static String printPrivateFlags(int privateFlags) {
- String output = "";
- int numFlags = 0;
- if ((privateFlags & WANTS_FOCUS) == WANTS_FOCUS) {
- output += "WANTS_FOCUS";
- numFlags++;
- }
- if ((privateFlags & FOCUSED) == FOCUSED) {
- if (numFlags > 0) {
- output += " ";
- }
- output += "FOCUSED";
- numFlags++;
- }
- if ((privateFlags & SELECTED) == SELECTED) {
- if (numFlags > 0) {
- output += " ";
- }
- output += "SELECTED";
- numFlags++;
- }
- if ((privateFlags & IS_ROOT_NAMESPACE) == IS_ROOT_NAMESPACE) {
- if (numFlags > 0) {
- output += " ";
- }
- output += "IS_ROOT_NAMESPACE";
- numFlags++;
- }
- if ((privateFlags & HAS_BOUNDS) == HAS_BOUNDS) {
- if (numFlags > 0) {
- output += " ";
- }
- output += "HAS_BOUNDS";
- numFlags++;
- }
- if ((privateFlags & DRAWN) == DRAWN) {
- if (numFlags > 0) {
- output += " ";
- }
- output += "DRAWN";
- // USELESS HERE numFlags++;
- }
- return output;
- }
- /**
- * Indicates whether or not this view's layout will be requested during
- * the next hierarchy layout pass.
- *
- * @return true if the layout will be forced during next layout pass
- */
- public boolean isLayoutRequested() {
- return (mPrivateFlags & FORCE_LAYOUT) == FORCE_LAYOUT;
- }
- /**
- * Assign a size and position to a view and all of its
- * descendants
- *
- * 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.
- *
- * @param l Left position, relative to parent
- * @param t Top position, relative to parent
- * @param r Right position, relative to parent
- * @param b Bottom position, relative to parent
- */
- @SuppressWarnings({"unchecked"})
- public void layout(int l, int t, int r, int b) {
- int oldL = mLeft;
- int oldT = mTop;
- int oldB = mBottom;
- int oldR = mRight;
- boolean changed = setFrame(l, t, r, b);
- if (changed || (mPrivateFlags & LAYOUT_REQUIRED) == LAYOUT_REQUIRED) {
- if (ViewDebug.TRACE_HIERARCHY) {
- ViewDebug.trace(this, ViewDebug.HierarchyTraceType.ON_LAYOUT);
- }
- onLayout(changed, l, t, r, b);
- mPrivateFlags &= ~LAYOUT_REQUIRED;
- ListenerInfo li = mListenerInfo;
- if (li != null && li.mOnLayoutChangeListeners != null) {
- ArrayList listenersCopy =
- (ArrayList)li.mOnLayoutChangeListeners.clone();
- int numListeners = listenersCopy.size();
- for (int i = 0; i < numListeners; ++i) {
- listenersCopy.get(i).onLayoutChange(this, l, t, r, b, oldL, oldT, oldR, oldB);
- }
- }
- }
- mPrivateFlags &= ~FORCE_LAYOUT;
- }
- /**
- * Called from layout when this view should
- * assign a size and position to each of its children.
- *
- * Derived classes with children should override
- * this method and call layout on each of
- * their children.
- * @param changed This is a new size or position for this view
- * @param left Left position, relative to parent
- * @param top Top position, relative to parent
- * @param right Right position, relative to parent
- * @param bottom Bottom position, relative to parent
- */
- protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
- }
- /**
- * Assign a size and position to this view.
- *
- * This is called from layout.
- *
- * @param left Left position, relative to parent
- * @param top Top position, relative to parent
- * @param right Right position, relative to parent
- * @param bottom Bottom position, relative to parent
- * @return true if the new size and position are different than the
- * previous ones
- * {@hide}
- */
- protected boolean setFrame(int left, int top, int right, int bottom) {
- boolean changed = false;
- if (DBG) {
- Log.d("View", this + " View.setFrame(" + left + "," + top + ","
- + right + "," + bottom + ")");
- }
- if (mLeft != left || mRight != right || mTop != top || mBottom != bottom) {
- changed = true;
- // Remember our drawn bit
- int drawn = mPrivateFlags & DRAWN;
- int oldWidth = mRight - mLeft;
- int oldHeight = mBottom - mTop;
- int newWidth = right - left;
- int newHeight = bottom - top;
- boolean sizeChanged = (newWidth != oldWidth) || (newHeight != oldHeight);
- // Invalidate our old position
- invalidate(sizeChanged);
- mLeft = left;
- mTop = top;
- mRight = right;
- mBottom = bottom;
- mPrivateFlags |= HAS_BOUNDS;
- if (sizeChanged) {
- if ((mPrivateFlags & PIVOT_EXPLICITLY_SET) == 0) {
- // A change in dimension means an auto-centered pivot point changes, too
- if (mTransformationInfo != null) {
- mTransformationInfo.mMatrixDirty = true;
- }
- }
- onSizeChanged(newWidth, newHeight, oldWidth, oldHeight);
- }
- if ((mViewFlags & VISIBILITY_MASK) == VISIBLE) {
- // If we are visible, force the DRAWN bit to on so that
- // this invalidate will go through (at least to our parent).
- // This is because someone may have invalidated this view
- // before this call to setFrame came in, thereby clearing
- // the DRAWN bit.
- mPrivateFlags |= DRAWN;
- invalidate(sizeChanged);
- // parent display list may need to be recreated based on a change in the bounds
- // of any child
- invalidateParentCaches();
- }
- // Reset drawn bit to original value (invalidate turns it off)
- mPrivateFlags |= drawn;
- mBackgroundSizeChanged = true;
- }
- return changed;
- }
- /**
- * Finalize inflating a view from XML. This is called as the last phase
- * of inflation, after all child views have been added.
- *
- * 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) {
- if (mAttachInfo != null) {
- mAttachInfo.mHandler.postAtTime(what, who, when);
- } else {
- ViewRootImpl.getRunQueue().postDelayed(what, when - SystemClock.uptimeMillis());
- }
- }
- }
- /**
- * 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) {
- if (mAttachInfo != null) {
- mAttachInfo.mHandler.removeCallbacks(what, who);
- } else {
- ViewRootImpl.getRunQueue().removeCallbacks(what);
- }
- }
- }
- /**
- * 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);
- }
- }
- /**
- * Return the layout direction of a given Drawable.
- *
- * @param who the Drawable to query
- *
- * @hide
- */
- public int getResolvedLayoutDirection(Drawable who) {
- return (who == mBGDrawable) ? getResolvedLayoutDirection() : LAYOUT_DIRECTION_DEFAULT;
- }
- /**
- * 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(android.graphics.drawable.Drawable)
- * @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(int[])
- */
- 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(int[])
- * @see #drawableStateChanged()
- * @see #onCreateDrawableState(int)
- */
- 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(int[], int[])
- */
- 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(int)}.
- *
- * @param baseState The base state values returned by
- * {@link #onCreateDrawableState(int)}, 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(int)
- */
- 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) {
- if (d == mBGDrawable) {
- return;
- }
- 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)) {
- switch (d.getResolvedLayoutDirectionSelf()) {
- case LAYOUT_DIRECTION_RTL:
- setPadding(padding.right, padding.top, padding.left, padding.bottom);
- break;
- case LAYOUT_DIRECTION_LTR:
- default:
- 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;
- mUserPaddingRelative = 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) {
- final int offset = (viewFlags & SCROLLBARS_INSET_MASK) == 0
- ? 0 : getVerticalScrollbarWidth();
- switch (mVerticalScrollbarPosition) {
- case SCROLLBAR_POSITION_DEFAULT:
- if (getResolvedLayoutDirection() == LAYOUT_DIRECTION_RTL) {
- left += offset;
- } else {
- right += offset;
- }
- break;
- 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();
- }
- }
- /**
- * Sets the relative 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 #getPaddingStart}, {@link #getPaddingTop},
- * {@link #getPaddingEnd} 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_paddingStart
- * @attr ref android.R.styleable#View_paddingEnd
- * @attr ref android.R.styleable#View_paddingTop
- * @param start the start padding in pixels
- * @param top the top padding in pixels
- * @param end the end padding in pixels
- * @param bottom the bottom padding in pixels
- *
- * @hide
- */
- public void setPaddingRelative(int start, int top, int end, int bottom) {
- mUserPaddingRelative = true;
- mUserPaddingStart = start;
- mUserPaddingEnd = end;
- switch(getResolvedLayoutDirection()) {
- case LAYOUT_DIRECTION_RTL:
- setPadding(end, top, start, bottom);
- break;
- case LAYOUT_DIRECTION_LTR:
- default:
- setPadding(start, top, end, bottom);
- }
- }
- /**
- * 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 start 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 start padding in pixels
- *
- * @hide
- */
- public int getPaddingStart() {
- return (getResolvedLayoutDirection() == LAYOUT_DIRECTION_RTL) ?
- mPaddingRight : 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;
- }
- /**
- * Returns the end 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 end padding in pixels
- *
- * @hide
- */
- public int getPaddingEnd() {
- return (getResolvedLayoutDirection() == LAYOUT_DIRECTION_RTL) ?
- mPaddingLeft : mPaddingRight;
- }
- /**
- * Return if the padding as been set thru relative values
- * {@link #setPaddingRelative(int, int, int, int)} or thru
- * @attr ref android.R.styleable#View_paddingStart or
- * @attr ref android.R.styleable#View_paddingEnd
- *
- * @return true if the padding is relative or false if it is not.
- *
- * @hide
- */
- public boolean isPaddingRelative() {
- return mUserPaddingRelative;
- }
- /**
- * 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.
- *
- * @return the topmost view containing this view
- */
- public View getRootView() {
- if (mAttachInfo != null) {
- final View v = mAttachInfo.mRootView;
- if (v != null) {
- return v;
- }
- }
- View parent = this;
- while (parent.mParent != null && parent.mParent instanceof View) {
- parent = (View) parent.mParent;
- }
- return parent;
- }
- /**
- * 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.
- *
- * @param location an array of two integers in which to hold the coordinates
- */
- public void getLocationOnScreen(int[] location) {
- getLocationInWindow(location);
- final AttachInfo info = mAttachInfo;
- if (info != null) {
- location[0] += info.mWindowLeft;
- location[1] += info.mWindowTop;
- }
- }
- /**
- * 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.
- *
- * @param location an array of two integers in which to hold the coordinates
- */
- public void getLocationInWindow(int[] location) {
- if (location == null || location.length < 2) {
- throw new IllegalArgumentException("location must be an array of two integers");
- }
- if (mAttachInfo == null) {
- // When the view is not attached to a window, this method does not make sense
- location[0] = location[1] = 0;
- return;
- }
- float[] position = mAttachInfo.mTmpTransformLocation;
- position[0] = position[1] = 0.0f;
- if (!hasIdentityMatrix()) {
- getMatrix().mapPoints(position);
- }
- position[0] += mLeft;
- position[1] += mTop;
- ViewParent viewParent = mParent;
- while (viewParent instanceof View) {
- final View view = (View) viewParent;
- position[0] -= view.mScrollX;
- position[1] -= view.mScrollY;
- if (!view.hasIdentityMatrix()) {
- view.getMatrix().mapPoints(position);
- }
- position[0] += view.mLeft;
- position[1] += view.mTop;
- viewParent = view.mParent;
- }
- if (viewParent instanceof ViewRootImpl) {
- // *cough*
- final ViewRootImpl vr = (ViewRootImpl) viewParent;
- position[1] -= vr.mCurScrollY;
- }
- location[0] = (int) (position[0] + 0.5f);
- location[1] = (int) (position[1] + 0.5f);
- }
- /**
- * {@hide}
- * @param id the id of the view to be found
- * @return the view of the specified id, null if cannot be found
- */
- protected View findViewTraversal(int id) {
- if (id == mID) {
- return this;
- }
- return null;
- }
- /**
- * {@hide}
- * @param tag the tag of the view to be found
- * @return the view of specified tag, null if cannot be found
- */
- protected View findViewWithTagTraversal(Object tag) {
- if (tag != null && tag.equals(mTag)) {
- return this;
- }
- return null;
- }
- /**
- * {@hide}
- * @param predicate The predicate to evaluate.
- * @param childToSkip If not null, ignores this child during the recursive traversal.
- * @return The first view that matches the predicate or null.
- */
- protected View findViewByPredicateTraversal(Predicate predicate, View childToSkip) {
- if (predicate.apply(this)) {
- return this;
- }
- return null;
- }
- /**
- * Look for a child view with the given id. If this view has the given
- * id, return this view.
- *
- * @param id The id to search for.
- * @return The view that has the given id in the hierarchy or null
- */
- public final View findViewById(int id) {
- if (id < 0) {
- return null;
- }
- return findViewTraversal(id);
- }
- /**
- * Finds a view by its unuque and stable accessibility id.
- *
- * @param accessibilityId The searched accessibility id.
- * @return The found view.
- */
- final View findViewByAccessibilityId(int accessibilityId) {
- if (accessibilityId < 0) {
- return null;
- }
- return findViewByAccessibilityIdTraversal(accessibilityId);
- }
- /**
- * Performs the traversal to find a view by its unuque and stable accessibility id.
- *
- * Note: This method does not stop at the root namespace
- * boundary since the user can touch the screen at an arbitrary location
- * potentially crossing the root namespace bounday which will send an
- * accessibility event to accessibility services and they should be able
- * to obtain the event source. Also accessibility ids are guaranteed to be
- * unique in the window.
- *
- * @param accessibilityId The accessibility id.
- * @return The found view.
- */
- View findViewByAccessibilityIdTraversal(int accessibilityId) {
- if (getAccessibilityViewId() == accessibilityId) {
- return this;
- }
- return null;
- }
- /**
- * Look for a child view with the given tag. If this view has the given
- * tag, return this view.
- *
- * @param tag The tag to search for, using "tag.equals(getTag())".
- * @return The View that has the given tag in the hierarchy or null
- */
- public final View findViewWithTag(Object tag) {
- if (tag == null) {
- return null;
- }
- return findViewWithTagTraversal(tag);
- }
- /**
- * {@hide}
- * Look for a child view that matches the specified predicate.
- * If this view matches the predicate, return this view.
- *
- * @param predicate The predicate to evaluate.
- * @return The first view that matches the predicate or null.
- */
- public final View findViewByPredicate(Predicate predicate) {
- return findViewByPredicateTraversal(predicate, null);
- }
- /**
- * {@hide}
- * Look for a child view that matches the specified predicate,
- * starting with the specified view and its descendents and then
- * recusively searching the ancestors and siblings of that view
- * until this view is reached.
- *
- * This method is useful in cases where the predicate does not match
- * a single unique view (perhaps multiple views use the same id)
- * and we are trying to find the view that is "closest" in scope to the
- * starting view.
- *
- * @param start The view to start from.
- * @param predicate The predicate to evaluate.
- * @return The first view that matches the predicate or null.
- */
- public final View findViewByPredicateInsideOut(View start, Predicate predicate) {
- View childToSkip = null;
- for (;;) {
- View view = start.findViewByPredicateTraversal(predicate, childToSkip);
- if (view != null || start == this) {
- return view;
- }
- ViewParent parent = start.getParent();
- if (parent == null || !(parent instanceof View)) {
- return null;
- }
- childToSkip = start;
- start = (View) parent;
- }
- }
- /**
- * Sets the identifier for this view. The identifier does not have to be
- * unique in this view's hierarchy. The identifier should be a positive
- * number.
- *
- * @see #NO_ID
- * @see #getId()
- * @see #findViewById(int)
- *
- * @param id a number used to identify the view
- *
- * @attr ref android.R.styleable#View_id
- */
- public void setId(int id) {
- mID = id;
- }
- /**
- * {@hide}
- *
- * @param isRoot true if the view belongs to the root namespace, false
- * otherwise
- */
- public void setIsRootNamespace(boolean isRoot) {
- if (isRoot) {
- mPrivateFlags |= IS_ROOT_NAMESPACE;
- } else {
- mPrivateFlags &= ~IS_ROOT_NAMESPACE;
- }
- }
- /**
- * {@hide}
- *
- * @return true if the view belongs to the root namespace, false otherwise
- */
- public boolean isRootNamespace() {
- return (mPrivateFlags&IS_ROOT_NAMESPACE) != 0;
- }
- /**
- * Returns this view's identifier.
- *
- * @return a positive integer used to identify the view or {@link #NO_ID}
- * if the view has no ID
- *
- * @see #setId(int)
- * @see #findViewById(int)
- * @attr ref android.R.styleable#View_id
- */
- @ViewDebug.CapturedViewProperty
- public int getId() {
- return mID;
- }
- /**
- * Returns this view's tag.
- *
- * @return the Object stored in this view as a tag
- *
- * @see #setTag(Object)
- * @see #getTag(int)
- */
- @ViewDebug.ExportedProperty
- public Object getTag() {
- return mTag;
- }
- /**
- * Sets the tag associated with this view. A tag can be used to mark
- * a view in its hierarchy and does not have to be unique within the
- * hierarchy. Tags can also be used to store data within a view without
- * resorting to another data structure.
- *
- * @param tag an Object to tag the view with
- *
- * @see #getTag()
- * @see #setTag(int, Object)
- */
- public void setTag(final Object tag) {
- mTag = tag;
- }
- /**
- * Returns the tag associated with this view and the specified key.
- *
- * @param key The key identifying the tag
- *
- * @return the Object stored in this view as a tag
- *
- * @see #setTag(int, Object)
- * @see #getTag()
- */
- public Object getTag(int key) {
- if (mKeyedTags != null) return mKeyedTags.get(key);
- return null;
- }
- /**
- * Sets a tag associated with this view and a key. A tag can be used
- * to mark a view in its hierarchy and does not have to be unique within
- * the hierarchy. Tags can also be used to store data within a view
- * without resorting to another data structure.
- *
- * The specified key should be an id declared in the resources of the
- * application to ensure it is unique (see the ID resource type ).
- * Keys identified as belonging to
- * the Android framework or not associated with any package will cause
- * an {@link IllegalArgumentException} to be thrown.
- *
- * @param key The key identifying the tag
- * @param tag An Object to tag the view with
- *
- * @throws IllegalArgumentException If they specified key is not valid
- *
- * @see #setTag(Object)
- * @see #getTag(int)
- */
- public void setTag(int key, final Object tag) {
- // If the package id is 0x00 or 0x01, it's either an undefined package
- // or a framework id
- if ((key >>> 24) < 2) {
- throw new IllegalArgumentException("The key must be an application-specific "
- + "resource id.");
- }
- setKeyedTag(key, tag);
- }
- /**
- * Variation of {@link #setTag(int, Object)} that enforces the key to be a
- * framework id.
- *
- * @hide
- */
- public void setTagInternal(int key, Object tag) {
- if ((key >>> 24) != 0x1) {
- throw new IllegalArgumentException("The key must be a framework-specific "
- + "resource id.");
- }
- setKeyedTag(key, tag);
- }
- private void setKeyedTag(int key, Object tag) {
- if (mKeyedTags == null) {
- mKeyedTags = new SparseArray();
- }
- mKeyedTags.put(key, tag);
- }
- /**
- * @param consistency The type of consistency. See ViewDebug for more information.
- *
- * @hide
- */
- protected boolean dispatchConsistencyCheck(int consistency) {
- return onConsistencyCheck(consistency);
- }
- /**
- * 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.
- *
- * @hide
- */
- protected boolean onConsistencyCheck(int consistency) {
- boolean result = true;
- final boolean checkLayout = (consistency & ViewDebug.CONSISTENCY_LAYOUT) != 0;
- final boolean checkDrawing = (consistency & ViewDebug.CONSISTENCY_DRAWING) != 0;
- if (checkLayout) {
- if (getParent() == null) {
- result = false;
- android.util.Log.d(ViewDebug.CONSISTENCY_LOG_TAG,
- "View " + this + " does not have a parent.");
- }
- if (mAttachInfo == null) {
- result = false;
- android.util.Log.d(ViewDebug.CONSISTENCY_LOG_TAG,
- "View " + this + " is not attached to a window.");
- }
- }
- if (checkDrawing) {
- // Do not check the DIRTY/DRAWN flags because views can call invalidate()
- // from their draw() method
- if ((mPrivateFlags & DRAWN) != DRAWN &&
- (mPrivateFlags & DRAWING_CACHE_VALID) == DRAWING_CACHE_VALID) {
- result = false;
- android.util.Log.d(ViewDebug.CONSISTENCY_LOG_TAG,
- "View " + this + " was invalidated but its drawing cache is valid.");
- }
- }
- return result;
- }
- /**
- * Prints information about this view in the log output, with the tag
- * {@link #VIEW_LOG_TAG}.
- *
- * @hide
- */
- public void debug() {
- debug(0);
- }
- /**
- * Prints information about this view in the log output, with the tag
- * {@link #VIEW_LOG_TAG}. Each line in the output is preceded with an
- * indentation defined by the depth
.
- *
- * @param depth the indentation level
- *
- * @hide
- */
- protected void debug(int depth) {
- String output = debugIndent(depth - 1);
- output += "+ " + this;
- int id = getId();
- if (id != -1) {
- output += " (id=" + id + ")";
- }
- Object tag = getTag();
- if (tag != null) {
- output += " (tag=" + tag + ")";
- }
- Log.d(VIEW_LOG_TAG, output);
- if ((mPrivateFlags & FOCUSED) != 0) {
- output = debugIndent(depth) + " FOCUSED";
- Log.d(VIEW_LOG_TAG, output);
- }
- output = debugIndent(depth);
- output += "frame={" + mLeft + ", " + mTop + ", " + mRight
- + ", " + mBottom + "} scroll={" + mScrollX + ", " + mScrollY
- + "} ";
- Log.d(VIEW_LOG_TAG, output);
- if (mPaddingLeft != 0 || mPaddingTop != 0 || mPaddingRight != 0
- || mPaddingBottom != 0) {
- output = debugIndent(depth);
- output += "padding={" + mPaddingLeft + ", " + mPaddingTop
- + ", " + mPaddingRight + ", " + mPaddingBottom + "}";
- Log.d(VIEW_LOG_TAG, output);
- }
- output = debugIndent(depth);
- output += "mMeasureWidth=" + mMeasuredWidth +
- " mMeasureHeight=" + mMeasuredHeight;
- Log.d(VIEW_LOG_TAG, output);
- output = debugIndent(depth);
- if (mLayoutParams == null) {
- output += "BAD! no layout params";
- } else {
- output = mLayoutParams.debug(output);
- }
- Log.d(VIEW_LOG_TAG, output);
- output = debugIndent(depth);
- output += "flags={";
- output += View.printFlags(mViewFlags);
- output += "}";
- Log.d(VIEW_LOG_TAG, output);
- output = debugIndent(depth);
- output += "privateFlags={";
- output += View.printPrivateFlags(mPrivateFlags);
- output += "}";
- Log.d(VIEW_LOG_TAG, output);
- }
- /**
- * Creates an string of whitespaces used for indentation.
- *
- * @param depth the indentation level
- * @return a String containing (depth * 2 + 3) * 2 white spaces
- *
- * @hide
- */
- protected static String debugIndent(int depth) {
- StringBuilder spaces = new StringBuilder((depth * 2 + 3) * 2);
- for (int i = 0; i < (depth * 2) + 3; i++) {
- spaces.append(' ').append(' ');
- }
- return spaces.toString();
- }
- /**
- * Return the offset of the widget's text baseline from the widget's top
- * boundary. If this widget does not support baseline alignment, this
- * method returns -1.
- *
- * @return the offset of the baseline within the widget's bounds or -1
- * if baseline alignment is not supported
- */
- @ViewDebug.ExportedProperty(category = "layout")
- public int getBaseline() {
- return -1;
- }
- /**
- * Call this when something has changed which has invalidated the
- * layout of this view. This will schedule a layout pass of the view
- * tree.
- */
- public void requestLayout() {
- if (ViewDebug.TRACE_HIERARCHY) {
- ViewDebug.trace(this, ViewDebug.HierarchyTraceType.REQUEST_LAYOUT);
- }
- if (getAccessibilityNodeProvider() != null) {
- throw new IllegalStateException("Views with AccessibilityNodeProvider"
- + " can't have children.");
- }
- mPrivateFlags |= FORCE_LAYOUT;
- mPrivateFlags |= INVALIDATED;
- if (mParent != null) {
- if (mLayoutParams != null) {
- mLayoutParams.resolveWithDirection(getResolvedLayoutDirection());
- }
- if (!mParent.isLayoutRequested()) {
- mParent.requestLayout();
- }
- }
- }
- /**
- * Forces this view to be laid out during the next layout pass.
- * This method does not call requestLayout() or forceLayout()
- * on the parent.
- */
- public void forceLayout() {
- mPrivateFlags |= FORCE_LAYOUT;
- mPrivateFlags |= INVALIDATED;
- }
- /**
- *
- * This is called to find out how big a view should be. The parent
- * supplies constraint information in the width and height parameters.
- *
- *
- *
- * The actual measurement work of a view is performed in
- * {@link #onMeasure(int, int)}, called by this method. Therefore, only
- * {@link #onMeasure(int, int)} can and must be overridden by subclasses.
- *
- *
- *
- * @param widthMeasureSpec Horizontal space requirements as imposed by the
- * parent
- * @param heightMeasureSpec Vertical space requirements as imposed by the
- * parent
- *
- * @see #onMeasure(int, int)
- */
- public final void measure(int widthMeasureSpec, int heightMeasureSpec) {
- if ((mPrivateFlags & FORCE_LAYOUT) == FORCE_LAYOUT ||
- widthMeasureSpec != mOldWidthMeasureSpec ||
- heightMeasureSpec != mOldHeightMeasureSpec) {
- // first clears the measured dimension flag
- mPrivateFlags &= ~MEASURED_DIMENSION_SET;
- if (ViewDebug.TRACE_HIERARCHY) {
- ViewDebug.trace(this, ViewDebug.HierarchyTraceType.ON_MEASURE);
- }
- // measure ourselves, this should set the measured dimension flag back
- onMeasure(widthMeasureSpec, heightMeasureSpec);
- // flag not set, setMeasuredDimension() was not invoked, we raise
- // an exception to warn the developer
- if ((mPrivateFlags & MEASURED_DIMENSION_SET) != MEASURED_DIMENSION_SET) {
- throw new IllegalStateException("onMeasure() did not set the"
- + " measured dimension by calling"
- + " setMeasuredDimension()");
- }
- mPrivateFlags |= LAYOUT_REQUIRED;
- }
- mOldWidthMeasureSpec = widthMeasureSpec;
- mOldHeightMeasureSpec = heightMeasureSpec;
- }
- /**
- *
- * Measure the view and its content to determine the measured width and the
- * measured height. This method is invoked by {@link #measure(int, int)} and
- * should be overriden by subclasses to provide accurate and efficient
- * measurement of their contents.
- *
- *
- *
- * CONTRACT: When overriding this method, you
- * must call {@link #setMeasuredDimension(int, int)} to store the
- * measured width and height of this view. Failure to do so will trigger an
- * IllegalStateException
, thrown by
- * {@link #measure(int, int)}. Calling the superclass'
- * {@link #onMeasure(int, int)} is a valid use.
- *
- *
- *
- * The base class implementation of measure defaults to the background size,
- * unless a larger size is allowed by the MeasureSpec. Subclasses should
- * override {@link #onMeasure(int, int)} to provide better measurements of
- * their content.
- *
- *
- *
- * If this method is overridden, it is the subclass's responsibility to make
- * sure the measured height and width are at least the view's minimum height
- * and width ({@link #getSuggestedMinimumHeight()} and
- * {@link #getSuggestedMinimumWidth()}).
- *
- *
- * @param widthMeasureSpec horizontal space requirements as imposed by the parent.
- * The requirements are encoded with
- * {@link android.view.View.MeasureSpec}.
- * @param heightMeasureSpec vertical space requirements as imposed by the parent.
- * The requirements are encoded with
- * {@link android.view.View.MeasureSpec}.
- *
- * @see #getMeasuredWidth()
- * @see #getMeasuredHeight()
- * @see #setMeasuredDimension(int, int)
- * @see #getSuggestedMinimumHeight()
- * @see #getSuggestedMinimumWidth()
- * @see android.view.View.MeasureSpec#getMode(int)
- * @see android.view.View.MeasureSpec#getSize(int)
- */
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec),
- getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec));
- }
- /**
- * This mehod must be called by {@link #onMeasure(int, int)} to store the
- * measured width and measured height. Failing to do so will trigger an
- * exception at measurement time.
- *
- * @param measuredWidth The measured width of this view. May be a complex
- * bit mask as defined by {@link #MEASURED_SIZE_MASK} and
- * {@link #MEASURED_STATE_TOO_SMALL}.
- * @param measuredHeight The measured height of this view. May be a complex
- * bit mask as defined by {@link #MEASURED_SIZE_MASK} and
- * {@link #MEASURED_STATE_TOO_SMALL}.
- */
- protected final void setMeasuredDimension(int measuredWidth, int measuredHeight) {
- mMeasuredWidth = measuredWidth;
- mMeasuredHeight = measuredHeight;
- mPrivateFlags |= MEASURED_DIMENSION_SET;
- }
- /**
- * Merge two states as returned by {@link #getMeasuredState()}.
- * @param curState The current state as returned from a view or the result
- * of combining multiple views.
- * @param newState The new view state to combine.
- * @return Returns a new integer reflecting the combination of the two
- * states.
- */
- public static int combineMeasuredStates(int curState, int newState) {
- return curState | newState;
- }
- /**
- * Version of {@link #resolveSizeAndState(int, int, int)}
- * returning only the {@link #MEASURED_SIZE_MASK} bits of the result.
- */
- public static int resolveSize(int size, int measureSpec) {
- return resolveSizeAndState(size, measureSpec, 0) & MEASURED_SIZE_MASK;
- }
- /**
- * Utility to reconcile a desired size and state, with constraints imposed
- * by a MeasureSpec. Will take the desired size, unless a different size
- * is imposed by the constraints. The returned value is a compound integer,
- * with the resolved size in the {@link #MEASURED_SIZE_MASK} bits and
- * optionally the bit {@link #MEASURED_STATE_TOO_SMALL} set if the resulting
- * size is smaller than the size the view wants to be.
- *
- * @param size How big the view wants to be
- * @param measureSpec Constraints imposed by the parent
- * @return Size information bit mask as defined by
- * {@link #MEASURED_SIZE_MASK} and {@link #MEASURED_STATE_TOO_SMALL}.
- */
- public static int resolveSizeAndState(int size, int measureSpec, int childMeasuredState) {
- int result = size;
- int specMode = MeasureSpec.getMode(measureSpec);
- int specSize = MeasureSpec.getSize(measureSpec);
- switch (specMode) {
- case MeasureSpec.UNSPECIFIED:
- result = size;
- break;
- case MeasureSpec.AT_MOST:
- if (specSize < size) {
- result = specSize | MEASURED_STATE_TOO_SMALL;
- } else {
- result = size;
- }
- break;
- case MeasureSpec.EXACTLY:
- result = specSize;
- break;
- }
- return result | (childMeasuredState&MEASURED_STATE_MASK);
- }
- /**
- * Utility to return a default size. Uses the supplied size if the
- * MeasureSpec imposed no constraints. Will get larger if allowed
- * by the MeasureSpec.
- *
- * @param size Default size for this view
- * @param measureSpec Constraints imposed by the parent
- * @return The size this view should be.
- */
- public static int getDefaultSize(int size, int measureSpec) {
- int result = size;
- int specMode = MeasureSpec.getMode(measureSpec);
- int specSize = MeasureSpec.getSize(measureSpec);
- switch (specMode) {
- case MeasureSpec.UNSPECIFIED:
- result = size;
- break;
- case MeasureSpec.AT_MOST:
- case MeasureSpec.EXACTLY:
- result = specSize;
- break;
- }
- return result;
- }
- /**
- * Returns the suggested minimum height that the view should use. This
- * returns the maximum of the view's minimum height
- * and the background's minimum height
- * ({@link android.graphics.drawable.Drawable#getMinimumHeight()}).
- *
- * When being used in {@link #onMeasure(int, int)}, the caller should still
- * ensure the returned height is within the requirements of the parent.
- *
- * @return The suggested minimum height of the view.
- */
- protected int getSuggestedMinimumHeight() {
- int suggestedMinHeight = mMinHeight;
- if (mBGDrawable != null) {
- final int bgMinHeight = mBGDrawable.getMinimumHeight();
- if (suggestedMinHeight < bgMinHeight) {
- suggestedMinHeight = bgMinHeight;
- }
- }
- return suggestedMinHeight;
- }
- /**
- * Returns the suggested minimum width that the view should use. This
- * returns the maximum of the view's minimum width)
- * and the background's minimum width
- * ({@link android.graphics.drawable.Drawable#getMinimumWidth()}).
- *
- * When being used in {@link #onMeasure(int, int)}, the caller should still
- * ensure the returned width is within the requirements of the parent.
- *
- * @return The suggested minimum width of the view.
- */
- protected int getSuggestedMinimumWidth() {
- int suggestedMinWidth = mMinWidth;
- if (mBGDrawable != null) {
- final int bgMinWidth = mBGDrawable.getMinimumWidth();
- if (suggestedMinWidth < bgMinWidth) {
- suggestedMinWidth = bgMinWidth;
- }
- }
- return suggestedMinWidth;
- }
- /**
- * Sets the minimum height of the view. It is not guaranteed the view will
- * be able to achieve this minimum height (for example, if its parent layout
- * constrains it with less available height).
- *
- * @param minHeight The minimum height the view will try to be.
- */
- public void setMinimumHeight(int minHeight) {
- mMinHeight = minHeight;
- }
- /**
- * Sets the minimum width of the view. It is not guaranteed the view will
- * be able to achieve this minimum width (for example, if its parent layout
- * constrains it with less available width).
- *
- * @param minWidth The minimum width the view will try to be.
- */
- public void setMinimumWidth(int minWidth) {
- mMinWidth = minWidth;
- }
- /**
- * Get the animation currently associated with this view.
- *
- * @return The animation that is currently playing or
- * scheduled to play for this view.
- */
- public Animation getAnimation() {
- return mCurrentAnimation;
- }
- /**
- * Start the specified animation now.
- *
- * @param animation the animation to start now
- */
- public void startAnimation(Animation animation) {
- animation.setStartTime(Animation.START_ON_FIRST_FRAME);
- setAnimation(animation);
- invalidateParentCaches();
- invalidate(true);
- }
- /**
- * Cancels any animations for this view.
- */
- public void clearAnimation() {
- if (mCurrentAnimation != null) {
- mCurrentAnimation.detach();
- }
- mCurrentAnimation = null;
- invalidateParentIfNeeded();
- }
- /**
- * Sets the next animation to play for this view.
- * If you want the animation to play immediately, use
- * startAnimation. This method provides allows fine-grained
- * control over the start time and invalidation, but you
- * must make sure that 1) the animation has a start time set, and
- * 2) the view will be invalidated when the animation is supposed to
- * start.
- *
- * @param animation The next animation, or null.
- */
- public void setAnimation(Animation animation) {
- mCurrentAnimation = animation;
- if (animation != null) {
- animation.reset();
- }
- }
- /**
- * Invoked by a parent ViewGroup to notify the start of the animation
- * currently associated with this view. If you override this method,
- * always call super.onAnimationStart();
- *
- * @see #setAnimation(android.view.animation.Animation)
- * @see #getAnimation()
- */
- protected void onAnimationStart() {
- mPrivateFlags |= ANIMATION_STARTED;
- }
- /**
- * Invoked by a parent ViewGroup to notify the end of the animation
- * currently associated with this view. If you override this method,
- * always call super.onAnimationEnd();
- *
- * @see #setAnimation(android.view.animation.Animation)
- * @see #getAnimation()
- */
- protected void onAnimationEnd() {
- mPrivateFlags &= ~ANIMATION_STARTED;
- }
- /**
- * Invoked if there is a Transform that involves alpha. Subclass that can
- * draw themselves with the specified alpha should return true, and then
- * respect that alpha when their onDraw() is called. If this returns false
- * then the view may be redirected to draw into an offscreen buffer to
- * fulfill the request, which will look fine, but may be slower than if the
- * subclass handles it internally. The default implementation returns false.
- *
- * @param alpha The alpha (0..255) to apply to the view's drawing
- * @return true if the view can draw with the specified alpha.
- */
- protected boolean onSetAlpha(int alpha) {
- return false;
- }
- /**
- * This is used by the RootView to perform an optimization when
- * the view hierarchy contains one or several SurfaceView.
- * SurfaceView is always considered transparent, but its children are not,
- * therefore all View objects remove themselves from the global transparent
- * region (passed as a parameter to this function).
- *
- * @param region The transparent region for this ViewAncestor (window).
- *
- * @return Returns true if the effective visibility of the view at this
- * point is opaque, regardless of the transparent region; returns false
- * if it is possible for underlying windows to be seen behind the view.
- *
- * {@hide}
- */
- public boolean gatherTransparentRegion(Region region) {
- final AttachInfo attachInfo = mAttachInfo;
- if (region != null && attachInfo != null) {
- final int pflags = mPrivateFlags;
- if ((pflags & SKIP_DRAW) == 0) {
- // The SKIP_DRAW flag IS NOT set, so this view draws. We need to
- // remove it from the transparent region.
- final int[] location = attachInfo.mTransparentLocation;
- getLocationInWindow(location);
- region.op(location[0], location[1], location[0] + mRight - mLeft,
- location[1] + mBottom - mTop, Region.Op.DIFFERENCE);
- } else if ((pflags & ONLY_DRAWS_BACKGROUND) != 0 && mBGDrawable != null) {
- // The ONLY_DRAWS_BACKGROUND flag IS set and the background drawable
- // exists, so we remove the background drawable's non-transparent
- // parts from this transparent region.
- applyDrawableToTransparentRegion(mBGDrawable, region);
- }
- }
- return true;
- }
- /**
- * Play a sound effect for this view.
- *
- *
The framework will play sound effects for some built in actions, such as
- * clicking, but you may wish to play these effects in your widget,
- * for instance, for internal navigation.
- *
- *
The sound effect will only be played if sound effects are enabled by the user, and
- * {@link #isSoundEffectsEnabled()} is true.
- *
- * @param soundConstant One of the constants defined in {@link SoundEffectConstants}
- */
- public void playSoundEffect(int soundConstant) {
- if (mAttachInfo == null || mAttachInfo.mRootCallbacks == null || !isSoundEffectsEnabled()) {
- return;
- }
- mAttachInfo.mRootCallbacks.playSoundEffect(soundConstant);
- }
- /**
- * BZZZTT!!1!
- *
- *
Provide haptic feedback to the user for this view.
- *
- *
The framework will provide haptic feedback for some built in actions,
- * such as long presses, but you may wish to provide feedback for your
- * own widget.
- *
- *
The feedback will only be performed if
- * {@link #isHapticFeedbackEnabled()} is true.
- *
- * @param feedbackConstant One of the constants defined in
- * {@link HapticFeedbackConstants}
- */
- public boolean performHapticFeedback(int feedbackConstant) {
- return performHapticFeedback(feedbackConstant, 0);
- }
- /**
- * BZZZTT!!1!
- *
- *
Like {@link #performHapticFeedback(int)}, with additional options.
- *
- * @param feedbackConstant One of the constants defined in
- * {@link HapticFeedbackConstants}
- * @param flags Additional flags as per {@link HapticFeedbackConstants}.
- */
- public boolean performHapticFeedback(int feedbackConstant, int flags) {
- if (mAttachInfo == null) {
- return false;
- }
- //noinspection SimplifiableIfStatement
- if ((flags & HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING) == 0
- && !isHapticFeedbackEnabled()) {
- return false;
- }
- return mAttachInfo.mRootCallbacks.performHapticFeedback(feedbackConstant,
- (flags & HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING) != 0);
- }
- /**
- * Request that the visibility of the status bar be changed.
- * @param visibility Bitwise-or of flags {@link #SYSTEM_UI_FLAG_LOW_PROFILE} or
- * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}.
- */
- public void setSystemUiVisibility(int visibility) {
- if (visibility != mSystemUiVisibility) {
- mSystemUiVisibility = visibility;
- if (mParent != null && mAttachInfo != null && !mAttachInfo.mRecomputeGlobalAttributes) {
- mParent.recomputeViewAttributes(this);
- }
- }
- }
- /**
- * Returns the status bar visibility that this view has requested.
- * @return Bitwise-or of flags {@link #SYSTEM_UI_FLAG_LOW_PROFILE} or
- * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}.
- */
- public int getSystemUiVisibility() {
- return mSystemUiVisibility;
- }
- /**
- * Set a listener to receive callbacks when the visibility of the system bar changes.
- * @param l The {@link OnSystemUiVisibilityChangeListener} to receive callbacks.
- */
- public void setOnSystemUiVisibilityChangeListener(OnSystemUiVisibilityChangeListener l) {
- getListenerInfo().mOnSystemUiVisibilityChangeListener = l;
- if (mParent != null && mAttachInfo != null && !mAttachInfo.mRecomputeGlobalAttributes) {
- mParent.recomputeViewAttributes(this);
- }
- }
- /**
- * Dispatch callbacks to {@link #setOnSystemUiVisibilityChangeListener} down
- * the view hierarchy.
- */
- public void dispatchSystemUiVisibilityChanged(int visibility) {
- ListenerInfo li = mListenerInfo;
- if (li != null && li.mOnSystemUiVisibilityChangeListener != null) {
- li.mOnSystemUiVisibilityChangeListener.onSystemUiVisibilityChange(
- visibility & PUBLIC_STATUS_BAR_VISIBILITY_MASK);
- }
- }
- void updateLocalSystemUiVisibility(int localValue, int localChanges) {
- int val = (mSystemUiVisibility&~localChanges) | (localValue&localChanges);
- if (val != mSystemUiVisibility) {
- setSystemUiVisibility(val);
- }
- }
- /**
- * Creates an image that the system displays during the drag and drop
- * operation. This is called a "drag shadow". The default implementation
- * for a DragShadowBuilder based on a View returns an image that has exactly the same
- * appearance as the given View. The default also positions the center of the drag shadow
- * directly under the touch point. If no View is provided (the constructor with no parameters
- * is used), and {@link #onProvideShadowMetrics(Point,Point) onProvideShadowMetrics()} and
- * {@link #onDrawShadow(Canvas) onDrawShadow()} are not overriden, then the
- * default is an invisible drag shadow.
- *
- * You are not required to use the View you provide to the constructor as the basis of the
- * drag shadow. The {@link #onDrawShadow(Canvas) onDrawShadow()} method allows you to draw
- * anything you want as the drag shadow.
- *
- *
- * You pass a DragShadowBuilder object to the system when you start the drag. The system
- * calls {@link #onProvideShadowMetrics(Point,Point) onProvideShadowMetrics()} to get the
- * size and position of the drag shadow. It uses this data to construct a
- * {@link android.graphics.Canvas} object, then it calls {@link #onDrawShadow(Canvas) onDrawShadow()}
- * so that your application can draw the shadow image in the Canvas.
- *
- *
- *
- *
Developer Guides
- *
For a guide to implementing drag and drop features, read the
- * Drag and Drop developer guide.
- *
- */
- public static class DragShadowBuilder {
- private final WeakReference mView;
- /**
- * Constructs a shadow image builder based on a View. By default, the resulting drag
- * shadow will have the same appearance and dimensions as the View, with the touch point
- * over the center of the View.
- * @param view A View. Any View in scope can be used.
- */
- public DragShadowBuilder(View view) {
- mView = new WeakReference(view);
- }
- /**
- * Construct a shadow builder object with no associated View. This
- * constructor variant is only useful when the {@link #onProvideShadowMetrics(Point, Point)}
- * and {@link #onDrawShadow(Canvas)} methods are also overridden in order
- * to supply the drag shadow's dimensions and appearance without
- * reference to any View object. If they are not overridden, then the result is an
- * invisible drag shadow.
- */
- public DragShadowBuilder() {
- mView = new WeakReference(null);
- }
- /**
- * Returns the View object that had been passed to the
- * {@link #View.DragShadowBuilder(View)}
- * constructor. If that View parameter was {@code null} or if the
- * {@link #View.DragShadowBuilder()}
- * constructor was used to instantiate the builder object, this method will return
- * null.
- *
- * @return The View object associate with this builder object.
- */
- @SuppressWarnings({"JavadocReference"})
- final public View getView() {
- return mView.get();
- }
- /**
- * Provides the metrics for the shadow image. These include the dimensions of
- * the shadow image, and the point within that shadow that should
- * be centered under the touch location while dragging.
- *
- * The default implementation sets the dimensions of the shadow to be the
- * same as the dimensions of the View itself and centers the shadow under
- * the touch point.
- *
- *
- * @param shadowSize A {@link android.graphics.Point} containing the width and height
- * of the shadow image. Your application must set {@link android.graphics.Point#x} to the
- * desired width and must set {@link android.graphics.Point#y} to the desired height of the
- * image.
- *
- * @param shadowTouchPoint A {@link android.graphics.Point} for the position within the
- * shadow image that should be underneath the touch point during the drag and drop
- * operation. Your application must set {@link android.graphics.Point#x} to the
- * X coordinate and {@link android.graphics.Point#y} to the Y coordinate of this position.
- */
- public void onProvideShadowMetrics(Point shadowSize, Point shadowTouchPoint) {
- final View view = mView.get();
- if (view != null) {
- shadowSize.set(view.getWidth(), view.getHeight());
- shadowTouchPoint.set(shadowSize.x / 2, shadowSize.y / 2);
- } else {
- Log.e(View.VIEW_LOG_TAG, "Asked for drag thumb metrics but no view");
- }
- }
- /**
- * Draws the shadow image. The system creates the {@link android.graphics.Canvas} object
- * based on the dimensions it received from the
- * {@link #onProvideShadowMetrics(Point, Point)} callback.
- *
- * @param canvas A {@link android.graphics.Canvas} object in which to draw the shadow image.
- */
- public void onDrawShadow(Canvas canvas) {
- final View view = mView.get();
- if (view != null) {
- view.draw(canvas);
- } else {
- Log.e(View.VIEW_LOG_TAG, "Asked to draw drag shadow but no view");
- }
- }
- }
- /**
- * Starts a drag and drop operation. When your application calls this method, it passes a
- * {@link android.view.View.DragShadowBuilder} object to the system. The
- * system calls this object's {@link DragShadowBuilder#onProvideShadowMetrics(Point, Point)}
- * to get metrics for the drag shadow, and then calls the object's
- * {@link DragShadowBuilder#onDrawShadow(Canvas)} to draw the drag shadow itself.
- *
- * Once the system has the drag shadow, it begins the drag and drop operation by sending
- * drag events to all the View objects in your application that are currently visible. It does
- * this either by calling the View object's drag listener (an implementation of
- * {@link android.view.View.OnDragListener#onDrag(View,DragEvent) onDrag()} or by calling the
- * View object's {@link android.view.View#onDragEvent(DragEvent) onDragEvent()} method.
- * Both are passed a {@link android.view.DragEvent} object that has a
- * {@link android.view.DragEvent#getAction()} value of
- * {@link android.view.DragEvent#ACTION_DRAG_STARTED}.
- *
- *
- * Your application can invoke startDrag() on any attached View object. The View object does not
- * need to be the one used in {@link android.view.View.DragShadowBuilder}, nor does it need to
- * be related to the View the user selected for dragging.
- *
- * @param data A {@link android.content.ClipData} object pointing to the data to be
- * transferred by the drag and drop operation.
- * @param shadowBuilder A {@link android.view.View.DragShadowBuilder} object for building the
- * drag shadow.
- * @param myLocalState An {@link java.lang.Object} containing local data about the drag and
- * drop operation. This Object is put into every DragEvent object sent by the system during the
- * current drag.
- *
- * myLocalState is a lightweight mechanism for the sending information from the dragged View
- * to the target Views. For example, it can contain flags that differentiate between a
- * a copy operation and a move operation.
- *
- * @param flags Flags that control the drag and drop operation. No flags are currently defined,
- * so the parameter should be set to 0.
- * @return {@code true} if the method completes successfully, or
- * {@code false} if it fails anywhere. Returning {@code false} means the system was unable to
- * do a drag, and so no drag operation is in progress.
- */
- public final boolean startDrag(ClipData data, DragShadowBuilder shadowBuilder,
- Object myLocalState, int flags) {
- if (ViewDebug.DEBUG_DRAG) {
- Log.d(VIEW_LOG_TAG, "startDrag: data=" + data + " flags=" + flags);
- }
- boolean okay = false;
- Point shadowSize = new Point();
- Point shadowTouchPoint = new Point();
- shadowBuilder.onProvideShadowMetrics(shadowSize, shadowTouchPoint);
- if ((shadowSize.x < 0) || (shadowSize.y < 0) ||
- (shadowTouchPoint.x < 0) || (shadowTouchPoint.y < 0)) {
- throw new IllegalStateException("Drag shadow dimensions must not be negative");
- }
- if (ViewDebug.DEBUG_DRAG) {
- Log.d(VIEW_LOG_TAG, "drag shadow: width=" + shadowSize.x + " height=" + shadowSize.y
- + " shadowX=" + shadowTouchPoint.x + " shadowY=" + shadowTouchPoint.y);
- }
- Surface surface = new Surface();
- try {
- IBinder token = mAttachInfo.mSession.prepareDrag(mAttachInfo.mWindow,
- flags, shadowSize.x, shadowSize.y, surface);
- if (ViewDebug.DEBUG_DRAG) Log.d(VIEW_LOG_TAG, "prepareDrag returned token=" + token
- + " surface=" + surface);
- if (token != null) {
- Canvas canvas = surface.lockCanvas(null);
- try {
- canvas.drawColor(0, PorterDuff.Mode.CLEAR);
- shadowBuilder.onDrawShadow(canvas);
- } finally {
- surface.unlockCanvasAndPost(canvas);
- }
- final ViewRootImpl root = getViewRootImpl();
- // Cache the local state object for delivery with DragEvents
- root.setLocalDragState(myLocalState);
- // repurpose 'shadowSize' for the last touch point
- root.getLastTouchPoint(shadowSize);
- okay = mAttachInfo.mSession.performDrag(mAttachInfo.mWindow, token,
- shadowSize.x, shadowSize.y,
- shadowTouchPoint.x, shadowTouchPoint.y, data);
- if (ViewDebug.DEBUG_DRAG) Log.d(VIEW_LOG_TAG, "performDrag returned " + okay);
- // Off and running! Release our local surface instance; the drag
- // shadow surface is now managed by the system process.
- surface.release();
- }
- } catch (Exception e) {
- Log.e(VIEW_LOG_TAG, "Unable to initiate drag", e);
- surface.destroy();
- }
- return okay;
- }
- /**
- * Handles drag events sent by the system following a call to
- * {@link android.view.View#startDrag(ClipData,DragShadowBuilder,Object,int) startDrag()}.
- *
- * When the system calls this method, it passes a
- * {@link android.view.DragEvent} object. A call to
- * {@link android.view.DragEvent#getAction()} returns one of the action type constants defined
- * in DragEvent. The method uses these to determine what is happening in the drag and drop
- * operation.
- * @param event The {@link android.view.DragEvent} sent by the system.
- * The {@link android.view.DragEvent#getAction()} method returns an action type constant defined
- * in DragEvent, indicating the type of drag event represented by this object.
- * @return {@code true} if the method was successful, otherwise {@code false}.
- *
- * The method should return {@code true} in response to an action type of
- * {@link android.view.DragEvent#ACTION_DRAG_STARTED} to receive drag events for the current
- * operation.
- *
- *
- * The method should also return {@code true} in response to an action type of
- * {@link android.view.DragEvent#ACTION_DROP} if it consumed the drop, or
- * {@code false} if it didn't.
- *
- */
- public boolean onDragEvent(DragEvent event) {
- return false;
- }
- /**
- * Detects if this View is enabled and has a drag event listener.
- * If both are true, then it calls the drag event listener with the
- * {@link android.view.DragEvent} it received. If the drag event listener returns
- * {@code true}, then dispatchDragEvent() returns {@code true}.
- *
- * For all other cases, the method calls the
- * {@link android.view.View#onDragEvent(DragEvent) onDragEvent()} drag event handler
- * method and returns its result.
- *
- *
- * This ensures that a drag event is always consumed, even if the View does not have a drag
- * event listener. However, if the View has a listener and the listener returns true, then
- * onDragEvent() is not called.
- *
- */
- public boolean dispatchDragEvent(DragEvent event) {
- //noinspection SimplifiableIfStatement
- ListenerInfo li = mListenerInfo;
- if (li != null && li.mOnDragListener != null && (mViewFlags & ENABLED_MASK) == ENABLED
- && li.mOnDragListener.onDrag(this, event)) {
- return true;
- }
- return onDragEvent(event);
- }
- boolean canAcceptDrag() {
- return (mPrivateFlags2 & DRAG_CAN_ACCEPT) != 0;
- }
- /**
- * This needs to be a better API (NOT ON VIEW) before it is exposed. If
- * it is ever exposed at all.
- * @hide
- */
- public void onCloseSystemDialogs(String reason) {
- }
- /**
- * Given a Drawable whose bounds have been set to draw into this view,
- * update a Region being computed for
- * {@link #gatherTransparentRegion(android.graphics.Region)} so
- * that any non-transparent parts of the Drawable are removed from the
- * given transparent region.
- *
- * @param dr The Drawable whose transparency is to be applied to the region.
- * @param region A Region holding the current transparency information,
- * where any parts of the region that are set are considered to be
- * transparent. On return, this region will be modified to have the
- * transparency information reduced by the corresponding parts of the
- * Drawable that are not transparent.
- * {@hide}
- */
- public void applyDrawableToTransparentRegion(Drawable dr, Region region) {
- if (DBG) {
- Log.i("View", "Getting transparent region for: " + this);
- }
- final Region r = dr.getTransparentRegion();
- final Rect db = dr.getBounds();
- final AttachInfo attachInfo = mAttachInfo;
- if (r != null && attachInfo != null) {
- final int w = getRight()-getLeft();
- final int h = getBottom()-getTop();
- if (db.left > 0) {
- //Log.i("VIEW", "Drawable left " + db.left + " > view 0");
- r.op(0, 0, db.left, h, Region.Op.UNION);
- }
- if (db.right < w) {
- //Log.i("VIEW", "Drawable right " + db.right + " < view " + w);
- r.op(db.right, 0, w, h, Region.Op.UNION);
- }
- if (db.top > 0) {
- //Log.i("VIEW", "Drawable top " + db.top + " > view 0");
- r.op(0, 0, w, db.top, Region.Op.UNION);
- }
- if (db.bottom < h) {
- //Log.i("VIEW", "Drawable bottom " + db.bottom + " < view " + h);
- r.op(0, db.bottom, w, h, Region.Op.UNION);
- }
- final int[] location = attachInfo.mTransparentLocation;
- getLocationInWindow(location);
- r.translate(location[0], location[1]);
- region.op(r, Region.Op.INTERSECT);
- } else {
- region.op(db, Region.Op.DIFFERENCE);
- }
- }
- private void checkForLongClick(int delayOffset) {
- if ((mViewFlags & LONG_CLICKABLE) == LONG_CLICKABLE) {
- mHasPerformedLongPress = false;
- if (mPendingCheckForLongPress == null) {
- mPendingCheckForLongPress = new CheckForLongPress();
- }
- mPendingCheckForLongPress.rememberWindowAttachCount();
- postDelayed(mPendingCheckForLongPress,
- ViewConfiguration.getLongPressTimeout() - delayOffset);
- }
- }
- /**
- * Inflate a view from an XML resource. This convenience method wraps the {@link
- * LayoutInflater} class, which provides a full range of options for view inflation.
- *
- * @param context The Context object for your activity or application.
- * @param resource The resource ID to inflate
- * @param root A view group that will be the parent. Used to properly inflate the
- * layout_* parameters.
- * @see LayoutInflater
- */
- public static View inflate(Context context, int resource, ViewGroup root) {
- LayoutInflater factory = LayoutInflater.from(context);
- return factory.inflate(resource, root);
- }
- /**
- * Scroll the view with standard behavior for scrolling beyond the normal
- * content boundaries. Views that call this method should override
- * {@link #onOverScrolled(int, int, boolean, boolean)} to respond to the
- * results of an over-scroll operation.
- *
- * Views can use this method to handle any touch or fling-based scrolling.
- *
- * @param deltaX Change in X in pixels
- * @param deltaY Change in Y in pixels
- * @param scrollX Current X scroll value in pixels before applying deltaX
- * @param scrollY Current Y scroll value in pixels before applying deltaY
- * @param scrollRangeX Maximum content scroll range along the X axis
- * @param scrollRangeY Maximum content scroll range along the Y axis
- * @param maxOverScrollX Number of pixels to overscroll by in either direction
- * along the X axis.
- * @param maxOverScrollY Number of pixels to overscroll by in either direction
- * along the Y axis.
- * @param isTouchEvent true if this scroll operation is the result of a touch event.
- * @return true if scrolling was clamped to an over-scroll boundary along either
- * axis, false otherwise.
- */
- @SuppressWarnings({"UnusedParameters"})
- protected boolean overScrollBy(int deltaX, int deltaY,
- int scrollX, int scrollY,
- int scrollRangeX, int scrollRangeY,
- int maxOverScrollX, int maxOverScrollY,
- boolean isTouchEvent) {
- final int overScrollMode = mOverScrollMode;
- final boolean canScrollHorizontal =
- computeHorizontalScrollRange() > computeHorizontalScrollExtent();
- final boolean canScrollVertical =
- computeVerticalScrollRange() > computeVerticalScrollExtent();
- final boolean overScrollHorizontal = overScrollMode == OVER_SCROLL_ALWAYS ||
- (overScrollMode == OVER_SCROLL_IF_CONTENT_SCROLLS && canScrollHorizontal);
- final boolean overScrollVertical = overScrollMode == OVER_SCROLL_ALWAYS ||
- (overScrollMode == OVER_SCROLL_IF_CONTENT_SCROLLS && canScrollVertical);
- int newScrollX = scrollX + deltaX;
- if (!overScrollHorizontal) {
- maxOverScrollX = 0;
- }
- int newScrollY = scrollY + deltaY;
- if (!overScrollVertical) {
- maxOverScrollY = 0;
- }
- // Clamp values if at the limits and record
- final int left = -maxOverScrollX;
- final int right = maxOverScrollX + scrollRangeX;
- final int top = -maxOverScrollY;
- final int bottom = maxOverScrollY + scrollRangeY;
- boolean clampedX = false;
- if (newScrollX > right) {
- newScrollX = right;
- clampedX = true;
- } else if (newScrollX < left) {
- newScrollX = left;
- clampedX = true;
- }
- boolean clampedY = false;
- if (newScrollY > bottom) {
- newScrollY = bottom;
- clampedY = true;
- } else if (newScrollY < top) {
- newScrollY = top;
- clampedY = true;
- }
- onOverScrolled(newScrollX, newScrollY, clampedX, clampedY);
- return clampedX || clampedY;
- }
- /**
- * Called by {@link #overScrollBy(int, int, int, int, int, int, int, int, boolean)} to
- * respond to the results of an over-scroll operation.
- *
- * @param scrollX New X scroll value in pixels
- * @param scrollY New Y scroll value in pixels
- * @param clampedX True if scrollX was clamped to an over-scroll boundary
- * @param clampedY True if scrollY was clamped to an over-scroll boundary
- */
- protected void onOverScrolled(int scrollX, int scrollY,
- boolean clampedX, boolean clampedY) {
- // Intentionally empty.
- }
- /**
- * Returns the over-scroll mode for this view. The result will be
- * one of {@link #OVER_SCROLL_ALWAYS} (default), {@link #OVER_SCROLL_IF_CONTENT_SCROLLS}
- * (allow over-scrolling only if the view content is larger than the container),
- * or {@link #OVER_SCROLL_NEVER}.
- *
- * @return This view's over-scroll mode.
- */
- public int getOverScrollMode() {
- return mOverScrollMode;
- }
- /**
- * Set the over-scroll mode for this view. Valid over-scroll modes are
- * {@link #OVER_SCROLL_ALWAYS} (default), {@link #OVER_SCROLL_IF_CONTENT_SCROLLS}
- * (allow over-scrolling only if the view content is larger than the container),
- * or {@link #OVER_SCROLL_NEVER}.
- *
- * Setting the over-scroll mode of a view will have an effect only if the
- * view is capable of scrolling.
- *
- * @param overScrollMode The new over-scroll mode for this view.
- */
- public void setOverScrollMode(int overScrollMode) {
- if (overScrollMode != OVER_SCROLL_ALWAYS &&
- overScrollMode != OVER_SCROLL_IF_CONTENT_SCROLLS &&
- overScrollMode != OVER_SCROLL_NEVER) {
- throw new IllegalArgumentException("Invalid overscroll mode " + overScrollMode);
- }
- mOverScrollMode = overScrollMode;
- }
- /**
- * Gets a scale factor that determines the distance the view should scroll
- * vertically in response to {@link MotionEvent#ACTION_SCROLL}.
- * @return The vertical scroll scale factor.
- * @hide
- */
- protected float getVerticalScrollFactor() {
- if (mVerticalScrollFactor == 0) {
- TypedValue outValue = new TypedValue();
- if (!mContext.getTheme().resolveAttribute(
- com.android.internal.R.attr.listPreferredItemHeight, outValue, true)) {
- throw new IllegalStateException(
- "Expected theme to define listPreferredItemHeight.");
- }
- mVerticalScrollFactor = outValue.getDimension(
- mContext.getResources().getDisplayMetrics());
- }
- return mVerticalScrollFactor;
- }
- /**
- * Gets a scale factor that determines the distance the view should scroll
- * horizontally in response to {@link MotionEvent#ACTION_SCROLL}.
- * @return The horizontal scroll scale factor.
- * @hide
- */
- protected float getHorizontalScrollFactor() {
- // TODO: Should use something else.
- return getVerticalScrollFactor();
- }
- /**
- * Return the value specifying the text direction or policy that was set with
- * {@link #setTextDirection(int)}.
- *
- * @return the defined text direction. It can be one of:
- *
- * {@link #TEXT_DIRECTION_INHERIT},
- * {@link #TEXT_DIRECTION_FIRST_STRONG}
- * {@link #TEXT_DIRECTION_ANY_RTL},
- * {@link #TEXT_DIRECTION_LTR},
- * {@link #TEXT_DIRECTION_RTL},
- * {@link #TEXT_DIRECTION_LOCALE},
- *
- */
- public int getTextDirection() {
- return mTextDirection;
- }
- /**
- * Set the text direction.
- *
- * @param textDirection the direction to set. Should be one of:
- *
- * {@link #TEXT_DIRECTION_INHERIT},
- * {@link #TEXT_DIRECTION_FIRST_STRONG}
- * {@link #TEXT_DIRECTION_ANY_RTL},
- * {@link #TEXT_DIRECTION_LTR},
- * {@link #TEXT_DIRECTION_RTL},
- * {@link #TEXT_DIRECTION_LOCALE},
- *
- */
- public void setTextDirection(int textDirection) {
- if (textDirection != mTextDirection) {
- mTextDirection = textDirection;
- resetResolvedTextDirection();
- requestLayout();
- }
- }
- /**
- * Return the resolved text direction.
- *
- * @return the resolved text direction. Return one of:
- *
- * {@link #TEXT_DIRECTION_FIRST_STRONG}
- * {@link #TEXT_DIRECTION_ANY_RTL},
- * {@link #TEXT_DIRECTION_LTR},
- * {@link #TEXT_DIRECTION_RTL},
- * {@link #TEXT_DIRECTION_LOCALE},
- *
- */
- public int getResolvedTextDirection() {
- if (mResolvedTextDirection == TEXT_DIRECTION_INHERIT) {
- resolveTextDirection();
- }
- return mResolvedTextDirection;
- }
- /**
- * Resolve the text direction.
- *
- */
- protected void resolveTextDirection() {
- if (mTextDirection != TEXT_DIRECTION_INHERIT) {
- mResolvedTextDirection = mTextDirection;
- return;
- }
- if (mParent != null && mParent instanceof ViewGroup) {
- mResolvedTextDirection = ((ViewGroup) mParent).getResolvedTextDirection();
- return;
- }
- mResolvedTextDirection = TEXT_DIRECTION_FIRST_STRONG;
- }
- /**
- * Reset resolved text direction. Will be resolved during a call to getResolvedTextDirection().
- *
- */
- protected void resetResolvedTextDirection() {
- mResolvedTextDirection = TEXT_DIRECTION_INHERIT;
- }
- //
- // Properties
- //
- /**
- * A Property wrapper around the alpha
functionality handled by the
- * {@link View#setAlpha(float)} and {@link View#getAlpha()} methods.
- */
- public static final Property ALPHA = new FloatProperty("alpha") {
- @Override
- public void setValue(View object, float value) {
- object.setAlpha(value);
- }
- @Override
- public Float get(View object) {
- return object.getAlpha();
- }
- };
- /**
- * A Property wrapper around the translationX
functionality handled by the
- * {@link View#setTranslationX(float)} and {@link View#getTranslationX()} methods.
- */
- public static final Property TRANSLATION_X = new FloatProperty("translationX") {
- @Override
- public void setValue(View object, float value) {
- object.setTranslationX(value);
- }
- @Override
- public Float get(View object) {
- return object.getTranslationX();
- }
- };
- /**
- * A Property wrapper around the translationY
functionality handled by the
- * {@link View#setTranslationY(float)} and {@link View#getTranslationY()} methods.
- */
- public static final Property TRANSLATION_Y = new FloatProperty("translationY") {
- @Override
- public void setValue(View object, float value) {
- object.setTranslationY(value);
- }
- @Override
- public Float get(View object) {
- return object.getTranslationY();
- }
- };
- /**
- * A Property wrapper around the x
functionality handled by the
- * {@link View#setX(float)} and {@link View#getX()} methods.
- */
- public static final Property X = new FloatProperty("x") {
- @Override
- public void setValue(View object, float value) {
- object.setX(value);
- }
- @Override
- public Float get(View object) {
- return object.getX();
- }
- };
- /**
- * A Property wrapper around the y
functionality handled by the
- * {@link View#setY(float)} and {@link View#getY()} methods.
- */
- public static final Property Y = new FloatProperty("y") {
- @Override
- public void setValue(View object, float value) {
- object.setY(value);
- }
- @Override
- public Float get(View object) {
- return object.getY();
- }
- };
- /**
- * A Property wrapper around the rotation
functionality handled by the
- * {@link View#setRotation(float)} and {@link View#getRotation()} methods.
- */
- public static final Property ROTATION = new FloatProperty("rotation") {
- @Override
- public void setValue(View object, float value) {
- object.setRotation(value);
- }
- @Override
- public Float get(View object) {
- return object.getRotation();
- }
- };
- /**
- * A Property wrapper around the rotationX
functionality handled by the
- * {@link View#setRotationX(float)} and {@link View#getRotationX()} methods.
- */
- public static final Property ROTATION_X = new FloatProperty("rotationX") {
- @Override
- public void setValue(View object, float value) {
- object.setRotationX(value);
- }
- @Override
- public Float get(View object) {
- return object.getRotationX();
- }
- };
- /**
- * A Property wrapper around the rotationY
functionality handled by the
- * {@link View#setRotationY(float)} and {@link View#getRotationY()} methods.
- */
- public static final Property ROTATION_Y = new FloatProperty("rotationY") {
- @Override
- public void setValue(View object, float value) {
- object.setRotationY(value);
- }
- @Override
- public Float get(View object) {
- return object.getRotationY();
- }
- };
- /**
- * A Property wrapper around the scaleX
functionality handled by the
- * {@link View#setScaleX(float)} and {@link View#getScaleX()} methods.
- */
- public static final Property SCALE_X = new FloatProperty("scaleX") {
- @Override
- public void setValue(View object, float value) {
- object.setScaleX(value);
- }
- @Override
- public Float get(View object) {
- return object.getScaleX();
- }
- };
- /**
- * A Property wrapper around the scaleY
functionality handled by the
- * {@link View#setScaleY(float)} and {@link View#getScaleY()} methods.
- */
- public static final Property SCALE_Y = new FloatProperty("scaleY") {
- @Override
- public void setValue(View object, float value) {
- object.setScaleY(value);
- }
- @Override
- public Float get(View object) {
- return object.getScaleY();
- }
- };
- /**
- * A MeasureSpec encapsulates the layout requirements passed from parent to child.
- * Each MeasureSpec represents a requirement for either the width or the height.
- * A MeasureSpec is comprised of a size and a mode. There are three possible
- * modes:
- *
- * UNSPECIFIED
- *
- * The parent has not imposed any constraint on the child. It can be whatever size
- * it wants.
- *
- *
- * EXACTLY
- *
- * The parent has determined an exact size for the child. The child is going to be
- * given those bounds regardless of how big it wants to be.
- *
- *
- * AT_MOST
- *
- * The child can be as large as it wants up to the specified size.
- *
- *
- *
- * MeasureSpecs are implemented as ints to reduce object allocation. This class
- * is provided to pack and unpack the <size, mode> tuple into the int.
- */
- public static class MeasureSpec {
- private static final int MODE_SHIFT = 30;
- private static final int MODE_MASK = 0x3 << MODE_SHIFT;
- /**
- * Measure specification mode: The parent has not imposed any constraint
- * on the child. It can be whatever size it wants.
- */
- public static final int UNSPECIFIED = 0 << MODE_SHIFT;
- /**
- * Measure specification mode: The parent has determined an exact size
- * for the child. The child is going to be given those bounds regardless
- * of how big it wants to be.
- */
- public static final int EXACTLY = 1 << MODE_SHIFT;
- /**
- * Measure specification mode: The child can be as large as it wants up
- * to the specified size.
- */
- public static final int AT_MOST = 2 << MODE_SHIFT;
- /**
- * Creates a measure specification based on the supplied size and mode.
- *
- * The mode must always be one of the following:
- *
- * {@link android.view.View.MeasureSpec#UNSPECIFIED}
- * {@link android.view.View.MeasureSpec#EXACTLY}
- * {@link android.view.View.MeasureSpec#AT_MOST}
- *
- *
- * @param size the size of the measure specification
- * @param mode the mode of the measure specification
- * @return the measure specification based on size and mode
- */
- public static int makeMeasureSpec(int size, int mode) {
- return size + mode;
- }
- /**
- * Extracts the mode from the supplied measure specification.
- *
- * @param measureSpec the measure specification to extract the mode from
- * @return {@link android.view.View.MeasureSpec#UNSPECIFIED},
- * {@link android.view.View.MeasureSpec#AT_MOST} or
- * {@link android.view.View.MeasureSpec#EXACTLY}
- */
- public static int getMode(int measureSpec) {
- return (measureSpec & MODE_MASK);
- }
- /**
- * Extracts the size from the supplied measure specification.
- *
- * @param measureSpec the measure specification to extract the size from
- * @return the size in pixels defined in the supplied measure specification
- */
- public static int getSize(int measureSpec) {
- return (measureSpec & ~MODE_MASK);
- }
- /**
- * Returns a String representation of the specified measure
- * specification.
- *
- * @param measureSpec the measure specification to convert to a String
- * @return a String with the following format: "MeasureSpec: MODE SIZE"
- */
- public static String toString(int measureSpec) {
- int mode = getMode(measureSpec);
- int size = getSize(measureSpec);
- StringBuilder sb = new StringBuilder("MeasureSpec: ");
- if (mode == UNSPECIFIED)
- sb.append("UNSPECIFIED ");
- else if (mode == EXACTLY)
- sb.append("EXACTLY ");
- else if (mode == AT_MOST)
- sb.append("AT_MOST ");
- else
- sb.append(mode).append(" ");
- sb.append(size);
- return sb.toString();
- }
- }
- class CheckForLongPress implements Runnable {
- private int mOriginalWindowAttachCount;
- public void run() {
- if (isPressed() && (mParent != null)
- && mOriginalWindowAttachCount == mWindowAttachCount) {
- if (performLongClick()) {
- mHasPerformedLongPress = true;
- }
- }
- }
- public void rememberWindowAttachCount() {
- mOriginalWindowAttachCount = mWindowAttachCount;
- }
- }
- private final class CheckForTap implements Runnable {
- public void run() {
- mPrivateFlags &= ~PREPRESSED;
- mPrivateFlags |= PRESSED;
- refreshDrawableState();
- checkForLongClick(ViewConfiguration.getTapTimeout());
- }
- }
- private final class PerformClick implements Runnable {
- public void run() {
- performClick();
- }
- }
- /** @hide */
- public void hackTurnOffWindowResizeAnim(boolean off) {
- mAttachInfo.mTurnOffWindowResizeAnim = off;
- }
- /**
- * This method returns a ViewPropertyAnimator object, which can be used to animate
- * specific properties on this View.
- *
- * @return ViewPropertyAnimator The ViewPropertyAnimator associated with this View.
- */
- public ViewPropertyAnimator animate() {
- if (mAnimator == null) {
- mAnimator = new ViewPropertyAnimator(this);
- }
- return mAnimator;
- }
- /**
- * Interface definition for a callback to be invoked when a key event is
- * dispatched to this view. The callback will be invoked before the key
- * event is given to the view.
- */
- public interface OnKeyListener {
- /**
- * Called when a key is dispatched to a view. This allows listeners to
- * get a chance to respond before the target view.
- *
- * @param v The view the key has been dispatched to.
- * @param keyCode The code for the physical key that was pressed
- * @param event The KeyEvent object containing full information about
- * the event.
- * @return True if the listener has consumed the event, false otherwise.
- */
- boolean onKey(View v, int keyCode, KeyEvent event);
- }
- /**
- * Interface definition for a callback to be invoked when a touch event is
- * dispatched to this view. The callback will be invoked before the touch
- * event is given to the view.
- */
- public interface OnTouchListener {
- /**
- * Called when a touch event is dispatched to a view. This allows listeners to
- * get a chance to respond before the target view.
- *
- * @param v The view the touch event has been dispatched to.
- * @param event The MotionEvent object containing full information about
- * the event.
- * @return True if the listener has consumed the event, false otherwise.
- */
- boolean onTouch(View v, MotionEvent event);
- }
- /**
- * Interface definition for a callback to be invoked when a hover event is
- * dispatched to this view. The callback will be invoked before the hover
- * event is given to the view.
- */
- public interface OnHoverListener {
- /**
- * Called when a hover event is dispatched to a view. This allows listeners to
- * get a chance to respond before the target view.
- *
- * @param v The view the hover event has been dispatched to.
- * @param event The MotionEvent object containing full information about
- * the event.
- * @return True if the listener has consumed the event, false otherwise.
- */
- boolean onHover(View v, MotionEvent event);
- }
- /**
- * Interface definition for a callback to be invoked when a generic motion event is
- * dispatched to this view. The callback will be invoked before the generic motion
- * event is given to the view.
- */
- public interface OnGenericMotionListener {
- /**
- * Called when a generic motion event is dispatched to a view. This allows listeners to
- * get a chance to respond before the target view.
- *
- * @param v The view the generic motion event has been dispatched to.
- * @param event The MotionEvent object containing full information about
- * the event.
- * @return True if the listener has consumed the event, false otherwise.
- */
- boolean onGenericMotion(View v, MotionEvent event);
- }
- /**
- * Interface definition for a callback to be invoked when a view has been clicked and held.
- */
- public interface OnLongClickListener {
- /**
- * Called when a view has been clicked and held.
- *
- * @param v The view that was clicked and held.
- *
- * @return true if the callback consumed the long click, false otherwise.
- */
- boolean onLongClick(View v);
- }
- /**
- * Interface definition for a callback to be invoked when a drag is being dispatched
- * to this view. The callback will be invoked before the hosting view's own
- * onDrag(event) method. If the listener wants to fall back to the hosting view's
- * onDrag(event) behavior, it should return 'false' from this callback.
- *
- *
- *
Developer Guides
- *
For a guide to implementing drag and drop features, read the
- * Drag and Drop developer guide.
- *
- */
- public interface OnDragListener {
- /**
- * Called when a drag event is dispatched to a view. This allows listeners
- * to get a chance to override base View behavior.
- *
- * @param v The View that received the drag event.
- * @param event The {@link android.view.DragEvent} object for the drag event.
- * @return {@code true} if the drag event was handled successfully, or {@code false}
- * if the drag event was not handled. Note that {@code false} will trigger the View
- * to call its {@link #onDragEvent(DragEvent) onDragEvent()} handler.
- */
- boolean onDrag(View v, DragEvent event);
- }
- /**
- * Interface definition for a callback to be invoked when the focus state of
- * a view changed.
- */
- public interface OnFocusChangeListener {
- /**
- * Called when the focus state of a view has changed.
- *
- * @param v The view whose state has changed.
- * @param hasFocus The new focus state of v.
- */
- void onFocusChange(View v, boolean hasFocus);
- }
- /**
- * Interface definition for a callback to be invoked when a view is clicked.
- */
- public interface OnClickListener {
- /**
- * Called when a view has been clicked.
- *
- * @param v The view that was clicked.
- */
- void onClick(View v);
- }
- /**
- * Interface definition for a callback to be invoked when the context menu
- * for this view is being built.
- */
- public interface OnCreateContextMenuListener {
- /**
- * Called when the context menu for this view is being built. It is not
- * safe to hold onto the menu after this method returns.
- *
- * @param menu The context menu that is being built
- * @param v The view for which the context menu is being built
- * @param menuInfo Extra information about the item for which the
- * context menu should be shown. This information will vary
- * depending on the class of v.
- */
- void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo);
- }
- /**
- * Interface definition for a callback to be invoked when the status bar changes
- * visibility. This reports global changes to the system UI
- * state, not just what the application is requesting.
- *
- * @see View#setOnSystemUiVisibilityChangeListener(android.view.View.OnSystemUiVisibilityChangeListener)
- */
- public interface OnSystemUiVisibilityChangeListener {
- /**
- * Called when the status bar changes visibility because of a call to
- * {@link View#setSystemUiVisibility(int)}.
- *
- * @param visibility Bitwise-or of flags {@link #SYSTEM_UI_FLAG_LOW_PROFILE} or
- * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}. This tells you the
- * global state of the UI visibility flags, not what your
- * app is currently applying.
- */
- public void onSystemUiVisibilityChange(int visibility);
- }
- /**
- * Interface definition for a callback to be invoked when this view is attached
- * or detached from its window.
- */
- public interface OnAttachStateChangeListener {
- /**
- * Called when the view is attached to a window.
- * @param v The view that was attached
- */
- public void onViewAttachedToWindow(View v);
- /**
- * Called when the view is detached from a window.
- * @param v The view that was detached
- */
- public void onViewDetachedFromWindow(View v);
- }
- private final class UnsetPressedState implements Runnable {
- public void run() {
- setPressed(false);
- }
- }
- /**
- * Base class for derived classes that want to save and restore their own
- * state in {@link android.view.View#onSaveInstanceState()}.
- */
- public static class BaseSavedState extends AbsSavedState {
- /**
- * Constructor used when reading from a parcel. Reads the state of the superclass.
- *
- * @param source
- */
- public BaseSavedState(Parcel source) {
- super(source);
- }
- /**
- * Constructor called by derived classes when creating their SavedState objects
- *
- * @param superState The state of the superclass of this view
- */
- public BaseSavedState(Parcelable superState) {
- super(superState);
- }
- public static final Parcelable.Creator CREATOR =
- new Parcelable.Creator() {
- public BaseSavedState createFromParcel(Parcel in) {
- return new BaseSavedState(in);
- }
- public BaseSavedState[] newArray(int size) {
- return new BaseSavedState[size];
- }
- };
- }
- /**
- * A set of information given to a view when it is attached to its parent
- * window.
- */
- static class AttachInfo {
- interface Callbacks {
- void playSoundEffect(int effectId);
- boolean performHapticFeedback(int effectId, boolean always);
- }
- /**
- * InvalidateInfo is used to post invalidate(int, int, int, int) messages
- * to a Handler. This class contains the target (View) to invalidate and
- * the coordinates of the dirty rectangle.
- *
- * For performance purposes, this class also implements a pool of up to
- * POOL_LIMIT objects that get reused. This reduces memory allocations
- * whenever possible.
- */
- static class InvalidateInfo implements Poolable {
- private static final int POOL_LIMIT = 10;
- private static final Pool sPool = Pools.synchronizedPool(
- Pools.finitePool(new PoolableManager() {
- public InvalidateInfo newInstance() {
- return new InvalidateInfo();
- }
- public void onAcquired(InvalidateInfo element) {
- }
- public void onReleased(InvalidateInfo element) {
- element.target = null;
- }
- }, POOL_LIMIT)
- );
- private InvalidateInfo mNext;
- private boolean mIsPooled;
- View target;
- int left;
- int top;
- int right;
- int bottom;
- public void setNextPoolable(InvalidateInfo element) {
- mNext = element;
- }
- public InvalidateInfo getNextPoolable() {
- return mNext;
- }
- static InvalidateInfo acquire() {
- return sPool.acquire();
- }
- void release() {
- sPool.release(this);
- }
- public boolean isPooled() {
- return mIsPooled;
- }
- public void setPooled(boolean isPooled) {
- mIsPooled = isPooled;
- }
- }
- final IWindowSession mSession;
- final IWindow mWindow;
- final IBinder mWindowToken;
- final Callbacks mRootCallbacks;
- HardwareCanvas mHardwareCanvas;
- /**
- * The top view of the hierarchy.
- */
- View mRootView;
- IBinder mPanelParentWindowToken;
- Surface mSurface;
- boolean mHardwareAccelerated;
- boolean mHardwareAccelerationRequested;
- HardwareRenderer mHardwareRenderer;
- /**
- * Scale factor used by the compatibility mode
- */
- float mApplicationScale;
- /**
- * Indicates whether the application is in compatibility mode
- */
- boolean mScalingRequired;
- /**
- * If set, ViewAncestor doesn't use its lame animation for when the window resizes.
- */
- boolean mTurnOffWindowResizeAnim;
- /**
- * Left position of this view's window
- */
- int mWindowLeft;
- /**
- * Top position of this view's window
- */
- int mWindowTop;
- /**
- * Indicates whether views need to use 32-bit drawing caches
- */
- boolean mUse32BitDrawingCache;
- /**
- * For windows that are full-screen but using insets to layout inside
- * of the screen decorations, these are the current insets for the
- * content of the window.
- */
- final Rect mContentInsets = new Rect();
- /**
- * For windows that are full-screen but using insets to layout inside
- * of the screen decorations, these are the current insets for the
- * actual visible parts of the window.
- */
- final Rect mVisibleInsets = new Rect();
- /**
- * The internal insets given by this window. This value is
- * supplied by the client (through
- * {@link ViewTreeObserver.OnComputeInternalInsetsListener}) and will
- * be given to the window manager when changed to be used in laying
- * out windows behind it.
- */
- final ViewTreeObserver.InternalInsetsInfo mGivenInternalInsets
- = new ViewTreeObserver.InternalInsetsInfo();
- /**
- * All views in the window's hierarchy that serve as scroll containers,
- * used to determine if the window can be resized or must be panned
- * to adjust for a soft input area.
- */
- final ArrayList mScrollContainers = new ArrayList();
- final KeyEvent.DispatcherState mKeyDispatchState
- = new KeyEvent.DispatcherState();
- /**
- * Indicates whether the view's window currently has the focus.
- */
- boolean mHasWindowFocus;
- /**
- * The current visibility of the window.
- */
- int mWindowVisibility;
- /**
- * Indicates the time at which drawing started to occur.
- */
- long mDrawingTime;
- /**
- * Indicates whether or not ignoring the DIRTY_MASK flags.
- */
- boolean mIgnoreDirtyState;
- /**
- * This flag tracks when the mIgnoreDirtyState flag is set during draw(),
- * to avoid clearing that flag prematurely.
- */
- boolean mSetIgnoreDirtyState = false;
- /**
- * Indicates whether the view's window is currently in touch mode.
- */
- boolean mInTouchMode;
- /**
- * Indicates that ViewAncestor should trigger a global layout change
- * the next time it performs a traversal
- */
- boolean mRecomputeGlobalAttributes;
- /**
- * Always report new attributes at next traversal.
- */
- boolean mForceReportNewAttributes;
- /**
- * Set during a traveral if any views want to keep the screen on.
- */
- boolean mKeepScreenOn;
- /**
- * Bitwise-or of all of the values that views have passed to setSystemUiVisibility().
- */
- int mSystemUiVisibility;
- /**
- * True if a view in this hierarchy has an OnSystemUiVisibilityChangeListener
- * attached.
- */
- boolean mHasSystemUiListeners;
- /**
- * Set if the visibility of any views has changed.
- */
- boolean mViewVisibilityChanged;
- /**
- * Set to true if a view has been scrolled.
- */
- boolean mViewScrollChanged;
- /**
- * Global to the view hierarchy used as a temporary for dealing with
- * x/y points in the transparent region computations.
- */
- final int[] mTransparentLocation = new int[2];
- /**
- * Global to the view hierarchy used as a temporary for dealing with
- * x/y points in the ViewGroup.invalidateChild implementation.
- */
- final int[] mInvalidateChildLocation = new int[2];
- /**
- * Global to the view hierarchy used as a temporary for dealing with
- * x/y location when view is transformed.
- */
- final float[] mTmpTransformLocation = new float[2];
- /**
- * The view tree observer used to dispatch global events like
- * layout, pre-draw, touch mode change, etc.
- */
- final ViewTreeObserver mTreeObserver = new ViewTreeObserver();
- /**
- * A Canvas used by the view hierarchy to perform bitmap caching.
- */
- Canvas mCanvas;
- /**
- * The view root impl.
- */
- final ViewRootImpl mViewRootImpl;
- /**
- * A Handler supplied by a view's {@link android.view.ViewRootImpl}. This
- * handler can be used to pump events in the UI events queue.
- */
- final Handler mHandler;
- /**
- * Temporary for use in computing invalidate rectangles while
- * calling up the hierarchy.
- */
- final Rect mTmpInvalRect = new Rect();
- /**
- * Temporary for use in computing hit areas with transformed views
- */
- final RectF mTmpTransformRect = new RectF();
- /**
- * Temporary list for use in collecting focusable descendents of a view.
- */
- final ArrayList mFocusablesTempList = new ArrayList(24);
- /**
- * The id of the window for accessibility purposes.
- */
- int mAccessibilityWindowId = View.NO_ID;
- /**
- * Creates a new set of attachment information with the specified
- * events handler and thread.
- *
- * @param handler the events handler the view must use
- */
- AttachInfo(IWindowSession session, IWindow window,
- ViewRootImpl viewRootImpl, Handler handler, Callbacks effectPlayer) {
- mSession = session;
- mWindow = window;
- mWindowToken = window.asBinder();
- mViewRootImpl = viewRootImpl;
- mHandler = handler;
- mRootCallbacks = effectPlayer;
- }
- }
- /**
- * ScrollabilityCache holds various fields used by a View when scrolling
- * is supported. This avoids keeping too many unused fields in most
- * instances of View.
- */
- private static class ScrollabilityCache implements Runnable {
- /**
- * Scrollbars are not visible
- */
- public static final int OFF = 0;
- /**
- * Scrollbars are visible
- */
- public static final int ON = 1;
- /**
- * Scrollbars are fading away
- */
- public static final int FADING = 2;
- public boolean fadeScrollBars;
- public int fadingEdgeLength;
- public int scrollBarDefaultDelayBeforeFade;
- public int scrollBarFadeDuration;
- public int scrollBarSize;
- public ScrollBarDrawable scrollBar;
- public float[] interpolatorValues;
- public View host;
- public final Paint paint;
- public final Matrix matrix;
- public Shader shader;
- public final Interpolator scrollBarInterpolator = new Interpolator(1, 2);
- private static final float[] OPAQUE = { 255 };
- private static final float[] TRANSPARENT = { 0.0f };
- /**
- * When fading should start. This time moves into the future every time
- * a new scroll happens. Measured based on SystemClock.uptimeMillis()
- */
- public long fadeStartTime;
- /**
- * The current state of the scrollbars: ON, OFF, or FADING
- */
- public int state = OFF;
- private int mLastColor;
- public ScrollabilityCache(ViewConfiguration configuration, View host) {
- fadingEdgeLength = configuration.getScaledFadingEdgeLength();
- scrollBarSize = configuration.getScaledScrollBarSize();
- scrollBarDefaultDelayBeforeFade = ViewConfiguration.getScrollDefaultDelay();
- scrollBarFadeDuration = ViewConfiguration.getScrollBarFadeDuration();
- paint = new Paint();
- matrix = new Matrix();
- // 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));
- this.host = host;
- }
- public void setFadeColor(int color) {
- if (color != 0 && color != mLastColor) {
- mLastColor = color;
- color |= 0xFF000000;
- shader = new LinearGradient(0, 0, 0, 1, color | 0xFF000000,
- color & 0x00FFFFFF, Shader.TileMode.CLAMP);
- paint.setShader(shader);
- // Restore the default transfer mode (src_over)
- paint.setXfermode(null);
- }
- }
- public void run() {
- long now = AnimationUtils.currentAnimationTimeMillis();
- if (now >= fadeStartTime) {
- // the animation fades the scrollbars out by changing
- // the opacity (alpha) from fully opaque to fully
- // transparent
- int nextFrame = (int) now;
- int framesCount = 0;
- Interpolator interpolator = scrollBarInterpolator;
- // Start opaque
- interpolator.setKeyFrame(framesCount++, nextFrame, OPAQUE);
- // End transparent
- nextFrame += scrollBarFadeDuration;
- interpolator.setKeyFrame(framesCount, nextFrame, TRANSPARENT);
- state = FADING;
- // Kick off the fade animation
- host.invalidate(true);
- }
- }
- }
- /**
- * Resuable callback for sending
- * {@link AccessibilityEvent#TYPE_VIEW_SCROLLED} accessibility event.
- */
- private class SendViewScrolledAccessibilityEvent implements Runnable {
- public volatile boolean mIsPending;
- public void run() {
- sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SCROLLED);
- mIsPending = false;
- }
- }
- /**
- *
- * This class represents a delegate that can be registered in a {@link View}
- * to enhance accessibility support via composition rather via inheritance.
- * It is specifically targeted to widget developers that extend basic View
- * classes i.e. classes in package android.view, that would like their
- * applications to be backwards compatible.
- *
- *
- * A scenario in which a developer would like to use an accessibility delegate
- * is overriding a method introduced in a later API version then the minimal API
- * version supported by the application. For example, the method
- * {@link View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)} is not available
- * in API version 4 when the accessibility APIs were first introduced. If a
- * developer would like his application to run on API version 4 devices (assuming
- * all other APIs used by the application are version 4 or lower) and take advantage
- * of this method, instead of overriding the method which would break the application's
- * backwards compatibility, he can override the corresponding method in this
- * delegate and register the delegate in the target View if the API version of
- * the system is high enough i.e. the API version is same or higher to the API
- * version that introduced
- * {@link View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)}.
- *
- *
- * Here is an example implementation:
- *
- *
- * if (Build.VERSION.SDK_INT >= 14) {
- * // If the API version is equal of higher than the version in
- * // which onInitializeAccessibilityNodeInfo was introduced we
- * // register a delegate with a customized implementation.
- * View view = findViewById(R.id.view_id);
- * view.setAccessibilityDelegate(new AccessibilityDelegate() {
- * public void onInitializeAccessibilityNodeInfo(View host,
- * AccessibilityNodeInfo info) {
- * // Let the default implementation populate the info.
- * super.onInitializeAccessibilityNodeInfo(host, info);
- * // Set some other information.
- * info.setEnabled(host.isEnabled());
- * }
- * });
- * }
- *
- *
- * This delegate contains methods that correspond to the accessibility methods
- * in View. If a delegate has been specified the implementation in View hands
- * off handling to the corresponding method in this delegate. The default
- * implementation the delegate methods behaves exactly as the corresponding
- * method in View for the case of no accessibility delegate been set. Hence,
- * to customize the behavior of a View method, clients can override only the
- * corresponding delegate method without altering the behavior of the rest
- * accessibility related methods of the host view.
- *
- */
- public static class AccessibilityDelegate {
- /**
- * Sends an accessibility event of the given type. If accessibility is not
- * enabled this method has no effect.
- *
- * The default implementation behaves as {@link View#sendAccessibilityEvent(int)
- * View#sendAccessibilityEvent(int)} for the case of no accessibility delegate
- * been set.
- *
- *
- * @param host The View hosting the delegate.
- * @param eventType The type of the event to send.
- *
- * @see View#sendAccessibilityEvent(int) View#sendAccessibilityEvent(int)
- */
- public void sendAccessibilityEvent(View host, int eventType) {
- host.sendAccessibilityEventInternal(eventType);
- }
- /**
- * Sends an accessibility event. This method behaves exactly as
- * {@link #sendAccessibilityEvent(View, int)} but takes as an argument an
- * empty {@link AccessibilityEvent} and does not perform a check whether
- * accessibility is enabled.
- *
- * The default implementation behaves as
- * {@link View#sendAccessibilityEventUnchecked(AccessibilityEvent)
- * View#sendAccessibilityEventUnchecked(AccessibilityEvent)} for
- * the case of no accessibility delegate been set.
- *
- *
- * @param host The View hosting the delegate.
- * @param event The event to send.
- *
- * @see View#sendAccessibilityEventUnchecked(AccessibilityEvent)
- * View#sendAccessibilityEventUnchecked(AccessibilityEvent)
- */
- public void sendAccessibilityEventUnchecked(View host, AccessibilityEvent event) {
- host.sendAccessibilityEventUncheckedInternal(event);
- }
- /**
- * Dispatches an {@link AccessibilityEvent} to the host {@link View} first and then
- * to its children for adding their text content to the event.
- *
- * The default implementation behaves as
- * {@link View#dispatchPopulateAccessibilityEvent(AccessibilityEvent)
- * View#dispatchPopulateAccessibilityEvent(AccessibilityEvent)} for
- * the case of no accessibility delegate been set.
- *
- *
- * @param host The View hosting the delegate.
- * @param event The event.
- * @return True if the event population was completed.
- *
- * @see View#dispatchPopulateAccessibilityEvent(AccessibilityEvent)
- * View#dispatchPopulateAccessibilityEvent(AccessibilityEvent)
- */
- public boolean dispatchPopulateAccessibilityEvent(View host, AccessibilityEvent event) {
- return host.dispatchPopulateAccessibilityEventInternal(event);
- }
- /**
- * Gives a chance to the host View to populate the accessibility event with its
- * text content.
- *
- * The default implementation behaves as
- * {@link View#onPopulateAccessibilityEvent(AccessibilityEvent)
- * View#onPopulateAccessibilityEvent(AccessibilityEvent)} for
- * the case of no accessibility delegate been set.
- *
- *
- * @param host The View hosting the delegate.
- * @param event The accessibility event which to populate.
- *
- * @see View#onPopulateAccessibilityEvent(AccessibilityEvent)
- * View#onPopulateAccessibilityEvent(AccessibilityEvent)
- */
- public void onPopulateAccessibilityEvent(View host, AccessibilityEvent event) {
- host.onPopulateAccessibilityEventInternal(event);
- }
- /**
- * Initializes an {@link AccessibilityEvent} with information about the
- * the host View which is the event source.
- *
- * The default implementation behaves as
- * {@link View#onInitializeAccessibilityEvent(AccessibilityEvent)
- * View#onInitializeAccessibilityEvent(AccessibilityEvent)} for
- * the case of no accessibility delegate been set.
- *
- *
- * @param host The View hosting the delegate.
- * @param event The event to initialize.
- *
- * @see View#onInitializeAccessibilityEvent(AccessibilityEvent)
- * View#onInitializeAccessibilityEvent(AccessibilityEvent)
- */
- public void onInitializeAccessibilityEvent(View host, AccessibilityEvent event) {
- host.onInitializeAccessibilityEventInternal(event);
- }
- /**
- * Initializes an {@link AccessibilityNodeInfo} with information about the host view.
- *
- * The default implementation behaves as
- * {@link View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)
- * View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)} for
- * the case of no accessibility delegate been set.
- *
- *
- * @param host The View hosting the delegate.
- * @param info The instance to initialize.
- *
- * @see View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)
- * View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)
- */
- public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) {
- host.onInitializeAccessibilityNodeInfoInternal(info);
- }
- /**
- * Called when a child of the host View has requested sending an
- * {@link AccessibilityEvent} and gives an opportunity to the parent (the host)
- * to augment the event.
- *
- * The default implementation behaves as
- * {@link ViewGroup#onRequestSendAccessibilityEvent(View, AccessibilityEvent)
- * ViewGroup#onRequestSendAccessibilityEvent(View, AccessibilityEvent)} for
- * the case of no accessibility delegate been set.
- *
- *
- * @param host The View hosting the delegate.
- * @param child The child which requests sending the event.
- * @param event The event to be sent.
- * @return True if the event should be sent
- *
- * @see ViewGroup#onRequestSendAccessibilityEvent(View, AccessibilityEvent)
- * ViewGroup#onRequestSendAccessibilityEvent(View, AccessibilityEvent)
- */
- public boolean onRequestSendAccessibilityEvent(ViewGroup host, View child,
- AccessibilityEvent event) {
- return host.onRequestSendAccessibilityEventInternal(child, event);
- }
- /**
- * Gets the provider for managing a virtual view hierarchy rooted at this View
- * and reported to {@link android.accessibilityservice.AccessibilityService}s
- * that explore the window content.
- *
- * The default implementation behaves as
- * {@link View#getAccessibilityNodeProvider() View#getAccessibilityNodeProvider()} for
- * the case of no accessibility delegate been set.
- *
- *
- * @return The provider.
- *
- * @see AccessibilityNodeProvider
- */
- public AccessibilityNodeProvider getAccessibilityNodeProvider(View host) {
- return null;
- }
- }
-}
diff --git a/src/test/resources/test_candidates/ch_8_classes/sec_8_4_method_declarations/sec_8_4_3_method_modifiers/sec_8_4_3_4_native_methods/SimpleNativeMethod.java b/src/test/resources/test_candidates/ch_8_classes/sec_8_4_method_declarations/sec_8_4_3_method_modifiers/sec_8_4_3_4_native_methods/SimpleNativeMethod.java
index bf221900..4cac7faa 100644
--- a/src/test/resources/test_candidates/ch_8_classes/sec_8_4_method_declarations/sec_8_4_3_method_modifiers/sec_8_4_3_4_native_methods/SimpleNativeMethod.java
+++ b/src/test/resources/test_candidates/ch_8_classes/sec_8_4_method_declarations/sec_8_4_3_method_modifiers/sec_8_4_3_4_native_methods/SimpleNativeMethod.java
@@ -1,9 +1,11 @@
+// @todo #165:90m method() is left for the future
+
public class SimpleNativeMethod {
static native void method();
public static void main(String[] args) {
- //method(); TODO: I leave it for the future
+ //method();
System.out.println("passed");
}
}
diff --git a/src/test/resources/test_ready/ch_8_classes/sec_8_4_method_declarations/sec_8_4_3_method_modifiers/sec_8_4_3_4_native_methods/SampleTest.java b/src/test/resources/test_ready/ch_8_classes/sec_8_4_method_declarations/sec_8_4_3_method_modifiers/sec_8_4_3_4_native_methods/SampleTest.java
index bf221900..d080780c 100644
--- a/src/test/resources/test_ready/ch_8_classes/sec_8_4_method_declarations/sec_8_4_3_method_modifiers/sec_8_4_3_4_native_methods/SampleTest.java
+++ b/src/test/resources/test_ready/ch_8_classes/sec_8_4_method_declarations/sec_8_4_3_method_modifiers/sec_8_4_3_4_native_methods/SampleTest.java
@@ -1,9 +1,10 @@
+// @todo #165:90m method() is left for the future
public class SimpleNativeMethod {
static native void method();
public static void main(String[] args) {
- //method(); TODO: I leave it for the future
+ //method();
System.out.println("passed");
}
}