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

Commit c1647930 authored by Sumedh Sen's avatar Sumedh Sen Committed by Song Chun Fan
Browse files

Make AppSnippet parcelable

AppSnippet is used in Pia in 4 activities. Each time, it is expensive to
parse the app's logo and label from PackageManager and the APK file of
the app being installed. Thus, lets compute the AppSnippet once and pass
it as an intent extra to whichever activity needs it.

This also solves the bug where InstallSuccess showed an activity's name
in place of the app label since the temporary directory used to create
AppSnippet is already destroyed after app installation.

Bug: 290862169
Test: Manually install an APK and observe the app install / update
dialog
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:719d00a979005e1b5919694305b015e1970992d9)
Merged-In: I2095b092e1a7b3186ff4cdc4c81effce51377b19
Change-Id: I2095b092e1a7b3186ff4cdc4c81effce51377b19

Original patch:
 From 719d00a9 Mon Sep 17 00:00:00 2001
From: Sumedh Sen <sumedhsen@google.com>
Date: Tue, 18 Jul 2023 15:00:59 -0700
Subject: [PATCH] Make AppSnippet parcelable

AppSnippet is used in Pia in 4 activities. Each time, it is expensive to
parse the app's logo and label from PackageManager and the APK file of
the app being installed. Thus, lets compute the AppSnippet once and pass
it as an intent extra to whichever activity needs it.

This also solves the bug where InstallSuccess showed an activity's name
in place of the app label since the temporary directory used to create
AppSnippet is already destroyed after app installation.

Bug: 290862169
Test: Manually install an APK and observe the app install / update
dialog

Change-Id: I2095b092e1a7b3186ff4cdc4c81effce51377b19
---
parent 07b1e6f8
Loading
Loading
Loading
Loading
+2 −10
Original line number Diff line number Diff line
@@ -33,8 +33,6 @@ import android.view.View;

import androidx.annotation.Nullable;

import java.io.File;

/**
 * Installation failed: Return status code to the caller or display failure UI to user
 */
