diff options
| -rw-r--r-- | api/current.txt | 17 | ||||
| -rw-r--r-- | api/system-current.txt | 17 | ||||
| -rw-r--r-- | core/java/android/view/View.java | 339 | ||||
| -rw-r--r-- | core/java/android/widget/FrameLayout.java | 326 | ||||
| -rw-r--r-- | core/res/res/values/attrs.xml | 127 |
5 files changed, 421 insertions, 405 deletions
diff --git a/api/current.txt b/api/current.txt index d8d8998d5a43..5478de2c7302 100644 --- a/api/current.txt +++ b/api/current.txt @@ -34442,6 +34442,10 @@ package android.view { method public boolean getFitsSystemWindows(); method public java.util.ArrayList<android.view.View> getFocusables(int); method public void getFocusedRect(android.graphics.Rect); + method public android.graphics.drawable.Drawable getForeground(); + method public int getForegroundGravity(); + method public android.content.res.ColorStateList getForegroundTintList(); + method public android.graphics.PorterDuff.Mode getForegroundTintMode(); method public boolean getGlobalVisibleRect(android.graphics.Rect, android.graphics.Point); method public final boolean getGlobalVisibleRect(android.graphics.Rect); method public android.os.Handler getHandler(); @@ -34613,6 +34617,7 @@ package android.view { method protected void onDisplayHint(int); method public boolean onDragEvent(android.view.DragEvent); method protected void onDraw(android.graphics.Canvas); + method public void onDrawForeground(android.graphics.Canvas); method protected final void onDrawScrollBars(android.graphics.Canvas); method public boolean onFilterTouchEventForSecurity(android.view.MotionEvent); method protected void onFinishInflate(); @@ -34718,6 +34723,10 @@ package android.view { method public void setFitsSystemWindows(boolean); method public void setFocusable(boolean); method public void setFocusableInTouchMode(boolean); + method public void setForeground(android.graphics.drawable.Drawable); + method public void setForegroundGravity(int); + method public void setForegroundTintList(android.content.res.ColorStateList); + method public void setForegroundTintMode(android.graphics.PorterDuff.Mode); method public void setHapticFeedbackEnabled(boolean); method public void setHasTransientState(boolean); method public void setHorizontalFadingEdgeEnabled(boolean); @@ -38546,16 +38555,8 @@ package android.widget { ctor public FrameLayout(android.content.Context, android.util.AttributeSet, int); ctor public FrameLayout(android.content.Context, android.util.AttributeSet, int, int); method public deprecated boolean getConsiderGoneChildrenWhenMeasuring(); - method public android.graphics.drawable.Drawable getForeground(); - method public int getForegroundGravity(); - method public android.content.res.ColorStateList getForegroundTintList(); - method public android.graphics.PorterDuff.Mode getForegroundTintMode(); method public boolean getMeasureAllChildren(); method protected void onLayout(boolean, int, int, int, int); - method public void setForeground(android.graphics.drawable.Drawable); - method public void setForegroundGravity(int); - method public void setForegroundTintList(android.content.res.ColorStateList); - method public void setForegroundTintMode(android.graphics.PorterDuff.Mode); method public void setMeasureAllChildren(boolean); } diff --git a/api/system-current.txt b/api/system-current.txt index 71474a30ab50..fb7037e5de62 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -36806,6 +36806,10 @@ package android.view { method public boolean getFitsSystemWindows(); method public java.util.ArrayList<android.view.View> getFocusables(int); method public void getFocusedRect(android.graphics.Rect); + method public android.graphics.drawable.Drawable getForeground(); + method public int getForegroundGravity(); + method public android.content.res.ColorStateList getForegroundTintList(); + method public android.graphics.PorterDuff.Mode getForegroundTintMode(); method public boolean getGlobalVisibleRect(android.graphics.Rect, android.graphics.Point); method public final boolean getGlobalVisibleRect(android.graphics.Rect); method public android.os.Handler getHandler(); @@ -36977,6 +36981,7 @@ package android.view { method protected void onDisplayHint(int); method public boolean onDragEvent(android.view.DragEvent); method protected void onDraw(android.graphics.Canvas); + method public void onDrawForeground(android.graphics.Canvas); method protected final void onDrawScrollBars(android.graphics.Canvas); method public boolean onFilterTouchEventForSecurity(android.view.MotionEvent); method protected void onFinishInflate(); @@ -37082,6 +37087,10 @@ package android.view { method public void setFitsSystemWindows(boolean); method public void setFocusable(boolean); method public void setFocusableInTouchMode(boolean); + method public void setForeground(android.graphics.drawable.Drawable); + method public void setForegroundGravity(int); + method public void setForegroundTintList(android.content.res.ColorStateList); + method public void setForegroundTintMode(android.graphics.PorterDuff.Mode); method public void setHapticFeedbackEnabled(boolean); method public void setHasTransientState(boolean); method public void setHorizontalFadingEdgeEnabled(boolean); @@ -41211,16 +41220,8 @@ package android.widget { ctor public FrameLayout(android.content.Context, android.util.AttributeSet, int); ctor public FrameLayout(android.content.Context, android.util.AttributeSet, int, int); method public deprecated boolean getConsiderGoneChildrenWhenMeasuring(); - method public android.graphics.drawable.Drawable getForeground(); - method public int getForegroundGravity(); - method public android.content.res.ColorStateList getForegroundTintList(); - method public android.graphics.PorterDuff.Mode getForegroundTintMode(); method public boolean getMeasureAllChildren(); method protected void onLayout(boolean, int, int, int, int); - method public void setForeground(android.graphics.drawable.Drawable); - method public void setForegroundGravity(int); - method public void setForegroundTintList(android.content.res.ColorStateList); - method public void setForegroundTintMode(android.graphics.PorterDuff.Mode); method public void setMeasureAllChildren(boolean); } diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index f5de8e3d505c..c29b5c965c4a 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -3168,6 +3168,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback, private Drawable mBackground; private TintInfo mBackgroundTint; + @ViewDebug.ExportedProperty(deepExport = true, prefix = "fg_") + private ForegroundInfo mForegroundInfo; + /** * RenderNode used for backgrounds. * <p> @@ -3182,13 +3185,23 @@ public class View implements Drawable.Callback, KeyEvent.Callback, private String mTransitionName; - private static class TintInfo { + static class TintInfo { ColorStateList mTintList; PorterDuff.Mode mTintMode; boolean mHasTintMode; boolean mHasTintList; } + private static class ForegroundInfo { + private Drawable mDrawable; + private TintInfo mTintInfo; + private int mGravity = Gravity.START | Gravity.TOP; + private boolean mInsidePadding = true; + private boolean mBoundsChanged; + private final Rect mSelfBounds = new Rect(); + private final Rect mOverlayBounds = new Rect(); + } + static class ListenerInfo { /** * Listener used to dispatch focus change events. @@ -4056,6 +4069,25 @@ public class View implements Drawable.Callback, KeyEvent.Callback, setOutlineProviderFromAttribute(a.getInt(R.styleable.View_outlineProvider, PROVIDER_BACKGROUND)); break; + case R.styleable.View_foreground: + setForeground(a.getDrawable(attr)); + break; + case R.styleable.View_foregroundGravity: + setForegroundGravity(a.getInt(attr, Gravity.NO_GRAVITY)); + break; + case R.styleable.View_foregroundTintMode: + setForegroundTintMode(Drawable.parseTintMode(a.getInt(attr, -1), null)); + break; + case R.styleable.View_foregroundTint: + setForegroundTintList(a.getColorStateList(attr)); + break; + case R.styleable.View_foregroundInsidePadding: + if (mForegroundInfo == null) { + mForegroundInfo = new ForegroundInfo(); + } + mForegroundInfo.mInsidePadding = a.getBoolean(attr, + mForegroundInfo.mInsidePadding); + break; } } @@ -8801,6 +8833,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback, if (dr != null && visible != dr.isVisible()) { dr.setVisible(visible, false); } + final Drawable fg = mForegroundInfo != null ? mForegroundInfo.mDrawable : null; + if (fg != null && visible != fg.isVisible()) { + fg.setVisible(visible, false); + } } /** @@ -9917,6 +9953,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } mBackgroundSizeChanged = true; + if (mForegroundInfo != null) { + mForegroundInfo.mBoundsChanged = true; + } final AttachInfo ai = mAttachInfo; if (ai != null) { @@ -10755,6 +10794,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback, invalidate(true); } mBackgroundSizeChanged = true; + if (mForegroundInfo != null) { + mForegroundInfo.mBoundsChanged = true; + } invalidateParentIfNeeded(); if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) == PFLAG2_VIEW_QUICK_REJECTED) { // View was rejected last time it was drawn by its parent; this may have changed @@ -10820,6 +10862,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback, invalidate(true); } mBackgroundSizeChanged = true; + if (mForegroundInfo != null) { + mForegroundInfo.mBoundsChanged = true; + } invalidateParentIfNeeded(); if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) == PFLAG2_VIEW_QUICK_REJECTED) { // View was rejected last time it was drawn by its parent; this may have changed @@ -10879,6 +10924,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback, invalidate(true); } mBackgroundSizeChanged = true; + if (mForegroundInfo != null) { + mForegroundInfo.mBoundsChanged = true; + } invalidateParentIfNeeded(); if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) == PFLAG2_VIEW_QUICK_REJECTED) { // View was rejected last time it was drawn by its parent; this may have changed @@ -10935,6 +10983,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback, invalidate(true); } mBackgroundSizeChanged = true; + if (mForegroundInfo != null) { + mForegroundInfo.mBoundsChanged = true; + } invalidateParentIfNeeded(); if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) == PFLAG2_VIEW_QUICK_REJECTED) { // View was rejected last time it was drawn by its parent; this may have changed @@ -15313,13 +15364,14 @@ public class View implements Drawable.Callback, KeyEvent.Callback, // Step 4, draw the children dispatchDraw(canvas); - // Step 6, draw decorations (scrollbars) - onDrawScrollBars(canvas); - + // Overlay is part of the content and draws beneath Foreground if (mOverlay != null && !mOverlay.isEmpty()) { mOverlay.getOverlayView().dispatchDraw(canvas); } + // Step 6, draw decorations (foreground, scrollbars) + onDrawForeground(canvas); + // we're done... return; } @@ -15461,12 +15513,13 @@ public class View implements Drawable.Callback, KeyEvent.Callback, canvas.restoreToCount(saveCount); - // Step 6, draw decorations (scrollbars) - onDrawScrollBars(canvas); - + // Overlay is part of the content and draws beneath Foreground if (mOverlay != null && !mOverlay.isEmpty()) { mOverlay.getOverlayView().dispatchDraw(canvas); } + + // Step 6, draw decorations (foreground, scrollbars) + onDrawForeground(canvas); } /** @@ -15849,6 +15902,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback, mPrivateFlags |= drawn; mBackgroundSizeChanged = true; + if (mForegroundInfo != null) { + mForegroundInfo.mBoundsChanged = true; + } notifySubtreeAccessibilityStateChangedIfNeeded(); } @@ -15992,6 +16048,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback, if (mBackground != null) { mBackground.setLayoutDirection(layoutDirection); } + if (mForegroundInfo != null && mForegroundInfo.mDrawable != null) { + mForegroundInfo.mDrawable.setLayoutDirection(layoutDirection); + } mPrivateFlags2 |= PFLAG2_DRAWABLE_RESOLVED; onResolveDrawables(layoutDirection); } @@ -16047,7 +16106,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback, */ @CallSuper protected boolean verifyDrawable(Drawable who) { - return who == mBackground || (mScrollCache != null && mScrollCache.scrollBar == who); + return who == mBackground || (mScrollCache != null && mScrollCache.scrollBar == who) + || (mForegroundInfo != null && mForegroundInfo.mDrawable == who); } /** @@ -16065,9 +16125,14 @@ public class View implements Drawable.Callback, KeyEvent.Callback, protected void drawableStateChanged() { final int[] state = getDrawableState(); - final Drawable d = mBackground; - if (d != null && d.isStateful()) { - d.setState(state); + final Drawable bg = mBackground; + if (bg != null && bg.isStateful()) { + bg.setState(state); + } + + final Drawable fg = mForegroundInfo != null ? mForegroundInfo.mDrawable : null; + if (fg != null && fg.isStateful()) { + fg.setState(state); } if (mScrollCache != null) { @@ -16099,6 +16164,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback, if (mBackground != null) { mBackground.setHotspot(x, y); } + if (mForegroundInfo != null && mForegroundInfo.mDrawable != null) { + mForegroundInfo.mDrawable.setHotspot(x, y); + } dispatchDrawableHotspotChanged(x, y); } @@ -16270,6 +16338,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback, if (mStateListAnimator != null) { mStateListAnimator.jumpToCurrentState(); } + if (mForegroundInfo != null && mForegroundInfo.mDrawable != null) { + mForegroundInfo.mDrawable.jumpToCurrentState(); + } } /** @@ -16554,6 +16625,248 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } /** + * Returns the drawable used as the foreground of this View. The + * foreground drawable, if non-null, is always drawn on top of the view's content. + * + * @return a Drawable or null if no foreground was set + * + * @see #onDrawForeground(Canvas) + */ + public Drawable getForeground() { + return mForegroundInfo != null ? mForegroundInfo.mDrawable : null; + } + + /** + * Supply a Drawable that is to be rendered on top of all of the content in the view. + * + * @param foreground the Drawable to be drawn on top of the children + * + * @attr ref android.R.styleable#View_foreground + */ + public void setForeground(Drawable foreground) { + if (mForegroundInfo == null) { + if (foreground == null) { + // Nothing to do. + return; + } + mForegroundInfo = new ForegroundInfo(); + } + + if (foreground == mForegroundInfo.mDrawable) { + // Nothing to do + return; + } + + if (mForegroundInfo.mDrawable != null) { + mForegroundInfo.mDrawable.setCallback(null); + unscheduleDrawable(mForegroundInfo.mDrawable); + } + + mForegroundInfo.mDrawable = foreground; + if (foreground != null) { + setWillNotDraw(false); + foreground.setCallback(this); + foreground.setLayoutDirection(getLayoutDirection()); + if (foreground.isStateful()) { + foreground.setState(getDrawableState()); + } + applyForegroundTint(); + } + requestLayout(); + invalidate(); + } + + /** + * Magic bit used to support features of framework-internal window decor implementation details. + * This used to live exclusively in FrameLayout. + * + * @return true if the foreground should draw inside the padding region or false + * if it should draw inset by the view's padding + * @hide internal use only; only used by FrameLayout and internal screen layouts. + */ + public boolean isForegroundInsidePadding() { + return mForegroundInfo != null ? mForegroundInfo.mInsidePadding : true; + } + + /** + * Describes how the foreground is positioned. + * + * @return foreground gravity. + * + * @see #setForegroundGravity(int) + * + * @attr ref android.R.styleable#View_foregroundGravity + */ + public int getForegroundGravity() { + return mForegroundInfo != null ? mForegroundInfo.mGravity + : Gravity.START | Gravity.TOP; + } + + /** + * Describes how the foreground is positioned. Defaults to START and TOP. + * + * @param gravity see {@link android.view.Gravity} + * + * @see #getForegroundGravity() + * + * @attr ref android.R.styleable#View_foregroundGravity + */ + public void setForegroundGravity(int gravity) { + if (mForegroundInfo == null) { + mForegroundInfo = new ForegroundInfo(); + } + + if (mForegroundInfo.mGravity != gravity) { + if ((gravity & Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK) == 0) { + gravity |= Gravity.START; + } + + if ((gravity & Gravity.VERTICAL_GRAVITY_MASK) == 0) { + gravity |= Gravity.TOP; + } + + mForegroundInfo.mGravity = gravity; + requestLayout(); + } + } + + /** + * Applies a tint to the foreground drawable. Does not modify the current tint + * mode, which is {@link PorterDuff.Mode#SRC_IN} by default. + * <p> + * Subsequent calls to {@link #setForeground(Drawable)} will automatically + * mutate the drawable and apply the specified tint and tint mode using + * {@link Drawable#setTintList(ColorStateList)}. + * + * @param tint the tint to apply, may be {@code null} to clear tint + * + * @attr ref android.R.styleable#View_foregroundTint + * @see #getForegroundTintList() + * @see Drawable#setTintList(ColorStateList) + */ + public void setForegroundTintList(@Nullable ColorStateList tint) { + if (mForegroundInfo == null) { + mForegroundInfo = new ForegroundInfo(); + } + if (mForegroundInfo.mTintInfo == null) { + mForegroundInfo.mTintInfo = new TintInfo(); + } + mForegroundInfo.mTintInfo.mTintList = tint; + mForegroundInfo.mTintInfo.mHasTintList = true; + + applyForegroundTint(); + } + + /** + * Return the tint applied to the foreground drawable, if specified. + * + * @return the tint applied to the foreground drawable + * @attr ref android.R.styleable#View_foregroundTint + * @see #setForegroundTintList(ColorStateList) + */ + @Nullable + public ColorStateList getForegroundTintList() { + return mForegroundInfo != null && mForegroundInfo.mTintInfo != null + ? mBackgroundTint.mTintList : null; + } + + /** + * Specifies the blending mode used to apply the tint specified by + * {@link #setForegroundTintList(ColorStateList)}} to the background + * drawable. The default mode is {@link PorterDuff.Mode#SRC_IN}. + * + * @param tintMode the blending mode used to apply the tint, may be + * {@code null} to clear tint + * @attr ref android.R.styleable#View_foregroundTintMode + * @see #getForegroundTintMode() + * @see Drawable#setTintMode(PorterDuff.Mode) + */ + public void setForegroundTintMode(@Nullable PorterDuff.Mode tintMode) { + if (mBackgroundTint == null) { + mBackgroundTint = new TintInfo(); + } + mBackgroundTint.mTintMode = tintMode; + mBackgroundTint.mHasTintMode = true; + + applyBackgroundTint(); + } + + /** + * Return the blending mode used to apply the tint to the foreground + * drawable, if specified. + * + * @return the blending mode used to apply the tint to the foreground + * drawable + * @attr ref android.R.styleable#View_foregroundTintMode + * @see #setBackgroundTintMode(PorterDuff.Mode) + */ + @Nullable + public PorterDuff.Mode getForegroundTintMode() { + return mForegroundInfo != null && mForegroundInfo.mTintInfo != null + ? mForegroundInfo.mTintInfo.mTintMode : null; + } + + private void applyForegroundTint() { + if (mForegroundInfo != null && mForegroundInfo.mDrawable != null + && mForegroundInfo.mTintInfo != null) { + final TintInfo tintInfo = mForegroundInfo.mTintInfo; + if (tintInfo.mHasTintList || tintInfo.mHasTintMode) { + mForegroundInfo.mDrawable = mForegroundInfo.mDrawable.mutate(); + + if (tintInfo.mHasTintList) { + mForegroundInfo.mDrawable.setTintList(tintInfo.mTintList); + } + + if (tintInfo.mHasTintMode) { + mForegroundInfo.mDrawable.setTintMode(tintInfo.mTintMode); + } + + // The drawable (or one of its children) may not have been + // stateful before applying the tint, so let's try again. + if (mForegroundInfo.mDrawable.isStateful()) { + mForegroundInfo.mDrawable.setState(getDrawableState()); + } + } + } + } + + /** + * Draw any foreground content for this view. + * + * <p>Foreground content may consist of scroll bars, a {@link #setForeground foreground} + * drawable or other view-specific decorations. The foreground is drawn on top of the + * primary view content.</p> + * + * @param canvas canvas to draw into + */ + public void onDrawForeground(Canvas canvas) { + onDrawScrollBars(canvas); + + final Drawable foreground = mForegroundInfo != null ? mForegroundInfo.mDrawable : null; + if (foreground != null) { + if (mForegroundInfo.mBoundsChanged) { + mForegroundInfo.mBoundsChanged = false; + final Rect selfBounds = mForegroundInfo.mSelfBounds; + final Rect overlayBounds = mForegroundInfo.mOverlayBounds; + + if (mForegroundInfo.mInsidePadding) { + selfBounds.set(0, 0, getWidth(), getHeight()); + } else { + selfBounds.set(getPaddingLeft(), getPaddingTop(), + getWidth() - getPaddingRight(), getHeight() - getPaddingBottom()); + } + + final int ld = getLayoutDirection(); + Gravity.apply(mForegroundInfo.mGravity, foreground.getIntrinsicWidth(), + foreground.getIntrinsicHeight(), selfBounds, overlayBounds, ld); + foreground.setBounds(overlayBounds); + } + + foreground.draw(canvas); + } + } + + /** * 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}, @@ -18090,6 +18403,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback, // parts from this transparent region. applyDrawableToTransparentRegion(mBackground, region); } + final Drawable foreground = mForegroundInfo != null ? mForegroundInfo.mDrawable : null; + if (foreground != null) { + applyDrawableToTransparentRegion(mForegroundInfo.mDrawable, region); + } } return true; } diff --git a/core/java/android/widget/FrameLayout.java b/core/java/android/widget/FrameLayout.java index f6d198b214e9..0602944e0de6 100644 --- a/core/java/android/widget/FrameLayout.java +++ b/core/java/android/widget/FrameLayout.java @@ -53,8 +53,6 @@ import com.android.internal.R; * only if {@link #setMeasureAllChildren(boolean) setConsiderGoneChildrenWhenMeasuring()} * is set to true. * - * @attr ref android.R.styleable#FrameLayout_foreground - * @attr ref android.R.styleable#FrameLayout_foregroundGravity * @attr ref android.R.styleable#FrameLayout_measureAllChildren */ @RemoteView @@ -64,13 +62,6 @@ public class FrameLayout extends ViewGroup { @ViewDebug.ExportedProperty(category = "measurement") boolean mMeasureAllChildren = false; - @ViewDebug.ExportedProperty(category = "drawing") - private Drawable mForeground; - private ColorStateList mForegroundTintList = null; - private PorterDuff.Mode mForegroundTintMode = null; - private boolean mHasForegroundTint = false; - private boolean mHasForegroundTintMode = false; - @ViewDebug.ExportedProperty(category = "padding") private int mForegroundPaddingLeft = 0; @@ -85,15 +76,6 @@ public class FrameLayout extends ViewGroup { private final Rect mSelfBounds = new Rect(); private final Rect mOverlayBounds = new Rect(); - - @ViewDebug.ExportedProperty(category = "drawing") - private int mForegroundGravity = Gravity.FILL; - - /** {@hide} */ - @ViewDebug.ExportedProperty(category = "drawing") - protected boolean mForegroundInPadding = true; - - boolean mForegroundBoundsChanged = false; private final ArrayList<View> mMatchParentChildren = new ArrayList<View>(1); @@ -115,48 +97,12 @@ public class FrameLayout extends ViewGroup { final TypedArray a = context.obtainStyledAttributes( attrs, com.android.internal.R.styleable.FrameLayout, defStyleAttr, defStyleRes); - - mForegroundGravity = a.getInt( - com.android.internal.R.styleable.FrameLayout_foregroundGravity, mForegroundGravity); - - final Drawable d = a.getDrawable(com.android.internal.R.styleable.FrameLayout_foreground); - if (d != null) { - setForeground(d); - } if (a.getBoolean(com.android.internal.R.styleable.FrameLayout_measureAllChildren, false)) { setMeasureAllChildren(true); } - if (a.hasValue(R.styleable.FrameLayout_foregroundTintMode)) { - mForegroundTintMode = Drawable.parseTintMode(a.getInt( - R.styleable.FrameLayout_foregroundTintMode, -1), mForegroundTintMode); - mHasForegroundTintMode = true; - } - - if (a.hasValue(R.styleable.FrameLayout_foregroundTint)) { - mForegroundTintList = a.getColorStateList(R.styleable.FrameLayout_foregroundTint); - mHasForegroundTint = true; - } - - mForegroundInPadding = a.getBoolean(R.styleable.FrameLayout_foregroundInsidePadding, true); - a.recycle(); - - applyForegroundTint(); - } - - /** - * Describes how the foreground is positioned. - * - * @return foreground gravity. - * - * @see #setForegroundGravity(int) - * - * @attr ref android.R.styleable#FrameLayout_foregroundGravity - */ - public int getForegroundGravity() { - return mForegroundGravity; } /** @@ -166,25 +112,18 @@ public class FrameLayout extends ViewGroup { * * @see #getForegroundGravity() * - * @attr ref android.R.styleable#FrameLayout_foregroundGravity + * @attr ref android.R.styleable#View_foregroundGravity */ @android.view.RemotableViewMethod public void setForegroundGravity(int foregroundGravity) { - if (mForegroundGravity != foregroundGravity) { - if ((foregroundGravity & Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK) == 0) { - foregroundGravity |= Gravity.START; - } - - if ((foregroundGravity & Gravity.VERTICAL_GRAVITY_MASK) == 0) { - foregroundGravity |= Gravity.TOP; - } - - mForegroundGravity = foregroundGravity; - + if (getForegroundGravity() != foregroundGravity) { + super.setForegroundGravity(foregroundGravity); - if (mForegroundGravity == Gravity.FILL && mForeground != null) { + // calling get* again here because the set above may apply default constraints + final Drawable foreground = getForeground(); + if (getForegroundGravity() == Gravity.FILL && foreground != null) { Rect padding = new Rect(); - if (mForeground.getPadding(padding)) { + if (foreground.getPadding(padding)) { mForegroundPaddingLeft = padding.left; mForegroundPaddingTop = padding.top; mForegroundPaddingRight = padding.right; @@ -201,53 +140,6 @@ public class FrameLayout extends ViewGroup { } } - @Override - protected void onVisibilityChanged(@NonNull View changedView, @Visibility int visibility) { - super.onVisibilityChanged(changedView, visibility); - - final Drawable dr = mForeground; - if (dr != null) { - final boolean visible = visibility == VISIBLE && getVisibility() == VISIBLE; - if (visible != dr.isVisible()) { - dr.setVisible(visible, false); - } - } - } - - /** - * {@inheritDoc} - */ - @Override - protected boolean verifyDrawable(Drawable who) { - return super.verifyDrawable(who) || (who == mForeground); - } - - @Override - public void jumpDrawablesToCurrentState() { - super.jumpDrawablesToCurrentState(); - if (mForeground != null) mForeground.jumpToCurrentState(); - } - - /** - * {@inheritDoc} - */ - @Override - protected void drawableStateChanged() { - super.drawableStateChanged(); - if (mForeground != null && mForeground.isStateful()) { - mForeground.setState(getDrawableState()); - } - } - - @Override - public void drawableHotspotChanged(float x, float y) { - super.drawableHotspotChanged(x, y); - - if (mForeground != null) { - mForeground.setHotspot(x, y); - } - } - /** * Returns a set of layout parameters with a width of * {@link android.view.ViewGroup.LayoutParams#MATCH_PARENT}, @@ -258,161 +150,23 @@ public class FrameLayout extends ViewGroup { return new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT); } - /** - * Supply a Drawable that is to be rendered on top of all of the child - * views in the frame layout. Any padding in the Drawable will be taken - * into account by ensuring that the children are inset to be placed - * inside of the padding area. - * - * @param d The Drawable to be drawn on top of the children. - * - * @attr ref android.R.styleable#FrameLayout_foreground - */ - public void setForeground(Drawable d) { - if (mForeground != d) { - if (mForeground != null) { - mForeground.setCallback(null); - unscheduleDrawable(mForeground); - } - - mForeground = d; - mForegroundPaddingLeft = 0; - mForegroundPaddingTop = 0; - mForegroundPaddingRight = 0; - mForegroundPaddingBottom = 0; - - if (d != null) { - setWillNotDraw(false); - d.setCallback(this); - d.setLayoutDirection(getLayoutDirection()); - if (d.isStateful()) { - d.setState(getDrawableState()); - } - applyForegroundTint(); - if (mForegroundGravity == Gravity.FILL) { - Rect padding = new Rect(); - if (d.getPadding(padding)) { - mForegroundPaddingLeft = padding.left; - mForegroundPaddingTop = padding.top; - mForegroundPaddingRight = padding.right; - mForegroundPaddingBottom = padding.bottom; - } - } - } else { - setWillNotDraw(true); - } - requestLayout(); - invalidate(); - } - } - - /** - * Returns the drawable used as the foreground of this FrameLayout. The - * foreground drawable, if non-null, is always drawn on top of the children. - * - * @return A Drawable or null if no foreground was set. - */ - public Drawable getForeground() { - return mForeground; - } - - /** - * Applies a tint to the foreground drawable. Does not modify the current - * tint mode, which is {@link PorterDuff.Mode#SRC_IN} by default. - * <p> - * Subsequent calls to {@link #setForeground(Drawable)} will automatically - * mutate the drawable and apply the specified tint and tint mode using - * {@link Drawable#setTintList(ColorStateList)}. - * - * @param tint the tint to apply, may be {@code null} to clear tint - * - * @attr ref android.R.styleable#FrameLayout_foregroundTint - * @see #getForegroundTintList() - * @see Drawable#setTintList(ColorStateList) - */ - public void setForegroundTintList(@Nullable ColorStateList tint) { - mForegroundTintList = tint; - mHasForegroundTint = true; - - applyForegroundTint(); - } - - /** - * @return the tint applied to the foreground drawable - * @attr ref android.R.styleable#FrameLayout_foregroundTint - * @see #setForegroundTintList(ColorStateList) - */ - @Nullable - public ColorStateList getForegroundTintList() { - return mForegroundTintList; - } - - /** - * Specifies the blending mode used to apply the tint specified by - * {@link #setForegroundTintList(ColorStateList)}} to the foreground drawable. - * The default mode is {@link PorterDuff.Mode#SRC_IN}. - * - * @param tintMode the blending mode used to apply the tint, may be - * {@code null} to clear tint - * @attr ref android.R.styleable#FrameLayout_foregroundTintMode - * @see #getForegroundTintMode() - * @see Drawable#setTintMode(PorterDuff.Mode) - */ - public void setForegroundTintMode(@Nullable PorterDuff.Mode tintMode) { - mForegroundTintMode = tintMode; - mHasForegroundTintMode = true; - - applyForegroundTint(); - } - - /** - * @return the blending mode used to apply the tint to the foreground - * drawable - * @attr ref android.R.styleable#FrameLayout_foregroundTintMode - * @see #setForegroundTintMode(PorterDuff.Mode) - */ - @Nullable - public PorterDuff.Mode getForegroundTintMode() { - return mForegroundTintMode; - } - - private void applyForegroundTint() { - if (mForeground != null && (mHasForegroundTint || mHasForegroundTintMode)) { - mForeground = mForeground.mutate(); - - if (mHasForegroundTint) { - mForeground.setTintList(mForegroundTintList); - } - - if (mHasForegroundTintMode) { - mForeground.setTintMode(mForegroundTintMode); - } - - // The drawable (or one of its children) may not have been - // stateful before applying the tint, so let's try again. - if (mForeground.isStateful()) { - mForeground.setState(getDrawableState()); - } - } - } - int getPaddingLeftWithForeground() { - return mForegroundInPadding ? Math.max(mPaddingLeft, mForegroundPaddingLeft) : + return isForegroundInsidePadding() ? Math.max(mPaddingLeft, mForegroundPaddingLeft) : mPaddingLeft + mForegroundPaddingLeft; } int getPaddingRightWithForeground() { - return mForegroundInPadding ? Math.max(mPaddingRight, mForegroundPaddingRight) : + return isForegroundInsidePadding() ? Math.max(mPaddingRight, mForegroundPaddingRight) : mPaddingRight + mForegroundPaddingRight; } private int getPaddingTopWithForeground() { - return mForegroundInPadding ? Math.max(mPaddingTop, mForegroundPaddingTop) : + return isForegroundInsidePadding() ? Math.max(mPaddingTop, mForegroundPaddingTop) : mPaddingTop + mForegroundPaddingTop; } private int getPaddingBottomWithForeground() { - return mForegroundInPadding ? Math.max(mPaddingBottom, mForegroundPaddingBottom) : + return isForegroundInsidePadding() ? Math.max(mPaddingBottom, mForegroundPaddingBottom) : mPaddingBottom + mForegroundPaddingBottom; } @@ -527,8 +281,6 @@ public class FrameLayout extends ViewGroup { final int parentTop = getPaddingTopWithForeground(); final int parentBottom = bottom - top - getPaddingBottomWithForeground(); - mForegroundBoundsChanged = true; - for (int i = 0; i < count; i++) { final View child = getChildAt(i); if (child.getVisibility() != GONE) { @@ -585,62 +337,6 @@ public class FrameLayout extends ViewGroup { } /** - * {@inheritDoc} - */ - @Override - protected void onSizeChanged(int w, int h, int oldw, int oldh) { - super.onSizeChanged(w, h, oldw, oldh); - mForegroundBoundsChanged = true; - } - - /** - * {@inheritDoc} - */ - @Override - public void draw(Canvas canvas) { - super.draw(canvas); - - if (mForeground != null) { - final Drawable foreground = mForeground; - - if (mForegroundBoundsChanged) { - mForegroundBoundsChanged = false; - final Rect selfBounds = mSelfBounds; - final Rect overlayBounds = mOverlayBounds; - - final int w = mRight-mLeft; - final int h = mBottom-mTop; - - if (mForegroundInPadding) { - selfBounds.set(0, 0, w, h); - } else { - selfBounds.set(mPaddingLeft, mPaddingTop, w - mPaddingRight, h - mPaddingBottom); - } - - final int layoutDirection = getLayoutDirection(); - Gravity.apply(mForegroundGravity, foreground.getIntrinsicWidth(), - foreground.getIntrinsicHeight(), selfBounds, overlayBounds, - layoutDirection); - foreground.setBounds(overlayBounds); - } - - foreground.draw(canvas); - } - } - - /** - * {@inheritDoc} - */ - @Override - public boolean gatherTransparentRegion(Region region) { - boolean opaque = super.gatherTransparentRegion(region); - if (region != null && mForeground != null) { - applyDrawableToTransparentRegion(mForeground, region); - } - return opaque; - } - - /** * Sets whether to consider all children, or just those in * the VISIBLE or INVISIBLE state, when measuring. Defaults to false. * diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml index b5576c5047a2..79a6bde84468 100644 --- a/core/res/res/values/attrs.xml +++ b/core/res/res/values/attrs.xml @@ -2633,6 +2633,70 @@ <enum name="paddedBounds" value="3" /> </attr> + <!-- Defines the drawable to draw over the content. This can be used as an overlay. + The foreground drawable participates in the padding of the content if the gravity + is set to fill. --> + <attr name="foreground" format="reference|color" /> + <!-- Defines the gravity to apply to the foreground drawable. The gravity defaults + to fill. --> + <attr name="foregroundGravity"> + <!-- Push object to the top of its container, not changing its size. --> + <flag name="top" value="0x30" /> + <!-- Push object to the bottom of its container, not changing its size. --> + <flag name="bottom" value="0x50" /> + <!-- Push object to the left of its container, not changing its size. --> + <flag name="left" value="0x03" /> + <!-- Push object to the right of its container, not changing its size. --> + <flag name="right" value="0x05" /> + <!-- Place object in the vertical center of its container, not changing its size. --> + <flag name="center_vertical" value="0x10" /> + <!-- Grow the vertical size of the object if needed so it completely fills its container. --> + <flag name="fill_vertical" value="0x70" /> + <!-- Place object in the horizontal center of its container, not changing its size. --> + <flag name="center_horizontal" value="0x01" /> + <!-- Grow the horizontal size of the object if needed so it completely fills its container. --> + <flag name="fill_horizontal" value="0x07" /> + <!-- Place the object in the center of its container in both the vertical and horizontal axis, not changing its size. --> + <flag name="center" value="0x11" /> + <!-- Grow the horizontal and vertical size of the object if needed so it completely fills its container. --> + <flag name="fill" value="0x77" /> + <!-- Additional option that can be set to have the top and/or bottom edges of + the child clipped to its container's bounds. + The clip will be based on the vertical gravity: a top gravity will clip the bottom + edge, a bottom gravity will clip the top edge, and neither will clip both edges. --> + <flag name="clip_vertical" value="0x80" /> + <!-- Additional option that can be set to have the left and/or right edges of + the child clipped to its container's bounds. + The clip will be based on the horizontal gravity: a left gravity will clip the right + edge, a right gravity will clip the left edge, and neither will clip both edges. --> + <flag name="clip_horizontal" value="0x08" /> + </attr> + <!-- Defines whether the foreground drawable should be drawn inside the padding. + This property is turned on by default. --> + <attr name="foregroundInsidePadding" format="boolean" /> + <!-- Tint to apply to the foreground. --> + <attr name="foregroundTint" format="color" /> + <!-- Blending mode used to apply the foreground tint. --> + <attr name="foregroundTintMode"> + <!-- The tint is drawn on top of the drawable. + [Sa + (1 - Sa)*Da, Rc = Sc + (1 - Sa)*Dc] --> + <enum name="src_over" value="3" /> + <!-- The tint is masked by the alpha channel of the drawable. The drawable’s + color channels are thrown out. [Sa * Da, Sc * Da] --> + <enum name="src_in" value="5" /> + <!-- The tint is drawn above the drawable, but with the drawable’s alpha + channel masking the result. [Da, Sc * Da + (1 - Sa) * Dc] --> + <enum name="src_atop" value="9" /> + <!-- Multiplies the color and alpha channels of the drawable with those of + the tint. [Sa * Da, Sc * Dc] --> + <enum name="multiply" value="14" /> + <!-- [Sa + Da - Sa * Da, Sc + Dc - Sc * Dc] --> + <enum name="screen" value="15" /> + <!-- Combines the tint and drawable color and alpha channels, clamping the + result to valid color values. Saturate(S + D) --> + <enum name="add" value="16" /> + </attr> + </declare-styleable> <!-- Attributes that can be assigned to a tag for a particular View. --> @@ -3366,72 +3430,9 @@ <attr name="padding" /> </declare-styleable> <declare-styleable name="FrameLayout"> - <!-- Defines the drawable to draw over the content. This can be used as an overlay. - The foreground drawable participates in the padding of the content if the gravity - is set to fill. --> - <attr name="foreground" format="reference|color" /> - <!-- Defines the gravity to apply to the foreground drawable. The gravity defaults - to fill. --> - <attr name="foregroundGravity"> - <!-- Push object to the top of its container, not changing its size. --> - <flag name="top" value="0x30" /> - <!-- Push object to the bottom of its container, not changing its size. --> - <flag name="bottom" value="0x50" /> - <!-- Push object to the left of its container, not changing its size. --> - <flag name="left" value="0x03" /> - <!-- Push object to the right of its container, not changing its size. --> - <flag name="right" value="0x05" /> - <!-- Place object in the vertical center of its container, not changing its size. --> - <flag name="center_vertical" value="0x10" /> - <!-- Grow the vertical size of the object if needed so it completely fills its container. --> - <flag name="fill_vertical" value="0x70" /> - <!-- Place object in the horizontal center of its container, not changing its size. --> - <flag name="center_horizontal" value="0x01" /> - <!-- Grow the horizontal size of the object if needed so it completely fills its container. --> - <flag name="fill_horizontal" value="0x07" /> - <!-- Place the object in the center of its container in both the vertical and horizontal axis, not changing its size. --> - <flag name="center" value="0x11" /> - <!-- Grow the horizontal and vertical size of the object if needed so it completely fills its container. --> - <flag name="fill" value="0x77" /> - <!-- Additional option that can be set to have the top and/or bottom edges of - the child clipped to its container's bounds. - The clip will be based on the vertical gravity: a top gravity will clip the bottom - edge, a bottom gravity will clip the top edge, and neither will clip both edges. --> - <flag name="clip_vertical" value="0x80" /> - <!-- Additional option that can be set to have the left and/or right edges of - the child clipped to its container's bounds. - The clip will be based on the horizontal gravity: a left gravity will clip the right - edge, a right gravity will clip the left edge, and neither will clip both edges. --> - <flag name="clip_horizontal" value="0x08" /> - </attr> - <!-- Defines whether the foreground drawable should be drawn inside the padding. - This property is turned on by default. --> - <attr name="foregroundInsidePadding" format="boolean" /> <!-- Determines whether to measure all children or just those in the VISIBLE or INVISIBLE state when measuring. Defaults to false. --> <attr name="measureAllChildren" format="boolean" /> - <!-- Tint to apply to the foreground. --> - <attr name="foregroundTint" format="color" /> - <!-- Blending mode used to apply the foreground tint. --> - <attr name="foregroundTintMode"> - <!-- The tint is drawn on top of the drawable. - [Sa + (1 - Sa)*Da, Rc = Sc + (1 - Sa)*Dc] --> - <enum name="src_over" value="3" /> - <!-- The tint is masked by the alpha channel of the drawable. The drawable’s - color channels are thrown out. [Sa * Da, Sc * Da] --> - <enum name="src_in" value="5" /> - <!-- The tint is drawn above the drawable, but with the drawable’s alpha - channel masking the result. [Da, Sc * Da + (1 - Sa) * Dc] --> - <enum name="src_atop" value="9" /> - <!-- Multiplies the color and alpha channels of the drawable with those of - the tint. [Sa * Da, Sc * Dc] --> - <enum name="multiply" value="14" /> - <!-- [Sa + Da - Sa * Da, Sc + Dc - Sc * Dc] --> - <enum name="screen" value="15" /> - <!-- Combines the tint and drawable color and alpha channels, clamping the - result to valid color values. Saturate(S + D) --> - <enum name="add" value="16" /> - </attr> </declare-styleable> <declare-styleable name="ExpandableListView"> <!-- Indicator shown beside the group View. This can be a stateful Drawable. --> |