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

Commit 9846820b authored by Songchun Fan's avatar Songchun Fan Committed by Song Chun Fan
Browse files

[pm/archive] align draft session's icon overlay state with the current

launcher

The draft session's app icon is displayed at the beginning of the
unarchiving. Adapt its style to match the cloud icon overlay style of
the current launcher to avoid UI flickering.

BUG: 350758155
Test: manual
Test: atest android.content.pm.cts.PackageInstallerArchiveTest#archiveApp_getApplicationIcon_draftSessionOverlayDisabledIfLauncherOverlayDisabled

Change-Id: I37e553e0f144ff0b3cc86dafae8d857f1b6fcf24
Flag: EXEMPT bugfix
parent aa97cd9d
Loading
Loading
Loading
Loading
+35 −8
Original line number Diff line number Diff line
@@ -869,18 +869,25 @@ public class PackageArchiver {
    private int createDraftSession(String packageName, String installerPackage,
            String callerPackageName,
            IntentSender statusReceiver, int userId) throws IOException {
        Computer snapshot = mPm.snapshotComputer();
        PackageInstaller.SessionParams sessionParams = new PackageInstaller.SessionParams(
                PackageInstaller.SessionParams.MODE_FULL_INSTALL);
        sessionParams.setAppPackageName(packageName);
        sessionParams.setAppLabel(
                mContext.getString(com.android.internal.R.string.unarchival_session_app_label));
        sessionParams.setAppIcon(
                getArchivedAppIcon(packageName, UserHandle.of(userId), callerPackageName));
        // The draft session's app icon is based on the current launcher's icon overlay appops mode
        String launcherPackageName = getCurrentLauncherPackageName(userId);
        int launcherUid = launcherPackageName != null
                ? snapshot.getPackageUid(launcherPackageName, 0, userId)
                : Process.SYSTEM_UID;
        sessionParams.setAppIcon(getArchivedAppIcon(packageName, UserHandle.of(userId),
                isOverlayEnabled(launcherUid,
                        launcherPackageName == null ? callerPackageName : launcherPackageName)));
        // To make sure SessionInfo::isUnarchival returns true for draft sessions,
        // INSTALL_UNARCHIVE is also set.
        sessionParams.installFlags = (INSTALL_UNARCHIVE_DRAFT | INSTALL_UNARCHIVE);

        int installerUid = mPm.snapshotComputer().getPackageUid(installerPackage, 0, userId);
        int installerUid = snapshot.getPackageUid(installerPackage, 0, userId);
        // Handles case of repeated unarchival calls for the same package.
        int existingSessionId = mPm.mInstallerService.getExistingDraftSessionId(installerUid,
                sessionParams,
@@ -926,12 +933,27 @@ public class PackageArchiver {
    /**
     * Returns the icon of an archived app. This is the icon of the main activity of the app.
     *
     * <p> The icon is returned without any treatment/overlay. In the rare case the app had multiple
     * launcher activities, only one of the icons is returned arbitrarily.
     * <p> In the rare case the app had multiple launcher activities, only one of the icons is
     * returned arbitrarily.
     *
     * <p> By default, the icon will be overlay'd with a cloud icon on top. A launcher app can
     * disable the cloud overlay via the
     * {@link LauncherApps.ArchiveCompatibilityParams#setEnableIconOverlay(boolean)} API.
     * The default launcher's cloud overlay mode determines the cloud overlay status returned by
     * any other callers. That is, if the current launcher has the cloud overlay disabled, any other
     * app that fetches the app icon will also get an icon that has the cloud overlay disabled.
     * This is to prevent style mismatch caused by icons that are fetched by different callers.
     */
    @Nullable
    public Bitmap getArchivedAppIcon(@NonNull String packageName, @NonNull UserHandle user,
            String callingPackageName) {
        return getArchivedAppIcon(packageName, user,
                isOverlayEnabled(Binder.getCallingUid(), callingPackageName));
    }

    @Nullable
    private Bitmap getArchivedAppIcon(@NonNull String packageName, @NonNull UserHandle user,
            boolean isOverlayEnabled) {
        Objects.requireNonNull(packageName);
        Objects.requireNonNull(user);

@@ -955,14 +977,19 @@ public class PackageArchiver {
        // In the rare case the archived app defined more than two launcher activities, we choose
        // the first one arbitrarily.
        Bitmap icon = decodeIcon(archiveState.getActivityInfos().get(0));
        if (icon != null && getAppOpsManager().checkOp(
                AppOpsManager.OP_ARCHIVE_ICON_OVERLAY, callingUid, callingPackageName)
                == MODE_ALLOWED) {

        if (icon != null && isOverlayEnabled) {
            icon = includeCloudOverlay(icon);
        }
        return icon;
    }

    private boolean isOverlayEnabled(int callingUid, String packageName) {
        return getAppOpsManager().checkOp(
                AppOpsManager.OP_ARCHIVE_ICON_OVERLAY, callingUid, packageName)
                == MODE_ALLOWED;
    }

    /**
     * This method first checks the ArchiveState for the provided userId and then tries to fallback
     * to other users if the current user is not archived.