Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0c1172f9 authored by Alex Buynytskyy's avatar Alex Buynytskyy Committed by Android (Google) Code Review
Browse files

Merge "Force restrict all archived packages' icons' size." into main

parents c672afbd 3e7b627d
Loading
Loading
Loading
Loading
+5 −6
Original line number Diff line number Diff line
@@ -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();

@@ -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();
            }
@@ -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) {
+10 −6
Original line number Diff line number Diff line
@@ -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;
@@ -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(),
@@ -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.
@@ -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)) {
@@ -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");
        }
@@ -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);
+4 −1
Original line number Diff line number Diff line
@@ -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);
+9 −2
Original line number Diff line number Diff line
@@ -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;
@@ -100,6 +101,8 @@ public class PackageArchiverTest {
    @Mock
    private LauncherApps mLauncherApps;
    @Mock
    private ActivityManager mActivityManager;
    @Mock
    private PackageManager mPackageManager;
    @Mock
    private PackageInstallerService mInstallerService;
@@ -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());
@@ -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));
    }
@@ -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();