diff options
14 files changed, 908 insertions, 1502 deletions
diff --git a/api/current.txt b/api/current.txt index 5fffbb0f8aca..5a304fb67f11 100644 --- a/api/current.txt +++ b/api/current.txt @@ -11792,15 +11792,8 @@ package android.graphics.drawable {      method public final void setTileModeY(android.graphics.Shader.TileMode);    } -  public class ClipDrawable extends android.graphics.drawable.Drawable implements android.graphics.drawable.Drawable.Callback { +  public class ClipDrawable extends android.graphics.drawable.DrawableWrapper {      ctor public ClipDrawable(android.graphics.drawable.Drawable, int, int); -    method public void draw(android.graphics.Canvas); -    method public int getOpacity(); -    method public void invalidateDrawable(android.graphics.drawable.Drawable); -    method public void scheduleDrawable(android.graphics.drawable.Drawable, java.lang.Runnable, long); -    method public void setAlpha(int); -    method public void setColorFilter(android.graphics.ColorFilter); -    method public void unscheduleDrawable(android.graphics.drawable.Drawable, java.lang.Runnable);      field public static final int HORIZONTAL = 1; // 0x1      field public static final int VERTICAL = 2; // 0x2    } @@ -11842,8 +11835,10 @@ package android.graphics.drawable {      method public android.graphics.Rect getDirtyBounds();      method public boolean getDither();      method public boolean getFilterBitmap(); +    method public void getHotspotBounds(android.graphics.Rect);      method public int getIntrinsicHeight();      method public int getIntrinsicWidth(); +    method public int getLayoutDirection();      method public final int getLevel();      method public int getMinimumHeight();      method public int getMinimumWidth(); @@ -11861,6 +11856,7 @@ package android.graphics.drawable {      method public void jumpToCurrentState();      method public android.graphics.drawable.Drawable mutate();      method protected void onBoundsChange(android.graphics.Rect); +    method public boolean onLayoutDirectionChange(int);      method protected boolean onLevelChange(int);      method protected boolean onStateChange(int[]);      method public static int resolveOpacity(int, int); @@ -11877,6 +11873,7 @@ package android.graphics.drawable {      method public void setFilterBitmap(boolean);      method public void setHotspot(float, float);      method public void setHotspotBounds(int, int, int, int); +    method public final boolean setLayoutDirection(int);      method public final boolean setLevel(int);      method public boolean setState(int[]);      method public void setTint(int); @@ -11941,6 +11938,19 @@ package android.graphics.drawable {      method public final void setVariablePadding(boolean);    } +  public abstract class DrawableWrapper extends android.graphics.drawable.Drawable implements android.graphics.drawable.Drawable.Callback { +    ctor public DrawableWrapper(android.graphics.drawable.Drawable); +    method public void draw(android.graphics.Canvas); +    method public android.graphics.drawable.Drawable getDrawable(); +    method public int getOpacity(); +    method public void invalidateDrawable(android.graphics.drawable.Drawable); +    method public void scheduleDrawable(android.graphics.drawable.Drawable, java.lang.Runnable, long); +    method public void setAlpha(int); +    method public void setColorFilter(android.graphics.ColorFilter); +    method public void setDrawable(android.graphics.drawable.Drawable); +    method public void unscheduleDrawable(android.graphics.drawable.Drawable, java.lang.Runnable); +  } +    public class GradientDrawable extends android.graphics.drawable.Drawable {      ctor public GradientDrawable();      ctor public GradientDrawable(android.graphics.drawable.GradientDrawable.Orientation, int[]); @@ -11988,17 +11998,9 @@ package android.graphics.drawable {      enum_constant public static final android.graphics.drawable.GradientDrawable.Orientation TR_BL;    } -  public class InsetDrawable extends android.graphics.drawable.Drawable implements android.graphics.drawable.Drawable.Callback { +  public class InsetDrawable extends android.graphics.drawable.DrawableWrapper {      ctor public InsetDrawable(android.graphics.drawable.Drawable, int);      ctor public InsetDrawable(android.graphics.drawable.Drawable, int, int, int, int); -    method public void draw(android.graphics.Canvas); -    method public android.graphics.drawable.Drawable getDrawable(); -    method public int getOpacity(); -    method public void invalidateDrawable(android.graphics.drawable.Drawable); -    method public void scheduleDrawable(android.graphics.drawable.Drawable, java.lang.Runnable, long); -    method public void setAlpha(int); -    method public void setColorFilter(android.graphics.ColorFilter); -    method public void unscheduleDrawable(android.graphics.drawable.Drawable, java.lang.Runnable);    }    public class LayerDrawable extends android.graphics.drawable.Drawable implements android.graphics.drawable.Drawable.Callback { @@ -12078,41 +12080,24 @@ package android.graphics.drawable {      field public static final int RADIUS_AUTO = -1; // 0xffffffff    } -  public class RotateDrawable extends android.graphics.drawable.Drawable implements android.graphics.drawable.Drawable.Callback { +  public class RotateDrawable extends android.graphics.drawable.DrawableWrapper {      ctor public RotateDrawable(); -    method public void draw(android.graphics.Canvas); -    method public android.graphics.drawable.Drawable getDrawable();      method public float getFromDegrees(); -    method public int getOpacity();      method public float getPivotX();      method public float getPivotY();      method public float getToDegrees(); -    method public void invalidateDrawable(android.graphics.drawable.Drawable);      method public boolean isPivotXRelative();      method public boolean isPivotYRelative(); -    method public void scheduleDrawable(android.graphics.drawable.Drawable, java.lang.Runnable, long); -    method public void setAlpha(int); -    method public void setColorFilter(android.graphics.ColorFilter); -    method public void setDrawable(android.graphics.drawable.Drawable);      method public void setFromDegrees(float);      method public void setPivotX(float);      method public void setPivotXRelative(boolean);      method public void setPivotY(float);      method public void setPivotYRelative(boolean);      method public void setToDegrees(float); -    method public void unscheduleDrawable(android.graphics.drawable.Drawable, java.lang.Runnable);    } -  public class ScaleDrawable extends android.graphics.drawable.Drawable implements android.graphics.drawable.Drawable.Callback { +  public class ScaleDrawable extends android.graphics.drawable.DrawableWrapper {      ctor public ScaleDrawable(android.graphics.drawable.Drawable, int, float, float); -    method public void draw(android.graphics.Canvas); -    method public android.graphics.drawable.Drawable getDrawable(); -    method public int getOpacity(); -    method public void invalidateDrawable(android.graphics.drawable.Drawable); -    method public void scheduleDrawable(android.graphics.drawable.Drawable, java.lang.Runnable, long); -    method public void setAlpha(int); -    method public void setColorFilter(android.graphics.ColorFilter); -    method public void unscheduleDrawable(android.graphics.drawable.Drawable, java.lang.Runnable);    }    public class ShapeDrawable extends android.graphics.drawable.Drawable { diff --git a/api/system-current.txt b/api/system-current.txt index c43f2c7e0357..28c57f85c211 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -12066,15 +12066,8 @@ package android.graphics.drawable {      method public final void setTileModeY(android.graphics.Shader.TileMode);    } -  public class ClipDrawable extends android.graphics.drawable.Drawable implements android.graphics.drawable.Drawable.Callback { +  public class ClipDrawable extends android.graphics.drawable.DrawableWrapper {      ctor public ClipDrawable(android.graphics.drawable.Drawable, int, int); -    method public void draw(android.graphics.Canvas); -    method public int getOpacity(); -    method public void invalidateDrawable(android.graphics.drawable.Drawable); -    method public void scheduleDrawable(android.graphics.drawable.Drawable, java.lang.Runnable, long); -    method public void setAlpha(int); -    method public void setColorFilter(android.graphics.ColorFilter); -    method public void unscheduleDrawable(android.graphics.drawable.Drawable, java.lang.Runnable);      field public static final int HORIZONTAL = 1; // 0x1      field public static final int VERTICAL = 2; // 0x2    } @@ -12116,8 +12109,10 @@ package android.graphics.drawable {      method public android.graphics.Rect getDirtyBounds();      method public boolean getDither();      method public boolean getFilterBitmap(); +    method public void getHotspotBounds(android.graphics.Rect);      method public int getIntrinsicHeight();      method public int getIntrinsicWidth(); +    method public int getLayoutDirection();      method public final int getLevel();      method public int getMinimumHeight();      method public int getMinimumWidth(); @@ -12135,6 +12130,7 @@ package android.graphics.drawable {      method public void jumpToCurrentState();      method public android.graphics.drawable.Drawable mutate();      method protected void onBoundsChange(android.graphics.Rect); +    method public boolean onLayoutDirectionChange(int);      method protected boolean onLevelChange(int);      method protected boolean onStateChange(int[]);      method public static int resolveOpacity(int, int); @@ -12151,6 +12147,7 @@ package android.graphics.drawable {      method public void setFilterBitmap(boolean);      method public void setHotspot(float, float);      method public void setHotspotBounds(int, int, int, int); +    method public final boolean setLayoutDirection(int);      method public final boolean setLevel(int);      method public boolean setState(int[]);      method public void setTint(int); @@ -12215,6 +12212,19 @@ package android.graphics.drawable {      method public final void setVariablePadding(boolean);    } +  public abstract class DrawableWrapper extends android.graphics.drawable.Drawable implements android.graphics.drawable.Drawable.Callback { +    ctor public DrawableWrapper(android.graphics.drawable.Drawable); +    method public void draw(android.graphics.Canvas); +    method public android.graphics.drawable.Drawable getDrawable(); +    method public int getOpacity(); +    method public void invalidateDrawable(android.graphics.drawable.Drawable); +    method public void scheduleDrawable(android.graphics.drawable.Drawable, java.lang.Runnable, long); +    method public void setAlpha(int); +    method public void setColorFilter(android.graphics.ColorFilter); +    method public void setDrawable(android.graphics.drawable.Drawable); +    method public void unscheduleDrawable(android.graphics.drawable.Drawable, java.lang.Runnable); +  } +    public class GradientDrawable extends android.graphics.drawable.Drawable {      ctor public GradientDrawable();      ctor public GradientDrawable(android.graphics.drawable.GradientDrawable.Orientation, int[]); @@ -12262,17 +12272,9 @@ package android.graphics.drawable {      enum_constant public static final android.graphics.drawable.GradientDrawable.Orientation TR_BL;    } -  public class InsetDrawable extends android.graphics.drawable.Drawable implements android.graphics.drawable.Drawable.Callback { +  public class InsetDrawable extends android.graphics.drawable.DrawableWrapper {      ctor public InsetDrawable(android.graphics.drawable.Drawable, int);      ctor public InsetDrawable(android.graphics.drawable.Drawable, int, int, int, int); -    method public void draw(android.graphics.Canvas); -    method public android.graphics.drawable.Drawable getDrawable(); -    method public int getOpacity(); -    method public void invalidateDrawable(android.graphics.drawable.Drawable); -    method public void scheduleDrawable(android.graphics.drawable.Drawable, java.lang.Runnable, long); -    method public void setAlpha(int); -    method public void setColorFilter(android.graphics.ColorFilter); -    method public void unscheduleDrawable(android.graphics.drawable.Drawable, java.lang.Runnable);    }    public class LayerDrawable extends android.graphics.drawable.Drawable implements android.graphics.drawable.Drawable.Callback { @@ -12352,41 +12354,24 @@ package android.graphics.drawable {      field public static final int RADIUS_AUTO = -1; // 0xffffffff    } -  public class RotateDrawable extends android.graphics.drawable.Drawable implements android.graphics.drawable.Drawable.Callback { +  public class RotateDrawable extends android.graphics.drawable.DrawableWrapper {      ctor public RotateDrawable(); -    method public void draw(android.graphics.Canvas); -    method public android.graphics.drawable.Drawable getDrawable();      method public float getFromDegrees(); -    method public int getOpacity();      method public float getPivotX();      method public float getPivotY();      method public float getToDegrees(); -    method public void invalidateDrawable(android.graphics.drawable.Drawable);      method public boolean isPivotXRelative();      method public boolean isPivotYRelative(); -    method public void scheduleDrawable(android.graphics.drawable.Drawable, java.lang.Runnable, long); -    method public void setAlpha(int); -    method public void setColorFilter(android.graphics.ColorFilter); -    method public void setDrawable(android.graphics.drawable.Drawable);      method public void setFromDegrees(float);      method public void setPivotX(float);      method public void setPivotXRelative(boolean);      method public void setPivotY(float);      method public void setPivotYRelative(boolean);      method public void setToDegrees(float); -    method public void unscheduleDrawable(android.graphics.drawable.Drawable, java.lang.Runnable);    } -  public class ScaleDrawable extends android.graphics.drawable.Drawable implements android.graphics.drawable.Drawable.Callback { +  public class ScaleDrawable extends android.graphics.drawable.DrawableWrapper {      ctor public ScaleDrawable(android.graphics.drawable.Drawable, int, float, float); -    method public void draw(android.graphics.Canvas); -    method public android.graphics.drawable.Drawable getDrawable(); -    method public int getOpacity(); -    method public void invalidateDrawable(android.graphics.drawable.Drawable); -    method public void scheduleDrawable(android.graphics.drawable.Drawable, java.lang.Runnable, long); -    method public void setAlpha(int); -    method public void setColorFilter(android.graphics.ColorFilter); -    method public void unscheduleDrawable(android.graphics.drawable.Drawable, java.lang.Runnable);    }    public class ShapeDrawable extends android.graphics.drawable.Drawable { diff --git a/graphics/java/android/graphics/drawable/AnimatedRotateDrawable.java b/graphics/java/android/graphics/drawable/AnimatedRotateDrawable.java index d2799e1a496c..db94d896477c 100644 --- a/graphics/java/android/graphics/drawable/AnimatedRotateDrawable.java +++ b/graphics/java/android/graphics/drawable/AnimatedRotateDrawable.java @@ -20,15 +20,11 @@ import android.annotation.NonNull;  import android.annotation.Nullable;  import android.graphics.Canvas;  import android.graphics.Rect; -import android.graphics.ColorFilter; -import android.graphics.PorterDuff.Mode; -import android.content.res.ColorStateList;  import android.content.res.Resources;  import android.content.res.TypedArray;  import android.content.res.Resources.Theme;  import android.util.AttributeSet;  import android.util.TypedValue; -import android.util.Log;  import android.os.SystemClock;  import org.xmlpull.v1.XmlPullParser; @@ -41,35 +37,15 @@ import com.android.internal.R;  /**   * @hide   */ -public class AnimatedRotateDrawable extends Drawable implements Drawable.Callback, Runnable, -        Animatable { -    private static final String TAG = "AnimatedRotateDrawable"; - +public class AnimatedRotateDrawable extends DrawableWrapper implements Runnable, Animatable {      private AnimatedRotateState mState; -    private boolean mMutated; +      private float mCurrentDegrees;      private float mIncrement;      private boolean mRunning;      public AnimatedRotateDrawable() { -        this(null, null); -    } - -    private AnimatedRotateDrawable(AnimatedRotateState rotateState, Resources res) { -        mState = new AnimatedRotateState(rotateState, this, res); -        init(); -    } - -    private void init() { -        final AnimatedRotateState state = mState; -        mIncrement = 360.0f / state.mFramesCount; -        final Drawable drawable = state.mDrawable; -        if (drawable != null) { -            drawable.setFilterBitmap(true); -            if (drawable instanceof BitmapDrawable) { -                ((BitmapDrawable) drawable).setAntiAlias(true); -            } -        } +        this(new AnimatedRotateState(null), null);      }      @Override @@ -131,8 +107,7 @@ public class AnimatedRotateDrawable extends Drawable implements Drawable.Callbac      @Override      public boolean setVisible(boolean visible, boolean restart) { -        mState.mDrawable.setVisible(visible, restart); -        boolean changed = super.setVisible(visible, restart); +        final boolean changed = super.setVisible(visible, restart);          if (visible) {              if (changed || restart) {                  mCurrentDegrees = 0.0f; @@ -144,123 +119,6 @@ public class AnimatedRotateDrawable extends Drawable implements Drawable.Callbac          return changed;      } -    /** -     * Returns the drawable rotated by this RotateDrawable. -     */ -    public Drawable getDrawable() { -        return mState.mDrawable; -    } - -    @Override -    public int getChangingConfigurations() { -        return super.getChangingConfigurations() -                | mState.mChangingConfigurations -                | mState.mDrawable.getChangingConfigurations(); -    } - -    @Override -    public void setAlpha(int alpha) { -        mState.mDrawable.setAlpha(alpha); -    } - -    @Override -    public int getAlpha() { -        return mState.mDrawable.getAlpha(); -    } - -    @Override -    public void setColorFilter(ColorFilter cf) { -        mState.mDrawable.setColorFilter(cf); -    } - -    @Override -    public void setTintList(ColorStateList tint) { -        mState.mDrawable.setTintList(tint); -    } - -    @Override -    public void setTintMode(Mode tintMode) { -        mState.mDrawable.setTintMode(tintMode); -    } - -    @Override -    public int getOpacity() { -        return mState.mDrawable.getOpacity(); -    } - -    @Override -    public boolean canApplyTheme() { -        return (mState != null && mState.canApplyTheme()) || super.canApplyTheme(); -    } - -    @Override -    public void invalidateDrawable(Drawable who) { -        final Callback callback = getCallback(); -        if (callback != null) { -            callback.invalidateDrawable(this); -        } -    } - -    @Override -    public void scheduleDrawable(Drawable who, Runnable what, long when) { -        final Callback callback = getCallback(); -        if (callback != null) { -            callback.scheduleDrawable(this, what, when); -        } -    } - -    @Override -    public void unscheduleDrawable(Drawable who, Runnable what) { -        final Callback callback = getCallback(); -        if (callback != null) { -            callback.unscheduleDrawable(this, what); -        } -    } - -    @Override -    public boolean getPadding(Rect padding) { -        return mState.mDrawable.getPadding(padding); -    } - -    @Override -    public boolean isStateful() { -        return mState.mDrawable.isStateful(); -    } - -    @Override -    protected void onBoundsChange(Rect bounds) { -        mState.mDrawable.setBounds(bounds.left, bounds.top, bounds.right, bounds.bottom); -    } - -    @Override -    protected boolean onLevelChange(int level) { -        return mState.mDrawable.setLevel(level); -    } - -    @Override -    protected boolean onStateChange(int[] state) { -        return mState.mDrawable.setState(state); -    } - -    @Override -    public int getIntrinsicWidth() { -        return mState.mDrawable.getIntrinsicWidth(); -    } - -    @Override -    public int getIntrinsicHeight() { -        return mState.mDrawable.getIntrinsicHeight(); -    } - -    @Override -    public ConstantState getConstantState() { -        if (mState.canConstantState()) { -            mState.mChangingConfigurations = getChangingConfigurations(); -            return mState; -        } -        return null; -    } -      @Override      public void inflate(@NonNull Resources r, @NonNull XmlPullParser parser,              @NonNull AttributeSet attrs, @Nullable Theme theme) @@ -268,50 +126,27 @@ public class AnimatedRotateDrawable extends Drawable implements Drawable.Callbac          final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.AnimatedRotateDrawable);          super.inflateWithAttributes(r, parser, a, R.styleable.AnimatedRotateDrawable_visible);          updateStateFromTypedArray(a); +        verifyRequiredAttributes(a);          a.recycle(); -        inflateChildElements(r, parser, attrs, theme); - -        init(); +        updateLocalState();      } -    @Override -    public void applyTheme(@Nullable Theme t) { -        super.applyTheme(t); - -        final AnimatedRotateState state = mState; -        if (state == null) { -            return; -        } - -        if (state.mThemeAttrs != null) { -            final TypedArray a = t.resolveAttributes( -                    state.mThemeAttrs, R.styleable.AnimatedRotateDrawable); -            try { -                updateStateFromTypedArray(a); -                verifyRequiredAttributes(a); -            } catch (XmlPullParserException e) { -                throw new RuntimeException(e); -            } finally { -                a.recycle(); -            } -        } - -        if (state.mDrawable != null && state.mDrawable.canApplyTheme()) { -            state.mDrawable.applyTheme(t); +    private void verifyRequiredAttributes(TypedArray a) throws XmlPullParserException { +        // If we're not waiting on a theme, verify required attributes. +        if (getDrawable() == null && (mState.mThemeAttrs == null +                || mState.mThemeAttrs[R.styleable.AnimatedRotateDrawable_drawable] == 0)) { +            throw new XmlPullParserException(a.getPositionDescription() +                    + ": <animated-rotate> tag requires a 'drawable' attribute or " +                    + "child tag defining a drawable");          } - -        init();      } -    private void updateStateFromTypedArray(TypedArray a) { -        final AnimatedRotateState state = mState; - -        // Account for any configuration changes. -        state.mChangingConfigurations |= a.getChangingConfigurations(); +    @Override +    void updateStateFromTypedArray(TypedArray a) { +        super.updateStateFromTypedArray(a); -        // Extract the theme attributes, if any. -        state.mThemeAttrs = a.extractThemeAttrs(); +        final AnimatedRotateState state = mState;          if (a.hasValue(R.styleable.AnimatedRotateDrawable_pivotX)) {              final TypedValue tv = a.peekValue(R.styleable.AnimatedRotateDrawable_pivotX); @@ -332,43 +167,35 @@ public class AnimatedRotateDrawable extends Drawable implements Drawable.Callbac          final Drawable dr = a.getDrawable(R.styleable.AnimatedRotateDrawable_drawable);          if (dr != null) { -            state.mDrawable = dr; -            dr.setCallback(this); +            setDrawable(dr);          }      } -    private void inflateChildElements(Resources r, XmlPullParser parser, AttributeSet attrs, -            Theme theme) throws XmlPullParserException, IOException { +    @Override +    public void applyTheme(@Nullable Theme t) {          final AnimatedRotateState state = mState; +        if (state == null) { +            return; +        } -        Drawable dr = null; -        int outerDepth = parser.getDepth(); -        int type; -        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT -                && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { -            if (type != XmlPullParser.START_TAG) { -                continue; -            } - -            if ((dr = Drawable.createFromXmlInner(r, parser, attrs, theme)) == null) { -                Log.w(TAG, "Bad element under <animated-rotate>: " + parser.getName()); +        if (state.mThemeAttrs != null) { +            final TypedArray a = t.resolveAttributes( +                    state.mThemeAttrs, R.styleable.AnimatedRotateDrawable); +            try { +                updateStateFromTypedArray(a); +                verifyRequiredAttributes(a); +            } catch (XmlPullParserException e) { +                throw new RuntimeException(e); +            } finally { +                a.recycle();              }          } -        if (dr != null) { -            state.mDrawable = dr; -            dr.setCallback(this); -        } -    } +        // The drawable may have changed as a result of applying the theme, so +        // apply the theme to the wrapped drawable last. +        super.applyTheme(t); -    private void verifyRequiredAttributes(TypedArray a) throws XmlPullParserException { -        // If we're not waiting on a theme, verify required attributes. -        if (mState.mDrawable == null && (mState.mThemeAttrs == null -                || mState.mThemeAttrs[R.styleable.AnimatedRotateDrawable_drawable] == 0)) { -            throw new XmlPullParserException(a.getPositionDescription() -                    + ": <animated-rotate> tag requires a 'drawable' attribute or " -                    + "child tag defining a drawable"); -        } +        updateLocalState();      }      public void setFramesCount(int framesCount) { @@ -380,25 +207,7 @@ public class AnimatedRotateDrawable extends Drawable implements Drawable.Callbac          mState.mFrameDuration = framesDuration;      } -    @Override -    public Drawable mutate() { -        if (!mMutated && super.mutate() == this) { -            mState.mDrawable.mutate(); -            mMutated = true; -        } -        return this; -    } - -    /** -     * @hide -     */ -    public void clearMutated() { -        super.clearMutated(); -        mState.mDrawable.clearMutated(); -        mMutated = false; -    } - -    final static class AnimatedRotateState extends Drawable.ConstantState { +    static final class AnimatedRotateState extends DrawableWrapper.DrawableWrapperState {          Drawable mDrawable;          int[] mThemeAttrs; @@ -414,35 +223,20 @@ public class AnimatedRotateDrawable extends Drawable implements Drawable.Callbac          private boolean mCanConstantState;          private boolean mCheckedConstantState; -        public AnimatedRotateState(AnimatedRotateState orig, AnimatedRotateDrawable owner, -                Resources res) { +        public AnimatedRotateState(AnimatedRotateState orig) { +            super(orig); +              if (orig != null) { -                if (res != null) { -                    mDrawable = orig.mDrawable.getConstantState().newDrawable(res); -                } else { -                    mDrawable = orig.mDrawable.getConstantState().newDrawable(); -                } -                mDrawable.setCallback(owner); -                mDrawable.setLayoutDirection(orig.mDrawable.getLayoutDirection()); -                mDrawable.setBounds(orig.mDrawable.getBounds()); -                mDrawable.setLevel(orig.mDrawable.getLevel()); -                mThemeAttrs = orig.mThemeAttrs;                  mPivotXRel = orig.mPivotXRel;                  mPivotX = orig.mPivotX;                  mPivotYRel = orig.mPivotYRel;                  mPivotY = orig.mPivotY;                  mFramesCount = orig.mFramesCount;                  mFrameDuration = orig.mFrameDuration; -                mCanConstantState = mCheckedConstantState = true;              }          }          @Override -        public Drawable newDrawable() { -            return new AnimatedRotateDrawable(this, null); -        } - -        @Override          public Drawable newDrawable(Resources res) {              return new AnimatedRotateDrawable(this, res);          } @@ -467,4 +261,27 @@ public class AnimatedRotateDrawable extends Drawable implements Drawable.Callbac              return mCanConstantState;          }      } + +    private AnimatedRotateDrawable(AnimatedRotateState state, Resources res) { +        super(state, res); + +        mState = state; + +        updateLocalState(); +    } + +    private void updateLocalState() { +        final AnimatedRotateState state = mState; +        mIncrement = 360.0f / state.mFramesCount; + +        // Force the wrapped drawable to use filtering and AA, if applicable, +        // so that it looks smooth when rotated. +        final Drawable drawable = state.mDrawable; +        if (drawable != null) { +            drawable.setFilterBitmap(true); +            if (drawable instanceof BitmapDrawable) { +                ((BitmapDrawable) drawable).setAntiAlias(true); +            } +        } +    }  } diff --git a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java index 2a17a607f83d..17e5b0b6bab1 100644 --- a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java +++ b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java @@ -197,6 +197,11 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable {      }      @Override +    public boolean onLayoutDirectionChange(int layoutDirection) { +        return mAnimatedVectorState.mVectorDrawable.setLayoutDirection(layoutDirection); +    } + +    @Override      public int getAlpha() {          return mAnimatedVectorState.mVectorDrawable.getAlpha();      } @@ -237,12 +242,6 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable {          return super.setVisible(visible, restart);      } -    /** {@hide} */ -    @Override -    public void setLayoutDirection(int layoutDirection) { -        mAnimatedVectorState.mVectorDrawable.setLayoutDirection(layoutDirection); -    } -      @Override      public boolean isStateful() {          return mAnimatedVectorState.mVectorDrawable.isStateful(); diff --git a/graphics/java/android/graphics/drawable/ClipDrawable.java b/graphics/java/android/graphics/drawable/ClipDrawable.java index e5b2b768cd16..f3574e84254a 100644 --- a/graphics/java/android/graphics/drawable/ClipDrawable.java +++ b/graphics/java/android/graphics/drawable/ClipDrawable.java @@ -50,32 +50,36 @@ import java.io.IOException;   * @attr ref android.R.styleable#ClipDrawable_gravity   * @attr ref android.R.styleable#ClipDrawable_drawable   */ -public class ClipDrawable extends Drawable implements Drawable.Callback { -    private ClipState mState; -    private final Rect mTmpRect = new Rect(); - +public class ClipDrawable extends DrawableWrapper {      public static final int HORIZONTAL = 1;      public static final int VERTICAL = 2; -    private boolean mMutated; +    private static final int MAX_LEVEL = 10000; + +    private final Rect mTmpRect = new Rect(); + +    private ClipState mState;      ClipDrawable() { -        this(null, null); +        this(new ClipState(null), null);      }      /** -     * @param orientation Bitwise-or of {@link #HORIZONTAL} and/or {@link #VERTICAL} +     * Creates a new clip drawable with the specified gravity and orientation. +     * +     * @param drawable the drawable to clip +     * @param gravity gravity constant (see {@link Gravity} used to position +     *                the clipped drawable within the parent container +     * @param orientation bitwise-or of {@link #HORIZONTAL} and/or +     *                   {@link #VERTICAL}       */      public ClipDrawable(Drawable drawable, int gravity, int orientation) { -        this(null, null); +        this(new ClipState(null), null); -        mState.mDrawable = drawable;          mState.mGravity = gravity;          mState.mOrientation = orientation; -        if (drawable != null) { -            drawable.setCallback(this); -        } +        setDrawable(drawable);      }      @Override @@ -84,39 +88,15 @@ public class ClipDrawable extends Drawable implements Drawable.Callback {          super.inflate(r, parser, attrs, theme);          final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.ClipDrawable); - -        // Reset mDrawable to preserve old multiple-inflate behavior. This is -        // silly, but we have CTS tests that rely on it. -        mState.mDrawable = null; -          updateStateFromTypedArray(a); -        inflateChildElements(r, parser, attrs, theme); +        inflateChildDrawable(r, parser, attrs, theme);          verifyRequiredAttributes(a);          a.recycle();      } -    private void inflateChildElements(Resources r, XmlPullParser parser, AttributeSet attrs, -            Theme theme) throws XmlPullParserException, IOException { -        Drawable dr = null; -        int type; -        final int outerDepth = parser.getDepth(); -        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT -                && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { -            if (type != XmlPullParser.START_TAG) { -                continue; -            } -            dr = Drawable.createFromXmlInner(r, parser, attrs, theme); -        } - -        if (dr != null) { -            mState.mDrawable = dr; -            dr.setCallback(this); -        } -    } -      private void verifyRequiredAttributes(TypedArray a) throws XmlPullParserException {          // If we're not waiting on a theme, verify required attributes. -        if (mState.mDrawable == null && (mState.mThemeAttrs == null +        if (getDrawable() == null && (mState.mThemeAttrs == null                  || mState.mThemeAttrs[R.styleable.ClipDrawable_drawable] == 0)) {              throw new XmlPullParserException(a.getPositionDescription()                      + ": <clip> tag requires a 'drawable' attribute or " @@ -124,292 +104,110 @@ public class ClipDrawable extends Drawable implements Drawable.Callback {          }      } -    private void updateStateFromTypedArray(TypedArray a) { -        final ClipState state = mState; - -        // Account for any configuration changes. -        state.mChangingConfigurations |= a.getChangingConfigurations(); - -        // Extract the theme attributes, if any. -        state.mThemeAttrs = a.extractThemeAttrs(); +    @Override +    void updateStateFromTypedArray(TypedArray a) { +        super.updateStateFromTypedArray(a); -        state.mOrientation = a.getInt(R.styleable.ClipDrawable_clipOrientation, state.mOrientation); -        state.mGravity = a.getInt(R.styleable.ClipDrawable_gravity, state.mGravity); +        final ClipState state = mState; +        state.mOrientation = a.getInt( +                R.styleable.ClipDrawable_clipOrientation, state.mOrientation); +        state.mGravity = a.getInt( +                R.styleable.ClipDrawable_gravity, state.mGravity);          final Drawable dr = a.getDrawable(R.styleable.ClipDrawable_drawable);          if (dr != null) { -            state.mDrawable = dr; -            dr.setCallback(this); +            setDrawable(dr);          }      }      @Override      public void applyTheme(Theme t) { -        super.applyTheme(t); -          final ClipState state = mState; -        if (state == null || state.mThemeAttrs == null) { +        if (state == null) {              return;          } -        final TypedArray a = t.resolveAttributes(state.mThemeAttrs, R.styleable.ClipDrawable); -        try { -            updateStateFromTypedArray(a); -            verifyRequiredAttributes(a); -        } catch (XmlPullParserException e) { -            throw new RuntimeException(e); -        } finally { -            a.recycle(); -        } - -        if (state.mDrawable != null && state.mDrawable.canApplyTheme()) { -            state.mDrawable.applyTheme(t); -        } -    } - -    @Override -    public boolean canApplyTheme() { -        return (mState != null && mState.canApplyTheme()) || super.canApplyTheme(); -    } - -    // overrides from Drawable.Callback - -    @Override -    public void invalidateDrawable(Drawable who) { -        final Callback callback = getCallback(); -        if (callback != null) { -            callback.invalidateDrawable(this); -        } -    } - -    @Override -    public void scheduleDrawable(Drawable who, Runnable what, long when) { -        final Callback callback = getCallback(); -        if (callback != null) { -            callback.scheduleDrawable(this, what, when); -        } -    } - -    @Override -    public void unscheduleDrawable(Drawable who, Runnable what) { -        final Callback callback = getCallback(); -        if (callback != null) { -            callback.unscheduleDrawable(this, what); +        if (state.mThemeAttrs != null) { +            final TypedArray a = t.resolveAttributes(state.mThemeAttrs, R.styleable.ClipDrawable); +            try { +                updateStateFromTypedArray(a); +                verifyRequiredAttributes(a); +            } catch (XmlPullParserException e) { +                throw new RuntimeException(e); +            } finally { +                a.recycle(); +            }          } -    } - -    // overrides from Drawable - -    @Override -    public int getChangingConfigurations() { -        return super.getChangingConfigurations() -                | mState.mChangingConfigurations -                | mState.mDrawable.getChangingConfigurations(); -    } - -    @Override -    public boolean getPadding(Rect padding) { -        // XXX need to adjust padding! -        return mState.mDrawable.getPadding(padding); -    } - -    @Override -    public boolean setVisible(boolean visible, boolean restart) { -        mState.mDrawable.setVisible(visible, restart); -        return super.setVisible(visible, restart); -    } -    @Override -    public void setAlpha(int alpha) { -        mState.mDrawable.setAlpha(alpha); -    } - -    @Override -    public int getAlpha() { -        return mState.mDrawable.getAlpha(); -    } - -    @Override -    public void setColorFilter(ColorFilter cf) { -        mState.mDrawable.setColorFilter(cf); -    } - -    @Override -    public void setTintList(ColorStateList tint) { -        mState.mDrawable.setTintList(tint); -    } - -    @Override -    public void setTintMode(Mode tintMode) { -        mState.mDrawable.setTintMode(tintMode); -    } - -    @Override -    public int getOpacity() { -        return mState.mDrawable.getOpacity(); -    } - -    @Override -    public boolean isStateful() { -        return mState.mDrawable.isStateful(); -    } - -    @Override -    protected boolean onStateChange(int[] state) { -        return mState.mDrawable.setState(state); +        // The drawable may have changed as a result of applying the theme, so +        // apply the theme to the wrapped drawable last. +        super.applyTheme(t);      }      @Override      protected boolean onLevelChange(int level) { -        mState.mDrawable.setLevel(level); +        super.onLevelChange(level);          invalidateSelf();          return true;      }      @Override -    protected void onBoundsChange(Rect bounds) { -        mState.mDrawable.setBounds(bounds); -    } - -    @Override      public void draw(Canvas canvas) { - -        if (mState.mDrawable.getLevel() == 0) { +        final Drawable dr = getDrawable(); +        if (dr.getLevel() == 0) {              return;          }          final Rect r = mTmpRect;          final Rect bounds = getBounds(); -        int level = getLevel(); +        final int level = getLevel(); +          int w = bounds.width();          final int iw = 0; //mState.mDrawable.getIntrinsicWidth();          if ((mState.mOrientation & HORIZONTAL) != 0) { -            w -= (w - iw) * (10000 - level) / 10000; +            w -= (w - iw) * (MAX_LEVEL - level) / MAX_LEVEL;          } +          int h = bounds.height();          final int ih = 0; //mState.mDrawable.getIntrinsicHeight();          if ((mState.mOrientation & VERTICAL) != 0) { -            h -= (h - ih) * (10000 - level) / 10000; +            h -= (h - ih) * (MAX_LEVEL - level) / MAX_LEVEL;          } +          final int layoutDirection = getLayoutDirection();          Gravity.apply(mState.mGravity, w, h, bounds, r, layoutDirection);          if (w > 0 && h > 0) {              canvas.save();              canvas.clipRect(r); -            mState.mDrawable.draw(canvas); +            dr.draw(canvas);              canvas.restore();          }      } -    @Override -    public int getIntrinsicWidth() { -        return mState.mDrawable.getIntrinsicWidth(); -    } - -    @Override -    public int getIntrinsicHeight() { -        return mState.mDrawable.getIntrinsicHeight(); -    } - -    @Override -    public ConstantState getConstantState() { -        if (mState.canConstantState()) { -            mState.mChangingConfigurations = getChangingConfigurations(); -            return mState; -        } -        return null; -    } - -    /** @hide */ -    @Override -    public void setLayoutDirection(int layoutDirection) { -        mState.mDrawable.setLayoutDirection(layoutDirection); -        super.setLayoutDirection(layoutDirection); -    } - -    @Override -    public Drawable mutate() { -        if (!mMutated && super.mutate() == this) { -            mState.mDrawable.mutate(); -            mMutated = true; -        } -        return this; -    } - -    /** -     * @hide -     */ -    public void clearMutated() { -        super.clearMutated(); -        mState.mDrawable.clearMutated(); -        mMutated = false; -    } - -    final static class ClipState extends ConstantState { -        int[] mThemeAttrs; -        int mChangingConfigurations; - -        Drawable mDrawable; - +    static final class ClipState extends DrawableWrapper.DrawableWrapperState {          int mOrientation = HORIZONTAL;          int mGravity = Gravity.LEFT; -        private boolean mCheckedConstantState; -        private boolean mCanConstantState; +        ClipState(ClipState orig) { +            super(orig); -        ClipState(ClipState orig, ClipDrawable owner, Resources res) {              if (orig != null) { -                mThemeAttrs = orig.mThemeAttrs; -                mChangingConfigurations = orig.mChangingConfigurations; -                if (res != null) { -                    mDrawable = orig.mDrawable.getConstantState().newDrawable(res); -                } else { -                    mDrawable = orig.mDrawable.getConstantState().newDrawable(); -                } -                mDrawable.setCallback(owner); -                mDrawable.setLayoutDirection(orig.mDrawable.getLayoutDirection()); -                mDrawable.setBounds(orig.mDrawable.getBounds()); -                mDrawable.setLevel(orig.mDrawable.getLevel());                  mOrientation = orig.mOrientation;                  mGravity = orig.mGravity; -                mCheckedConstantState = mCanConstantState = true;              }          }          @Override -        public boolean canApplyTheme() { -            return mThemeAttrs != null || (mDrawable != null && mDrawable.canApplyTheme()) -                    || super.canApplyTheme(); -        } - -        @Override -        public Drawable newDrawable() { -            return new ClipDrawable(this, null); -        } - -        @Override          public Drawable newDrawable(Resources res) {              return new ClipDrawable(this, res);          } - -        @Override -        public int getChangingConfigurations() { -            return mChangingConfigurations; -        } - -        boolean canConstantState() { -            if (!mCheckedConstantState) { -                mCanConstantState = mDrawable.getConstantState() != null; -                mCheckedConstantState = true; -            } - -            return mCanConstantState; -        }      }      private ClipDrawable(ClipState state, Resources res) { -        mState = new ClipState(state, this, res); +        super(state, res); + +        mState = state;      }  } diff --git a/graphics/java/android/graphics/drawable/Drawable.java b/graphics/java/android/graphics/drawable/Drawable.java index fa269e02d9d9..247f94a8debf 100644 --- a/graphics/java/android/graphics/drawable/Drawable.java +++ b/graphics/java/android/graphics/drawable/Drawable.java @@ -422,27 +422,41 @@ public abstract class Drawable {       * Returns the resolved layout direction for this Drawable.       *       * @return One of {@link android.view.View#LAYOUT_DIRECTION_LTR}, -     *   {@link android.view.View#LAYOUT_DIRECTION_RTL} -     * -     * @hide +     *         {@link android.view.View#LAYOUT_DIRECTION_RTL} +     * @see #setLayoutDirection(int)       */      public int getLayoutDirection() {          return mLayoutDirection;      }      /** -     * Set the layout direction for this drawable. Should be a resolved direction as the -     * Drawable as no capacity to do the resolution on his own. +     * Set the layout direction for this drawable. Should be a resolved +     * layout direction, as the Drawable as no capacity to do the resolution on +     * its own.       * -     * @param layoutDirection One of {@link android.view.View#LAYOUT_DIRECTION_LTR}, -     *   {@link android.view.View#LAYOUT_DIRECTION_RTL} -     * -     * @hide +     * @param layoutDirection the resolved layout direction for the drawable, +     *                        either {@link android.view.View#LAYOUT_DIRECTION_LTR} +     *                        or {@link android.view.View#LAYOUT_DIRECTION_RTL} +     * @see #getLayoutDirection()       */ -    public void setLayoutDirection(@View.ResolvedLayoutDir int layoutDirection) { -        if (getLayoutDirection() != layoutDirection) { +    public final boolean setLayoutDirection(@View.ResolvedLayoutDir int layoutDirection) { +        if (mLayoutDirection != layoutDirection) {              mLayoutDirection = layoutDirection; +            return onLayoutDirectionChange(layoutDirection);          } +        return false; +    } + +    /** +     * Called when the drawable's resolved layout direction changes. +     * +     * @param layoutDirection the new resolved layout direction +     * @return true if the layout direction change has caused the appearance of +     *         the drawable to change and it needs to be re-drawn +     * @see #setLayoutDirection(int) +     */ +    public boolean onLayoutDirectionChange(@View.ResolvedLayoutDir int layoutDirection) { +        return false;      }      /** @@ -553,14 +567,20 @@ public abstract class Drawable {       * Sets the bounds to which the hotspot is constrained, if they should be       * different from the drawable bounds.       * -     * @param left -     * @param top -     * @param right -     * @param bottom +     * @param left position in pixels of the left bound +     * @param top position in pixels of the top bound +     * @param right position in pixels of the right bound +     * @param bottom position in pixels of the bottom bound +     * @see #getHotspotBounds(android.graphics.Rect)       */      public void setHotspotBounds(int left, int top, int right, int bottom) {} -    /** @hide For internal use only. Individual results may vary. */ +    /** +     * Populates {@code outRect} with the hotspot bounds. +     * +     * @param outRect the rect to populate with the hotspot bounds +     * @see #setHotspotBounds(int, int, int, int) +     */      public void getHotspotBounds(Rect outRect) {          outRect.set(getBounds());      } diff --git a/graphics/java/android/graphics/drawable/DrawableContainer.java b/graphics/java/android/graphics/drawable/DrawableContainer.java index 557f563044f2..70693f210601 100644 --- a/graphics/java/android/graphics/drawable/DrawableContainer.java +++ b/graphics/java/android/graphics/drawable/DrawableContainer.java @@ -306,7 +306,6 @@ public class DrawableContainer extends Drawable implements Drawable.Callback {          }      } -    /** @hide */      @Override      public void getHotspotBounds(Rect outRect) {          if (mHotspotBounds != null) { @@ -339,6 +338,13 @@ public class DrawableContainer extends Drawable implements Drawable.Callback {      }      @Override +    public boolean onLayoutDirectionChange(int layoutDirection) { +        // Let the container handle setting its own layout direction. Otherwise, +        // we're accessing potentially unused states. +        return mDrawableContainerState.setLayoutDirection(layoutDirection, getCurrentIndex()); +    } + +    @Override      public int getIntrinsicWidth() {          if (mDrawableContainerState.isConstantSize()) {              return mDrawableContainerState.getConstantWidth(); @@ -829,18 +835,25 @@ public class DrawableContainer extends Drawable implements Drawable.Callback {              return null;          } -        final void setLayoutDirection(int layoutDirection) { +        final boolean setLayoutDirection(int layoutDirection, int currentIndex) { +            boolean changed = false; +              // No need to call createAllFutures, since future drawables will              // change layout direction when they are prepared.              final int N = mNumChildren;              final Drawable[] drawables = mDrawables;              for (int i = 0; i < N; i++) {                  if (drawables[i] != null) { -                    drawables[i].setLayoutDirection(layoutDirection); +                    final boolean childChanged = drawables[i].setLayoutDirection(layoutDirection); +                    if (i == currentIndex) { +                        changed = childChanged; +                    }                  }              }              mLayoutDirection = layoutDirection; + +            return changed;          }          final void applyTheme(Theme theme) { diff --git a/graphics/java/android/graphics/drawable/DrawableWrapper.java b/graphics/java/android/graphics/drawable/DrawableWrapper.java new file mode 100644 index 000000000000..b17bab03218b --- /dev/null +++ b/graphics/java/android/graphics/drawable/DrawableWrapper.java @@ -0,0 +1,443 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.graphics.drawable; + +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.content.res.ColorStateList; +import android.content.res.Resources; +import android.content.res.TypedArray; +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.ColorFilter; +import android.graphics.Insets; +import android.graphics.Outline; +import android.graphics.PixelFormat; +import android.graphics.PorterDuff; +import android.graphics.Rect; +import android.util.AttributeSet; +import android.view.View; + +import java.io.IOException; +import java.util.Collection; + +/** + * Drawable container with only one child element. + */ +public abstract class DrawableWrapper extends Drawable implements Drawable.Callback { +    private DrawableWrapperState mState; +    private Drawable mDrawable; +    private boolean mMutated; + +    DrawableWrapper(DrawableWrapperState state, Resources res) { +        mState = state; + +        updateLocalState(res); +    } + +    /** +     * Creates a new wrapper around the specified drawable. +     * +     * @param dr the drawable to wrap +     */ +    public DrawableWrapper(@Nullable Drawable dr) { +        mState = null; +        mDrawable = dr; +    } + +    /** +     * Initializes local dynamic properties from state. This should be called +     * after significant state changes, e.g. from the One True Constructor and +     * after inflating or applying a theme. +     */ +    private void updateLocalState(Resources res) { +        if (mState != null && mState.mDrawableState != null) { +            final Drawable dr = mState.mDrawableState.newDrawable(res); +            setDrawable(dr); +        } +    } + +    /** +     * Sets the wrapped drawable. +     * +     * @param dr the wrapped drawable +     */ +    public void setDrawable(@Nullable Drawable dr) { +        if (mDrawable != null) { +            mDrawable.setCallback(null); +        } + +        mDrawable = dr; + +        if (dr != null) { +            dr.setCallback(this); + +            // Only call setters for data that's stored in the base Drawable. +            dr.setVisible(isVisible(), true); +            dr.setState(getState()); +            dr.setLevel(getLevel()); +            dr.setBounds(getBounds()); +            dr.setLayoutDirection(getLayoutDirection()); + +            if (mState != null) { +                mState.mDrawableState = dr.getConstantState(); +            } +        } + +        invalidateSelf(); +    } + +    /** +     * @return the wrapped drawable +     */ +    @Nullable +    public Drawable getDrawable() { +        return mDrawable; +    } + +    void updateStateFromTypedArray(TypedArray a) { +        final DrawableWrapperState state = mState; +        if (state == null) { +            return; +        } + +        // Account for any configuration changes. +        state.mChangingConfigurations |= a.getChangingConfigurations(); + +        // Extract the theme attributes, if any. +        state.mThemeAttrs = a.extractThemeAttrs(); + +        // TODO: Consider using R.styleable.DrawableWrapper_drawable +    } + +    @Override +    public void applyTheme(Resources.Theme t) { +        super.applyTheme(t); + +        final DrawableWrapperState state = mState; +        if (state == null) { +            return; +        } + +        if (mDrawable != null && mDrawable.canApplyTheme()) { +            mDrawable.applyTheme(t); +        } +    } + +    @Override +    public boolean canApplyTheme() { +        return (mState != null && mState.canApplyTheme()) || super.canApplyTheme(); +    } + +    @Override +    public void invalidateDrawable(Drawable who) { +        final Callback callback = getCallback(); +        if (callback != null) { +            callback.invalidateDrawable(this); +        } +    } + +    @Override +    public void scheduleDrawable(Drawable who, Runnable what, long when) { +        final Callback callback = getCallback(); +        if (callback != null) { +            callback.scheduleDrawable(this, what, when); +        } +    } + +    @Override +    public void unscheduleDrawable(Drawable who, Runnable what) { +        final Callback callback = getCallback(); +        if (callback != null) { +            callback.unscheduleDrawable(this, what); +        } +    } + +    @Override +    public void draw(@NonNull Canvas canvas) { +        if (mDrawable != null) { +            mDrawable.draw(canvas); +        } +    } + +    @Override +    public int getChangingConfigurations() { +        return super.getChangingConfigurations() +                | (mState != null ? mState.mChangingConfigurations : 0) +                | mDrawable.getChangingConfigurations(); +    } + +    @Override +    public boolean getPadding(@NonNull Rect padding) { +        return mDrawable != null && mDrawable.getPadding(padding); +    } + +    /** @hide */ +    @Override +    public Insets getOpticalInsets() { +        return mDrawable != null ? mDrawable.getOpticalInsets() : Insets.NONE; +    } + +    @Override +    public void setHotspot(float x, float y) { +        if (mDrawable != null) { +            mDrawable.setHotspot(x, y); +        } +    } + +    @Override +    public void setHotspotBounds(int left, int top, int right, int bottom) { +        if (mDrawable != null) { +            mDrawable.setHotspotBounds(left, top, right, bottom); +        } +    } + +    @Override +    public void getHotspotBounds(@NonNull Rect outRect) { +        if (mDrawable != null) { +            mDrawable.getHotspotBounds(outRect); +        } else { +            outRect.set(getBounds()); +        } +    } + +    @Override +    public boolean setVisible(boolean visible, boolean restart) { +        final boolean superChanged = super.setVisible(visible, restart); +        final boolean changed = mDrawable != null && mDrawable.setVisible(visible, restart); +        return superChanged | changed; +    } + +    @Override +    public void setAlpha(int alpha) { +        if (mDrawable != null) { +            mDrawable.setAlpha(alpha); +        } +    } + +    @Override +    public int getAlpha() { +        return mDrawable != null ? mDrawable.getAlpha() : 255; +    } + +    @Override +    public void setColorFilter(@Nullable ColorFilter cf) { +        if (mDrawable != null) { +            mDrawable.setColorFilter(cf); +        } +    } + +    @Override +    public void setTintList(@Nullable ColorStateList tint) { +        if (mDrawable != null) { +            mDrawable.setTintList(tint); +        } +    } + +    @Override +    public void setTintMode(@Nullable PorterDuff.Mode tintMode) { +        if (mDrawable != null) { +            mDrawable.setTintMode(tintMode); +        } +    } + +    @Override +    public boolean onLayoutDirectionChange(@View.ResolvedLayoutDir int layoutDirection) { +        return mDrawable != null && mDrawable.setLayoutDirection(layoutDirection); +    } + +    @Override +    public int getOpacity() { +        return mDrawable != null ? mDrawable.getOpacity() : PixelFormat.TRANSPARENT; +    } + +    @Override +    public boolean isStateful() { +        return mDrawable != null && mDrawable.isStateful(); +    } + +    @Override +    protected boolean onStateChange(int[] state) { +        if (mDrawable != null) { +            final boolean changed = mDrawable.setState(state); +            if (changed) { +                onBoundsChange(getBounds()); +            } +            return changed; +        } +        return false; +    } + +    @Override +    protected boolean onLevelChange(int level) { +        return mDrawable != null && mDrawable.setLevel(level); +    } + +    @Override +    protected void onBoundsChange(@NonNull Rect bounds) { +        if (mDrawable != null) { +            mDrawable.setBounds(bounds); +        } +    } + +    @Override +    public int getIntrinsicWidth() { +        return mDrawable != null ? mDrawable.getIntrinsicWidth() : -1; +    } + +    @Override +    public int getIntrinsicHeight() { +        return mDrawable != null ? mDrawable.getIntrinsicHeight() : -1; +    } + +    @Override +    public void getOutline(@NonNull Outline outline) { +        if (mDrawable != null) { +            mDrawable.getOutline(outline); +        } else { +            super.getOutline(outline); +        } +    } + +    @Override +    @Nullable +    public ConstantState getConstantState() { +        if (mState != null && mState.canConstantState()) { +            mState.mChangingConfigurations = getChangingConfigurations(); +            return mState; +        } +        return null; +    } + +    @Override +    @NonNull +    public Drawable mutate() { +        if (!mMutated && super.mutate() == this) { +            mState = mutateConstantState(); +            if (mDrawable != null) { +                mDrawable.mutate(); +            } +            if (mState != null) { +                mState.mDrawableState = mDrawable != null ? mDrawable.getConstantState() : null; +            } +            mMutated = true; +        } +        return this; +    } + +    /** +     * Mutates the constant state and returns the new state. Responsible for +     * updating any local copy. +     * <p> +     * This method should never call the super implementation; it should always +     * mutate and return its own constant state. +     * +     * @return the new state +     */ +    DrawableWrapperState mutateConstantState() { +        return mState; +    } + +    /** +     * @hide Only used by the framework for pre-loading resources. +     */ +    public void clearMutated() { +        super.clearMutated(); +        if (mDrawable != null) { +            mDrawable.clearMutated(); +        } +        mMutated = false; +    } + +    /** +     * Called during inflation to inflate the child element. +     */ +    void inflateChildDrawable(Resources r, XmlPullParser parser, AttributeSet attrs, +            Resources.Theme theme) throws XmlPullParserException, IOException { +        // Drawable specified on the root element takes precedence. +        if (getDrawable() != null) { +            return; +        } + +        // Seek to the first child element. +        Drawable dr = null; +        int type; +        final int outerDepth = parser.getDepth(); +        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT +                && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { +            if (type == XmlPullParser.START_TAG) { +                dr = Drawable.createFromXmlInner(r, parser, attrs, theme); +                break; +            } +        } + +        if (dr != null) { +            setDrawable(dr); +        } +    } + +    abstract static class DrawableWrapperState extends Drawable.ConstantState { +        int[] mThemeAttrs; +        int mChangingConfigurations; + +        Drawable.ConstantState mDrawableState; + +        DrawableWrapperState(DrawableWrapperState orig) { +            if (orig != null) { +                mThemeAttrs = orig.mThemeAttrs; +                mChangingConfigurations = orig.mChangingConfigurations; +                mDrawableState = orig.mDrawableState; +            } +        } + +        @Override +        public boolean canApplyTheme() { +            return mThemeAttrs != null +                    || (mDrawableState != null && mDrawableState.canApplyTheme()) +                    || super.canApplyTheme(); +        } + +        @Override +        public int addAtlasableBitmaps(Collection<Bitmap> atlasList) { +            final Drawable.ConstantState state = mDrawableState; +            if (state != null) { +                return state.addAtlasableBitmaps(atlasList); +            } +            return 0; +        } + +        @Override +        public Drawable newDrawable() { +            return newDrawable(null); +        } + +        @Override +        public abstract Drawable newDrawable(Resources res); + +        @Override +        public int getChangingConfigurations() { +            return mChangingConfigurations; +        } + +        public boolean canConstantState() { +            return mDrawableState != null; +        } +    } +} diff --git a/graphics/java/android/graphics/drawable/InsetDrawable.java b/graphics/java/android/graphics/drawable/InsetDrawable.java index 50a6df4adc55..b0cd386ab2c4 100644 --- a/graphics/java/android/graphics/drawable/InsetDrawable.java +++ b/graphics/java/android/graphics/drawable/InsetDrawable.java @@ -18,27 +18,20 @@ package android.graphics.drawable;  import com.android.internal.R; -import android.annotation.NonNull; -  import org.xmlpull.v1.XmlPullParser;  import org.xmlpull.v1.XmlPullParserException; -import android.content.res.ColorStateList; +import android.annotation.NonNull;  import android.content.res.Resources; -import android.content.res.TypedArray;  import android.content.res.Resources.Theme; -import android.graphics.Bitmap; -import android.graphics.Canvas; -import android.graphics.ColorFilter; +import android.content.res.TypedArray;  import android.graphics.Insets;  import android.graphics.Outline;  import android.graphics.PixelFormat; -import android.graphics.PorterDuff.Mode;  import android.graphics.Rect;  import android.util.AttributeSet;  import java.io.IOException; -import java.util.Collection;  /**   * A Drawable that insets another Drawable by a specified distance. @@ -56,13 +49,10 @@ import java.util.Collection;   * @attr ref android.R.styleable#InsetDrawable_insetTop   * @attr ref android.R.styleable#InsetDrawable_insetBottom   */ -public class InsetDrawable extends Drawable implements Drawable.Callback { +public class InsetDrawable extends DrawableWrapper {      private final Rect mTmpRect = new Rect();      private InsetState mState; -    private Drawable mDrawable; - -    private boolean mMutated;      /**       * No-arg constructor used by drawable inflation. @@ -94,72 +84,29 @@ public class InsetDrawable extends Drawable implements Drawable.Callback {              int insetBottom) {          this(new InsetState(), null); -        mState.mDrawableState = drawable == null ? null : drawable.getConstantState();          mState.mInsetLeft = insetLeft;          mState.mInsetTop = insetTop;          mState.mInsetRight = insetRight;          mState.mInsetBottom = insetBottom; -        mDrawable = drawable; - -        if (drawable != null) { -            drawable.setCallback(this); -        } +        setDrawable(drawable);      }      @Override      public void inflate(Resources r, XmlPullParser parser, AttributeSet attrs, Theme theme)              throws XmlPullParserException, IOException { -        final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.InsetDrawable); -        super.inflateWithAttributes(r, parser, a, R.styleable.InsetDrawable_visible); +        super.inflate(r, parser, attrs, theme); +        final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.InsetDrawable);          updateStateFromTypedArray(a); -        inflateChildElements(r, parser, attrs, theme); +        inflateChildDrawable(r, parser, attrs, theme);          verifyRequiredAttributes(a);          a.recycle();      } -    private void setDrawable(Drawable dr) { -        if (mDrawable != null) { -            mDrawable.setCallback(null); -        } - -        mDrawable = dr; - -        if (dr != null) { -            dr.setCallback(this); -            dr.setVisible(isVisible(), true); -            dr.setState(getState()); -            dr.setLevel(getLevel()); -            dr.setBounds(getBounds()); -            dr.setLayoutDirection(getLayoutDirection()); -        } -    } - -    private void inflateChildElements(Resources r, XmlPullParser parser, AttributeSet attrs, -            Theme theme) throws XmlPullParserException, IOException { -        // Load inner XML elements. -        if (mDrawable == null) { -            int type; -            while ((type=parser.next()) == XmlPullParser.TEXT) { -            } -            if (type != XmlPullParser.START_TAG) { -                throw new XmlPullParserException(parser.getPositionDescription() -                        + ": <inset> tag requires a 'drawable' attribute or " -                        + "child tag defining a drawable"); -            } - -            final Drawable dr = Drawable.createFromXmlInner(r, parser, attrs, theme); -            if (dr != null) { -                mState.mDrawableState = dr.getConstantState(); -                setDrawable(dr); -            } -        } -    } -      private void verifyRequiredAttributes(TypedArray a) throws XmlPullParserException {          // If we're not waiting on a theme, verify required attributes. -        if (mDrawable == null && (mState.mThemeAttrs == null +        if (getDrawable() == null && (mState.mThemeAttrs == null                  || mState.mThemeAttrs[R.styleable.InsetDrawable_drawable] == 0)) {              throw new XmlPullParserException(a.getPositionDescription()                      + ": <inset> tag requires a 'drawable' attribute or " @@ -167,15 +114,11 @@ public class InsetDrawable extends Drawable implements Drawable.Callback {          }      } -    private void updateStateFromTypedArray(TypedArray a) throws XmlPullParserException { -        final InsetState state = mState; - -        // Account for any configuration changes. -        state.mChangingConfigurations |= a.getChangingConfigurations(); - -        // Extract the theme attributes, if any. -        state.mThemeAttrs = a.extractThemeAttrs(); +    @Override +    void updateStateFromTypedArray(TypedArray a) { +        super.updateStateFromTypedArray(a); +        final InsetState state = mState;          final int N = a.getIndexCount();          for (int i = 0; i < N; i++) {              final int attr = a.getIndex(i); @@ -183,7 +126,6 @@ public class InsetDrawable extends Drawable implements Drawable.Callback {                  case R.styleable.InsetDrawable_drawable:                      final Drawable dr = a.getDrawable(attr);                      if (dr != null) { -                        mState.mDrawableState = dr.getConstantState();                          setDrawable(dr);                      }                      break; @@ -214,8 +156,6 @@ public class InsetDrawable extends Drawable implements Drawable.Callback {      @Override      public void applyTheme(Theme t) { -        super.applyTheme(t); -          final InsetState state = mState;          if (state == null) {              return; @@ -233,55 +173,14 @@ public class InsetDrawable extends Drawable implements Drawable.Callback {              }          } -        if (mDrawable != null && mDrawable.canApplyTheme()) { -            mDrawable.applyTheme(t); -        } -    } - -    @Override -    public boolean canApplyTheme() { -        return (mState != null && mState.canApplyTheme()) || super.canApplyTheme(); -    } - -    @Override -    public void invalidateDrawable(Drawable who) { -        final Callback callback = getCallback(); -        if (callback != null) { -            callback.invalidateDrawable(this); -        } -    } - -    @Override -    public void scheduleDrawable(Drawable who, Runnable what, long when) { -        final Callback callback = getCallback(); -        if (callback != null) { -            callback.scheduleDrawable(this, what, when); -        } -    } - -    @Override -    public void unscheduleDrawable(Drawable who, Runnable what) { -        final Callback callback = getCallback(); -        if (callback != null) { -            callback.unscheduleDrawable(this, what); -        } -    } - -    @Override -    public void draw(Canvas canvas) { -        mDrawable.draw(canvas); -    } - -    @Override -    public int getChangingConfigurations() { -        return super.getChangingConfigurations() -                | mState.mChangingConfigurations -                | mDrawable.getChangingConfigurations(); +        // The drawable may have changed as a result of applying the theme, so +        // apply the theme to the wrapped drawable last. +        super.applyTheme(t);      }      @Override      public boolean getPadding(Rect padding) { -        final boolean pad = mDrawable.getPadding(padding); +        final boolean pad = super.getPadding(padding);          padding.left += mState.mInsetLeft;          padding.right += mState.mInsetRight; @@ -303,62 +202,9 @@ public class InsetDrawable extends Drawable implements Drawable.Callback {      }      @Override -    public void setHotspot(float x, float y) { -        mDrawable.setHotspot(x, y); -    } - -    @Override -    public void setHotspotBounds(int left, int top, int right, int bottom) { -        mDrawable.setHotspotBounds(left, top, right, bottom); -    } - -    /** @hide */ -    @Override -    public void getHotspotBounds(Rect outRect) { -        mDrawable.getHotspotBounds(outRect); -    } - -    @Override -    public boolean setVisible(boolean visible, boolean restart) { -        mDrawable.setVisible(visible, restart); -        return super.setVisible(visible, restart); -    } - -    @Override -    public void setAlpha(int alpha) { -        mDrawable.setAlpha(alpha); -    } - -    @Override -    public int getAlpha() { -        return mDrawable.getAlpha(); -    } - -    @Override -    public void setColorFilter(ColorFilter cf) { -        mDrawable.setColorFilter(cf); -    } - -    @Override -    public void setTintList(ColorStateList tint) { -        mDrawable.setTintList(tint); -    } - -    @Override -    public void setTintMode(Mode tintMode) { -        mDrawable.setTintMode(tintMode); -    } - -    /** {@hide} */ -    @Override -    public void setLayoutDirection(int layoutDirection) { -        mDrawable.setLayoutDirection(layoutDirection); -    } - -    @Override      public int getOpacity() {          final InsetState state = mState; -        final int opacity = mDrawable.getOpacity(); +        final int opacity = getDrawable().getOpacity();          if (opacity == PixelFormat.OPAQUE && (state.mInsetLeft > 0 || state.mInsetTop > 0                  || state.mInsetRight > 0 || state.mInsetBottom > 0)) {              return PixelFormat.TRANSLUCENT; @@ -367,23 +213,6 @@ public class InsetDrawable extends Drawable implements Drawable.Callback {      }      @Override -    public boolean isStateful() { -        return mDrawable.isStateful(); -    } - -    @Override -    protected boolean onStateChange(int[] state) { -        final boolean changed = mDrawable.setState(state); -        onBoundsChange(getBounds()); -        return changed; -    } - -    @Override -    protected boolean onLevelChange(int level) { -        return mDrawable.setLevel(level); -    } - -    @Override      protected void onBoundsChange(Rect bounds) {          final Rect r = mTmpRect;          r.set(bounds); @@ -393,22 +222,23 @@ public class InsetDrawable extends Drawable implements Drawable.Callback {          r.right -= mState.mInsetRight;          r.bottom -= mState.mInsetBottom; -        mDrawable.setBounds(r.left, r.top, r.right, r.bottom); +        // Apply inset bounds to the wrapped drawable. +        super.onBoundsChange(r);      }      @Override      public int getIntrinsicWidth() { -        return mDrawable.getIntrinsicWidth() + mState.mInsetLeft + mState.mInsetRight; +        return getDrawable().getIntrinsicWidth() + mState.mInsetLeft + mState.mInsetRight;      }      @Override      public int getIntrinsicHeight() { -        return mDrawable.getIntrinsicHeight() + mState.mInsetTop + mState.mInsetBottom; +        return getDrawable().getIntrinsicHeight() + mState.mInsetTop + mState.mInsetBottom;      }      @Override      public void getOutline(@NonNull Outline outline) { -        mDrawable.getOutline(outline); +        getDrawable().getOutline(outline);      }      @Override @@ -421,33 +251,12 @@ public class InsetDrawable extends Drawable implements Drawable.Callback {      }      @Override -    public Drawable mutate() { -        if (!mMutated && super.mutate() == this) { -            mState = new InsetState(mState); -            mDrawable.mutate(); -            mState.mDrawableState = mDrawable.getConstantState(); -            mMutated = true; -        } -        return this; +    DrawableWrapperState mutateConstantState() { +        mState = new InsetState(mState); +        return mState;      } -    /** -     * @hide -     */ -    public void clearMutated() { -        super.clearMutated(); -        mDrawable.clearMutated(); -        mMutated = false; -    } - -    /** -     * Returns the drawable wrapped by this InsetDrawable. May be null. -     */ -    public Drawable getDrawable() { -        return mDrawable; -    } - -    private static final class InsetState extends ConstantState { +    static final class InsetState extends DrawableWrapper.DrawableWrapperState {          int[] mThemeAttrs;          int mChangingConfigurations; @@ -458,15 +267,14 @@ public class InsetDrawable extends Drawable implements Drawable.Callback {          int mInsetRight = 0;          int mInsetBottom = 0; -        public InsetState() { -            // Empty constructor. +        InsetState() { +            this(null);          } -        public InsetState(InsetState orig) { +        InsetState(InsetState orig) { +            super(orig); +              if (orig != null) { -                mThemeAttrs = orig.mThemeAttrs; -                mChangingConfigurations = orig.mChangingConfigurations; -                mDrawableState = orig.mDrawableState;                  mInsetLeft = orig.mInsetLeft;                  mInsetTop = orig.mInsetTop;                  mInsetRight = orig.mInsetRight; @@ -475,39 +283,9 @@ public class InsetDrawable extends Drawable implements Drawable.Callback {          }          @Override -        public boolean canApplyTheme() { -            return mThemeAttrs != null -                    || (mDrawableState != null && mDrawableState.canApplyTheme()) -                    || super.canApplyTheme(); -        } - -        @Override -        public int addAtlasableBitmaps(Collection<Bitmap> atlasList) { -            final ConstantState state = mDrawableState; -            if (state != null) { -                return state.addAtlasableBitmaps(atlasList); -            } -            return 0; -        } - -        @Override -        public Drawable newDrawable() { -            return new InsetDrawable(this, null); -        } - -        @Override          public Drawable newDrawable(Resources res) {              return new InsetDrawable(this, res);          } - -        @Override -        public int getChangingConfigurations() { -            return mChangingConfigurations; -        } - -        public boolean canConstantState() { -            return mDrawableState != null; -        }      }      /** @@ -515,21 +293,9 @@ public class InsetDrawable extends Drawable implements Drawable.Callback {       * constructors to set the state and initialize local properties.       */      private InsetDrawable(InsetState state, Resources res) { -        mState = state; - -        updateLocalState(res); -    } +        super(state, res); -    /** -     * Initializes local dynamic properties from state. This should be called -     * after significant state changes, e.g. from the One True Constructor and -     * after inflating or applying a theme. -     */ -    private void updateLocalState(Resources res) { -        if (mState.mDrawableState != null) { -            final Drawable dr = mState.mDrawableState.newDrawable(res); -            setDrawable(dr); -        } +        mState = state;      }  } diff --git a/graphics/java/android/graphics/drawable/LayerDrawable.java b/graphics/java/android/graphics/drawable/LayerDrawable.java index 616aebd528c3..08849dffd0ad 100644 --- a/graphics/java/android/graphics/drawable/LayerDrawable.java +++ b/graphics/java/android/graphics/drawable/LayerDrawable.java @@ -834,7 +834,6 @@ public class LayerDrawable extends Drawable implements Drawable.Callback {          }      } -    /** @hide */      @Override      public void getHotspotBounds(Rect outRect) {          if (mHotspotBounds != null) { @@ -1230,16 +1229,16 @@ public class LayerDrawable extends Drawable implements Drawable.Callback {          mMutated = false;      } -    /** @hide */      @Override -    public void setLayoutDirection(int layoutDirection) { -        super.setLayoutDirection(layoutDirection); +    public boolean onLayoutDirectionChange(int layoutDirection) { +        boolean changed = false;          final ChildDrawable[] array = mLayerState.mChildren;          final int N = mLayerState.mNum;          for (int i = 0; i < N; i++) { -            array[i].mDrawable.setLayoutDirection(layoutDirection); +            changed |= array[i].mDrawable.setLayoutDirection(layoutDirection);          }          updateLayerBounds(getBounds()); +        return changed;      }      static class ChildDrawable { diff --git a/graphics/java/android/graphics/drawable/RippleDrawable.java b/graphics/java/android/graphics/drawable/RippleDrawable.java index 556c59f61fa5..c6ea91dac73a 100644 --- a/graphics/java/android/graphics/drawable/RippleDrawable.java +++ b/graphics/java/android/graphics/drawable/RippleDrawable.java @@ -614,7 +614,6 @@ public class RippleDrawable extends LayerDrawable {          onHotspotBoundsChanged();      } -    /** @hide */      @Override      public void getHotspotBounds(Rect outRect) {          outRect.set(mHotspotBounds); diff --git a/graphics/java/android/graphics/drawable/RotateDrawable.java b/graphics/java/android/graphics/drawable/RotateDrawable.java index e1991fe83b9b..595061cd3136 100644 --- a/graphics/java/android/graphics/drawable/RotateDrawable.java +++ b/graphics/java/android/graphics/drawable/RotateDrawable.java @@ -29,6 +29,7 @@ import android.content.res.ColorStateList;  import android.content.res.Resources;  import android.content.res.TypedArray;  import android.content.res.Resources.Theme; +import android.util.MathUtils;  import android.util.TypedValue;  import android.util.AttributeSet; @@ -51,12 +52,10 @@ import java.io.IOException;   * @attr ref android.R.styleable#RotateDrawable_pivotY   * @attr ref android.R.styleable#RotateDrawable_drawable   */ -public class RotateDrawable extends Drawable implements Drawable.Callback { -    private static final float MAX_LEVEL = 10000.0f; +public class RotateDrawable extends DrawableWrapper { +    private static final int MAX_LEVEL = 10000; -    private final RotateState mState; - -    private boolean mMutated; +    private RotateState mState;      /**       * Create a new rotating drawable with an empty state. @@ -65,100 +64,108 @@ public class RotateDrawable extends Drawable implements Drawable.Callback {          this(null, null);      } -    /** -     * Create a new rotating drawable with the specified state. A copy of -     * this state is used as the internal state for the newly created -     * drawable. -     * -     * @param rotateState the state for this drawable -     */ -    private RotateDrawable(RotateState rotateState, Resources res) { -        mState = new RotateState(rotateState, this, res); -    } -      @Override -    public void draw(Canvas canvas) { -        final RotateState st = mState; -        final Drawable d = st.mDrawable; -        final Rect bounds = d.getBounds(); -        final int w = bounds.right - bounds.left; -        final int h = bounds.bottom - bounds.top; -        final float px = st.mPivotXRel ? (w * st.mPivotX) : st.mPivotX; -        final float py = st.mPivotYRel ? (h * st.mPivotY) : st.mPivotY; +    public void inflate(Resources r, XmlPullParser parser, AttributeSet attrs, Theme theme) +            throws XmlPullParserException, IOException { +        final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.RotateDrawable); +        super.inflateWithAttributes(r, parser, a, R.styleable.RotateDrawable_visible); -        final int saveCount = canvas.save(); -        canvas.rotate(st.mCurrentDegrees, px + bounds.left, py + bounds.top); -        d.draw(canvas); -        canvas.restoreToCount(saveCount); +        updateStateFromTypedArray(a); +        inflateChildDrawable(r, parser, attrs, theme); +        verifyRequiredAttributes(a); +        a.recycle();      } -    /** -     * Sets the drawable rotated by this RotateDrawable. -     * -     * @param drawable The drawable to rotate -     */ -    public void setDrawable(Drawable drawable) { -        final Drawable oldDrawable = mState.mDrawable; -        if (oldDrawable != drawable) { -            if (oldDrawable != null) { -                oldDrawable.setCallback(null); -            } -            mState.mDrawable = drawable; -            if (drawable != null) { -                drawable.setCallback(this); -            } +    private void verifyRequiredAttributes(TypedArray a) throws XmlPullParserException { +        // If we're not waiting on a theme, verify required attributes. +        if (getDrawable() == null && (mState.mThemeAttrs == null +                || mState.mThemeAttrs[R.styleable.RotateDrawable_drawable] == 0)) { +            throw new XmlPullParserException(a.getPositionDescription() +                    + ": <rotate> tag requires a 'drawable' attribute or " +                    + "child tag defining a drawable");          }      } -    /** -     * @return The drawable rotated by this RotateDrawable -     */ -    public Drawable getDrawable() { -        return mState.mDrawable; -    } -      @Override -    public int getChangingConfigurations() { -        return super.getChangingConfigurations() -                | mState.mChangingConfigurations -                | mState.mDrawable.getChangingConfigurations(); -    } +    void updateStateFromTypedArray(TypedArray a) { +        super.updateStateFromTypedArray(a); -    @Override -    public void setAlpha(int alpha) { -        mState.mDrawable.setAlpha(alpha); -    } +        final RotateState state = mState; -    @Override -    public int getAlpha() { -        return mState.mDrawable.getAlpha(); -    } +        // Account for any configuration changes. +        state.mChangingConfigurations |= a.getChangingConfigurations(); -    @Override -    public void setColorFilter(ColorFilter cf) { -        mState.mDrawable.setColorFilter(cf); -    } +        // Extract the theme attributes, if any. +        state.mThemeAttrs = a.extractThemeAttrs(); -    @Override -    public void setTintList(ColorStateList tint) { -        mState.mDrawable.setTintList(tint); +        if (a.hasValue(R.styleable.RotateDrawable_pivotX)) { +            final TypedValue tv = a.peekValue(R.styleable.RotateDrawable_pivotX); +            state.mPivotXRel = tv.type == TypedValue.TYPE_FRACTION; +            state.mPivotX = state.mPivotXRel ? tv.getFraction(1.0f, 1.0f) : tv.getFloat(); +        } + +        if (a.hasValue(R.styleable.RotateDrawable_pivotY)) { +            final TypedValue tv = a.peekValue(R.styleable.RotateDrawable_pivotY); +            state.mPivotYRel = tv.type == TypedValue.TYPE_FRACTION; +            state.mPivotY = state.mPivotYRel ? tv.getFraction(1.0f, 1.0f) : tv.getFloat(); +        } + +        state.mFromDegrees = a.getFloat( +                R.styleable.RotateDrawable_fromDegrees, state.mFromDegrees); +        state.mToDegrees = a.getFloat( +                R.styleable.RotateDrawable_toDegrees, state.mToDegrees); +        state.mCurrentDegrees = state.mFromDegrees; + +        final Drawable dr = a.getDrawable(R.styleable.RotateDrawable_drawable); +        if (dr != null) { +            setDrawable(dr); +        }      }      @Override -    public void setTintMode(Mode tintMode) { -        mState.mDrawable.setTintMode(tintMode); +    public void applyTheme(Theme t) { +        final RotateState state = mState; +        if (state == null) { +            return; +        } + +        if (state.mThemeAttrs != null) { +            final TypedArray a = t.resolveAttributes(state.mThemeAttrs, R.styleable.RotateDrawable); +            try { +                updateStateFromTypedArray(a); +                verifyRequiredAttributes(a); +            } catch (XmlPullParserException e) { +                throw new RuntimeException(e); +            } finally { +                a.recycle(); +            } +        } + +        // The drawable may have changed as a result of applying the theme, so +        // apply the theme to the wrapped drawable last. +        super.applyTheme(t);      }      @Override -    public int getOpacity() { -        return mState.mDrawable.getOpacity(); +    public void draw(Canvas canvas) { +        final Drawable d = getDrawable(); +        final Rect bounds = d.getBounds(); +        final int w = bounds.right - bounds.left; +        final int h = bounds.bottom - bounds.top; +        final RotateState st = mState; +        final float px = st.mPivotXRel ? (w * st.mPivotX) : st.mPivotX; +        final float py = st.mPivotYRel ? (h * st.mPivotY) : st.mPivotY; + +        final int saveCount = canvas.save(); +        canvas.rotate(st.mCurrentDegrees, px + bounds.left, py + bounds.top); +        d.draw(canvas); +        canvas.restoreToCount(saveCount);      }      /**       * Sets the start angle for rotation.       * -     * @param fromDegrees Starting angle in degrees -     * +     * @param fromDegrees starting angle in degrees       * @see #getFromDegrees()       * @attr ref android.R.styleable#RotateDrawable_fromDegrees       */ @@ -170,8 +177,7 @@ public class RotateDrawable extends Drawable implements Drawable.Callback {      }      /** -     * @return The starting angle for rotation in degrees -     * +     * @return starting angle for rotation in degrees       * @see #setFromDegrees(float)       * @attr ref android.R.styleable#RotateDrawable_fromDegrees       */ @@ -182,8 +188,7 @@ public class RotateDrawable extends Drawable implements Drawable.Callback {      /**       * Sets the end angle for rotation.       * -     * @param toDegrees Ending angle in degrees -     * +     * @param toDegrees ending angle in degrees       * @see #getToDegrees()       * @attr ref android.R.styleable#RotateDrawable_toDegrees       */ @@ -195,8 +200,7 @@ public class RotateDrawable extends Drawable implements Drawable.Callback {      }      /** -     * @return The ending angle for rotation in degrees -     * +     * @return ending angle for rotation in degrees       * @see #setToDegrees(float)       * @attr ref android.R.styleable#RotateDrawable_toDegrees       */ @@ -211,7 +215,6 @@ public class RotateDrawable extends Drawable implements Drawable.Callback {       *            relative, the position represents a fraction of the drawable       *            width. Otherwise, the position represents an absolute value in       *            pixels. -     *       * @see #setPivotXRelative(boolean)       * @attr ref android.R.styleable#RotateDrawable_pivotX       */ @@ -224,7 +227,6 @@ public class RotateDrawable extends Drawable implements Drawable.Callback {      /**       * @return X position around which to rotate -     *       * @see #setPivotX(float)       * @attr ref android.R.styleable#RotateDrawable_pivotX       */ @@ -236,9 +238,8 @@ public class RotateDrawable extends Drawable implements Drawable.Callback {       * Sets whether the X pivot value represents a fraction of the drawable       * width or an absolute value in pixels.       * -     * @param relative True if the X pivot represents a fraction of the drawable +     * @param relative true if the X pivot represents a fraction of the drawable       *            width, or false if it represents an absolute value in pixels -     *       * @see #isPivotXRelative()       */      public void setPivotXRelative(boolean relative) { @@ -249,9 +250,8 @@ public class RotateDrawable extends Drawable implements Drawable.Callback {      }      /** -     * @return True if the X pivot represents a fraction of the drawable width, +     * @return true if the X pivot represents a fraction of the drawable width,       *         or false if it represents an absolute value in pixels -     *       * @see #setPivotXRelative(boolean)       */      public boolean isPivotXRelative() { @@ -265,7 +265,6 @@ public class RotateDrawable extends Drawable implements Drawable.Callback {       *            relative, the position represents a fraction of the drawable       *            height. Otherwise, the position represents an absolute value       *            in pixels. -     *       * @see #getPivotY()       * @attr ref android.R.styleable#RotateDrawable_pivotY       */ @@ -278,7 +277,6 @@ public class RotateDrawable extends Drawable implements Drawable.Callback {      /**       * @return Y position around which to rotate -     *       * @see #setPivotY(float)       * @attr ref android.R.styleable#RotateDrawable_pivotY       */ @@ -292,7 +290,6 @@ public class RotateDrawable extends Drawable implements Drawable.Callback {       *       * @param relative True if the Y pivot represents a fraction of the drawable       *            height, or false if it represents an absolute value in pixels -     *       * @see #isPivotYRelative()       */      public void setPivotYRelative(boolean relative) { @@ -303,9 +300,8 @@ public class RotateDrawable extends Drawable implements Drawable.Callback {      }      /** -     * @return True if the Y pivot represents a fraction of the drawable height, +     * @return true if the Y pivot represents a fraction of the drawable height,       *         or false if it represents an absolute value in pixels -     *       * @see #setPivotYRelative(boolean)       */      public boolean isPivotYRelative() { @@ -313,254 +309,36 @@ public class RotateDrawable extends Drawable implements Drawable.Callback {      }      @Override -    public boolean canApplyTheme() { -        return (mState != null && mState.canApplyTheme()) || super.canApplyTheme(); -    } - -    @Override -    public void invalidateDrawable(Drawable who) { -        final Callback callback = getCallback(); -        if (callback != null) { -            callback.invalidateDrawable(this); -        } -    } - -    @Override -    public void scheduleDrawable(Drawable who, Runnable what, long when) { -        final Callback callback = getCallback(); -        if (callback != null) { -            callback.scheduleDrawable(this, what, when); -        } -    } - -    @Override -    public void unscheduleDrawable(Drawable who, Runnable what) { -        final Callback callback = getCallback(); -        if (callback != null) { -            callback.unscheduleDrawable(this, what); -        } -    } - -   @Override -    public boolean getPadding(Rect padding) { -        return mState.mDrawable.getPadding(padding); -    } - -    @Override -    public boolean setVisible(boolean visible, boolean restart) { -        mState.mDrawable.setVisible(visible, restart); -        return super.setVisible(visible, restart); -    } - -    @Override -    public boolean isStateful() { -        return mState.mDrawable.isStateful(); -    } - -    @Override -    protected boolean onStateChange(int[] state) { -        final boolean changed = mState.mDrawable.setState(state); -        onBoundsChange(getBounds()); -        return changed; -    } - -    @Override      protected boolean onLevelChange(int level) { -        mState.mDrawable.setLevel(level); -        onBoundsChange(getBounds()); +        super.onLevelChange(level); -        mState.mCurrentDegrees = mState.mFromDegrees + -                (mState.mToDegrees - mState.mFromDegrees) * -                        (level / MAX_LEVEL); +        final float value = level / (float) MAX_LEVEL; +        final float degrees = MathUtils.lerp(mState.mFromDegrees, mState.mToDegrees, value); +        mState.mCurrentDegrees = degrees;          invalidateSelf();          return true;      }      @Override -    protected void onBoundsChange(Rect bounds) { -        mState.mDrawable.setBounds(bounds.left, bounds.top, -                bounds.right, bounds.bottom); -    } - -    @Override -    public int getIntrinsicWidth() { -        return mState.mDrawable.getIntrinsicWidth(); -    } - -    @Override -    public int getIntrinsicHeight() { -        return mState.mDrawable.getIntrinsicHeight(); -    } - -    @Override -    public ConstantState getConstantState() { -        if (mState.canConstantState()) { -            mState.mChangingConfigurations = getChangingConfigurations(); -            return mState; -        } -        return null; -    } - -    @Override -    public void inflate(Resources r, XmlPullParser parser, AttributeSet attrs, Theme theme) -            throws XmlPullParserException, IOException { -        final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.RotateDrawable); -        super.inflateWithAttributes(r, parser, a, R.styleable.RotateDrawable_visible); - -        // Reset mDrawable to preserve old multiple-inflate behavior. This is -        // silly, but we have CTS tests that rely on it. -        mState.mDrawable = null; - -        updateStateFromTypedArray(a); -        inflateChildElements(r, parser, attrs, theme); -        verifyRequiredAttributes(a); -        a.recycle(); -    } - -    @Override -    public void applyTheme(Theme t) { -        super.applyTheme(t); - -        final RotateState state = mState; -        if (state == null) { -            return; -        } - -        if (state.mThemeAttrs != null) { -            final TypedArray a = t.resolveAttributes(state.mThemeAttrs, R.styleable.RotateDrawable); -            try { -                updateStateFromTypedArray(a); -                verifyRequiredAttributes(a); -            } catch (XmlPullParserException e) { -                throw new RuntimeException(e); -            } finally { -                a.recycle(); -            } -        } - -        if (state.mDrawable != null && state.mDrawable.canApplyTheme()) { -            state.mDrawable.applyTheme(t); -        } - -    } - -    private void inflateChildElements(Resources r, XmlPullParser parser, AttributeSet attrs, -            Theme theme) throws XmlPullParserException, IOException { -        Drawable dr = null; -        int type; -        final int outerDepth = parser.getDepth(); -        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT -                && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { -            if (type != XmlPullParser.START_TAG) { -                continue; -            } -            dr = Drawable.createFromXmlInner(r, parser, attrs, theme); -        } - -        if (dr != null) { -            mState.mDrawable = dr; -            dr.setCallback(this); -        } -    } - -    private void verifyRequiredAttributes(TypedArray a) throws XmlPullParserException { -        // If we're not waiting on a theme, verify required attributes. -        if (mState.mDrawable == null && (mState.mThemeAttrs == null -                || mState.mThemeAttrs[R.styleable.ScaleDrawable_drawable] == 0)) { -            throw new XmlPullParserException(a.getPositionDescription() -                    + ": <rotate> tag requires a 'drawable' attribute or " -                    + "child tag defining a drawable"); -        } -    } - -    private void updateStateFromTypedArray(TypedArray a) { -        final RotateState state = mState; - -        // Account for any configuration changes. -        state.mChangingConfigurations |= a.getChangingConfigurations(); - -        // Extract the theme attributes, if any. -        state.mThemeAttrs = a.extractThemeAttrs(); - -        if (a.hasValue(R.styleable.RotateDrawable_pivotX)) { -            final TypedValue tv = a.peekValue(R.styleable.RotateDrawable_pivotX); -            state.mPivotXRel = tv.type == TypedValue.TYPE_FRACTION; -            state.mPivotX = state.mPivotXRel ? tv.getFraction(1.0f, 1.0f) : tv.getFloat(); -        } - -        if (a.hasValue(R.styleable.RotateDrawable_pivotY)) { -            final TypedValue tv = a.peekValue(R.styleable.RotateDrawable_pivotY); -            state.mPivotYRel = tv.type == TypedValue.TYPE_FRACTION; -            state.mPivotY = state.mPivotYRel ? tv.getFraction(1.0f, 1.0f) : tv.getFloat(); -        } - -        state.mFromDegrees = a.getFloat(R.styleable.RotateDrawable_fromDegrees, state.mFromDegrees); -        state.mToDegrees = a.getFloat(R.styleable.RotateDrawable_toDegrees, state.mToDegrees); -        state.mCurrentDegrees = state.mFromDegrees; - -        final Drawable dr = a.getDrawable(R.styleable.RotateDrawable_drawable); -        if (dr != null) { -            state.mDrawable = dr; -            dr.setCallback(this); -        } -    } - -    @Override -    public Drawable mutate() { -        if (!mMutated && super.mutate() == this) { -            mState.mDrawable.mutate(); -            mMutated = true; -        } -        return this; -    } - -    /** -     * @hide -     */ -    public void clearMutated() { -        super.clearMutated(); -        mState.mDrawable.clearMutated(); -        mMutated = false; +    DrawableWrapperState mutateConstantState() { +        mState = new RotateState(mState); +        return mState;      } -    /** -     * Represents the state of a rotation for a given drawable. The same -     * rotate drawable can be invoked with different states to drive several -     * rotations at the same time. -     */ -    final static class RotateState extends Drawable.ConstantState { -        int[] mThemeAttrs; -        int mChangingConfigurations; - -        Drawable mDrawable; - +    static final class RotateState extends DrawableWrapper.DrawableWrapperState {          boolean mPivotXRel = true;          float mPivotX = 0.5f;          boolean mPivotYRel = true;          float mPivotY = 0.5f; -          float mFromDegrees = 0.0f;          float mToDegrees = 360.0f; -          float mCurrentDegrees = 0.0f; -        private boolean mCheckedConstantState; -        private boolean mCanConstantState; +        RotateState(RotateState orig) { +            super(orig); -        RotateState(RotateState orig, RotateDrawable owner, Resources res) {              if (orig != null) { -                mThemeAttrs = orig.mThemeAttrs; -                mChangingConfigurations = orig.mChangingConfigurations; -                if (res != null) { -                    mDrawable = orig.mDrawable.getConstantState().newDrawable(res); -                } else { -                    mDrawable = orig.mDrawable.getConstantState().newDrawable(); -                } -                mDrawable.setCallback(owner); -                mDrawable.setLayoutDirection(orig.mDrawable.getLayoutDirection()); -                mDrawable.setBounds(orig.mDrawable.getBounds()); -                mDrawable.setLevel(orig.mDrawable.getLevel());                  mPivotXRel = orig.mPivotXRel;                  mPivotX = orig.mPivotX;                  mPivotYRel = orig.mPivotYRel; @@ -568,38 +346,18 @@ public class RotateDrawable extends Drawable implements Drawable.Callback {                  mFromDegrees = orig.mFromDegrees;                  mToDegrees = orig.mToDegrees;                  mCurrentDegrees = orig.mCurrentDegrees; -                mCheckedConstantState = mCanConstantState = true;              }          }          @Override -        public boolean canApplyTheme() { -            return mThemeAttrs != null || (mDrawable != null && mDrawable.canApplyTheme()) -                    || super.canApplyTheme(); -        } - -        @Override -        public Drawable newDrawable() { -            return new RotateDrawable(this, null); -        } - -        @Override          public Drawable newDrawable(Resources res) {              return new RotateDrawable(this, res);          } +    } -        @Override -        public int getChangingConfigurations() { -            return mChangingConfigurations; -        } - -        public boolean canConstantState() { -            if (!mCheckedConstantState) { -                mCanConstantState = mDrawable.getConstantState() != null; -                mCheckedConstantState = true; -            } +    private RotateDrawable(RotateState state, Resources res) { +        super(state, res); -            return mCanConstantState; -        } +        mState = state;      }  } diff --git a/graphics/java/android/graphics/drawable/ScaleDrawable.java b/graphics/java/android/graphics/drawable/ScaleDrawable.java index da722f3ec749..0acbeda1979e 100644 --- a/graphics/java/android/graphics/drawable/ScaleDrawable.java +++ b/graphics/java/android/graphics/drawable/ScaleDrawable.java @@ -21,17 +21,17 @@ import com.android.internal.R;  import org.xmlpull.v1.XmlPullParser;  import org.xmlpull.v1.XmlPullParserException; -import android.content.res.ColorStateList;  import android.content.res.Resources; -import android.content.res.TypedArray;  import android.content.res.Resources.Theme; -import android.graphics.*; -import android.graphics.PorterDuff.Mode; -import android.view.Gravity; +import android.content.res.TypedArray; +import android.graphics.Canvas; +import android.graphics.PixelFormat; +import android.graphics.Rect;  import android.util.AttributeSet; +import android.util.TypedValue; +import android.view.Gravity;  import java.io.IOException; -import java.util.Collection;  /**   * A Drawable that changes the size of another Drawable based on its current @@ -49,44 +49,37 @@ import java.util.Collection;   * @attr ref android.R.styleable#ScaleDrawable_scaleGravity   * @attr ref android.R.styleable#ScaleDrawable_drawable   */ -public class ScaleDrawable extends Drawable implements Drawable.Callback { -    private ScaleState mState; -    private boolean mMutated; +public class ScaleDrawable extends DrawableWrapper { +    private static final int MAX_LEVEL = 10000; +      private final Rect mTmpRect = new Rect(); +    private ScaleState mState; +      ScaleDrawable() { -        this(null, null); +        this(new ScaleState(null), null);      } +    /** +     * Creates a new scale drawable with the specified gravity and scale +     * properties. +     * +     * @param drawable the drawable to scale +     * @param gravity gravity constant (see {@link Gravity} used to position +     *                the scaled drawable within the parent container +     * @param scaleWidth width scaling factor [0...1] to use then the level is +     *                   at the maximum value, or -1 to not scale width +     * @param scaleHeight height scaling factor [0...1] to use then the level +     *                    is at the maximum value, or -1 to not scale height +     */      public ScaleDrawable(Drawable drawable, int gravity, float scaleWidth, float scaleHeight) { -        this(null, null); +        this(new ScaleState(null), null); -        mState.mDrawable = drawable;          mState.mGravity = gravity;          mState.mScaleWidth = scaleWidth;          mState.mScaleHeight = scaleHeight; -        if (drawable != null) { -            drawable.setCallback(this); -        } -    } - -    /** -     * Returns the drawable scaled by this ScaleDrawable. -     */ -    public Drawable getDrawable() { -        return mState.mDrawable; -    } - -    private static float getPercent(TypedArray a, int name, float defaultValue) { -        final String s = a.getString(name); -        if (s != null) { -            if (s.endsWith("%")) { -                String f = s.substring(0, s.length() - 1); -                return Float.parseFloat(f) / 100.0f; -            } -        } -        return defaultValue; +        setDrawable(drawable);      }      @Override @@ -95,65 +88,15 @@ public class ScaleDrawable extends Drawable implements Drawable.Callback {          super.inflate(r, parser, attrs, theme);          final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.ScaleDrawable); - -        // Reset mDrawable to preserve old multiple-inflate behavior. This is -        // silly, but we have CTS tests that rely on it. -        mState.mDrawable = null; -          updateStateFromTypedArray(a); -        inflateChildElements(r, parser, attrs, theme); +        inflateChildDrawable(r, parser, attrs, theme);          verifyRequiredAttributes(a);          a.recycle();      } -    @Override -    public void applyTheme(Theme t) { -        super.applyTheme(t); - -        final ScaleState state = mState; -        if (state == null) { -            return; -        } - -        if (state.mThemeAttrs != null) { -            final TypedArray a = t.resolveAttributes(state.mThemeAttrs, R.styleable.ScaleDrawable); -            try { -                updateStateFromTypedArray(a); -                verifyRequiredAttributes(a); -            } catch (XmlPullParserException e) { -                throw new RuntimeException(e); -            } finally { -                a.recycle(); -            } -        } - -        if (state.mDrawable != null && state.mDrawable.canApplyTheme()) { -            state.mDrawable.applyTheme(t); -        } -    } - -    private void inflateChildElements(Resources r, XmlPullParser parser, AttributeSet attrs, -            Theme theme) throws XmlPullParserException, IOException { -        Drawable dr = null; -        int type; -        final int outerDepth = parser.getDepth(); -        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT -                && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { -            if (type != XmlPullParser.START_TAG) { -                continue; -            } -            dr = Drawable.createFromXmlInner(r, parser, attrs, theme); -        } - -        if (dr != null) { -            mState.mDrawable = dr; -            dr.setCallback(this); -        } -    } -      private void verifyRequiredAttributes(TypedArray a) throws XmlPullParserException {          // If we're not waiting on a theme, verify required attributes. -        if (mState.mDrawable == null && (mState.mThemeAttrs == null +        if (getDrawable() == null && (mState.mThemeAttrs == null                  || mState.mThemeAttrs[R.styleable.ScaleDrawable_drawable] == 0)) {              throw new XmlPullParserException(a.getPositionDescription()                      + ": <scale> tag requires a 'drawable' attribute or " @@ -161,127 +104,95 @@ public class ScaleDrawable extends Drawable implements Drawable.Callback {          }      } -    private void updateStateFromTypedArray(TypedArray a) { -        final ScaleState state = mState; - -        // Account for any configuration changes. -        state.mChangingConfigurations |= a.getChangingConfigurations(); - -        // Extract the theme attributes, if any. -        state.mThemeAttrs = a.extractThemeAttrs(); +    @Override +    void updateStateFromTypedArray(TypedArray a) { +        super.updateStateFromTypedArray(a); -        state.mScaleWidth = getPercent( -                a, R.styleable.ScaleDrawable_scaleWidth, state.mScaleWidth); -        state.mScaleHeight = getPercent( -                a, R.styleable.ScaleDrawable_scaleHeight, state.mScaleHeight); -        state.mGravity = a.getInt(R.styleable.ScaleDrawable_scaleGravity, state.mGravity); +        final ScaleState state = mState; +        state.mScaleWidth = getPercent(a, +                R.styleable.ScaleDrawable_scaleWidth, state.mScaleWidth); +        state.mScaleHeight = getPercent(a, +                R.styleable.ScaleDrawable_scaleHeight, state.mScaleHeight); +        state.mGravity = a.getInt( +                R.styleable.ScaleDrawable_scaleGravity, state.mGravity);          state.mUseIntrinsicSizeAsMin = a.getBoolean(                  R.styleable.ScaleDrawable_useIntrinsicSizeAsMinimum, state.mUseIntrinsicSizeAsMin);          final Drawable dr = a.getDrawable(R.styleable.ScaleDrawable_drawable);          if (dr != null) { -            state.mDrawable = dr; -            dr.setCallback(this); -        } -    } - -    @Override -    public boolean canApplyTheme() { -        return (mState != null && mState.canApplyTheme()) || super.canApplyTheme(); -    } - -    // overrides from Drawable.Callback - -    public void invalidateDrawable(Drawable who) { -        if (getCallback() != null) { -            getCallback().invalidateDrawable(this); +            setDrawable(dr);          }      } -    public void scheduleDrawable(Drawable who, Runnable what, long when) { -        if (getCallback() != null) { -            getCallback().scheduleDrawable(this, what, when); +    private static float getPercent(TypedArray a, int index, float defaultValue) { +        final int type = a.getType(index); +        if (type == TypedValue.TYPE_FRACTION || type == TypedValue.TYPE_NULL) { +            return a.getFraction(index, 1, 1, defaultValue);          } -    } -    public void unscheduleDrawable(Drawable who, Runnable what) { -        if (getCallback() != null) { -            getCallback().unscheduleDrawable(this, what); +        // Coerce to float. +        final String s = a.getString(index); +        if (s != null) { +            if (s.endsWith("%")) { +                final String f = s.substring(0, s.length() - 1); +                return Float.parseFloat(f) / 100.0f; +            }          } -    } - -    // overrides from Drawable - -    @Override -    public void draw(Canvas canvas) { -        if (mState.mDrawable.getLevel() != 0) -            mState.mDrawable.draw(canvas); -    } -    @Override -    public int getChangingConfigurations() { -        return super.getChangingConfigurations() -                | mState.mChangingConfigurations -                | mState.mDrawable.getChangingConfigurations(); -    } - -    @Override -    public boolean getPadding(Rect padding) { -        // XXX need to adjust padding! -        return mState.mDrawable.getPadding(padding); -    } - -    @Override -    public boolean setVisible(boolean visible, boolean restart) { -        mState.mDrawable.setVisible(visible, restart); -        return super.setVisible(visible, restart); -    } - -    @Override -    public void setAlpha(int alpha) { -        mState.mDrawable.setAlpha(alpha); +        return defaultValue;      }      @Override -    public int getAlpha() { -        return mState.mDrawable.getAlpha(); -    } +    public void applyTheme(Theme t) { +        final ScaleState state = mState; +        if (state == null) { +            return; +        } -    @Override -    public void setColorFilter(ColorFilter cf) { -        mState.mDrawable.setColorFilter(cf); -    } +        if (state.mThemeAttrs != null) { +            final TypedArray a = t.resolveAttributes( +                    state.mThemeAttrs, R.styleable.ScaleDrawable); +            try { +                updateStateFromTypedArray(a); +                verifyRequiredAttributes(a); +            } catch (XmlPullParserException e) { +                throw new RuntimeException(e); +            } finally { +                a.recycle(); +            } +        } -    @Override -    public void setTintList(ColorStateList tint) { -        mState.mDrawable.setTintList(tint); +        // The drawable may have changed as a result of applying the theme, so +        // apply the theme to the wrapped drawable last. +        super.applyTheme(t);      }      @Override -    public void setTintMode(Mode tintMode) { -        mState.mDrawable.setTintMode(tintMode); +    public void draw(Canvas canvas) { +        final Drawable d = getDrawable(); +        if (d != null && d.getLevel() != 0) { +            d.draw(canvas); +        }      }      @Override      public int getOpacity() { -        return mState.mDrawable.getOpacity(); -    } +        final Drawable d = getDrawable(); +        if (d.getLevel() == 0) { +            return PixelFormat.TRANSPARENT; +        } -    @Override -    public boolean isStateful() { -        return mState.mDrawable.isStateful(); -    } +        final int opacity = d.getOpacity(); +        if (opacity == PixelFormat.OPAQUE && d.getLevel() < MAX_LEVEL) { +            return PixelFormat.TRANSLUCENT; +        } -    @Override -    protected boolean onStateChange(int[] state) { -        boolean changed = mState.mDrawable.setState(state); -        onBoundsChange(getBounds()); -        return changed; +        return opacity;      }      @Override      protected boolean onLevelChange(int level) { -        mState.mDrawable.setLevel(level); +        super.onLevelChange(level);          onBoundsChange(getBounds());          invalidateSelf();          return true; @@ -289,144 +200,67 @@ public class ScaleDrawable extends Drawable implements Drawable.Callback {      @Override      protected void onBoundsChange(Rect bounds) { +        final Drawable d = getDrawable();          final Rect r = mTmpRect;          final boolean min = mState.mUseIntrinsicSizeAsMin; -        int level = getLevel(); +        final int level = getLevel(); +          int w = bounds.width();          if (mState.mScaleWidth > 0) { -            final int iw = min ? mState.mDrawable.getIntrinsicWidth() : 0; -            w -= (int) ((w - iw) * (10000 - level) * mState.mScaleWidth / 10000); +            final int iw = min ? d.getIntrinsicWidth() : 0; +            w -= (int) ((w - iw) * (MAX_LEVEL - level) * mState.mScaleWidth / MAX_LEVEL);          } +          int h = bounds.height();          if (mState.mScaleHeight > 0) { -            final int ih = min ? mState.mDrawable.getIntrinsicHeight() : 0; -            h -= (int) ((h - ih) * (10000 - level) * mState.mScaleHeight / 10000); +            final int ih = min ? d.getIntrinsicHeight() : 0; +            h -= (int) ((h - ih) * (MAX_LEVEL - level) * mState.mScaleHeight / MAX_LEVEL);          } +          final int layoutDirection = getLayoutDirection();          Gravity.apply(mState.mGravity, w, h, bounds, r, layoutDirection);          if (w > 0 && h > 0) { -            mState.mDrawable.setBounds(r.left, r.top, r.right, r.bottom); -        } -    } - -    @Override -    public int getIntrinsicWidth() { -        return mState.mDrawable.getIntrinsicWidth(); -    } - -    @Override -    public int getIntrinsicHeight() { -        return mState.mDrawable.getIntrinsicHeight(); -    } - -    @Override -    public ConstantState getConstantState() { -        if (mState.canConstantState()) { -            mState.mChangingConfigurations = getChangingConfigurations(); -            return mState; +            d.setBounds(r.left, r.top, r.right, r.bottom);          } -        return null;      }      @Override -    public Drawable mutate() { -        if (!mMutated && super.mutate() == this) { -            mState.mDrawable.mutate(); -            mMutated = true; -        } -        return this; +    DrawableWrapperState mutateConstantState() { +        mState = new ScaleState(mState); +        return mState;      } -    /** -     * @hide -     */ -    public void clearMutated() { -        super.clearMutated(); -        mState.mDrawable.clearMutated(); -        mMutated = false; -    } - -    final static class ScaleState extends ConstantState { +    static final class ScaleState extends DrawableWrapper.DrawableWrapperState {          /** Constant used to disable scaling for a particular dimension. */          private static final float DO_NOT_SCALE = -1.0f; -        int[] mThemeAttrs; -        int mChangingConfigurations; - -        Drawable mDrawable; -          float mScaleWidth = DO_NOT_SCALE;          float mScaleHeight = DO_NOT_SCALE;          int mGravity = Gravity.LEFT;          boolean mUseIntrinsicSizeAsMin = false; -        private boolean mCheckedConstantState; -        private boolean mCanConstantState; +        ScaleState(ScaleState orig) { +            super(orig); -        ScaleState(ScaleState orig, ScaleDrawable owner, Resources res) {              if (orig != null) { -                mThemeAttrs = orig.mThemeAttrs; -                mChangingConfigurations = orig.mChangingConfigurations; -                if (res != null) { -                    mDrawable = orig.mDrawable.getConstantState().newDrawable(res); -                } else { -                    mDrawable = orig.mDrawable.getConstantState().newDrawable(); -                } -                mDrawable.setCallback(owner); -                mDrawable.setLayoutDirection(orig.mDrawable.getLayoutDirection()); -                mDrawable.setBounds(orig.mDrawable.getBounds()); -                mDrawable.setLevel(orig.mDrawable.getLevel());                  mScaleWidth = orig.mScaleWidth;                  mScaleHeight = orig.mScaleHeight;                  mGravity = orig.mGravity;                  mUseIntrinsicSizeAsMin = orig.mUseIntrinsicSizeAsMin; -                mCheckedConstantState = mCanConstantState = true;              }          }          @Override -        public boolean canApplyTheme() { -            return mThemeAttrs != null || (mDrawable != null && mDrawable.canApplyTheme()) -                    || super.canApplyTheme(); -        } - -        @Override -        public Drawable newDrawable() { -            return new ScaleDrawable(this, null); -        } - -        @Override          public Drawable newDrawable(Resources res) {              return new ScaleDrawable(this, res);          } - -        @Override -        public int getChangingConfigurations() { -            return mChangingConfigurations; -        } - -        boolean canConstantState() { -            if (!mCheckedConstantState) { -                mCanConstantState = mDrawable.getConstantState() != null; -                mCheckedConstantState = true; -            } - -            return mCanConstantState; -        } - -        @Override -        public int addAtlasableBitmaps(Collection<Bitmap> atlasList) { -            final ConstantState state = mDrawable.getConstantState(); -            if (state != null) { -                return state.addAtlasableBitmaps(atlasList); -            } -            return 0; -        }      }      private ScaleDrawable(ScaleState state, Resources res) { -        mState = new ScaleState(state, this, res); +        super(state, res); + +        mState = state;      }  } diff --git a/graphics/java/android/graphics/drawable/StateListDrawable.java b/graphics/java/android/graphics/drawable/StateListDrawable.java index 59d0ba6b4ecf..c83af1156034 100644 --- a/graphics/java/android/graphics/drawable/StateListDrawable.java +++ b/graphics/java/android/graphics/drawable/StateListDrawable.java @@ -309,16 +309,6 @@ public class StateListDrawable extends DrawableContainer {          mMutated = false;      } -    /** @hide */ -    @Override -    public void setLayoutDirection(int layoutDirection) { -        super.setLayoutDirection(layoutDirection); - -        // Let the container handle setting its own layout direction. Otherwise, -        // we're accessing potentially unused states. -        mStateListState.setLayoutDirection(layoutDirection); -    } -      static class StateListState extends DrawableContainerState {          int[] mThemeAttrs;          int[][] mStateSets;  |