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

Commit 04fe042e authored by Rohit Goyal's avatar Rohit Goyal
Browse files

Add support for progress bar for archived apps in AllApps view.

Working Video: https://drive.google.com/file/d/1-cSD63FQLmqyeTkUuXqcSsjb03m31ULO/view?usp=sharing

Test: TaplPromiseIconUiTest
Bug: 302115555
Bug: 317108448
Flag: ACONFIG com.android.launcher3.enable_support_for_archiving DEVELOPMENT
Change-Id: Iebaa338789430c5e0a004bd8b05bdbda87cd986e
parent 0c8439e1
Loading
Loading
Loading
Loading
+10 −5
Original line number Diff line number Diff line
@@ -933,9 +933,7 @@ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver,
            if (mIcon instanceof PreloadIconDrawable) {
                preloadIconDrawable = (PreloadIconDrawable) mIcon;
                preloadIconDrawable.setLevel(progressLevel);
                // TODO(b/302115555): For archived apps, show icon as disabled if active session
                //  exists.
                preloadIconDrawable.setIsDisabled(info.getProgressLevel() == 0);
                preloadIconDrawable.setIsDisabled(isIconDisabled(info));
            } else {
                preloadIconDrawable = makePreloadIcon();
                setIcon(preloadIconDrawable);
@@ -960,11 +958,18 @@ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver,
        final PreloadIconDrawable preloadDrawable = newPendingIcon(getContext(), info);

        preloadDrawable.setLevel(progressLevel);
        // TODO(b/302115555): For archived apps, show icon as disabled if active session exists.
        preloadDrawable.setIsDisabled(info.getProgressLevel() == 0);
        preloadDrawable.setIsDisabled(isIconDisabled(info));
        return preloadDrawable;
    }

    private boolean isIconDisabled(ItemInfoWithIcon info) {
        if (info.isArchived()) {
            return info.getProgressLevel() == 0
                    && (info.runtimeStatusFlags & FLAG_INSTALL_SESSION_ACTIVE) != 0;
        }
        return info.getProgressLevel() == 0;
    }

    public void applyDotState(ItemInfo itemInfo, boolean animate) {
        if (mIcon instanceof FastBitmapDrawable) {
            boolean wasDotted = mDotInfo != null;
+17 −4
Original line number Diff line number Diff line
@@ -16,8 +16,10 @@

package com.android.launcher3.model;

import static com.android.launcher3.Flags.enableSupportForArchiving;
import static com.android.launcher3.model.data.AppInfo.COMPONENT_KEY_COMPARATOR;
import static com.android.launcher3.model.data.AppInfo.EMPTY_ARRAY;
import static com.android.launcher3.model.data.ItemInfoWithIcon.FLAG_ARCHIVED;

import android.content.ComponentName;
import android.content.Context;
@@ -53,6 +55,7 @@ import java.util.function.Predicate;
/**
 * Stores the list of all applications for the all apps view.
 */
@SuppressWarnings("NewApi")
public class AllAppsList {

    private static final String TAG = "AllAppsList";
@@ -200,13 +203,18 @@ public class AllAppsList {
            if (tgtComp != null && tgtComp.getPackageName().equals(installInfo.packageName)
                    && appInfo.user.equals(user)) {
                if (installInfo.state == PackageInstallInfo.STATUS_INSTALLED_DOWNLOADING
                        || installInfo.state == PackageInstallInfo.STATUS_INSTALLING) {
                        || installInfo.state == PackageInstallInfo.STATUS_INSTALLING
                        // In case unarchival fails, we would want to keep the icon and update
                        // back the progress to 0 for the all apps view without removing the
                        // icon, which is contrary to what happens during normal app installation
                        // flow.
                        || (installInfo.state == PackageInstallInfo.STATUS_FAILED
                                && appInfo.isArchived())) {
                    if (appInfo.isAppStartable()
                            && installInfo.state == PackageInstallInfo.STATUS_INSTALLING) {
                            && installInfo.state == PackageInstallInfo.STATUS_INSTALLING
                            && !appInfo.isArchived()) {
                        continue;
                    }
                    // TODO(b/302115555): Handle the case when archived apps are to be updated
                    //  during unarchival start.
                    appInfo.setProgressLevel(installInfo);

                    updatedAppInfos.add(appInfo);
@@ -322,6 +330,11 @@ public class AllAppsList {
                            PackageManagerHelper.getLoadingProgress(info),
                            PackageInstallInfo.STATUS_INSTALLED_DOWNLOADING);
                    applicationInfo.intent = launchIntent;
                    if (enableSupportForArchiving() && info.getActivityInfo().isArchived) {
                        // In case an app is archived, the respective item flag corresponding to
                        // archiving should also be applied during package updates
                        applicationInfo.runtimeStatusFlags |= FLAG_ARCHIVED;
                    }

                    mDataChanged = true;
                }
+22 −3
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ package com.android.launcher3.model;

import static com.android.launcher3.BuildConfig.WIDGET_ON_FIRST_SCREEN;
import static com.android.launcher3.Flags.enableLauncherBrMetricsFixed;
import static com.android.launcher3.Flags.enableSupportForArchiving;
import static com.android.launcher3.LauncherPrefs.IS_FIRST_LOAD_AFTER_RESTORE;
import static com.android.launcher3.LauncherPrefs.SHOULD_SHOW_SMARTSPACE;
import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APP_PAIR;
@@ -30,6 +31,7 @@ import static com.android.launcher3.model.BgDataModel.Callbacks.FLAG_QUIET_MODE_
import static com.android.launcher3.model.BgDataModel.Callbacks.FLAG_QUIET_MODE_ENABLED;
import static com.android.launcher3.model.BgDataModel.Callbacks.FLAG_WORK_PROFILE_QUIET_MODE_ENABLED;
import static com.android.launcher3.model.ModelUtils.filterCurrentWorkspaceItems;
import static com.android.launcher3.model.data.ItemInfoWithIcon.FLAG_INSTALL_SESSION_ACTIVE;
import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
import static com.android.launcher3.util.PackageManagerHelper.hasShortcutsPermission;

@@ -143,6 +145,7 @@ public class LoaderTask implements Runnable {
    private final UserManagerState mUserManagerState;
    protected final Map<ComponentKey, AppWidgetProviderInfo> mWidgetProvidersMap = new ArrayMap<>();
    private Map<ShortcutKey, ShortcutInfo> mShortcutKeyToPinnedShortcuts;
    private HashMap<PackageUserKey, SessionInfo> mInstallingPkgsCached;

    private boolean mStopped;

@@ -170,6 +173,7 @@ public class LoaderTask implements Runnable {
        mSessionHelper = InstallSessionHelper.INSTANCE.get(mApp.getContext());
        mIconCache = mApp.getIconCache();
        mUserManagerState = userManagerState;
        mInstallingPkgsCached = null;
    }

    protected synchronized void waitForIdle() {
@@ -418,6 +422,9 @@ public class LoaderTask implements Runnable {

            final HashMap<PackageUserKey, SessionInfo> installingPkgs =
                    mSessionHelper.getActiveSessions();
            if (enableSupportForArchiving()) {
                mInstallingPkgsCached = installingPkgs;
            }
            installingPkgs.forEach(mApp.getIconCache()::updateSessionCache);
            FileLog.d(TAG, "loadWorkspace: Packages with active install sessions: "
                    + installingPkgs.keySet().stream().map(info -> info.mPackageName).toList());
@@ -651,8 +658,20 @@ public class LoaderTask implements Runnable {
            for (int i = 0; i < apps.size(); i++) {
                LauncherActivityInfo app = apps.get(i);
                AppInfo appInfo = new AppInfo(app, user, quietMode);
                // TODO(b/302115555): Handle the case when archived apps with active sessions are
                //  loaded.
                if (enableSupportForArchiving() && app.getApplicationInfo().isArchived) {
                    // For archived apps, include progress info in case there is a pending
                    // install session post restart of device.
                    String appPackageName = app.getApplicationInfo().packageName;
                    SessionInfo si = mInstallingPkgsCached != null ? mInstallingPkgsCached.get(
                            new PackageUserKey(appPackageName, user))
                            : mSessionHelper.getActiveSessionInfo(user,
                                    appPackageName);
                    if (si != null) {
                        appInfo.runtimeStatusFlags |= FLAG_INSTALL_SESSION_ACTIVE;
                        appInfo.setProgressLevel((int) (si.getProgress() * 100),
                                PackageInstallInfo.STATUS_INSTALLING);
                    }
                }

                iconRequestInfos.add(new IconRequestInfo<>(
                        appInfo, app, /* useLowResIcon= */ false));
+17 −6
Original line number Diff line number Diff line
@@ -35,6 +35,7 @@ import androidx.test.runner.AndroidJUnit4;

import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherState;
import com.android.launcher3.tapl.AllApps;
import com.android.launcher3.ui.AbstractLauncherUiTest;
import com.android.launcher3.util.LauncherBindableItemsContainer.ItemOperator;
import com.android.launcher3.util.TestUtil;
@@ -143,16 +144,26 @@ public class TaplPromiseIconUiTest extends AbstractLauncherUiTest {
        assertThat(mDevice.executeShellCommand(String.format("pm archive %s", DUMMY_PACKAGE)))
                .isEqualTo("Success\n");

        final ItemOperator findPromiseApp = (info, view) ->
                info != null && TextUtils.equals(info.title, DUMMY_LABEL);

        // Create and add test session
        mSessionId = createSession(DUMMY_PACKAGE, /* label= */ "",
                Bitmap.createBitmap(100, 100, Bitmap.Config.ALPHA_8));

        // Verify promise icon is added
        waitForLauncherCondition("Test Promise App not found on workspace", launcher ->
                launcher.getWorkspace().getFirstMatch(findPromiseApp) != null);
        // Verify promise icon is added to all apps view. The icon may not be added to the
        // workspace even if there might be no icon present for archived app. But icon will
        // always be in all apps view. In case an icon is not added, an exception would be thrown.
        final AllApps allApps = mLauncher.getWorkspace().switchToAllApps();

        // Wait for the promise icon to be added.
        waitForLauncherCondition(
                DUMMY_PACKAGE + " app was not found on all apps after being archived",
                launcher -> {
                    try {
                        allApps.getAppIcon(DUMMY_LABEL);
                    } catch (Throwable t) {
                        return false;
                    }
                    return true;
                });

        // Remove session
        mTargetContext.getPackageManager().getPackageInstaller().abandonSession(mSessionId);