diff options
author | Fabrice Di Meglio <fdimeglio@google.com> | 2013-06-24 19:22:25 -0700 |
---|---|---|
committer | Fabrice Di Meglio <fdimeglio@google.com> | 2013-08-01 15:15:10 -0700 |
commit | 3f5a90b2fbba2a83a8a2c5babd5d466a5e0ad2aa (patch) | |
tree | 666fee2554ad0f795380960d425606804e8b7ede /graphics | |
parent | 851761574a775c6447ab2393d1ba42568ba08c1b (diff) | |
download | frameworks_base-3f5a90b2fbba2a83a8a2c5babd5d466a5e0ad2aa.zip frameworks_base-3f5a90b2fbba2a83a8a2c5babd5d466a5e0ad2aa.tar.gz frameworks_base-3f5a90b2fbba2a83a8a2c5babd5d466a5e0ad2aa.tar.bz2 |
Add automatic Drawable mirroring capability when in RTL layout direction
- default value is "no mirroring"
- introduce android:autoMirrored as a new attribute for Drawable,
BitmapDrawable, LayerDrawable, StateListDrawable and NinePatchDrawable
- setting android:autoMirrored="true" means that the drawable will
be mirrored when the layout direction is RTL (right-to-left)
- also fix an issue with ImageView drawable layout direction not
updated correctly when RTL properties were changed
See bug #7034321 Need Drawable RTL support
Change-Id: If595ee5106c786f38e786d3a032e182f784a9d97
Diffstat (limited to 'graphics')
6 files changed, 165 insertions, 7 deletions
diff --git a/graphics/java/android/graphics/drawable/BitmapDrawable.java b/graphics/java/android/graphics/drawable/BitmapDrawable.java index 8689261..5ceab36 100644 --- a/graphics/java/android/graphics/drawable/BitmapDrawable.java +++ b/graphics/java/android/graphics/drawable/BitmapDrawable.java @@ -23,12 +23,14 @@ import android.graphics.BitmapFactory; import android.graphics.BitmapShader; import android.graphics.Canvas; import android.graphics.ColorFilter; +import android.graphics.Matrix; import android.graphics.Paint; import android.graphics.PixelFormat; import android.graphics.Rect; import android.graphics.Shader; import android.util.AttributeSet; import android.util.DisplayMetrics; +import android.util.LayoutDirection; import android.view.Gravity; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; @@ -72,7 +74,10 @@ public class BitmapDrawable extends Drawable { // These are scaled to match the target density. private int mBitmapWidth; private int mBitmapHeight; - + + // Mirroring matrix for using with Shaders + private Matrix mMirrorMatrix; + /** * Create an empty drawable, not dealing with density. * @deprecated Use {@link #BitmapDrawable(android.content.res.Resources, android.graphics.Bitmap)} @@ -399,14 +404,51 @@ public class BitmapDrawable extends Drawable { } @Override + public void setAutoMirrored(boolean mirrored) { + if (mBitmapState.mAutoMirrored != mirrored) { + mBitmapState.mAutoMirrored = mirrored; + invalidateSelf(); + } + } + + @Override + public final boolean isAutoMirrored() { + return mBitmapState.mAutoMirrored; + } + + @Override public int getChangingConfigurations() { return super.getChangingConfigurations() | mBitmapState.mChangingConfigurations; } - + + private boolean needMirroring() { + return isAutoMirrored() && getLayoutDirection() == LayoutDirection.RTL; + } + + private void updateMirrorMatrix(float dx) { + if (mMirrorMatrix == null) { + mMirrorMatrix = new Matrix(); + } + mMirrorMatrix.setTranslate(dx, 0); + mMirrorMatrix.preScale(-1.0f, 1.0f); + } + @Override protected void onBoundsChange(Rect bounds) { super.onBoundsChange(bounds); mApplyGravity = true; + Shader shader = mBitmapState.mPaint.getShader(); + if (shader != null) { + if (needMirroring()) { + updateMirrorMatrix(bounds.right - bounds.left); + shader.setLocalMatrix(mMirrorMatrix); + } else { + if (mMirrorMatrix != null) { + mMirrorMatrix = null; + shader.setLocalMatrix(Matrix.IDENTITY_MATRIX); + } + } + } } @Override @@ -430,6 +472,7 @@ public class BitmapDrawable extends Drawable { } Shader shader = state.mPaint.getShader(); + final boolean needMirroring = needMirroring(); if (shader == null) { if (mApplyGravity) { final int layoutDirection = getLayoutDirection(); @@ -437,12 +480,31 @@ public class BitmapDrawable extends Drawable { getBounds(), mDstRect, layoutDirection); mApplyGravity = false; } + if (needMirroring) { + canvas.save(); + // Mirror the bitmap + canvas.translate(mDstRect.right - mDstRect.left, 0); + canvas.scale(-1.0f, 1.0f); + } canvas.drawBitmap(bitmap, null, mDstRect, state.mPaint); + if (needMirroring) { + canvas.restore(); + } } else { if (mApplyGravity) { copyBounds(mDstRect); mApplyGravity = false; } + if (needMirroring) { + // Mirror the bitmap + updateMirrorMatrix(mDstRect.right - mDstRect.left); + shader.setLocalMatrix(mMirrorMatrix); + } else { + if (mMirrorMatrix != null) { + mMirrorMatrix = null; + shader.setLocalMatrix(Matrix.IDENTITY_MATRIX); + } + } canvas.drawRect(mDstRect, state.mPaint); } } @@ -505,6 +567,8 @@ public class BitmapDrawable extends Drawable { setTargetDensity(r.getDisplayMetrics()); setMipMap(a.getBoolean(com.android.internal.R.styleable.BitmapDrawable_mipMap, bitmap.hasMipMap())); + setAutoMirrored(a.getBoolean(com.android.internal.R.styleable.BitmapDrawable_autoMirrored, + false)); final Paint paint = mBitmapState.mPaint; paint.setAntiAlias(a.getBoolean(com.android.internal.R.styleable.BitmapDrawable_antialias, @@ -567,6 +631,7 @@ public class BitmapDrawable extends Drawable { Shader.TileMode mTileModeY = null; int mTargetDensity = DisplayMetrics.DENSITY_DEFAULT; boolean mRebuildShader; + boolean mAutoMirrored; BitmapState(Bitmap bitmap) { mBitmap = bitmap; @@ -581,6 +646,7 @@ public class BitmapDrawable extends Drawable { mTargetDensity = bitmapState.mTargetDensity; mPaint = new Paint(bitmapState.mPaint); mRebuildShader = bitmapState.mRebuildShader; + mAutoMirrored = bitmapState.mAutoMirrored; } @Override diff --git a/graphics/java/android/graphics/drawable/Drawable.java b/graphics/java/android/graphics/drawable/Drawable.java index c8fce9e..8135716 100644 --- a/graphics/java/android/graphics/drawable/Drawable.java +++ b/graphics/java/android/graphics/drawable/Drawable.java @@ -572,6 +572,25 @@ public abstract class Drawable { } /** + * Set whether this Drawable is automatically mirrored when its layout direction is RTL + * (right-to left). See {@link android.util.LayoutDirection}. + * + * @param mirrored Set to true if the Drawable should be mirrored, false if not. + */ + public void setAutoMirrored(boolean mirrored) { + } + + /** + * Tells if this Drawable will be automatically mirrored when its layout direction is RTL + * right-to-left. See {@link android.util.LayoutDirection}. + * + * @return boolean Returns true if this Drawable will be automatically mirrored. + */ + public boolean isAutoMirrored() { + return false; + } + + /** * Return the opacity/transparency of this Drawable. The returned value is * one of the abstract format constants in * {@link android.graphics.PixelFormat}: diff --git a/graphics/java/android/graphics/drawable/DrawableContainer.java b/graphics/java/android/graphics/drawable/DrawableContainer.java index f9cd4e2..e350e8d 100644 --- a/graphics/java/android/graphics/drawable/DrawableContainer.java +++ b/graphics/java/android/graphics/drawable/DrawableContainer.java @@ -173,6 +173,19 @@ public class DrawableContainer extends Drawable implements Drawable.Callback { } @Override + public void setAutoMirrored(boolean mirrored) { + mDrawableContainerState.mAutoMirrored = mirrored; + if (mCurrDrawable != null) { + mCurrDrawable.mutate().setAutoMirrored(mDrawableContainerState.mAutoMirrored); + } + } + + @Override + public boolean isAutoMirrored() { + return mDrawableContainerState.mAutoMirrored; + } + + @Override public void jumpToCurrentState() { boolean changed = false; if (mLastDrawable != null) { @@ -334,6 +347,7 @@ public class DrawableContainer extends Drawable implements Drawable.Callback { d.setLevel(getLevel()); d.setBounds(getBounds()); d.setLayoutDirection(getLayoutDirection()); + d.setAutoMirrored(mDrawableContainerState.mAutoMirrored); } } else { mCurrDrawable = null; @@ -471,6 +485,8 @@ public class DrawableContainer extends Drawable implements Drawable.Callback { int mEnterFadeDuration; int mExitFadeDuration; + boolean mAutoMirrored; + DrawableContainerState(DrawableContainerState orig, DrawableContainer owner, Resources res) { mOwner = owner; @@ -490,6 +506,7 @@ public class DrawableContainer extends Drawable implements Drawable.Callback { mLayoutDirection = orig.mLayoutDirection; mEnterFadeDuration = orig.mEnterFadeDuration; mExitFadeDuration = orig.mExitFadeDuration; + mAutoMirrored = orig.mAutoMirrored; // Cloning the following values may require creating futures. mConstantPadding = orig.getConstantPadding(); diff --git a/graphics/java/android/graphics/drawable/LayerDrawable.java b/graphics/java/android/graphics/drawable/LayerDrawable.java index 206897b..81cc11b 100644 --- a/graphics/java/android/graphics/drawable/LayerDrawable.java +++ b/graphics/java/android/graphics/drawable/LayerDrawable.java @@ -119,6 +119,9 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { mOpacityOverride = a.getInt(com.android.internal.R.styleable.LayerDrawable_opacity, PixelFormat.UNKNOWN); + setAutoMirrored(a.getBoolean(com.android.internal.R.styleable.LayerDrawable_autoMirrored, + false)); + a.recycle(); final int innerDepth = parser.getDepth() + 1; @@ -200,6 +203,7 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { st.mChildren[i] = childDrawable; childDrawable.mId = id; childDrawable.mDrawable = layer; + childDrawable.mDrawable.setAutoMirrored(isAutoMirrored()); childDrawable.mInsetL = left; childDrawable.mInsetT = top; childDrawable.mInsetR = right; @@ -448,6 +452,21 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { } @Override + public void setAutoMirrored(boolean mirrored) { + mLayerState.mAutoMirrored = mirrored; + final ChildDrawable[] array = mLayerState.mChildren; + final int N = mLayerState.mNum; + for (int i=0; i<N; i++) { + array[i].mDrawable.setAutoMirrored(mirrored); + } + } + + @Override + public boolean isAutoMirrored() { + return mLayerState.mAutoMirrored; + } + + @Override public boolean isStateful() { return mLayerState.isStateful(); } @@ -630,6 +649,8 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { private boolean mCheckedConstantState; private boolean mCanConstantState; + private boolean mAutoMirrored; + LayerState(LayerState orig, LayerDrawable owner, Resources res) { if (orig != null) { final ChildDrawable[] origChildDrawable = orig.mChildren; @@ -663,6 +684,7 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { mHaveStateful = orig.mHaveStateful; mStateful = orig.mStateful; mCheckedConstantState = mCanConstantState = true; + mAutoMirrored = orig.mAutoMirrored; } else { mNum = 0; mChildren = null; diff --git a/graphics/java/android/graphics/drawable/NinePatchDrawable.java b/graphics/java/android/graphics/drawable/NinePatchDrawable.java index 86e4bad..720494b 100644 --- a/graphics/java/android/graphics/drawable/NinePatchDrawable.java +++ b/graphics/java/android/graphics/drawable/NinePatchDrawable.java @@ -30,6 +30,7 @@ import android.graphics.Rect; import android.graphics.Region; import android.util.AttributeSet; import android.util.DisplayMetrics; +import android.util.LayoutDirection; import android.util.TypedValue; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; @@ -132,6 +133,7 @@ public class NinePatchDrawable extends Drawable { // lazy allocation of a paint setDither(state.mDither); } + setAutoMirrored(state.mAutoMirrored); if (mNinePatch != null) { computeBitmapSize(); } @@ -216,7 +218,19 @@ public class NinePatchDrawable extends Drawable { @Override public void draw(Canvas canvas) { - mNinePatch.draw(canvas, getBounds(), mPaint); + final Rect bounds = getBounds(); + final boolean needMirroring = isAutoMirrored() && + getLayoutDirection() == LayoutDirection.RTL; + if (needMirroring) { + canvas.save(); + // Mirror the 9patch + canvas.translate(bounds.right - bounds.left, 0); + canvas.scale(-1.0f, 1.0f); + } + mNinePatch.draw(canvas, bounds, mPaint); + if (needMirroring) { + canvas.restore(); + } } @Override @@ -279,6 +293,16 @@ public class NinePatchDrawable extends Drawable { } @Override + public void setAutoMirrored(boolean mirrored) { + mNinePatchState.mAutoMirrored = mirrored; + } + + @Override + public boolean isAutoMirrored() { + return mNinePatchState.mAutoMirrored; + } + + @Override public void setFilterBitmap(boolean filter) { getPaint().setFilterBitmap(filter); invalidateSelf(); @@ -328,8 +352,11 @@ public class NinePatchDrawable extends Drawable { ": <nine-patch> requires a valid 9-patch source image"); } + final boolean automirrored = a.getBoolean( + com.android.internal.R.styleable.NinePatchDrawable_autoMirrored, false); + setNinePatchState(new NinePatchState(new NinePatch(bitmap, bitmap.getNinePatchChunk()), - padding, opticalInsets, dither), r); + padding, opticalInsets, dither, automirrored), r); mNinePatchState.mTargetDensity = mTargetDensity; a.recycle(); @@ -407,20 +434,23 @@ public class NinePatchDrawable extends Drawable { final boolean mDither; int mChangingConfigurations; int mTargetDensity = DisplayMetrics.DENSITY_DEFAULT; + boolean mAutoMirrored; NinePatchState(NinePatch ninePatch, Rect padding) { - this(ninePatch, padding, new Rect(), DEFAULT_DITHER); + this(ninePatch, padding, new Rect(), DEFAULT_DITHER, false); } NinePatchState(NinePatch ninePatch, Rect padding, Rect opticalInsets) { - this(ninePatch, padding, opticalInsets, DEFAULT_DITHER); + this(ninePatch, padding, opticalInsets, DEFAULT_DITHER, false); } - NinePatchState(NinePatch ninePatch, Rect rect, Rect opticalInsets, boolean dither) { + NinePatchState(NinePatch ninePatch, Rect rect, Rect opticalInsets, boolean dither, + boolean autoMirror) { mNinePatch = ninePatch; mPadding = rect; mOpticalInsets = Insets.of(opticalInsets); mDither = dither; + mAutoMirrored = autoMirror; } // Copy constructor @@ -434,6 +464,7 @@ public class NinePatchDrawable extends Drawable { mDither = state.mDither; mChangingConfigurations = state.mChangingConfigurations; mTargetDensity = state.mTargetDensity; + mAutoMirrored = state.mAutoMirrored; } @Override diff --git a/graphics/java/android/graphics/drawable/StateListDrawable.java b/graphics/java/android/graphics/drawable/StateListDrawable.java index e3c7bc5..48d66b7 100644 --- a/graphics/java/android/graphics/drawable/StateListDrawable.java +++ b/graphics/java/android/graphics/drawable/StateListDrawable.java @@ -132,6 +132,9 @@ public class StateListDrawable extends DrawableContainer { setDither(a.getBoolean(com.android.internal.R.styleable.StateListDrawable_dither, DEFAULT_DITHER)); + setAutoMirrored(a.getBoolean( + com.android.internal.R.styleable.StateListDrawable_autoMirrored, false)); + a.recycle(); int type; |