@@ -101,14 +99,8 @@ public class InstallFailed extends AlertActivity {
            // Set header icon and title
            PackageUtil.AppSnippet as;
            PackageManager pm = getPackageManager();

            if ("package".equals(packageURI.getScheme())) {
                as = new PackageUtil.AppSnippet(pm.getApplicationLabel(appInfo),
                        pm.getApplicationIcon(appInfo));
            } else {
                final File sourceFile = new File(packageURI.getPath());
                as = PackageUtil.getAppSnippet(this, appInfo, sourceFile);
            }
            as = intent.getParcelableExtra(PackageInstallerActivity.EXTRA_APP_SNIPPET,
                    PackageUtil.AppSnippet.class);

            // Store label for dialog
            mLabel = as.label;
+3 −1
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

package com.android.packageinstaller;

import static com.android.packageinstaller.PackageInstallerActivity.EXTRA_APP_SNIPPET;
import static com.android.packageinstaller.PackageInstallerActivity.EXTRA_STAGED_SESSION_ID;

import android.app.PendingIntent;
@@ -86,7 +87,8 @@ public class InstallInstalling extends AlertActivity {
            // ContentResolver.SCHEME_FILE
            // STAGED_SESSION_ID extra contains an ID of a previously staged install session.
            final File sourceFile = new File(mPackageURI.getPath());
            PackageUtil.AppSnippet as = PackageUtil.getAppSnippet(this, appInfo, sourceFile);
            PackageUtil.AppSnippet as = getIntent()
                    .getParcelableExtra(EXTRA_APP_SNIPPET, PackageUtil.AppSnippet.class);

            mAlert.setIcon(as.icon);
            mAlert.setTitle(as.label);
+2 −14
Original line number Diff line number Diff line
@@ -23,7 +23,6 @@ import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
@@ -31,7 +30,6 @@ import android.widget.Button;

import androidx.annotation.Nullable;

import java.io.File;
import java.util.List;

/**
@@ -66,18 +64,8 @@ public class InstallSuccess extends AlertActivity {
            ApplicationInfo appInfo =
                    intent.getParcelableExtra(PackageUtil.INTENT_ATTR_APPLICATION_INFO);
            mAppPackageName = appInfo.packageName;
            Uri packageURI = intent.getData();

            // Set header icon and title
            PackageManager pm = getPackageManager();

            if ("package".equals(packageURI.getScheme())) {
                mAppSnippet = new PackageUtil.AppSnippet(pm.getApplicationLabel(appInfo),
                        pm.getApplicationIcon(appInfo));
            } else {
                File sourceFile = new File(packageURI.getPath());
                mAppSnippet = PackageUtil.getAppSnippet(this, appInfo, sourceFile);
            }
            mAppSnippet = intent.getParcelableExtra(PackageInstallerActivity.EXTRA_APP_SNIPPET,
                    PackageUtil.AppSnippet.class);

            mLaunchIntent = getPackageManager().getLaunchIntentForPackage(mAppPackageName);

+4 −0
Original line number Diff line number Diff line
@@ -81,6 +81,7 @@ public class PackageInstallerActivity extends AlertActivity {
    static final String EXTRA_CALLING_ATTRIBUTION_TAG = "EXTRA_CALLING_ATTRIBUTION_TAG";
    static final String EXTRA_ORIGINAL_SOURCE_INFO = "EXTRA_ORIGINAL_SOURCE_INFO";
    static final String EXTRA_STAGED_SESSION_ID = "EXTRA_STAGED_SESSION_ID";
    static final String EXTRA_APP_SNIPPET = "EXTRA_APP_SNIPPET";
    private static final String ALLOW_UNKNOWN_SOURCES_KEY =
            PackageInstallerActivity.class.getName() + "ALLOW_UNKNOWN_SOURCES_KEY";

@@ -693,6 +694,9 @@ public class PackageInstallerActivity extends AlertActivity {
        if (stagedSessionId > 0) {
            newIntent.putExtra(EXTRA_STAGED_SESSION_ID, stagedSessionId);
        }
        if (mAppSnippet != null) {
            newIntent.putExtra(EXTRA_APP_SNIPPET, mAppSnippet);
        }
        newIntent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT);
        if (mLocalLOGV) Log.i(TAG, "downloaded app uri=" + mPackageURI);
        startActivity(newIntent);
+48 −1
Original line number Diff line number Diff line
@@ -27,8 +27,13 @@ import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.UserHandle;
import android.util.Log;
import android.view.View;
@@ -115,7 +120,7 @@ public class PackageUtil {
                icon);
    }

    static final class AppSnippet {
    static final class AppSnippet implements Parcelable {
        @NonNull public CharSequence label;
        @Nullable public Drawable icon;
        public AppSnippet(@NonNull CharSequence label, @Nullable Drawable icon) {
@@ -123,10 +128,52 @@ public class PackageUtil {
            this.icon = icon;
        }

        private AppSnippet(Parcel in) {
            label = in.readString();
            Bitmap bmp = in.readParcelable(getClass().getClassLoader(), Bitmap.class);
            icon = new BitmapDrawable(Resources.getSystem(), bmp);
        }

        @Override
        public String toString() {
            return "AppSnippet[" + label + (icon != null ? "(has" : "(no ") + " icon)]";
        }

        @Override
        public int describeContents() {
            return 0;
        }

        @Override
        public void writeToParcel(@NonNull Parcel dest, int flags) {
            dest.writeString(label.toString());
            Bitmap bmp = getBitmapFromDrawable(icon);
            dest.writeParcelable(bmp, 0);
        }

        private Bitmap getBitmapFromDrawable(Drawable drawable) {
            // Create an empty bitmap with the dimensions of our drawable
            final Bitmap bmp = Bitmap.createBitmap(drawable.getIntrinsicWidth(),
                    drawable.getIntrinsicHeight(),
                    Bitmap.Config.ARGB_8888);
            // Associate it with a canvas. This canvas will draw the icon on the bitmap
            final Canvas canvas = new Canvas(bmp);
            // Draw the drawable in the canvas. The canvas will ultimately paint the drawable in the
            // bitmap held within
            drawable.draw(canvas);

            return bmp;
        }

        public static final Parcelable.Creator<AppSnippet> CREATOR = new Parcelable.Creator<>() {
            public AppSnippet createFromParcel(Parcel in) {
                return new AppSnippet(in);
            }

            public AppSnippet[] newArray(int size) {
                return new AppSnippet[size];
            }
        };
    }

    /**