Loading core/java/android/content/pm/ArchivedActivity.java +5 −6 Original line number Diff line number Diff line Loading @@ -79,14 +79,14 @@ public final class ArchivedActivity { * @hide */ public static Bitmap drawableToBitmap(Drawable drawable) { return drawableToBitmap(drawable, /* maxIconSize= */ Integer.MAX_VALUE); return drawableToBitmap(drawable, /* iconSize= */ 0); } /** * Same as above, but. * Same as above, but scale the resulting image to fit iconSize. * @hide */ public static Bitmap drawableToBitmap(Drawable drawable, int maxIconSize) { public static Bitmap drawableToBitmap(Drawable drawable, int iconSize) { if (drawable instanceof BitmapDrawable) { return ((BitmapDrawable) drawable).getBitmap(); Loading @@ -106,8 +106,8 @@ public final class ArchivedActivity { Canvas canvas = new Canvas(bitmap); drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight()); drawable.draw(canvas); if (bitmap.getWidth() > maxIconSize || bitmap.getHeight() > maxIconSize) { var scaledBitmap = Bitmap.createScaledBitmap(bitmap, maxIconSize, maxIconSize, true); if (iconSize > 0 && bitmap.getWidth() > iconSize * 2 || bitmap.getHeight() > iconSize * 2) { var scaledBitmap = Bitmap.createScaledBitmap(bitmap, iconSize, iconSize, true); if (scaledBitmap != bitmap) { bitmap.recycle(); } Loading @@ -118,7 +118,6 @@ public final class ArchivedActivity { /** * Compress bitmap to PNG format. * The bitmap is going to be recycled. * @hide */ public static byte[] bytesFromBitmap(Bitmap bitmap) { Loading services/core/java/com/android/server/pm/PackageArchiver.java +10 −6 Original line number Diff line number Diff line Loading @@ -29,6 +29,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.annotation.UserIdInt; import android.app.ActivityManager; import android.app.AppOpsManager; import android.app.BroadcastOptions; import android.content.Context; Loading Loading @@ -214,10 +215,13 @@ public class PackageArchiver { ArchiveState createArchiveStateInternal(String packageName, int userId, List<LauncherActivityInfo> mainActivities, String installerPackage) throws IOException { final int iconSize = mContext.getSystemService( ActivityManager.class).getLauncherLargeIconSize(); List<ArchiveActivityInfo> archiveActivityInfos = new ArrayList<>(mainActivities.size()); for (int i = 0, size = mainActivities.size(); i < size; i++) { LauncherActivityInfo mainActivity = mainActivities.get(i); Path iconPath = storeIcon(packageName, mainActivity, userId, i); Path iconPath = storeIcon(packageName, mainActivity, userId, i, iconSize); ArchiveActivityInfo activityInfo = new ArchiveActivityInfo( mainActivity.getLabel().toString(), Loading Loading @@ -247,7 +251,7 @@ public class PackageArchiver { @VisibleForTesting Path storeIcon(String packageName, LauncherActivityInfo mainActivity, @UserIdInt int userId, int index) throws IOException { @UserIdInt int userId, int index, int iconSize) throws IOException { int iconResourceId = mainActivity.getActivityInfo().getIconResource(); if (iconResourceId == 0) { // The app doesn't define an icon. No need to store anything. Loading @@ -255,7 +259,7 @@ public class PackageArchiver { } File iconsDir = createIconsDir(userId); File iconFile = new File(iconsDir, packageName + "-" + index + ".png"); Bitmap icon = drawableToBitmap(mainActivity.getIcon(/* density= */ 0)); Bitmap icon = drawableToBitmap(mainActivity.getIcon(/* density= */ 0), iconSize); try (FileOutputStream out = new FileOutputStream(iconFile)) { // Note: Quality is ignored for PNGs. if (!icon.compress(Bitmap.CompressFormat.PNG, /* quality= */ 100, out)) { Loading Loading @@ -590,8 +594,8 @@ public class PackageArchiver { /** * Creates serializable archived activities from launcher activities. */ static ArchivedActivityParcel[] createArchivedActivities(List<LauncherActivityInfo> infos) throws IOException { static ArchivedActivityParcel[] createArchivedActivities(List<LauncherActivityInfo> infos, int iconSize) throws IOException { if (infos == null || infos.isEmpty()) { throw new IllegalArgumentException("No launcher activities"); } Loading @@ -606,7 +610,7 @@ public class PackageArchiver { archivedActivity.title = info.getLabel().toString(); archivedActivity.originalComponentName = info.getComponentName(); archivedActivity.iconBitmap = info.getActivityInfo().getIconResource() == 0 ? null : bytesFromBitmap(drawableToBitmap(info.getIcon(/* density= */ 0))); bytesFromBitmap(drawableToBitmap(info.getIcon(/* density= */ 0), iconSize)); // TODO(b/298452477) Handle monochrome icons. archivedActivity.monochromeIconBitmap = null; activities.add(archivedActivity); Loading services/core/java/com/android/server/pm/PackageManagerService.java +4 −1 Original line number Diff line number Diff line Loading @@ -1486,11 +1486,14 @@ public class PackageManagerService implements PackageSender, TestUtilityService archPkg.archivedActivities = PackageArchiver.createArchivedActivities( archiveState); } else { final int iconSize = mContext.getSystemService( ActivityManager.class).getLauncherLargeIconSize(); var mainActivities = mInstallerService.mPackageArchiver.getLauncherActivityInfos(packageName, userId); archPkg.archivedActivities = PackageArchiver.createArchivedActivities( mainActivities); mainActivities, iconSize); } } catch (Exception e) { throw new IllegalArgumentException("Package does not have a main activity", e); Loading services/tests/mockingservicestests/src/com/android/server/pm/PackageArchiverTest.java +9 −2 Original line number Diff line number Diff line Loading @@ -35,6 +35,7 @@ import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.app.ActivityManager; import android.app.AppOpsManager; import android.content.ComponentName; import android.content.Context; Loading Loading @@ -100,6 +101,8 @@ public class PackageArchiverTest { @Mock private LauncherApps mLauncherApps; @Mock private ActivityManager mActivityManager; @Mock private PackageManager mPackageManager; @Mock private PackageInstallerService mInstallerService; Loading Loading @@ -159,6 +162,10 @@ public class PackageArchiverTest { when(mContext.getSystemService(LauncherApps.class)).thenReturn(mLauncherApps); when(mLauncherApps.getActivityList(eq(PACKAGE), eq(UserHandle.CURRENT))).thenReturn( mLauncherActivityInfos); when(mContext.getSystemService(ActivityManager.class)).thenReturn(mActivityManager); when(mActivityManager.getLauncherLargeIconDensity()).thenReturn(100); doReturn(mComputer).when(mPackageManagerService).snapshotComputer(); when(mComputer.getPackageUid(eq(CALLER_PACKAGE), eq(0L), eq(mUserId))).thenReturn( Binder.getCallingUid()); Loading @@ -172,7 +179,7 @@ public class PackageArchiverTest { mArchiveManager = spy(new PackageArchiver(mContext, mPackageManagerService)); doReturn(ICON_PATH).when(mArchiveManager).storeIcon(eq(PACKAGE), any(LauncherActivityInfo.class), eq(mUserId), anyInt()); any(LauncherActivityInfo.class), eq(mUserId), anyInt(), anyInt()); doReturn(mIcon).when(mArchiveManager).decodeIcon( any(ArchiveState.ArchiveActivityInfo.class)); } Loading Loading @@ -277,7 +284,7 @@ public class PackageArchiverTest { public void archiveApp_storeIconFails() throws IntentSender.SendIntentException, IOException { IOException e = new IOException("IO"); doThrow(e).when(mArchiveManager).storeIcon(eq(PACKAGE), any(LauncherActivityInfo.class), eq(mUserId), anyInt()); any(LauncherActivityInfo.class), eq(mUserId), anyInt(), anyInt()); mArchiveManager.requestArchive(PACKAGE, CALLER_PACKAGE, mIntentSender, UserHandle.CURRENT); rule.mocks().getHandler().flush(); Loading Loading
core/java/android/content/pm/ArchivedActivity.java +5 −6 Original line number Diff line number Diff line Loading @@ -79,14 +79,14 @@ public final class ArchivedActivity { * @hide */ public static Bitmap drawableToBitmap(Drawable drawable) { return drawableToBitmap(drawable, /* maxIconSize= */ Integer.MAX_VALUE); return drawableToBitmap(drawable, /* iconSize= */ 0); } /** * Same as above, but. * Same as above, but scale the resulting image to fit iconSize. * @hide */ public static Bitmap drawableToBitmap(Drawable drawable, int maxIconSize) { public static Bitmap drawableToBitmap(Drawable drawable, int iconSize) { if (drawable instanceof BitmapDrawable) { return ((BitmapDrawable) drawable).getBitmap(); Loading @@ -106,8 +106,8 @@ public final class ArchivedActivity { Canvas canvas = new Canvas(bitmap); drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight()); drawable.draw(canvas); if (bitmap.getWidth() > maxIconSize || bitmap.getHeight() > maxIconSize) { var scaledBitmap = Bitmap.createScaledBitmap(bitmap, maxIconSize, maxIconSize, true); if (iconSize > 0 && bitmap.getWidth() > iconSize * 2 || bitmap.getHeight() > iconSize * 2) { var scaledBitmap = Bitmap.createScaledBitmap(bitmap, iconSize, iconSize, true); if (scaledBitmap != bitmap) { bitmap.recycle(); } Loading @@ -118,7 +118,6 @@ public final class ArchivedActivity { /** * Compress bitmap to PNG format. * The bitmap is going to be recycled. * @hide */ public static byte[] bytesFromBitmap(Bitmap bitmap) { Loading
services/core/java/com/android/server/pm/PackageArchiver.java +10 −6 Original line number Diff line number Diff line Loading @@ -29,6 +29,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.annotation.UserIdInt; import android.app.ActivityManager; import android.app.AppOpsManager; import android.app.BroadcastOptions; import android.content.Context; Loading Loading @@ -214,10 +215,13 @@ public class PackageArchiver { ArchiveState createArchiveStateInternal(String packageName, int userId, List<LauncherActivityInfo> mainActivities, String installerPackage) throws IOException { final int iconSize = mContext.getSystemService( ActivityManager.class).getLauncherLargeIconSize(); List<ArchiveActivityInfo> archiveActivityInfos = new ArrayList<>(mainActivities.size()); for (int i = 0, size = mainActivities.size(); i < size; i++) { LauncherActivityInfo mainActivity = mainActivities.get(i); Path iconPath = storeIcon(packageName, mainActivity, userId, i); Path iconPath = storeIcon(packageName, mainActivity, userId, i, iconSize); ArchiveActivityInfo activityInfo = new ArchiveActivityInfo( mainActivity.getLabel().toString(), Loading Loading @@ -247,7 +251,7 @@ public class PackageArchiver { @VisibleForTesting Path storeIcon(String packageName, LauncherActivityInfo mainActivity, @UserIdInt int userId, int index) throws IOException { @UserIdInt int userId, int index, int iconSize) throws IOException { int iconResourceId = mainActivity.getActivityInfo().getIconResource(); if (iconResourceId == 0) { // The app doesn't define an icon. No need to store anything. Loading @@ -255,7 +259,7 @@ public class PackageArchiver { } File iconsDir = createIconsDir(userId); File iconFile = new File(iconsDir, packageName + "-" + index + ".png"); Bitmap icon = drawableToBitmap(mainActivity.getIcon(/* density= */ 0)); Bitmap icon = drawableToBitmap(mainActivity.getIcon(/* density= */ 0), iconSize); try (FileOutputStream out = new FileOutputStream(iconFile)) { // Note: Quality is ignored for PNGs. if (!icon.compress(Bitmap.CompressFormat.PNG, /* quality= */ 100, out)) { Loading Loading @@ -590,8 +594,8 @@ public class PackageArchiver { /** * Creates serializable archived activities from launcher activities. */ static ArchivedActivityParcel[] createArchivedActivities(List<LauncherActivityInfo> infos) throws IOException { static ArchivedActivityParcel[] createArchivedActivities(List<LauncherActivityInfo> infos, int iconSize) throws IOException { if (infos == null || infos.isEmpty()) { throw new IllegalArgumentException("No launcher activities"); } Loading @@ -606,7 +610,7 @@ public class PackageArchiver { archivedActivity.title = info.getLabel().toString(); archivedActivity.originalComponentName = info.getComponentName(); archivedActivity.iconBitmap = info.getActivityInfo().getIconResource() == 0 ? null : bytesFromBitmap(drawableToBitmap(info.getIcon(/* density= */ 0))); bytesFromBitmap(drawableToBitmap(info.getIcon(/* density= */ 0), iconSize)); // TODO(b/298452477) Handle monochrome icons. archivedActivity.monochromeIconBitmap = null; activities.add(archivedActivity); Loading
services/core/java/com/android/server/pm/PackageManagerService.java +4 −1 Original line number Diff line number Diff line Loading @@ -1486,11 +1486,14 @@ public class PackageManagerService implements PackageSender, TestUtilityService archPkg.archivedActivities = PackageArchiver.createArchivedActivities( archiveState); } else { final int iconSize = mContext.getSystemService( ActivityManager.class).getLauncherLargeIconSize(); var mainActivities = mInstallerService.mPackageArchiver.getLauncherActivityInfos(packageName, userId); archPkg.archivedActivities = PackageArchiver.createArchivedActivities( mainActivities); mainActivities, iconSize); } } catch (Exception e) { throw new IllegalArgumentException("Package does not have a main activity", e); Loading
services/tests/mockingservicestests/src/com/android/server/pm/PackageArchiverTest.java +9 −2 Original line number Diff line number Diff line Loading @@ -35,6 +35,7 @@ import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.app.ActivityManager; import android.app.AppOpsManager; import android.content.ComponentName; import android.content.Context; Loading Loading @@ -100,6 +101,8 @@ public class PackageArchiverTest { @Mock private LauncherApps mLauncherApps; @Mock private ActivityManager mActivityManager; @Mock private PackageManager mPackageManager; @Mock private PackageInstallerService mInstallerService; Loading Loading @@ -159,6 +162,10 @@ public class PackageArchiverTest { when(mContext.getSystemService(LauncherApps.class)).thenReturn(mLauncherApps); when(mLauncherApps.getActivityList(eq(PACKAGE), eq(UserHandle.CURRENT))).thenReturn( mLauncherActivityInfos); when(mContext.getSystemService(ActivityManager.class)).thenReturn(mActivityManager); when(mActivityManager.getLauncherLargeIconDensity()).thenReturn(100); doReturn(mComputer).when(mPackageManagerService).snapshotComputer(); when(mComputer.getPackageUid(eq(CALLER_PACKAGE), eq(0L), eq(mUserId))).thenReturn( Binder.getCallingUid()); Loading @@ -172,7 +179,7 @@ public class PackageArchiverTest { mArchiveManager = spy(new PackageArchiver(mContext, mPackageManagerService)); doReturn(ICON_PATH).when(mArchiveManager).storeIcon(eq(PACKAGE), any(LauncherActivityInfo.class), eq(mUserId), anyInt()); any(LauncherActivityInfo.class), eq(mUserId), anyInt(), anyInt()); doReturn(mIcon).when(mArchiveManager).decodeIcon( any(ArchiveState.ArchiveActivityInfo.class)); } Loading Loading @@ -277,7 +284,7 @@ public class PackageArchiverTest { public void archiveApp_storeIconFails() throws IntentSender.SendIntentException, IOException { IOException e = new IOException("IO"); doThrow(e).when(mArchiveManager).storeIcon(eq(PACKAGE), any(LauncherActivityInfo.class), eq(mUserId), anyInt()); any(LauncherActivityInfo.class), eq(mUserId), anyInt(), anyInt()); mArchiveManager.requestArchive(PACKAGE, CALLER_PACKAGE, mIntentSender, UserHandle.CURRENT); rule.mocks().getHandler().flush(); Loading