Merge "Merge "Revert "Using clippath for adaptive icon drawable instead of bit..."" into tm-qpr-dev am: 132b386fc5" into tm-qpr-dev-plus-aosp
This commit is contained in:
committed by
Android (Google) Code Review
commit
deb34216ac
@@ -204,19 +204,6 @@ public class AdaptiveIconDrawableTest extends AndroidTestCase {
|
|||||||
assertEquals(100, Color.alpha(bitmap.getPixel(50, 50)));
|
assertEquals(100, Color.alpha(bitmap.getPixel(50, 50)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testSetBounds() throws Exception {
|
|
||||||
mIconDrawable = new AdaptiveIconDrawable(mBackgroundDrawable, mForegroundDrawable);
|
|
||||||
mIconDrawable.setBounds(0, 0, 100, 100);
|
|
||||||
|
|
||||||
assertEquals(new Rect(-25, -25, 125, 125), mBackgroundDrawable.getBounds());
|
|
||||||
assertEquals(new Rect(-25, -25, 125, 125), mForegroundDrawable.getBounds());
|
|
||||||
|
|
||||||
mIconDrawable.setBounds(10, 10, 110, 110);
|
|
||||||
assertEquals(new Rect(-15, -15, 135, 135), mBackgroundDrawable.getBounds());
|
|
||||||
assertEquals(new Rect(-15, -15, 135, 135), mForegroundDrawable.getBounds());
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// Utils
|
// Utils
|
||||||
//
|
//
|
||||||
|
|||||||
@@ -26,6 +26,8 @@ import android.content.res.ColorStateList;
|
|||||||
import android.content.res.Resources;
|
import android.content.res.Resources;
|
||||||
import android.content.res.Resources.Theme;
|
import android.content.res.Resources.Theme;
|
||||||
import android.content.res.TypedArray;
|
import android.content.res.TypedArray;
|
||||||
|
import android.graphics.Bitmap;
|
||||||
|
import android.graphics.BitmapShader;
|
||||||
import android.graphics.BlendMode;
|
import android.graphics.BlendMode;
|
||||||
import android.graphics.Canvas;
|
import android.graphics.Canvas;
|
||||||
import android.graphics.Color;
|
import android.graphics.Color;
|
||||||
@@ -37,6 +39,8 @@ import android.graphics.Path;
|
|||||||
import android.graphics.PixelFormat;
|
import android.graphics.PixelFormat;
|
||||||
import android.graphics.Rect;
|
import android.graphics.Rect;
|
||||||
import android.graphics.Region;
|
import android.graphics.Region;
|
||||||
|
import android.graphics.Shader;
|
||||||
|
import android.graphics.Shader.TileMode;
|
||||||
import android.util.AttributeSet;
|
import android.util.AttributeSet;
|
||||||
import android.util.DisplayMetrics;
|
import android.util.DisplayMetrics;
|
||||||
import android.util.PathParser;
|
import android.util.PathParser;
|
||||||
@@ -102,8 +106,7 @@ public class AdaptiveIconDrawable extends Drawable implements Drawable.Callback
|
|||||||
private static final float DEFAULT_VIEW_PORT_SCALE = 1f / (1 + 2 * EXTRA_INSET_PERCENTAGE);
|
private static final float DEFAULT_VIEW_PORT_SCALE = 1f / (1 + 2 * EXTRA_INSET_PERCENTAGE);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unused path.
|
* Clip path defined in R.string.config_icon_mask.
|
||||||
* TODO: Remove once the layoutLib is updated
|
|
||||||
*/
|
*/
|
||||||
private static Path sMask;
|
private static Path sMask;
|
||||||
|
|
||||||
@@ -111,10 +114,9 @@ public class AdaptiveIconDrawable extends Drawable implements Drawable.Callback
|
|||||||
* Scaled mask based on the view bounds.
|
* Scaled mask based on the view bounds.
|
||||||
*/
|
*/
|
||||||
private final Path mMask;
|
private final Path mMask;
|
||||||
private final Path mMaskTransformed;
|
private final Path mMaskScaleOnly;
|
||||||
private final Matrix mMaskMatrix;
|
private final Matrix mMaskMatrix;
|
||||||
private final Region mTransparentRegion;
|
private final Region mTransparentRegion;
|
||||||
private final Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Indices used to access {@link #mLayerState.mChildDrawable} array for foreground and
|
* Indices used to access {@link #mLayerState.mChildDrawable} array for foreground and
|
||||||
@@ -129,10 +131,19 @@ public class AdaptiveIconDrawable extends Drawable implements Drawable.Callback
|
|||||||
*/
|
*/
|
||||||
LayerState mLayerState;
|
LayerState mLayerState;
|
||||||
|
|
||||||
|
private Shader mLayersShader;
|
||||||
|
private Bitmap mLayersBitmap;
|
||||||
|
|
||||||
private final Rect mTmpOutRect = new Rect();
|
private final Rect mTmpOutRect = new Rect();
|
||||||
private Rect mHotspotBounds;
|
private Rect mHotspotBounds;
|
||||||
private boolean mMutated;
|
private boolean mMutated;
|
||||||
|
|
||||||
|
private boolean mSuspendChildInvalidation;
|
||||||
|
private boolean mChildRequestedInvalidation;
|
||||||
|
private final Canvas mCanvas;
|
||||||
|
private Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG |
|
||||||
|
Paint.FILTER_BITMAP_FLAG);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor used for xml inflation.
|
* Constructor used for xml inflation.
|
||||||
*/
|
*/
|
||||||
@@ -146,16 +157,19 @@ public class AdaptiveIconDrawable extends Drawable implements Drawable.Callback
|
|||||||
*/
|
*/
|
||||||
AdaptiveIconDrawable(@Nullable LayerState state, @Nullable Resources res) {
|
AdaptiveIconDrawable(@Nullable LayerState state, @Nullable Resources res) {
|
||||||
mLayerState = createConstantState(state, res);
|
mLayerState = createConstantState(state, res);
|
||||||
// config_icon_mask from context bound resource may have been changed using
|
// config_icon_mask from context bound resource may have been chaged using
|
||||||
// OverlayManager. Read that one first.
|
// OverlayManager. Read that one first.
|
||||||
Resources r = ActivityThread.currentActivityThread() == null
|
Resources r = ActivityThread.currentActivityThread() == null
|
||||||
? Resources.getSystem()
|
? Resources.getSystem()
|
||||||
: ActivityThread.currentActivityThread().getApplication().getResources();
|
: ActivityThread.currentActivityThread().getApplication().getResources();
|
||||||
mMask = PathParser.createPathFromPathData(r.getString(R.string.config_icon_mask));
|
// TODO: either make sMask update only when config_icon_mask changes OR
|
||||||
mMaskTransformed = new Path();
|
// get rid of it all-together in layoutlib
|
||||||
|
sMask = PathParser.createPathFromPathData(r.getString(R.string.config_icon_mask));
|
||||||
|
mMask = new Path(sMask);
|
||||||
|
mMaskScaleOnly = new Path(mMask);
|
||||||
mMaskMatrix = new Matrix();
|
mMaskMatrix = new Matrix();
|
||||||
|
mCanvas = new Canvas();
|
||||||
mTransparentRegion = new Region();
|
mTransparentRegion = new Region();
|
||||||
mPaint.setColor(Color.BLACK);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private ChildDrawable createChildDrawable(Drawable drawable) {
|
private ChildDrawable createChildDrawable(Drawable drawable) {
|
||||||
@@ -266,7 +280,7 @@ public class AdaptiveIconDrawable extends Drawable implements Drawable.Callback
|
|||||||
* @return the mask path object used to clip the drawable
|
* @return the mask path object used to clip the drawable
|
||||||
*/
|
*/
|
||||||
public Path getIconMask() {
|
public Path getIconMask() {
|
||||||
return mMaskTransformed;
|
return mMask;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -308,47 +322,92 @@ public class AdaptiveIconDrawable extends Drawable implements Drawable.Callback
|
|||||||
if (bounds.isEmpty()) {
|
if (bounds.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Set the child layer bounds bigger than the view port size
|
updateLayerBounds(bounds);
|
||||||
// by {@link #DEFAULT_VIEW_PORT_SCALE}
|
}
|
||||||
float cX = bounds.exactCenterX();
|
|
||||||
float cY = bounds.exactCenterY();
|
private void updateLayerBounds(Rect bounds) {
|
||||||
float insetWidth = bounds.width() / (DEFAULT_VIEW_PORT_SCALE * 2);
|
if (bounds.isEmpty()) {
|
||||||
float insetHeight = bounds.height() / (DEFAULT_VIEW_PORT_SCALE * 2);
|
return;
|
||||||
final Rect outRect = mTmpOutRect;
|
}
|
||||||
outRect.set(
|
try {
|
||||||
(int) (cX - insetWidth),
|
suspendChildInvalidation();
|
||||||
(int) (cY - insetHeight),
|
updateLayerBoundsInternal(bounds);
|
||||||
(int) (cX + insetWidth),
|
updateMaskBoundsInternal(bounds);
|
||||||
(int) (cY + insetHeight));
|
} finally {
|
||||||
|
resumeChildInvalidation();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the child layer bounds bigger than the view port size by {@link #DEFAULT_VIEW_PORT_SCALE}
|
||||||
|
*/
|
||||||
|
private void updateLayerBoundsInternal(Rect bounds) {
|
||||||
|
int cX = bounds.width() / 2;
|
||||||
|
int cY = bounds.height() / 2;
|
||||||
|
|
||||||
for (int i = 0, count = mLayerState.N_CHILDREN; i < count; i++) {
|
for (int i = 0, count = mLayerState.N_CHILDREN; i < count; i++) {
|
||||||
final ChildDrawable r = mLayerState.mChildren[i];
|
final ChildDrawable r = mLayerState.mChildren[i];
|
||||||
if (r.mDrawable != null) {
|
final Drawable d = r.mDrawable;
|
||||||
r.mDrawable.setBounds(outRect);
|
if (d == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
int insetWidth = (int) (bounds.width() / (DEFAULT_VIEW_PORT_SCALE * 2));
|
||||||
|
int insetHeight = (int) (bounds.height() / (DEFAULT_VIEW_PORT_SCALE * 2));
|
||||||
|
final Rect outRect = mTmpOutRect;
|
||||||
|
outRect.set(cX - insetWidth, cY - insetHeight, cX + insetWidth, cY + insetHeight);
|
||||||
|
|
||||||
|
d.setBounds(outRect);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update the clipping mask
|
private void updateMaskBoundsInternal(Rect b) {
|
||||||
mMaskMatrix.setScale(bounds.width() / MASK_SIZE, bounds.height() / MASK_SIZE);
|
// reset everything that depends on the view bounds
|
||||||
mMaskMatrix.postTranslate(bounds.left, bounds.top);
|
mMaskMatrix.setScale(b.width() / MASK_SIZE, b.height() / MASK_SIZE);
|
||||||
mMask.transform(mMaskMatrix, mMaskTransformed);
|
sMask.transform(mMaskMatrix, mMaskScaleOnly);
|
||||||
|
|
||||||
// Clear the transparent region, it is calculated lazily
|
mMaskMatrix.postTranslate(b.left, b.top);
|
||||||
|
sMask.transform(mMaskMatrix, mMask);
|
||||||
|
|
||||||
|
if (mLayersBitmap == null || mLayersBitmap.getWidth() != b.width()
|
||||||
|
|| mLayersBitmap.getHeight() != b.height()) {
|
||||||
|
mLayersBitmap = Bitmap.createBitmap(b.width(), b.height(), Bitmap.Config.ARGB_8888);
|
||||||
|
}
|
||||||
|
|
||||||
|
mPaint.setShader(null);
|
||||||
mTransparentRegion.setEmpty();
|
mTransparentRegion.setEmpty();
|
||||||
|
mLayersShader = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void draw(Canvas canvas) {
|
public void draw(Canvas canvas) {
|
||||||
int saveCount = canvas.save();
|
if (mLayersBitmap == null) {
|
||||||
canvas.clipPath(mMaskTransformed);
|
return;
|
||||||
canvas.drawPaint(mPaint);
|
}
|
||||||
|
if (mLayersShader == null) {
|
||||||
|
mCanvas.setBitmap(mLayersBitmap);
|
||||||
|
mCanvas.drawColor(Color.BLACK);
|
||||||
if (mLayerState.mChildren[BACKGROUND_ID].mDrawable != null) {
|
if (mLayerState.mChildren[BACKGROUND_ID].mDrawable != null) {
|
||||||
mLayerState.mChildren[BACKGROUND_ID].mDrawable.draw(canvas);
|
mLayerState.mChildren[BACKGROUND_ID].mDrawable.draw(mCanvas);
|
||||||
}
|
}
|
||||||
if (mLayerState.mChildren[FOREGROUND_ID].mDrawable != null) {
|
if (mLayerState.mChildren[FOREGROUND_ID].mDrawable != null) {
|
||||||
mLayerState.mChildren[FOREGROUND_ID].mDrawable.draw(canvas);
|
mLayerState.mChildren[FOREGROUND_ID].mDrawable.draw(mCanvas);
|
||||||
}
|
}
|
||||||
canvas.restoreToCount(saveCount);
|
mLayersShader = new BitmapShader(mLayersBitmap, TileMode.CLAMP, TileMode.CLAMP);
|
||||||
|
mPaint.setShader(mLayersShader);
|
||||||
|
}
|
||||||
|
if (mMaskScaleOnly != null) {
|
||||||
|
Rect bounds = getBounds();
|
||||||
|
canvas.translate(bounds.left, bounds.top);
|
||||||
|
canvas.drawPath(mMaskScaleOnly, mPaint);
|
||||||
|
canvas.translate(-bounds.left, -bounds.top);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void invalidateSelf() {
|
||||||
|
mLayersShader = null;
|
||||||
|
super.invalidateSelf();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -541,10 +600,38 @@ public class AdaptiveIconDrawable extends Drawable implements Drawable.Callback
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Temporarily suspends child invalidation.
|
||||||
|
*
|
||||||
|
* @see #resumeChildInvalidation()
|
||||||
|
*/
|
||||||
|
private void suspendChildInvalidation() {
|
||||||
|
mSuspendChildInvalidation = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resumes child invalidation after suspension, immediately performing an
|
||||||
|
* invalidation if one was requested by a child during suspension.
|
||||||
|
*
|
||||||
|
* @see #suspendChildInvalidation()
|
||||||
|
*/
|
||||||
|
private void resumeChildInvalidation() {
|
||||||
|
mSuspendChildInvalidation = false;
|
||||||
|
|
||||||
|
if (mChildRequestedInvalidation) {
|
||||||
|
mChildRequestedInvalidation = false;
|
||||||
|
invalidateSelf();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void invalidateDrawable(@NonNull Drawable who) {
|
public void invalidateDrawable(@NonNull Drawable who) {
|
||||||
|
if (mSuspendChildInvalidation) {
|
||||||
|
mChildRequestedInvalidation = true;
|
||||||
|
} else {
|
||||||
invalidateSelf();
|
invalidateSelf();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void scheduleDrawable(@NonNull Drawable who, @NonNull Runnable what, long when) {
|
public void scheduleDrawable(@NonNull Drawable who, @NonNull Runnable what, long when) {
|
||||||
@@ -627,13 +714,6 @@ public class AdaptiveIconDrawable extends Drawable implements Drawable.Callback
|
|||||||
@Override
|
@Override
|
||||||
public void setAlpha(int alpha) {
|
public void setAlpha(int alpha) {
|
||||||
mPaint.setAlpha(alpha);
|
mPaint.setAlpha(alpha);
|
||||||
final ChildDrawable[] array = mLayerState.mChildren;
|
|
||||||
for (int i = 0; i < mLayerState.N_CHILDREN; i++) {
|
|
||||||
final Drawable dr = array[i].mDrawable;
|
|
||||||
if (dr != null) {
|
|
||||||
dr.setAlpha(alpha);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -736,6 +816,10 @@ public class AdaptiveIconDrawable extends Drawable implements Drawable.Callback
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (changed) {
|
||||||
|
updateLayerBounds(getBounds());
|
||||||
|
}
|
||||||
|
|
||||||
return changed;
|
return changed;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -751,6 +835,10 @@ public class AdaptiveIconDrawable extends Drawable implements Drawable.Callback
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (changed) {
|
||||||
|
updateLayerBounds(getBounds());
|
||||||
|
}
|
||||||
|
|
||||||
return changed;
|
return changed;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -891,7 +979,6 @@ public class AdaptiveIconDrawable extends Drawable implements Drawable.Callback
|
|||||||
int mDensity;
|
int mDensity;
|
||||||
|
|
||||||
// The density to use when inflating/looking up the children drawables. A value of 0 means
|
// The density to use when inflating/looking up the children drawables. A value of 0 means
|
||||||
|
|
||||||
// use the system's density.
|
// use the system's density.
|
||||||
int mSrcDensityOverride = 0;
|
int mSrcDensityOverride = 0;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user