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

Commit 29801d28 authored by Alex Buynytskyy's avatar Alex Buynytskyy
Browse files

Archived install icon fixes.

- don't override icon with monochrome,
- always resize smaller icons,
- use AdaptiveIconDrawable to accomodate different shapes,
+ minor fix to not crash system server,
+ flaky test fix.

Fixes: 316225498
Test: atest PackageManagerTest
Change-Id: Ibf8b12a8505558cfcfef6f8150ca35c1e83de228
parent 4a412a38
Loading
Loading
Loading
Loading
+22 −17
Original line number Diff line number Diff line
@@ -91,12 +91,10 @@ public final class ArchivedActivityInfo {
     * @hide
     */
    public static Bitmap drawableToBitmap(Drawable drawable, int iconSize) {
        if (drawable instanceof BitmapDrawable) {
            return ((BitmapDrawable) drawable).getBitmap();

        }

        Bitmap bitmap;
        if (drawable instanceof BitmapDrawable) {
            bitmap = ((BitmapDrawable) drawable).getBitmap();
        } else {
            if (drawable.getIntrinsicWidth() <= 0 || drawable.getIntrinsicHeight() <= 0) {
                // Needed for drawables that are just a single color.
                bitmap = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888);
@@ -107,10 +105,17 @@ public final class ArchivedActivityInfo {
                        drawable.getIntrinsicHeight(),
                        Bitmap.Config.ARGB_8888);
            }

            Canvas canvas = new Canvas(bitmap);
            drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
            drawable.draw(canvas);
        if (iconSize > 0 && bitmap.getWidth() > iconSize * 2 || bitmap.getHeight() > iconSize * 2) {
        }
        if (iconSize <= 0) {
            return bitmap;
        }

        if (bitmap.getWidth() < iconSize || bitmap.getHeight() < iconSize
                || bitmap.getWidth() > iconSize * 2 || bitmap.getHeight() > iconSize * 2) {
            var scaledBitmap = Bitmap.createScaledBitmap(bitmap, iconSize, iconSize, true);
            if (scaledBitmap != bitmap) {
                bitmap.recycle();
@@ -235,7 +240,7 @@ public final class ArchivedActivityInfo {
    }

    @DataClass.Generated(
            time = 1698789991876L,
            time = 1705615445673L,
            codegenVersion = "1.0.23",
            sourceFile = "frameworks/base/core/java/android/content/pm/ArchivedActivityInfo.java",
            inputSignatures = "private @android.annotation.NonNull java.lang.CharSequence mLabel\nprivate @android.annotation.NonNull android.content.ComponentName mComponentName\nprivate @android.annotation.Nullable android.graphics.drawable.Drawable mIcon\nprivate @android.annotation.Nullable android.graphics.drawable.Drawable mMonochromeIcon\n @android.annotation.NonNull android.content.pm.ArchivedActivityParcel getParcel()\npublic static  android.graphics.Bitmap drawableToBitmap(android.graphics.drawable.Drawable)\npublic static  android.graphics.Bitmap drawableToBitmap(android.graphics.drawable.Drawable,int)\npublic static  byte[] bytesFromBitmap(android.graphics.Bitmap)\nprivate static  android.graphics.drawable.Drawable drawableFromCompressedBitmap(byte[])\nclass ArchivedActivityInfo extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genBuilder=false, genConstructor=false, genSetters=true)")
+43 −11
Original line number Diff line number Diff line
@@ -31,6 +31,7 @@ import static android.content.pm.PackageInstaller.UNARCHIVAL_STATUS_UNSET;
import static android.content.pm.PackageManager.DELETE_ARCHIVE;
import static android.content.pm.PackageManager.DELETE_KEEP_DATA;
import static android.content.pm.PackageManager.INSTALL_UNARCHIVE_DRAFT;
import static android.graphics.drawable.AdaptiveIconDrawable.getExtraInsetFraction;
import static android.os.PowerExemptionManager.REASON_PACKAGE_UNARCHIVE;
import static android.os.PowerExemptionManager.TEMPORARY_ALLOW_LIST_TYPE_FOREGROUND_SERVICE_ALLOWED;

@@ -66,8 +67,11 @@ import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffColorFilter;
import android.graphics.drawable.AdaptiveIconDrawable;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.InsetDrawable;
import android.graphics.drawable.LayerDrawable;
import android.os.Binder;
import android.os.Bundle;
@@ -379,9 +383,8 @@ public class PackageArchiver {
        verifyNotSystemApp(ps.getFlags());
        verifyInstalled(ps, userId);
        String responsibleInstallerPackage = getResponsibleInstallerPackage(ps);
        verifyInstaller(responsibleInstallerPackage, userId);
        ApplicationInfo installerInfo = snapshot.getApplicationInfo(
                responsibleInstallerPackage, /* flags= */ 0, userId);
        ApplicationInfo installerInfo = verifyInstaller(
                snapshot, responsibleInstallerPackage, userId);
        verifyOptOutStatus(packageName,
                UserHandle.getUid(userId, UserHandle.getUid(userId, ps.getAppId())));

@@ -421,10 +424,10 @@ public class PackageArchiver {
            List<ArchiveActivityInfo> archiveActivityInfos = new ArrayList<>(mainActivities.size());
            for (int i = 0, size = mainActivities.size(); i < size; ++i) {
                var mainActivity = mainActivities.get(i);
                Path iconPath = storeDrawable(
                        packageName, mainActivity.getIcon(), userId, i, iconSize);
                Path monochromePath =  storeDrawable(
                        packageName, mainActivity.getMonochromeIcon(), userId, i, iconSize);
                Path iconPath = storeAdaptiveDrawable(
                        packageName, mainActivity.getIcon(), userId, i * 2 + 0, iconSize);
                Path monochromePath = storeAdaptiveDrawable(
                        packageName, mainActivity.getMonochromeIcon(), userId, i * 2 + 1, iconSize);
                ArchiveActivityInfo activityInfo =
                        new ArchiveActivityInfo(
                                mainActivity.getLabel().toString(),
@@ -451,7 +454,8 @@ public class PackageArchiver {
        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, iconSize);
            Path iconPath = storeIcon(packageName, mainActivity, userId, i * 2 + 0, iconSize);
            // i * 2 + 1 reserved for monochromeIcon
            ArchiveActivityInfo activityInfo =
                    new ArchiveActivityInfo(
                            mainActivity.getLabel().toString(),
@@ -495,8 +499,30 @@ public class PackageArchiver {
        return iconFile.toPath();
    }

    private void verifyInstaller(String installerPackageName, int userId)
            throws PackageManager.NameNotFoundException {
    /**
     * Create an <a
     * href="https://developer.android.com/develop/ui/views/launch/icon_design_adaptive">
     * adaptive icon</a> from an icon.
     * This is necessary so the icon can be displayed properly by different launchers.
     */
    private static Path storeAdaptiveDrawable(String packageName, @Nullable Drawable iconDrawable,
            @UserIdInt int userId, int index, int iconSize) throws IOException {
        if (iconDrawable == null) {
            return null;
        }

        // see BaseIconFactory#createShapedIconBitmap
        float inset = getExtraInsetFraction();
        inset = inset / (1 + 2 * inset);
        Drawable d = new AdaptiveIconDrawable(new ColorDrawable(Color.BLACK),
                new InsetDrawable(iconDrawable/*d*/, inset, inset, inset, inset));

        return storeDrawable(packageName, d, userId, index, iconSize);
    }


    private ApplicationInfo verifyInstaller(Computer snapshot, String installerPackageName,
            int userId) throws PackageManager.NameNotFoundException {
        if (TextUtils.isEmpty(installerPackageName)) {
            throw new PackageManager.NameNotFoundException("No installer found");
        }
@@ -505,6 +531,12 @@ public class PackageArchiver {
                && !verifySupportsUnarchival(installerPackageName, userId)) {
            throw new PackageManager.NameNotFoundException("Installer does not support unarchival");
        }
        ApplicationInfo appInfo = snapshot.getApplicationInfo(
                installerPackageName, /* flags=*/ 0, userId);
        if (appInfo == null) {
            throw new PackageManager.NameNotFoundException("Failed to obtain Installer info");
        }
        return appInfo;
    }

    /**
@@ -570,7 +602,7 @@ public class PackageArchiver {
        }

        try {
            verifyInstaller(getResponsibleInstallerPackage(ps), userId);
            verifyInstaller(snapshot, getResponsibleInstallerPackage(ps), userId);
            getLauncherActivityInfos(packageName, userId);
        } catch (PackageManager.NameNotFoundException e) {
            return false;
+1 −1
Original line number Diff line number Diff line
@@ -419,7 +419,7 @@ public class PackageUserStateTest {
                "installerTitle");
        packageUserState.setArchiveState(archiveState);
        assertEquals(archiveState, packageUserState.getArchiveState());
        assertTrue(archiveState.getArchiveTimeMillis() > currentTimeMillis);
        assertTrue(archiveState.getArchiveTimeMillis() >= currentTimeMillis);
    }

    @Test