Merge "Update API, add more documentation on AdaptiveIconDrawable" into oc-dev

This commit is contained in:
Hyunyoung Song
2017-04-13 16:53:37 +00:00
committed by Android (Google) Code Review
8 changed files with 135 additions and 24 deletions

View File

@@ -13828,7 +13828,7 @@ package android.graphics.drawable {
public class AdaptiveIconDrawable extends android.graphics.drawable.Drawable implements android.graphics.drawable.Drawable.Callback {
method public void draw(android.graphics.Canvas);
method public android.graphics.drawable.Drawable getBackground();
method public static float getExtraInsetPercentage();
method public static float getExtraInsetFraction();
method public android.graphics.drawable.Drawable getForeground();
method public android.graphics.Path getIconMask();
method public int getOpacity();

View File

@@ -14595,7 +14595,7 @@ package android.graphics.drawable {
public class AdaptiveIconDrawable extends android.graphics.drawable.Drawable implements android.graphics.drawable.Drawable.Callback {
method public void draw(android.graphics.Canvas);
method public android.graphics.drawable.Drawable getBackground();
method public static float getExtraInsetPercentage();
method public static float getExtraInsetFraction();
method public android.graphics.drawable.Drawable getForeground();
method public android.graphics.Path getIconMask();
method public int getOpacity();

View File

@@ -13879,7 +13879,7 @@ package android.graphics.drawable {
public class AdaptiveIconDrawable extends android.graphics.drawable.Drawable implements android.graphics.drawable.Drawable.Callback {
method public void draw(android.graphics.Canvas);
method public android.graphics.drawable.Drawable getBackground();
method public static float getExtraInsetPercentage();
method public static float getExtraInsetFraction();
method public android.graphics.drawable.Drawable getForeground();
method public android.graphics.Path getIconMask();
method public int getOpacity();

View File

@@ -20,11 +20,8 @@ import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.PaintFlagsDrawFilter;
import android.graphics.Path;
import android.graphics.RectF;
import android.graphics.drawable.AdaptiveIconDrawable;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
@@ -49,7 +46,7 @@ public final class LauncherIcons {
public LauncherIcons(Context context) {
mRes = context.getResources();
DisplayMetrics metrics = mRes.getDisplayMetrics();
mShadowInset = (int) metrics.density / DisplayMetrics.DENSITY_DEFAULT;
mShadowInset = (int)(2 * metrics.density);
mCanvas.setDrawFilter(new PaintFlagsDrawFilter(Paint.DITHER_FLAG,
Paint.FILTER_BITMAP_FLAG));
mIconSize = (int) mRes.getDimensionPixelSize(android.R.dimen.app_icon_size);
@@ -91,7 +88,6 @@ public final class LauncherIcons {
return mShadowBitmap;
}
int shadowSize = mIconSize - mShadowInset;
mShadowBitmap = Bitmap.createBitmap(mIconSize, mIconSize, Bitmap.Config.ALPHA_8);
mCanvas.setBitmap(mShadowBitmap);

View File

@@ -2,18 +2,22 @@ package android.graphics.drawable;
import static org.junit.Assert.assertTrue;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Outline;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Path.Direction;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Region;
import android.test.AndroidTestCase;
import android.util.Log;
import android.util.PathParser;
import java.io.File;
import java.io.FileOutputStream;
import java.util.Arrays;
@@ -35,7 +39,7 @@ public class AdaptiveIconDrawableTest extends AndroidTestCase {
* Nothing is drawn.
*/
@Test
public void testDrawWithoutSetBounds() throws Exception {
public void testDraw_withoutBounds() throws Exception {
mBackgroundDrawable = new ColorDrawable(Color.BLUE);
mForegroundDrawable = new ColorDrawable(Color.RED);
mIconDrawable = new AdaptiveIconDrawable(mBackgroundDrawable, mForegroundDrawable);
@@ -59,7 +63,7 @@ public class AdaptiveIconDrawableTest extends AndroidTestCase {
* When setBound is called, translate accordingly.
*/
@Test
public void testDrawSetBounds() throws Exception {
public void testDraw_withBounds() throws Exception {
int dpi = 4 ;
int top = 18 * dpi;
int left = 18 * dpi;
@@ -102,6 +106,71 @@ public class AdaptiveIconDrawableTest extends AndroidTestCase {
}
}
/**
* When setBound isn't called before getIconMask method is called.
* default device config mask is returned.
*/
@Test
public void testGetIconMask_withoutBounds() throws Exception {
mIconDrawable = new AdaptiveIconDrawable(mBackgroundDrawable, mForegroundDrawable);
Path pathFromDrawable = mIconDrawable.getIconMask();
Path pathFromDeviceConfig = PathParser.createPathFromPathData(
Resources.getSystem().getString(com.android.internal.R.string.config_icon_mask));
RectF boundFromDrawable = new RectF();
pathFromDrawable.computeBounds(boundFromDrawable, true);
RectF boundFromDeviceConfig = new RectF();
pathFromDeviceConfig.computeBounds(boundFromDeviceConfig, true);
double delta = 0.01;
assertEquals("left", boundFromDrawable.left, boundFromDeviceConfig.left, delta);
assertEquals("top", boundFromDrawable.top, boundFromDeviceConfig.top, delta);
assertEquals("right", boundFromDrawable.right, boundFromDeviceConfig.right, delta);
assertEquals("bottom", boundFromDrawable.bottom, boundFromDeviceConfig.bottom, delta);
assertTrue("path from device config is convex.", pathFromDeviceConfig.isConvex());
assertTrue("path from drawable is convex.", pathFromDrawable.isConvex());
}
@Test
public void testGetIconMaskAfterSetBounds() throws Exception {
int dpi = 4;
int top = 18 * dpi;
int left = 18 * dpi;
int right = 90 * dpi;
int bottom = 90 * dpi;
mIconDrawable = new AdaptiveIconDrawable(mBackgroundDrawable, mForegroundDrawable);
mIconDrawable.setBounds(left, top, right, bottom);
RectF maskBounds = new RectF();
mIconDrawable.getIconMask().computeBounds(maskBounds, true);
double delta = 0.01;
assertEquals("left", left, maskBounds.left, delta);
assertEquals("top", top, maskBounds.top, delta);
assertEquals("right", right, maskBounds.right, delta);
assertEquals("bottom", bottom, maskBounds.bottom, delta);
assertTrue(mIconDrawable.getIconMask().isConvex());
}
@Test
public void testGetOutline_withBounds() throws Exception {
int dpi = 4;
int top = 18 * dpi;
int left = 18 * dpi;
int right = 90 * dpi;
int bottom = 90 * dpi;
mIconDrawable = new AdaptiveIconDrawable(mBackgroundDrawable, mForegroundDrawable);
mIconDrawable.setBounds(left, top, right, bottom);
Outline outline = new Outline();
mIconDrawable.getOutline(outline);
assertTrue("outline path should be convex", outline.mPath.isConvex());
}
//
// Utils
//

View File

@@ -119,13 +119,13 @@ public class IconTest extends AndroidTestCase {
final AdaptiveIconDrawable draw1 = (AdaptiveIconDrawable) im1.loadDrawable(mContext);
final Bitmap test1 = Bitmap.createBitmap(
(int)(draw1.getIntrinsicWidth() * (1 + 2 * AdaptiveIconDrawable.getExtraInsetPercentage())),
(int)(draw1.getIntrinsicHeight() * (1 + 2 * AdaptiveIconDrawable.getExtraInsetPercentage())),
(int)(draw1.getIntrinsicWidth() * (1 + 2 * AdaptiveIconDrawable.getExtraInsetFraction())),
(int)(draw1.getIntrinsicHeight() * (1 + 2 * AdaptiveIconDrawable.getExtraInsetFraction())),
Bitmap.Config.ARGB_8888);
draw1.setBounds(0, 0,
(int) (draw1.getIntrinsicWidth() * (1 + 2 * AdaptiveIconDrawable.getExtraInsetPercentage())),
(int) (draw1.getIntrinsicHeight() * (1 + 2 * AdaptiveIconDrawable.getExtraInsetPercentage())));
(int) (draw1.getIntrinsicWidth() * (1 + 2 * AdaptiveIconDrawable.getExtraInsetFraction())),
(int) (draw1.getIntrinsicHeight() * (1 + 2 * AdaptiveIconDrawable.getExtraInsetFraction())));
draw1.draw(new Canvas(test1));
final File dir = getContext().getExternalFilesDir(null);

View File

@@ -29,6 +29,7 @@ import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.BitmapShader;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.ColorFilter;
import android.graphics.Matrix;
import android.graphics.Outline;
@@ -51,12 +52,27 @@ import org.xmlpull.v1.XmlPullParserException;
import java.io.IOException;
/**
* This drawable supports two layers: foreground and background.
*
* <p>The layers are clipped when rendering using the mask path defined in the device configuration.
*
* <p>This class can also be created via XML inflation using <code>&lt;adaptive-icon></code> tag
* in addition to dynamic creation.
*
* <p>This drawable supports two drawable layers: foreground and background. The layers are clipped
* when rendering using the mask defined in the device configuration.
*
* <ul>
* <li>Both foreground and background layers should be sized at 108 x 108 dp.</li>
* <li>The inner 72 x 72 dp of the icon appears within the masked viewport.</li>
* <li>The outer 18 dp on each of the 4 sides of the layers is reserved for use by the system UI
* surfaces to create interesting visual effects, such as parallax or pulsing.</li>
* </ul>
*
* Such motion effect is achieved by internally setting the bounds of the foreground and
* background layer as following:
* <pre>
* Rect(getBounds().left - getBounds().getWidth() * #getExtraInsetFraction(),
* getBounds().top - getBounds().getHeight() * #getExtraInsetFraction(),
* getBounds().right + getBounds().getWidth() * #getExtraInsetFraction(),
* getBounds().bottom + getBounds().getHeight() * #getExtraInsetFraction())
* </pre>
*/
public class AdaptiveIconDrawable extends Drawable implements Drawable.Callback {
@@ -65,7 +81,11 @@ public class AdaptiveIconDrawable extends Drawable implements Drawable.Callback
* @hide
*/
public static final float MASK_SIZE = 100f;
private static final float SAFEZONE_SCALE = .9f;
/**
* Launcher icons design guideline
*/
private static final float SAFEZONE_SCALE = 72f/66f;
/**
* All four sides of the layers are padded with extra inset so as to provide
@@ -80,7 +100,7 @@ public class AdaptiveIconDrawable extends Drawable implements Drawable.Callback
private static final float DEFAULT_VIEW_PORT_SCALE = 1f / (1 + 2 * EXTRA_INSET_PERCENTAGE);
/**
* Clip path defined in {@link com.android.internal.R.string.config_icon_mask}.
* Clip path defined in R.string.config_icon_mask.
*/
private static Path sMask;
@@ -134,9 +154,10 @@ public class AdaptiveIconDrawable extends Drawable implements Drawable.Callback
if (sMask == null) {
sMask = PathParser.createPathFromPathData(
Resources.getSystem().getString(com.android.internal.R.string.config_icon_mask));
Resources.getSystem().getString(R.string.config_icon_mask));
}
mMask = new Path();
mMask = PathParser.createPathFromPathData(
Resources.getSystem().getString(R.string.config_icon_mask));
mMaskMatrix = new Matrix();
mCanvas = new Canvas();
mTransparentRegion = new Region();
@@ -212,13 +233,24 @@ public class AdaptiveIconDrawable extends Drawable implements Drawable.Callback
* All four sides of the layers are padded with extra inset so as to provide
* extra content to reveal within the clip path when performing affine transformations on the
* layers.
*
* @see #getForeground() and #getBackground() for more info on how this value is used
*/
public static float getExtraInsetFraction() {
return EXTRA_INSET_PERCENTAGE;
}
/**
* @hide
*/
public static float getExtraInsetPercentage() {
return EXTRA_INSET_PERCENTAGE;
}
/**
* Only call this method after bound is set on this drawable.
* When called before the bound is set, the returned path is identical to
* R.string.config_icon_mask. After the bound is set, the
* returned path's computed bound is same as the #getBounds().
*
* @return the mask path object used to clip the drawable
*/
@@ -227,6 +259,10 @@ public class AdaptiveIconDrawable extends Drawable implements Drawable.Callback
}
/**
* Returns the foreground drawable managed by this class. The bound of this drawable is
* extended by {@link #getExtraInsetFraction()} * getBounds().width on left/right sides and by
* {@link #getExtraInsetFraction()} * getBounds().height on top/bottom sides.
*
* @return the foreground drawable managed by this drawable
*/
public Drawable getForeground() {
@@ -234,6 +270,10 @@ public class AdaptiveIconDrawable extends Drawable implements Drawable.Callback
}
/**
* Returns the foreground drawable managed by this class. The bound of this drawable is
* extended by {@link #getExtraInsetFraction()} * getBounds().width on left/right sides and by
* {@link #getExtraInsetFraction()} * getBounds().height on top/bottom sides.
*
* @return the background drawable managed by this drawable
*/
public Drawable getBackground() {
@@ -293,10 +333,15 @@ public class AdaptiveIconDrawable extends Drawable implements Drawable.Callback
mMaskBitmap = Bitmap.createBitmap(b.width(), b.height(), Bitmap.Config.ALPHA_8);
mLayersBitmap = Bitmap.createBitmap(b.width(), b.height(), Bitmap.Config.ARGB_8888);
}
// mMaskBitmap bound [0, w] x [0, h]
mCanvas.setBitmap(mMaskBitmap);
mPaint.setShader(null);
mCanvas.drawPath(mMask, mPaint);
// mMask bound [left, top, right, bottom]
mMaskMatrix.postTranslate(b.left, b.top);
mMask.reset();
sMask.transform(mMaskMatrix, mMask);
// reset everything that depends on the view bounds
mTransparentRegion.setEmpty();
mLayersShader = null;
@@ -309,6 +354,7 @@ public class AdaptiveIconDrawable extends Drawable implements Drawable.Callback
}
if (mLayersShader == null) {
mCanvas.setBitmap(mLayersBitmap);
mCanvas.drawColor(Color.BLACK);
for (int i = 0; i < mLayerState.N_CHILDREN; i++) {
if (mLayerState.mChildren[i] == null) {
continue;

View File

@@ -708,7 +708,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest {
Drawable dr = mLauncherApps.getShortcutIconDrawable(
makeShortcutWithIcon("bmp64x64", bmp64x64_maskable), 0);
assertTrue(dr instanceof AdaptiveIconDrawable);
float viewportPercentage = 1 / (1 + 2 * AdaptiveIconDrawable.getExtraInsetPercentage());
float viewportPercentage = 1 / (1 + 2 * AdaptiveIconDrawable.getExtraInsetFraction());
assertEquals((int) (bmp64x64_maskable.getBitmap().getWidth() * viewportPercentage),
dr.getIntrinsicWidth());
assertEquals((int) (bmp64x64_maskable.getBitmap().getHeight() * viewportPercentage),