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

Commit a13efa06 authored by Joel Galenson's avatar Joel Galenson
Browse files

Optimize Permissions Hub and App Permissions screens.

The majority of the time spent loading the Permissions Hub was spent loading the labels and icons for all apps.  However, the screen does not show most apps, as they either have no uses or are system (which are not shown by default).  This commit makes us only load labels and icons for apps we will show.  We do the same thing for App Permissions, as it has the same issue.

On my dev device, loading both Permissions Hub and App Permissions takes less than half the time it used to.

Bug: 124052170
Test: Open Permissions Hub, change filters, select items and go back
Test: Open App Permissions Screen.
Change-Id: Ifd5d2b157793e6f277e185e0c3055e8f07f3f0d7
parent 3c88adb6
Loading
Loading
Loading
Loading
+51 −8
Original line number Diff line number Diff line
@@ -253,7 +253,8 @@ public class PermissionApps {

                    Pair<String, Drawable> appData = null;
                    if (mAppDataCache != null && !mSkipUi) {
                        appData = mAppDataCache.getAppData(user.getIdentifier(), app);
                        appData = mAppDataCache.getAppData(user.getIdentifier(),
                                app.applicationInfo);
                    }

                    String label;
@@ -326,8 +327,8 @@ public class PermissionApps {
    public static class PermissionApp implements Comparable<PermissionApp> {
        private final String mPackageName;
        private final AppPermissionGroup mAppPermissionGroup;
        private final String mLabel;
        private final Drawable mIcon;
        private String mLabel;
        private Drawable mIcon;
        private final ApplicationInfo mInfo;

        public PermissionApp(String packageName, AppPermissionGroup appPermissionGroup,
@@ -395,6 +396,19 @@ public class PermissionApps {
            return mAppPermissionGroup;
        }

        /**
         * Load this app's label and icon if they were not previously loaded.
         *
         * @param appDataCache the cache of already-loaded labels and icons.
         */
        public void loadLabelAndIcon(@NonNull AppDataCache appDataCache) {
            if (mInfo.packageName.equals(mLabel) || mIcon == null) {
                Pair<String, Drawable> appData = appDataCache.getAppData(getUid(), mInfo);
                mLabel = appData.first;
                mIcon = appData.second;
            }
        }

        @Override
        public int compareTo(PermissionApp another) {
            final int result = mLabel.compareTo(another.mLabel);
@@ -475,17 +489,17 @@ public class PermissionApps {
         * @return a pair of the label and icon.
         */
        public @NonNull Pair<String, Drawable> getAppData(int userId,
                @NonNull PackageInfo app) {
                @NonNull ApplicationInfo app) {
            ArrayMap<String, Pair<String, Drawable>> dataForUser = mCache.get(userId);
            if (dataForUser == null) {
                dataForUser = new ArrayMap<>();
                mCache.put(userId, dataForUser);
            }
            Pair<String, Drawable> data = dataForUser.get(app.applicationInfo.packageName);
            Pair<String, Drawable> data = dataForUser.get(app.packageName);
            if (data == null) {
                data = Pair.create(app.applicationInfo.loadLabel(mPm).toString(),
                        Utils.getBadgedIcon(mContext, app.applicationInfo));
                dataForUser.put(app.applicationInfo.packageName, data);
                data = Pair.create(app.loadLabel(mPm).toString(),
                        Utils.getBadgedIcon(mContext, app));
                dataForUser.put(app.packageName, data);
            }
            return data;
        }
@@ -494,4 +508,33 @@ public class PermissionApps {
    public interface Callback {
        void onPermissionsLoaded(PermissionApps permissionApps);
    }

    /**
     * Class used to asyncronously load apps' labels and icons.
     */
    public static class AppDataLoader extends AsyncTask<PermissionApp, Void, Void> {

        private final Context mContext;
        private final Runnable mCallback;

        public AppDataLoader(Context context, Runnable callback) {
            mContext = context;
            mCallback = callback;
        }

        @Override
        protected Void doInBackground(PermissionApp... args) {
            AppDataCache appDataCache = new AppDataCache(mContext.getPackageManager(), mContext);
            int numArgs = args.length;
            for (int i = 0; i < numArgs; i++) {
                args[i].loadLabelAndIcon(appDataCache);
            }
            return null;
        }

        @Override
        protected void onPostExecute(Void result) {
            mCallback.run();
        }
    }
}
+16 −16
Original line number Diff line number Diff line
@@ -54,17 +54,17 @@ public final class PermissionGroups implements LoaderCallbacks<List<PermissionGr
    private final ArrayList<PermissionGroup> mGroups = new ArrayList<>();
    private final Context mContext;
    private final PermissionsGroupsChangeCallback mCallback;
    private final boolean mGetUiInfo;
    private final boolean mGetAppUiInfo;

    public interface PermissionsGroupsChangeCallback {
        public void onPermissionGroupsChanged();
    }

    public PermissionGroups(Context context, LoaderManager loaderManager,
            PermissionsGroupsChangeCallback callback, boolean getUiInfo) {
            PermissionsGroupsChangeCallback callback, boolean getAppUiInfo) {
        mContext = context;
        mCallback = callback;
        mGetUiInfo = getUiInfo;
        mGetAppUiInfo = getAppUiInfo;

        // Don't update immediately as otherwise we can get a callback before this object is
        // initialized.
@@ -73,7 +73,7 @@ public final class PermissionGroups implements LoaderCallbacks<List<PermissionGr

    @Override
    public Loader<List<PermissionGroup>> onCreateLoader(int id, Bundle args) {
        return new PermissionsLoader(mContext, mGetUiInfo);
        return new PermissionsLoader(mContext, mGetAppUiInfo);
    }

    @Override
@@ -134,13 +134,13 @@ public final class PermissionGroups implements LoaderCallbacks<List<PermissionGr
     *
     * @param context Context to use
     * @param isCanceled callback checked if the group resolution should be aborted
     * @param getUiInfo If the UI info for apps should be updated
     * @param getAppUiInfo If the UI info for apps should be updated
     *
     * @return the list of all groups int the system
     */
    public static @NonNull List<PermissionGroup> getAllPermissionGroups(@NonNull Context context,
            @Nullable Supplier<Boolean> isCanceled, boolean getUiInfo) {
        return getPermissionGroups(context, isCanceled, getUiInfo, null, null);
            @Nullable Supplier<Boolean> isCanceled, boolean getAppUiInfo) {
        return getPermissionGroups(context, isCanceled, getAppUiInfo, null, null);
    }

    /**
@@ -148,15 +148,15 @@ public final class PermissionGroups implements LoaderCallbacks<List<PermissionGr
     *
     * @param context Context to use
     * @param isCanceled callback checked if the group resolution should be aborted
     * @param getUiInfo If the UI info for apps should be updated
     * @param getAppUiInfo If the UI info for apps should be updated
     * @param groupName Optional group to filter for.
     * @param packageName Optional package to filter for.
     *
     * @return the list of all groups int the system
     */
    public static @NonNull List<PermissionGroup> getPermissionGroups(@NonNull Context context,
            @Nullable Supplier<Boolean> isCanceled, boolean getUiInfo, @Nullable String groupName,
            @Nullable String  packageName) {
            @Nullable Supplier<Boolean> isCanceled, boolean getAppUiInfo,
            @Nullable String groupName, @Nullable String packageName) {
        ArraySet<String> launcherPkgs = Utils.getLauncherPackages(context);
        PermissionApps.PmCache pmCache = new PermissionApps.PmCache(
                context.getPackageManager());
@@ -205,7 +205,7 @@ public final class PermissionGroups implements LoaderCallbacks<List<PermissionGr

            PermissionApps permApps = new PermissionApps(context, groupInfo.name, packageName,
                    null, pmCache, appDataCache);
            permApps.refreshSync(getUiInfo);
            permApps.refreshSync(getAppUiInfo);

            // Create the group and add to the list.
            PermissionGroup group = new PermissionGroup(groupInfo.name,
@@ -258,7 +258,7 @@ public final class PermissionGroups implements LoaderCallbacks<List<PermissionGr

                PermissionApps permApps = new PermissionApps(context, permissionInfo.name,
                        packageName, null, pmCache, appDataCache);
                permApps.refreshSync(getUiInfo);
                permApps.refreshSync(getAppUiInfo);

                // Create the group and add to the list.
                PermissionGroup group = new PermissionGroup(permissionInfo.name,
@@ -302,11 +302,11 @@ public final class PermissionGroups implements LoaderCallbacks<List<PermissionGr

    private static final class PermissionsLoader extends AsyncTaskLoader<List<PermissionGroup>>
            implements PackageManager.OnPermissionsChangedListener {
        private final boolean mGetUiInfo;
        private final boolean mGetAppUiInfo;

        PermissionsLoader(Context context, boolean getUiInfo) {
        PermissionsLoader(Context context, boolean getAppUiInfo) {
            super(context);
            mGetUiInfo = getUiInfo;
            mGetAppUiInfo = getAppUiInfo;
        }

        @Override
@@ -323,7 +323,7 @@ public final class PermissionGroups implements LoaderCallbacks<List<PermissionGr
        @Override
        public List<PermissionGroup> loadInBackground() {
            return getAllPermissionGroups(getContext(), this::isLoadInBackgroundCanceled,
                    mGetUiInfo);
                    mGetAppUiInfo);
        }

        @Override
+2 −1
Original line number Diff line number Diff line
@@ -58,8 +58,9 @@ abstract class ManagePermissionsFragment extends PermissionsFrameFragment
        if (ab != null) {
            ab.setDisplayHomeAsUpEnabled(true);
        }

        mPermissions = new PermissionGroups(getContext(), getActivity().getLoaderManager(), this,
                true);
                false);
        mCollator = Collator.getInstance(
                getContext().getResources().getConfiguration().getLocales().get(0));
    }
+32 −23
Original line number Diff line number Diff line
@@ -35,6 +35,7 @@ import androidx.preference.PreferenceScreen;
import com.android.packageinstaller.permission.model.AppPermissionGroup;
import com.android.packageinstaller.permission.model.AppPermissionUsage;
import com.android.packageinstaller.permission.model.AppPermissionUsage.GroupUsage;
import com.android.packageinstaller.permission.model.PermissionApps;
import com.android.packageinstaller.permission.model.PermissionApps.PermissionApp;
import com.android.packageinstaller.permission.model.PermissionGroup;
import com.android.packageinstaller.permission.model.PermissionUsages;
@@ -108,7 +109,7 @@ public final class ManageStandardPermissionsFragment extends ManagePermissionsFr
                Long.MAX_VALUE, PermissionUsages.USAGE_FLAG_LAST
                        | PermissionUsages.USAGE_FLAG_HISTORICAL,
                getActivity().getLoaderManager(),
                true, this::updateRecentlyUsedWidget, false);
                false, this::updateRecentlyUsedWidget, false);

        return root;
    }
@@ -219,8 +220,15 @@ public final class ManageStandardPermissionsFragment extends ManagePermissionsFr
            return;
        }

        // Show the most recent three usages.
        int numAppsToShow = Math.min(usages.size(), MAXIMUM_APP_COUNT);

        PermissionApps.PermissionApp[] permApps = new PermissionApps.PermissionApp[numAppsToShow];
        for (int i = 0; i < numAppsToShow; i++) {
            permApps[i] = usages.get(i).first;
        }

        new PermissionApps.AppDataLoader(context, () -> {
            // Show the most recent three usages.
            int i = 0;
            for (; i < numAppsToShow; i++) {
                Pair<PermissionApp, GroupUsage> info = usages.get(i);
@@ -243,6 +251,7 @@ public final class ManageStandardPermissionsFragment extends ManagePermissionsFr
                mAppUsageController.removeAppEntity(i);
            }
            mAppUsageController.apply();
        }).execute(permApps);
    }

    private static int compareAccessTime(@NonNull GroupUsage x, @NonNull GroupUsage y) {
+38 −28
Original line number Diff line number Diff line
@@ -49,6 +49,8 @@ import androidx.preference.PreferenceScreen;
import com.android.packageinstaller.permission.model.AppPermissionGroup;
import com.android.packageinstaller.permission.model.AppPermissionUsage;
import com.android.packageinstaller.permission.model.AppPermissionUsage.GroupUsage;
import com.android.packageinstaller.permission.model.PermissionApps;
import com.android.packageinstaller.permission.model.PermissionApps.PermissionApp;
import com.android.packageinstaller.permission.model.PermissionUsages;
import com.android.packageinstaller.permission.ui.handheld.FilterSpinner.FilterSpinnerAdapter;
import com.android.packageinstaller.permission.ui.handheld.FilterSpinner.SpinnerItem;
@@ -337,7 +339,6 @@ public class PermissionUsageFragment extends SettingsWithButtonHeader implements
        }

        updateUI();
        setLoading(false, true);
    }

    @Override
@@ -367,9 +368,11 @@ public class PermissionUsageFragment extends SettingsWithButtonHeader implements
        long startTime = (timeFilterItem == null ? 0 : (curTime - timeFilterItem.getTime()));

        List<Pair<AppPermissionUsage, GroupUsage>> usages = new ArrayList<>();
        ArrayList<PermissionApp> permApps = new ArrayList<>();
        int numApps = appPermissionUsages.size();
        for (int appNum = 0; appNum < numApps; appNum++) {
            AppPermissionUsage appUsage = appPermissionUsages.get(appNum);
            boolean used = false;
            List<GroupUsage> appGroups = appUsage.getGroupUsages();
            int numGroups = appGroups.size();
            for (int groupNum = 0; groupNum < numGroups; groupNum++) {
@@ -395,6 +398,10 @@ public class PermissionUsageFragment extends SettingsWithButtonHeader implements
                }

                usages.add(Pair.create(appUsage, appGroups.get(groupNum)));
                used = true;
            }
            if (used) {
                permApps.add(appUsage.getApp());
            }
        }

@@ -437,6 +444,15 @@ public class PermissionUsageFragment extends SettingsWithButtonHeader implements
            Log.w(LOG_TAG, "Unexpected sort option: " + sortOption);
        }

        usages.removeIf((Pair<AppPermissionUsage, GroupUsage> usage) -> mFilterGroup != null
                && !mFilterGroup.equals(usage.second.getGroup().getName()));

        // If there are no entries, don't show anything.
        if (permApps.isEmpty()) {
            screen.removeAll();
        }

        new PermissionApps.AppDataLoader(context, () -> {
            ExpandablePreferenceGroup parent = null;
            AppPermissionUsage lastAppPermissionUsage = null;

@@ -446,10 +462,6 @@ public class PermissionUsageFragment extends SettingsWithButtonHeader implements
                AppPermissionUsage appPermissionUsage = usage.first;
                GroupUsage groupUsage = usage.second;

            if (mFilterGroup != null && !mFilterGroup.equals(groupUsage.getGroup().getName())) {
                continue;
            }

                String accessTimeString = Utils.getAbsoluteLastUsageString(context, groupUsage);

                if (lastAppPermissionUsage != appPermissionUsage) {
@@ -465,10 +477,8 @@ public class PermissionUsageFragment extends SettingsWithButtonHeader implements
                parent.addSummaryIcon(groupUsage.getGroup().getIconResId());
            }

        // If there are no entries, don't show anything.
        if (parent == null) {
            screen.removeAll();
        }
            setLoading(false, true);
        }).execute(permApps.toArray(new PermissionApps.PermissionApp[permApps.size()]));
    }

    private TimeFilterItem getSelectedFilterItem() {
@@ -502,7 +512,7 @@ public class PermissionUsageFragment extends SettingsWithButtonHeader implements
        mPermissionUsages.load(null /*filterPackageName*/, null /*filterPermissionGroup*/,
                filterTimeBeginMillis, Long.MAX_VALUE, PermissionUsages.USAGE_FLAG_LAST
                        | PermissionUsages.USAGE_FLAG_HISTORICAL, getActivity().getLoaderManager(),
                true /*getUiInfo*/, this /*callback*/, false /*sync*/);
                false /*getUiInfo*/, this /*callback*/, false /*sync*/);
    }

    /**