diff options
| -rw-r--r-- | api/current.txt | 2 | ||||
| -rw-r--r-- | api/system-current.txt | 2 | ||||
| -rw-r--r-- | api/test-current.txt | 2 | ||||
| -rw-r--r-- | core/java/android/util/LauncherIcons.java | 6 | ||||
| -rw-r--r-- | core/tests/coretests/src/android/graphics/drawable/AdaptiveIconDrawableTest.java | 73 | ||||
| -rw-r--r-- | core/tests/coretests/src/android/graphics/drawable/IconTest.java | 8 | ||||
| -rw-r--r-- | graphics/java/android/graphics/drawable/AdaptiveIconDrawable.java | 64 | ||||
| -rw-r--r-- | services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java | 2 |
8 files changed, 135 insertions, 24 deletions
diff --git a/api/current.txt b/api/current.txt index 3a01b5f87b4d..45fb4d96aad3 100644 --- a/api/current.txt +++ b/api/current.txt @@ -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(); diff --git a/api/system-current.txt b/api/system-current.txt index 1807fcb3e3a0..8ae3f516dbad 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -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(); diff --git a/api/test-current.txt b/api/test-current.txt index 82e403f5b6bd..fd8c2d001b6a 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -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(); diff --git a/core/java/android/util/LauncherIcons.java b/core/java/android/util/LauncherIcons.java index e5aa2b5b4ce7..89b9646e54b3 100644 --- a/core/java/android/util/LauncherIcons.java +++ b/core/java/android/util/LauncherIcons.java @@ -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); diff --git a/core/tests/coretests/src/android/graphics/drawable/AdaptiveIconDrawableTest.java b/core/tests/coretests/src/android/graphics/drawable/AdaptiveIconDrawableTest.java index 5ade66e59776..7550cb5211b9 100644 --- a/core/tests/coretests/src/android/graphics/drawable/AdaptiveIconDrawableTest.java +++ b/core/tests/coretests/src/android/graphics/drawable/AdaptiveIconDrawableTest.java @@ -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 // diff --git a/core/tests/coretests/src/android/graphics/drawable/IconTest.java b/core/tests/coretests/src/android/graphics/drawable/IconTest.java index b50955b82b36..b7a48c7e6825 100644 --- a/core/tests/coretests/src/android/graphics/drawable/IconTest.java +++ b/core/tests/coretests/src/android/graphics/drawable/IconTest.java @@ -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); diff --git a/graphics/java/android/graphics/drawable/AdaptiveIconDrawable.java b/graphics/java/android/graphics/drawable/AdaptiveIconDrawable.java index 6dfe03d83ac0..283a3e2b0b1e 100644 --- a/graphics/java/android/graphics/drawable/AdaptiveIconDrawable.java +++ b/graphics/java/android/graphics/drawable/AdaptiveIconDrawable.java @@ -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><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; diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java index 9861aa177135..cd39d8875692 100644 --- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java +++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java @@ -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), |