summaryrefslogtreecommitdiffstats
path: root/graphics
diff options
context:
space:
mode:
authorFabrice Di Meglio <fdimeglio@google.com>2013-06-24 19:22:25 -0700
committerFabrice Di Meglio <fdimeglio@google.com>2013-08-01 15:15:10 -0700
commit3f5a90b2fbba2a83a8a2c5babd5d466a5e0ad2aa (patch)
tree666fee2554ad0f795380960d425606804e8b7ede /graphics
parent851761574a775c6447ab2393d1ba42568ba08c1b (diff)
downloadframeworks_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')
-rw-r--r--graphics/java/android/graphics/drawable/BitmapDrawable.java70
-rw-r--r--graphics/java/android/graphics/drawable/Drawable.java19
-rw-r--r--graphics/java/android/graphics/drawable/DrawableContainer.java17
-rw-r--r--graphics/java/android/graphics/drawable/LayerDrawable.java22
-rw-r--r--graphics/java/android/graphics/drawable/NinePatchDrawable.java41
-rw-r--r--graphics/java/android/graphics/drawable/StateListDrawable.java3
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;