Loading core/java/android/content/pm/LauncherApps.java +12 −2 Original line number Diff line number Diff line Loading @@ -37,6 +37,7 @@ import android.graphics.Rect; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.graphics.drawable.Icon; import android.graphics.drawable.MaskableIconDrawable; import android.os.Bundle; import android.os.Handler; import android.os.Looper; Loading Loading @@ -803,7 +804,15 @@ public class LauncherApps { } try { final Bitmap bmp = BitmapFactory.decodeFileDescriptor(pfd.getFileDescriptor()); return (bmp == null) ? null : new BitmapDrawable(mContext.getResources(), bmp); if (bmp != null) { BitmapDrawable dr = new BitmapDrawable(mContext.getResources(), bmp); if (shortcut.hasMaskableBitmap()) { return new MaskableIconDrawable(null, dr); } else { return dr; } } return null; } finally { try { pfd.close(); Loading @@ -821,7 +830,8 @@ public class LauncherApps { return loadDrawableResourceFromPackage(shortcut.getPackage(), icon.getResId(), shortcut.getUserHandle(), density); } case Icon.TYPE_BITMAP: { case Icon.TYPE_BITMAP: case Icon.TYPE_BITMAP_MASKABLE: { return icon.loadDrawable(mContext); } default: Loading core/java/android/content/pm/ShortcutInfo.java +17 −2 Original line number Diff line number Diff line Loading @@ -91,6 +91,9 @@ public final class ShortcutInfo implements Parcelable { /** @hide */ public static final int FLAG_IMMUTABLE = 1 << 8; /** @hide */ public static final int FLAG_MASKABLE_BITMAP = 1 << 9; /** @hide */ @IntDef(flag = true, value = { Loading @@ -103,6 +106,7 @@ public final class ShortcutInfo implements Parcelable { FLAG_DISABLED, FLAG_STRINGS_RESOLVED, FLAG_IMMUTABLE, FLAG_MASKABLE_BITMAP, }) @Retention(RetentionPolicy.SOURCE) public @interface ShortcutFlags {} Loading Loading @@ -690,6 +694,7 @@ public final class ShortcutInfo implements Parcelable { switch (icon.getType()) { case Icon.TYPE_RESOURCE: case Icon.TYPE_BITMAP: case Icon.TYPE_BITMAP_MASKABLE: break; // OK default: throw getInvalidIconException(); Loading Loading @@ -815,8 +820,9 @@ public final class ShortcutInfo implements Parcelable { * <p>Tints set with {@link Icon#setTint} or {@link Icon#setTintList} are not supported * and will be ignored. * * <p>Only icons created with {@link Icon#createWithBitmap(Bitmap)} and * {@link Icon#createWithResource} are supported. * <p>Only icons created with {@link Icon#createWithBitmap(Bitmap)}, * {@link Icon#createWithMaskableBitmap(Bitmap)} * and {@link Icon#createWithResource} are supported. * Other types, such as URI-based icons, are not supported. * * @see LauncherApps#getShortcutIconDrawable(ShortcutInfo, int) Loading Loading @@ -1441,6 +1447,15 @@ public final class ShortcutInfo implements Parcelable { return hasFlags(FLAG_HAS_ICON_FILE); } /** * Return whether a shortcut's icon is maskable. * * @hide internal/unit tests only */ public boolean hasMaskableBitmap() { return hasFlags(FLAG_MASKABLE_BITMAP); } /** * Return whether a shortcut only contains "key" information only or not. If true, only the * following fields are available. Loading services/core/java/com/android/server/pm/ShortcutPackage.java +5 −0 Original line number Diff line number Diff line Loading @@ -1581,6 +1581,11 @@ class ShortcutPackage extends ShortcutPackageItem { Log.e(TAG_VERIFY, "Package " + getPackageName() + ": shortcut " + si.getId() + " still has an icon"); } if (si.hasMaskableBitmap() && !si.hasIconFile()) { failed = true; Log.e(TAG_VERIFY, "Package " + getPackageName() + ": shortcut " + si.getId() + " has maskable bitmap but was not saved to a file."); } if (si.hasIconFile() && si.hasIconResource()) { failed = true; Log.e(TAG_VERIFY, "Package " + getPackageName() + ": shortcut " + si.getId() Loading services/core/java/com/android/server/pm/ShortcutService.java +7 −2 Original line number Diff line number Diff line Loading @@ -1216,7 +1216,8 @@ public class ShortcutService extends IShortcutService.Stub { // he XML we'd lose the icon. We just remove all dangling files after saving the XML. shortcut.setIconResourceId(0); shortcut.setIconResName(null); shortcut.clearFlags(ShortcutInfo.FLAG_HAS_ICON_FILE | ShortcutInfo.FLAG_HAS_ICON_RES); shortcut.clearFlags(ShortcutInfo.FLAG_HAS_ICON_FILE | ShortcutInfo.FLAG_MASKABLE_BITMAP | ShortcutInfo.FLAG_HAS_ICON_RES); } public void cleanupBitmapsForPackage(@UserIdInt int userId, String packageName) { Loading Loading @@ -1351,7 +1352,8 @@ public class ShortcutService extends IShortcutService.Stub { shortcut.addFlags(ShortcutInfo.FLAG_HAS_ICON_RES); return; } case Icon.TYPE_BITMAP: { case Icon.TYPE_BITMAP: case Icon.TYPE_BITMAP_MASKABLE: { bitmap = icon.getBitmap(); // Don't recycle in this case. break; } Loading Loading @@ -1382,6 +1384,9 @@ public class ShortcutService extends IShortcutService.Stub { shortcut.setBitmapPath(out.getFile().getAbsolutePath()); shortcut.addFlags(ShortcutInfo.FLAG_HAS_ICON_FILE); if (icon.getType() == Icon.TYPE_BITMAP_MASKABLE) { shortcut.addFlags(ShortcutInfo.FLAG_MASKABLE_BITMAP); } } finally { IoUtils.closeQuietly(out); } Loading services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java +24 −5 Original line number Diff line number Diff line Loading @@ -75,7 +75,9 @@ import android.content.pm.ShortcutInfo; import android.graphics.Bitmap; import android.graphics.Bitmap.CompressFormat; import android.graphics.BitmapFactory; import android.graphics.drawable.Drawable; import android.graphics.drawable.Icon; import android.graphics.drawable.MaskableIconDrawable; import android.net.Uri; import android.os.Bundle; import android.os.Handler; Loading Loading @@ -244,6 +246,8 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { final Icon icon1 = Icon.createWithResource(getTestContext(), R.drawable.icon1); final Icon icon2 = Icon.createWithBitmap(BitmapFactory.decodeResource( getTestContext().getResources(), R.drawable.icon2)); final Icon icon3 = Icon.createWithMaskableBitmap(BitmapFactory.decodeResource( getTestContext().getResources(), R.drawable.icon2)); final ShortcutInfo si1 = makeShortcut( "shortcut1", Loading @@ -261,12 +265,18 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { icon2, makeIntent(Intent.ACTION_ASSIST, ShortcutActivity3.class), /* weight */ 12); final ShortcutInfo si3 = makeShortcut("shortcut3"); final ShortcutInfo si3 = makeShortcut( "shortcut3", "Title 3", /* activity */ null, icon3, makeIntent(Intent.ACTION_ASSIST, ShortcutActivity3.class), /* weight */ 13); assertTrue(mManager.setDynamicShortcuts(list(si1, si2))); assertTrue(mManager.setDynamicShortcuts(list(si1, si2, si3))); assertShortcutIds(assertAllNotKeyFieldsOnly( mManager.getDynamicShortcuts()), "shortcut1", "shortcut2"); "shortcut1", "shortcut2", "shortcut3"); assertEquals(2, mManager.getRemainingCallCount()); // TODO: Check fields Loading Loading @@ -550,7 +560,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { final Icon bmp32x32 = Icon.createWithBitmap(BitmapFactory.decodeResource( getTestContext().getResources(), R.drawable.black_32x32)); final Icon bmp64x64 = Icon.createWithBitmap(BitmapFactory.decodeResource( final Icon bmp64x64_maskable = Icon.createWithMaskableBitmap(BitmapFactory.decodeResource( getTestContext().getResources(), R.drawable.black_64x64)); final Icon bmp512x512 = Icon.createWithBitmap(BitmapFactory.decodeResource( getTestContext().getResources(), R.drawable.black_512x512)); Loading @@ -561,7 +571,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { makeShortcutWithIcon("res32x32", res32x32), makeShortcutWithIcon("res64x64", res64x64), makeShortcutWithIcon("bmp32x32", bmp32x32), makeShortcutWithIcon("bmp64x64", bmp64x64), makeShortcutWithIcon("bmp64x64", bmp64x64_maskable), makeShortcutWithIcon("bmp512x512", bmp512x512), makeShortcut("none") ))); Loading Loading @@ -691,6 +701,15 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { bmp = pfdToBitmap( mLauncherApps.getShortcutIconFd(CALLING_PACKAGE_1, "bmp32x32", HANDLE_USER_P0)); assertBitmapSize(128, 128, bmp); Drawable dr = mLauncherApps.getShortcutIconDrawable( makeShortcutWithIcon("bmp64x64", bmp64x64_maskable), 0); assertTrue(dr instanceof MaskableIconDrawable); float viewportPercentage = 1 / (1 + 2 * MaskableIconDrawable.getExtraInsetPercentage()); assertEquals((int) (bmp64x64_maskable.getBitmap().getWidth() * viewportPercentage), dr.getIntrinsicWidth()); assertEquals((int) (bmp64x64_maskable.getBitmap().getHeight() * viewportPercentage), dr.getIntrinsicHeight()); } public void testCleanupDanglingBitmaps() throws Exception { Loading Loading
core/java/android/content/pm/LauncherApps.java +12 −2 Original line number Diff line number Diff line Loading @@ -37,6 +37,7 @@ import android.graphics.Rect; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.graphics.drawable.Icon; import android.graphics.drawable.MaskableIconDrawable; import android.os.Bundle; import android.os.Handler; import android.os.Looper; Loading Loading @@ -803,7 +804,15 @@ public class LauncherApps { } try { final Bitmap bmp = BitmapFactory.decodeFileDescriptor(pfd.getFileDescriptor()); return (bmp == null) ? null : new BitmapDrawable(mContext.getResources(), bmp); if (bmp != null) { BitmapDrawable dr = new BitmapDrawable(mContext.getResources(), bmp); if (shortcut.hasMaskableBitmap()) { return new MaskableIconDrawable(null, dr); } else { return dr; } } return null; } finally { try { pfd.close(); Loading @@ -821,7 +830,8 @@ public class LauncherApps { return loadDrawableResourceFromPackage(shortcut.getPackage(), icon.getResId(), shortcut.getUserHandle(), density); } case Icon.TYPE_BITMAP: { case Icon.TYPE_BITMAP: case Icon.TYPE_BITMAP_MASKABLE: { return icon.loadDrawable(mContext); } default: Loading
core/java/android/content/pm/ShortcutInfo.java +17 −2 Original line number Diff line number Diff line Loading @@ -91,6 +91,9 @@ public final class ShortcutInfo implements Parcelable { /** @hide */ public static final int FLAG_IMMUTABLE = 1 << 8; /** @hide */ public static final int FLAG_MASKABLE_BITMAP = 1 << 9; /** @hide */ @IntDef(flag = true, value = { Loading @@ -103,6 +106,7 @@ public final class ShortcutInfo implements Parcelable { FLAG_DISABLED, FLAG_STRINGS_RESOLVED, FLAG_IMMUTABLE, FLAG_MASKABLE_BITMAP, }) @Retention(RetentionPolicy.SOURCE) public @interface ShortcutFlags {} Loading Loading @@ -690,6 +694,7 @@ public final class ShortcutInfo implements Parcelable { switch (icon.getType()) { case Icon.TYPE_RESOURCE: case Icon.TYPE_BITMAP: case Icon.TYPE_BITMAP_MASKABLE: break; // OK default: throw getInvalidIconException(); Loading Loading @@ -815,8 +820,9 @@ public final class ShortcutInfo implements Parcelable { * <p>Tints set with {@link Icon#setTint} or {@link Icon#setTintList} are not supported * and will be ignored. * * <p>Only icons created with {@link Icon#createWithBitmap(Bitmap)} and * {@link Icon#createWithResource} are supported. * <p>Only icons created with {@link Icon#createWithBitmap(Bitmap)}, * {@link Icon#createWithMaskableBitmap(Bitmap)} * and {@link Icon#createWithResource} are supported. * Other types, such as URI-based icons, are not supported. * * @see LauncherApps#getShortcutIconDrawable(ShortcutInfo, int) Loading Loading @@ -1441,6 +1447,15 @@ public final class ShortcutInfo implements Parcelable { return hasFlags(FLAG_HAS_ICON_FILE); } /** * Return whether a shortcut's icon is maskable. * * @hide internal/unit tests only */ public boolean hasMaskableBitmap() { return hasFlags(FLAG_MASKABLE_BITMAP); } /** * Return whether a shortcut only contains "key" information only or not. If true, only the * following fields are available. Loading
services/core/java/com/android/server/pm/ShortcutPackage.java +5 −0 Original line number Diff line number Diff line Loading @@ -1581,6 +1581,11 @@ class ShortcutPackage extends ShortcutPackageItem { Log.e(TAG_VERIFY, "Package " + getPackageName() + ": shortcut " + si.getId() + " still has an icon"); } if (si.hasMaskableBitmap() && !si.hasIconFile()) { failed = true; Log.e(TAG_VERIFY, "Package " + getPackageName() + ": shortcut " + si.getId() + " has maskable bitmap but was not saved to a file."); } if (si.hasIconFile() && si.hasIconResource()) { failed = true; Log.e(TAG_VERIFY, "Package " + getPackageName() + ": shortcut " + si.getId() Loading
services/core/java/com/android/server/pm/ShortcutService.java +7 −2 Original line number Diff line number Diff line Loading @@ -1216,7 +1216,8 @@ public class ShortcutService extends IShortcutService.Stub { // he XML we'd lose the icon. We just remove all dangling files after saving the XML. shortcut.setIconResourceId(0); shortcut.setIconResName(null); shortcut.clearFlags(ShortcutInfo.FLAG_HAS_ICON_FILE | ShortcutInfo.FLAG_HAS_ICON_RES); shortcut.clearFlags(ShortcutInfo.FLAG_HAS_ICON_FILE | ShortcutInfo.FLAG_MASKABLE_BITMAP | ShortcutInfo.FLAG_HAS_ICON_RES); } public void cleanupBitmapsForPackage(@UserIdInt int userId, String packageName) { Loading Loading @@ -1351,7 +1352,8 @@ public class ShortcutService extends IShortcutService.Stub { shortcut.addFlags(ShortcutInfo.FLAG_HAS_ICON_RES); return; } case Icon.TYPE_BITMAP: { case Icon.TYPE_BITMAP: case Icon.TYPE_BITMAP_MASKABLE: { bitmap = icon.getBitmap(); // Don't recycle in this case. break; } Loading Loading @@ -1382,6 +1384,9 @@ public class ShortcutService extends IShortcutService.Stub { shortcut.setBitmapPath(out.getFile().getAbsolutePath()); shortcut.addFlags(ShortcutInfo.FLAG_HAS_ICON_FILE); if (icon.getType() == Icon.TYPE_BITMAP_MASKABLE) { shortcut.addFlags(ShortcutInfo.FLAG_MASKABLE_BITMAP); } } finally { IoUtils.closeQuietly(out); } Loading
services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java +24 −5 Original line number Diff line number Diff line Loading @@ -75,7 +75,9 @@ import android.content.pm.ShortcutInfo; import android.graphics.Bitmap; import android.graphics.Bitmap.CompressFormat; import android.graphics.BitmapFactory; import android.graphics.drawable.Drawable; import android.graphics.drawable.Icon; import android.graphics.drawable.MaskableIconDrawable; import android.net.Uri; import android.os.Bundle; import android.os.Handler; Loading Loading @@ -244,6 +246,8 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { final Icon icon1 = Icon.createWithResource(getTestContext(), R.drawable.icon1); final Icon icon2 = Icon.createWithBitmap(BitmapFactory.decodeResource( getTestContext().getResources(), R.drawable.icon2)); final Icon icon3 = Icon.createWithMaskableBitmap(BitmapFactory.decodeResource( getTestContext().getResources(), R.drawable.icon2)); final ShortcutInfo si1 = makeShortcut( "shortcut1", Loading @@ -261,12 +265,18 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { icon2, makeIntent(Intent.ACTION_ASSIST, ShortcutActivity3.class), /* weight */ 12); final ShortcutInfo si3 = makeShortcut("shortcut3"); final ShortcutInfo si3 = makeShortcut( "shortcut3", "Title 3", /* activity */ null, icon3, makeIntent(Intent.ACTION_ASSIST, ShortcutActivity3.class), /* weight */ 13); assertTrue(mManager.setDynamicShortcuts(list(si1, si2))); assertTrue(mManager.setDynamicShortcuts(list(si1, si2, si3))); assertShortcutIds(assertAllNotKeyFieldsOnly( mManager.getDynamicShortcuts()), "shortcut1", "shortcut2"); "shortcut1", "shortcut2", "shortcut3"); assertEquals(2, mManager.getRemainingCallCount()); // TODO: Check fields Loading Loading @@ -550,7 +560,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { final Icon bmp32x32 = Icon.createWithBitmap(BitmapFactory.decodeResource( getTestContext().getResources(), R.drawable.black_32x32)); final Icon bmp64x64 = Icon.createWithBitmap(BitmapFactory.decodeResource( final Icon bmp64x64_maskable = Icon.createWithMaskableBitmap(BitmapFactory.decodeResource( getTestContext().getResources(), R.drawable.black_64x64)); final Icon bmp512x512 = Icon.createWithBitmap(BitmapFactory.decodeResource( getTestContext().getResources(), R.drawable.black_512x512)); Loading @@ -561,7 +571,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { makeShortcutWithIcon("res32x32", res32x32), makeShortcutWithIcon("res64x64", res64x64), makeShortcutWithIcon("bmp32x32", bmp32x32), makeShortcutWithIcon("bmp64x64", bmp64x64), makeShortcutWithIcon("bmp64x64", bmp64x64_maskable), makeShortcutWithIcon("bmp512x512", bmp512x512), makeShortcut("none") ))); Loading Loading @@ -691,6 +701,15 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { bmp = pfdToBitmap( mLauncherApps.getShortcutIconFd(CALLING_PACKAGE_1, "bmp32x32", HANDLE_USER_P0)); assertBitmapSize(128, 128, bmp); Drawable dr = mLauncherApps.getShortcutIconDrawable( makeShortcutWithIcon("bmp64x64", bmp64x64_maskable), 0); assertTrue(dr instanceof MaskableIconDrawable); float viewportPercentage = 1 / (1 + 2 * MaskableIconDrawable.getExtraInsetPercentage()); assertEquals((int) (bmp64x64_maskable.getBitmap().getWidth() * viewportPercentage), dr.getIntrinsicWidth()); assertEquals((int) (bmp64x64_maskable.getBitmap().getHeight() * viewportPercentage), dr.getIntrinsicHeight()); } public void testCleanupDanglingBitmaps() throws Exception { Loading