Add support for progress bar during unarchival of app.
* With this change, progress bar should appear whenever app update for archived app reaches non-zero progress.
* Once the update is cancelled, the progress bar should also disappear.
Test: PromiseIconUiTest and manually tested the progress bar using Play Store
Bug: 302115555
Flag: ACONFIG com.android.launcher3.enable_support_for_archiving DEVELOPMENT
Change-Id: Iacf7a0fd865dba34915fa09f59c63a1da6e47315
diff --git a/src/com/android/launcher3/BubbleTextView.java b/src/com/android/launcher3/BubbleTextView.java
index 91da7e6..a57eaa3 100644
--- a/src/com/android/launcher3/BubbleTextView.java
+++ b/src/com/android/launcher3/BubbleTextView.java
@@ -923,6 +923,8 @@
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);
} else {
preloadIconDrawable = makePreloadIcon();
@@ -948,6 +950,7 @@
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);
return preloadDrawable;
}
diff --git a/src/com/android/launcher3/model/AllAppsList.java b/src/com/android/launcher3/model/AllAppsList.java
index 190eb78..7cbfc37 100644
--- a/src/com/android/launcher3/model/AllAppsList.java
+++ b/src/com/android/launcher3/model/AllAppsList.java
@@ -205,6 +205,8 @@
&& installInfo.state == PackageInstallInfo.STATUS_INSTALLING) {
continue;
}
+ // TODO(b/302115555): Handle the case when archived apps are to be updated
+ // during unarchival start.
appInfo.setProgressLevel(installInfo);
updatedAppInfos.add(appInfo);
diff --git a/src/com/android/launcher3/model/LoaderTask.java b/src/com/android/launcher3/model/LoaderTask.java
index 8dc2ab3..7c40a31 100644
--- a/src/com/android/launcher3/model/LoaderTask.java
+++ b/src/com/android/launcher3/model/LoaderTask.java
@@ -17,6 +17,7 @@
package com.android.launcher3.model;
import static com.android.launcher3.BuildConfig.WIDGET_ON_FIRST_SCREEN;
+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;
@@ -131,6 +132,7 @@
* - all apps icons
* - deep shortcuts within apps
*/
+@SuppressWarnings("NewApi")
public class LoaderTask implements Runnable {
private static final String TAG = "LoaderTask";
public static final String SMARTSPACE_ON_HOME_SCREEN = "pref_smartspace_home_screen";
@@ -772,13 +774,21 @@
PackageInstallInfo.STATUS_INSTALLED_DOWNLOADING);
}
- if (c.restoreFlag != 0 && !TextUtils.isEmpty(targetPkg)) {
+ if ((c.restoreFlag != 0
+ || (enableSupportForArchiving()
+ && activityInfo != null
+ && activityInfo.getApplicationInfo().isArchived))
+ && !TextUtils.isEmpty(targetPkg)) {
tempPackageKey.update(targetPkg, c.user);
SessionInfo si = installingPkgs.get(tempPackageKey);
if (si == null) {
info.runtimeStatusFlags
&= ~ItemInfoWithIcon.FLAG_INSTALL_SESSION_ACTIVE;
- } else if (activityInfo == null) {
+ } else if (activityInfo == null
+ // For archived apps, include progress info in case there is
+ // a pending install session post restart of device.
+ || (enableSupportForArchiving()
+ && activityInfo.getApplicationInfo().isArchived)) {
int installProgress = (int) (si.getProgress() * 100);
info.setProgressLevel(installProgress,
@@ -1095,6 +1105,8 @@
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.
iconRequestInfos.add(new IconRequestInfo<>(
appInfo, app, /* useLowResIcon= */ false));
diff --git a/src/com/android/launcher3/model/PackageUpdatedTask.java b/src/com/android/launcher3/model/PackageUpdatedTask.java
index 4f2d398..069e96b 100644
--- a/src/com/android/launcher3/model/PackageUpdatedTask.java
+++ b/src/com/android/launcher3/model/PackageUpdatedTask.java
@@ -15,9 +15,11 @@
*/
package com.android.launcher3.model;
+import static com.android.launcher3.Flags.enableSupportForArchiving;
import static com.android.launcher3.model.BgDataModel.Callbacks.FLAG_PRIVATE_PROFILE_QUIET_MODE_ENABLED;
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.data.ItemInfoWithIcon.FLAG_ARCHIVED;
import static com.android.launcher3.model.data.WorkspaceItemInfo.FLAG_AUTOINSTALL_ICON;
import static com.android.launcher3.model.data.WorkspaceItemInfo.FLAG_RESTORED_ICON;
@@ -67,6 +69,7 @@
* Handles updates due to changes in package manager (app installed/updated/removed)
* or when a user availability changes.
*/
+@SuppressWarnings("NewApi")
public class PackageUpdatedTask extends BaseModelUpdateTask {
// TODO(b/290090023): Set to false after root causing is done.
@@ -269,6 +272,16 @@
: PackageManagerHelper.getLoadingProgress(
activities.get(0)),
PackageInstallInfo.STATUS_INSTALLED_DOWNLOADING);
+ // In case an app is archived, we need to make sure that archived state
+ // in WorkspaceItemInfo is refreshed.
+ if (enableSupportForArchiving() && !activities.isEmpty()) {
+ boolean newArchivalState = activities.get(
+ 0).getActivityInfo().isArchived;
+ if (newArchivalState != si.isArchived()) {
+ si.runtimeStatusFlags ^= FLAG_ARCHIVED;
+ infoUpdated = true;
+ }
+ }
if (si.itemType == Favorites.ITEM_TYPE_APPLICATION) {
iconCache.getTitleAndIcon(si, si.usingLowResIcon());
infoUpdated = true;
diff --git a/src/com/android/launcher3/model/data/AppInfo.java b/src/com/android/launcher3/model/data/AppInfo.java
index 6c2f589..872ce4b 100644
--- a/src/com/android/launcher3/model/data/AppInfo.java
+++ b/src/com/android/launcher3/model/data/AppInfo.java
@@ -16,6 +16,7 @@
package com.android.launcher3.model.data;
+import static com.android.launcher3.Flags.enableSupportForArchiving;
import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_ALL_APPS;
import android.content.ComponentName;
@@ -40,6 +41,7 @@
/**
* Represents an app in AllAppsView.
*/
+@SuppressWarnings("NewApi")
public class AppInfo extends ItemInfoWithIcon implements WorkspaceItemFactory {
public static final AppInfo[] EMPTY_ARRAY = new AppInfo[0];
@@ -172,6 +174,9 @@
if (PackageManagerHelper.isAppSuspended(appInfo)) {
info.runtimeStatusFlags |= FLAG_DISABLED_SUSPENDED;
}
+ if (enableSupportForArchiving() && lai.getActivityInfo().isArchived) {
+ info.runtimeStatusFlags |= FLAG_ARCHIVED;
+ }
info.runtimeStatusFlags |= (appInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0
? FLAG_SYSTEM_NO : FLAG_SYSTEM_YES;
diff --git a/src/com/android/launcher3/model/data/ItemInfoWithIcon.java b/src/com/android/launcher3/model/data/ItemInfoWithIcon.java
index 5141db9..58b12b1 100644
--- a/src/com/android/launcher3/model/data/ItemInfoWithIcon.java
+++ b/src/com/android/launcher3/model/data/ItemInfoWithIcon.java
@@ -16,6 +16,8 @@
package com.android.launcher3.model.data;
+import static com.android.launcher3.Flags.enableSupportForArchiving;
+
import android.content.Context;
import android.content.Intent;
import android.os.Process;
@@ -114,6 +116,12 @@
public static final int FLAG_NOT_PINNABLE = 1 << 13;
/**
+ * Flag indicating whether the package related to the item & user corresponds to that of
+ * archived app.
+ */
+ public static final int FLAG_ARCHIVED = 1 << 14;
+
+ /**
* Status associated with the system state of the underlying item. This is calculated every
* time a new info is created and not persisted on the disk.
*/
@@ -143,6 +151,15 @@
}
/**
+ * Returns true if the app corresponding to the item is archived. */
+ public boolean isArchived() {
+ if (!enableSupportForArchiving()) {
+ return false;
+ }
+ return (runtimeStatusFlags & FLAG_ARCHIVED) != 0;
+ }
+
+ /**
* Indicates whether we're using a low res icon
*/
public boolean usingLowResIcon() {
@@ -158,7 +175,7 @@
public boolean isAppStartable() {
return ((runtimeStatusFlags & FLAG_INSTALL_SESSION_ACTIVE) == 0)
&& (((runtimeStatusFlags & FLAG_INCREMENTAL_DOWNLOAD_ACTIVE) != 0)
- || mProgressLevel == 100);
+ || mProgressLevel == 100 || isArchived());
}
/**
@@ -167,7 +184,10 @@
* progress.
*/
public int getProgressLevel() {
- if ((runtimeStatusFlags & FLAG_SHOW_DOWNLOAD_PROGRESS_MASK) != 0) {
+ if (((runtimeStatusFlags & FLAG_SHOW_DOWNLOAD_PROGRESS_MASK) != 0)
+ // This condition for archived apps is so that in case unarchival/update of
+ // archived app is cancelled, the state transitions back to 0% installed state.
+ || isArchived()) {
return mProgressLevel;
}
return 100;
diff --git a/src/com/android/launcher3/model/data/WorkspaceItemInfo.java b/src/com/android/launcher3/model/data/WorkspaceItemInfo.java
index 3ce194d..c67ec5a 100644
--- a/src/com/android/launcher3/model/data/WorkspaceItemInfo.java
+++ b/src/com/android/launcher3/model/data/WorkspaceItemInfo.java
@@ -148,9 +148,19 @@
public final boolean isPromise() {
- return hasStatusFlag(FLAG_RESTORED_ICON | FLAG_AUTOINSTALL_ICON);
+ return hasStatusFlag(FLAG_RESTORED_ICON | FLAG_AUTOINSTALL_ICON)
+ // For archived apps, promise icons are always ready to be displayed.
+ || isArchived();
}
+ /**
+ * Returns true if the workspace item supports promise icon UI. There are a few cases where they
+ * are supported:
+ * 1. Icons to be restored via backup/restore.
+ * 2. Icons added as an auto-install app.
+ * 3. Icons added due to it being an active install session created by the user.
+ * 4. Icons for archived apps.
+ */
public boolean hasPromiseIconUi() {
return isPromise() && !hasStatusFlag(FLAG_SUPPORTS_WEB_UI);
}
diff --git a/src/com/android/launcher3/pm/InstallSessionHelper.java b/src/com/android/launcher3/pm/InstallSessionHelper.java
index cb3c16c..ca27eb2 100644
--- a/src/com/android/launcher3/pm/InstallSessionHelper.java
+++ b/src/com/android/launcher3/pm/InstallSessionHelper.java
@@ -16,6 +16,8 @@
package com.android.launcher3.pm;
+import static com.android.launcher3.Flags.enableSupportForArchiving;
+
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.LauncherApps;
@@ -51,6 +53,7 @@
/**
* Utility class to tracking install sessions
*/
+@SuppressWarnings("NewApi")
public class InstallSessionHelper {
@NonNull
@@ -227,6 +230,11 @@
}
public boolean verifySessionInfo(@Nullable final PackageInstaller.SessionInfo sessionInfo) {
+ // For archived apps we always want to show promise icons and the checks below don't apply.
+ if (enableSupportForArchiving() && sessionInfo != null && sessionInfo.isUnarchival()) {
+ return true;
+ }
+
return verify(sessionInfo) != null
&& sessionInfo.getInstallReason() == PackageManager.INSTALL_REASON_USER
&& sessionInfo.getAppIcon() != null
diff --git a/src/com/android/launcher3/pm/InstallSessionTracker.java b/src/com/android/launcher3/pm/InstallSessionTracker.java
index 41908d3..e4a2045 100644
--- a/src/com/android/launcher3/pm/InstallSessionTracker.java
+++ b/src/com/android/launcher3/pm/InstallSessionTracker.java
@@ -15,6 +15,7 @@
*/
package com.android.launcher3.pm;
+import static com.android.launcher3.Flags.enableSupportForArchiving;
import static com.android.launcher3.pm.InstallSessionHelper.getUserHandle;
import static com.android.launcher3.pm.PackageInstallInfo.STATUS_FAILED;
import static com.android.launcher3.pm.PackageInstallInfo.STATUS_INSTALLED;
@@ -36,6 +37,7 @@
import java.lang.ref.WeakReference;
import java.util.Objects;
+@SuppressWarnings("NewApi")
@WorkerThread
public class InstallSessionTracker extends PackageInstaller.SessionCallback {
@@ -77,6 +79,12 @@
}
helper.tryQueuePromiseAppIcon(sessionInfo);
+
+ if (enableSupportForArchiving() && sessionInfo != null && sessionInfo.isUnarchival()) {
+ // For archived apps, icon could already be present on the workspace. To make sure
+ // the icon state is updated, we send a change event.
+ callback.onPackageStateChanged(PackageInstallInfo.fromInstallingState(sessionInfo));
+ }
}
@Override
diff --git a/src/com/android/launcher3/touch/ItemClickHandler.java b/src/com/android/launcher3/touch/ItemClickHandler.java
index 839f98c..ff8b381 100644
--- a/src/com/android/launcher3/touch/ItemClickHandler.java
+++ b/src/com/android/launcher3/touch/ItemClickHandler.java
@@ -15,6 +15,7 @@
*/
package com.android.launcher3.touch;
+import static com.android.launcher3.Flags.enableSupportForArchiving;
import static com.android.launcher3.LauncherConstants.ActivityCodes.REQUEST_BIND_PENDING_APPWIDGET;
import static com.android.launcher3.LauncherConstants.ActivityCodes.REQUEST_RECONFIGURE_APPWIDGET;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_FOLDER_OPEN;
@@ -319,7 +320,8 @@
}
// Check for abandoned promise
- if ((v instanceof BubbleTextView) && shortcut.hasPromiseIconUi()) {
+ if ((v instanceof BubbleTextView) && shortcut.hasPromiseIconUi()
+ && (!enableSupportForArchiving() || !shortcut.isArchived())) {
String packageName = shortcut.getIntent().getComponent() != null
? shortcut.getIntent().getComponent().getPackageName()
: shortcut.getIntent().getPackage();