From 84269d349d093b6b0bd2b68e2306f7e0475cd4f5 Mon Sep 17 00:00:00 2001 From: Schneider Victor-tulias Date: Mon, 16 Nov 2020 13:25:46 -0500 Subject: [PATCH] Add UI updates for incremental app installs. 1. Changed Preload Icon UI to be grayscale while the app is not startable. 2. Added progress bar for when app is installed but still ownloading. 3. Updated Preload Icon progress and click handling to use new incremental api. Progress bar color updates will follow in a separate CL. Demo: https://drive.google.com/file/d/1H1EvtTorLeJwC1eiq10tm-TT81YZ6osk/view?usp=sharing Bug: 171008815 Test: manual Change-Id: I5874a5146d79a8c91d7d90ff0b9c1c427a3c95dd --- .../PackageInstallStateChangedTaskTest.java | 2 +- src/com/android/launcher3/BubbleTextView.java | 50 ++++++---- src/com/android/launcher3/Launcher.java | 5 +- src/com/android/launcher3/LauncherModel.java | 10 ++ src/com/android/launcher3/Utilities.java | 7 +- src/com/android/launcher3/Workspace.java | 2 +- .../launcher3/allapps/AllAppsStore.java | 12 ++- .../launcher3/folder/PreviewItemManager.java | 6 +- .../graphics/PreloadIconDrawable.java | 4 +- .../model/AddWorkspaceItemsTask.java | 5 +- .../android/launcher3/model/AllAppsList.java | 33 ++++--- .../android/launcher3/model/BgDataModel.java | 7 +- .../android/launcher3/model/LoaderCursor.java | 23 +++-- .../android/launcher3/model/LoaderTask.java | 24 ++++- ...PackageIncrementalDownloadUpdatedTask.java | 79 +++++++++++++++ .../model/PackageInstallStateChangedTask.java | 21 ++-- .../android/launcher3/model/data/AppInfo.java | 40 +++++++- .../model/data/ItemInfoWithIcon.java | 97 +++++++++++++++++++ .../launcher3/model/data/PromiseAppInfo.java | 54 ----------- .../model/data/WorkspaceItemInfo.java | 25 +---- .../launcher3/pm/PackageInstallInfo.java | 4 +- .../SecondaryDisplayLauncher.java | 14 +-- .../launcher3/touch/ItemClickHandler.java | 19 ++-- .../launcher3/util/PackageManagerHelper.java | 20 +++- 24 files changed, 400 insertions(+), 163 deletions(-) create mode 100644 src/com/android/launcher3/model/PackageIncrementalDownloadUpdatedTask.java delete mode 100644 src/com/android/launcher3/model/data/PromiseAppInfo.java diff --git a/robolectric_tests/src/com/android/launcher3/model/PackageInstallStateChangedTaskTest.java b/robolectric_tests/src/com/android/launcher3/model/PackageInstallStateChangedTaskTest.java index e43df21ae9..412ace03ff 100644 --- a/robolectric_tests/src/com/android/launcher3/model/PackageInstallStateChangedTaskTest.java +++ b/robolectric_tests/src/com/android/launcher3/model/PackageInstallStateChangedTaskTest.java @@ -67,7 +67,7 @@ public class PackageInstallStateChangedTaskTest { for (ItemInfo info : mModelHelper.getBgDataModel().itemsIdMap) { if (info instanceof WorkspaceItemInfo) { assertEquals(updates.contains(info.id) ? progress: 0, - ((WorkspaceItemInfo) info).getInstallProgress()); + ((WorkspaceItemInfo) info).getProgressLevel()); } else { assertEquals(updates.contains(info.id) ? progress: -1, ((LauncherAppWidgetInfo) info).installProgress); diff --git a/src/com/android/launcher3/BubbleTextView.java b/src/com/android/launcher3/BubbleTextView.java index 3eb52adf1a..f44f88b098 100644 --- a/src/com/android/launcher3/BubbleTextView.java +++ b/src/com/android/launcher3/BubbleTextView.java @@ -50,6 +50,7 @@ import android.view.View; import android.view.ViewDebug; import android.widget.TextView; +import androidx.annotation.Nullable; import androidx.core.graphics.ColorUtils; import com.android.launcher3.Launcher.OnResumeCallback; @@ -71,7 +72,6 @@ import com.android.launcher3.model.data.AppInfo; import com.android.launcher3.model.data.ItemInfo; import com.android.launcher3.model.data.ItemInfoWithIcon; import com.android.launcher3.model.data.PackageItemInfo; -import com.android.launcher3.model.data.PromiseAppInfo; import com.android.launcher3.model.data.RemoteActionItemInfo; import com.android.launcher3.model.data.WorkspaceItemInfo; import com.android.launcher3.util.SafeCloseable; @@ -287,10 +287,7 @@ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver, public void applyFromWorkspaceItem(WorkspaceItemInfo info, boolean promiseStateChanged) { applyIconAndLabel(info); setTag(info); - if (promiseStateChanged || (info.hasPromiseIconUi())) { - applyPromiseState(promiseStateChanged); - } - + applyLoadingState(promiseStateChanged); applyDotState(info, false /* animate */); } @@ -303,9 +300,8 @@ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver, // Verify high res immediately verifyHighRes(); - if (info instanceof PromiseAppInfo) { - PromiseAppInfo promiseAppInfo = (PromiseAppInfo) info; - applyProgressLevel(promiseAppInfo.level); + if ((info.runtimeStatusFlags & ItemInfoWithIcon.FLAG_SHOW_DOWNLOAD_PROGRESS_MASK) != 0) { + applyProgressLevel(info.getProgressLevel()); } applyDotState(info, false /* animate */); } @@ -335,6 +331,10 @@ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver, mDotParams.color = IconPalette.getMutedColor(info.bitmap.color, 0.54f); setIcon(iconDrawable); + applyLabel(info); + } + + private void applyLabel(ItemInfoWithIcon info) { setText(info.title); if (info.contentDescription != null) { setContentDescription(info.isDisabled() @@ -595,21 +595,35 @@ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver, mLongPressHelper.cancelLongPress(); } - public void applyPromiseState(boolean promiseStateChanged) { + /** Applies the loading progress value to the progress bar. + * + * If this app is installing, the progress bar will be updated with the installation progress. + * If this app is installed and downloading incrementally, the progress bar will be updated + * with the total download progress. + */ + public void applyLoadingState(boolean promiseStateChanged) { if (getTag() instanceof WorkspaceItemInfo) { WorkspaceItemInfo info = (WorkspaceItemInfo) getTag(); - final boolean isPromise = info.hasPromiseIconUi(); - final int progressLevel = isPromise ? - ((info.hasStatusFlag(WorkspaceItemInfo.FLAG_INSTALL_SESSION_ACTIVE) ? - info.getInstallProgress() : 0)) : 100; - - PreloadIconDrawable preloadDrawable = applyProgressLevel(progressLevel); - if (preloadDrawable != null && promiseStateChanged) { - preloadDrawable.maybePerformFinishedAnimation(); + int progressLevel = info.getProgressLevel(); + if ((info.runtimeStatusFlags & ItemInfoWithIcon.FLAG_INCREMENTAL_DOWNLOAD_ACTIVE) + != 0) { + updateProgressBarUi(progressLevel, progressLevel == 100); + } else if (info.hasPromiseIconUi() || (info.runtimeStatusFlags + & ItemInfoWithIcon.FLAG_INSTALL_SESSION_ACTIVE) != 0) { + updateProgressBarUi(progressLevel, promiseStateChanged); } } } + private void updateProgressBarUi(int progressLevel, boolean maybePerformFinishedAnimation) { + PreloadIconDrawable preloadDrawable = applyProgressLevel(progressLevel); + if (preloadDrawable != null && maybePerformFinishedAnimation) { + preloadDrawable.maybePerformFinishedAnimation(); + } + } + + /** Applies the given progress level to the this icon's progress bar. */ + @Nullable public PreloadIconDrawable applyProgressLevel(int progressLevel) { if (getTag() instanceof ItemInfoWithIcon) { ItemInfoWithIcon info = (ItemInfoWithIcon) getTag(); @@ -629,9 +643,11 @@ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver, if (mIcon instanceof PreloadIconDrawable) { preloadDrawable = (PreloadIconDrawable) mIcon; preloadDrawable.setLevel(progressLevel); + preloadDrawable.setIsDisabled(!info.isAppStartable()); } else { preloadDrawable = newPendingIcon(getContext(), info); preloadDrawable.setLevel(progressLevel); + preloadDrawable.setIsDisabled(!info.isAppStartable()); setIcon(preloadDrawable); } return preloadDrawable; diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java index e099d852f3..4d1b76610c 100644 --- a/src/com/android/launcher3/Launcher.java +++ b/src/com/android/launcher3/Launcher.java @@ -137,7 +137,6 @@ import com.android.launcher3.model.data.AppInfo; import com.android.launcher3.model.data.FolderInfo; import com.android.launcher3.model.data.ItemInfo; import com.android.launcher3.model.data.LauncherAppWidgetInfo; -import com.android.launcher3.model.data.PromiseAppInfo; import com.android.launcher3.model.data.WorkspaceItemInfo; import com.android.launcher3.notification.NotificationListener; import com.android.launcher3.pm.PinRequestHelper; @@ -2517,8 +2516,8 @@ public class Launcher extends StatefulActivity implements Launche } @Override - public void bindPromiseAppProgressUpdated(PromiseAppInfo app) { - mAppsView.getAppsStore().updatePromiseAppProgress(app); + public void bindIncrementalDownloadProgressUpdated(AppInfo app) { + mAppsView.getAppsStore().updateProgressBar(app); } @Override diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java index 8458152146..e89b9b060a 100644 --- a/src/com/android/launcher3/LauncherModel.java +++ b/src/com/android/launcher3/LauncherModel.java @@ -48,6 +48,7 @@ import com.android.launcher3.model.LoaderResults; import com.android.launcher3.model.LoaderTask; import com.android.launcher3.model.ModelDelegate; import com.android.launcher3.model.ModelWriter; +import com.android.launcher3.model.PackageIncrementalDownloadUpdatedTask; import com.android.launcher3.model.PackageInstallStateChangedTask; import com.android.launcher3.model.PackageUpdatedTask; import com.android.launcher3.model.ShortcutsChangedTask; @@ -195,6 +196,15 @@ public class LauncherModel extends LauncherApps.Callback implements InstallSessi PackageUpdatedTask.OP_UNSUSPEND, user, packageNames)); } + @Override + public void onPackageLoadingProgressChanged( + String packageName, UserHandle user, float progress) { + if (Utilities.ATLEAST_S) { + enqueueModelUpdateTask(new PackageIncrementalDownloadUpdatedTask( + packageName, user, progress)); + } + } + @Override public void onShortcutsChanged(String packageName, List shortcuts, UserHandle user) { diff --git a/src/com/android/launcher3/Utilities.java b/src/com/android/launcher3/Utilities.java index 5c2f35b981..df5d23428d 100644 --- a/src/com/android/launcher3/Utilities.java +++ b/src/com/android/launcher3/Utilities.java @@ -107,12 +107,13 @@ public final class Utilities { public static final String[] EMPTY_STRING_ARRAY = new String[0]; public static final Person[] EMPTY_PERSON_ARRAY = new Person[0]; - public static final boolean ATLEAST_R = BuildCompat.isAtLeastR(); + public static final boolean ATLEAST_P = Build.VERSION.SDK_INT >= Build.VERSION_CODES.P; public static final boolean ATLEAST_Q = Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q; - public static final boolean ATLEAST_P = - Build.VERSION.SDK_INT >= Build.VERSION_CODES.P; + public static final boolean ATLEAST_R = Build.VERSION.SDK_INT >= Build.VERSION_CODES.R; + + public static final boolean ATLEAST_S = BuildCompat.isAtLeastS(); /** * Set on a motion event dispatched from the nav bar. See {@link MotionEvent#setEdgeFlags(int)}. diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java index 777ea3c7d5..65eba20672 100644 --- a/src/com/android/launcher3/Workspace.java +++ b/src/com/android/launcher3/Workspace.java @@ -3154,7 +3154,7 @@ public class Workspace extends PagedView ItemOperator op = (info, v) -> { if (info instanceof WorkspaceItemInfo && v instanceof BubbleTextView && updates.contains(info)) { - ((BubbleTextView) v).applyPromiseState(false /* promiseStateChanged */); + ((BubbleTextView) v).applyLoadingState(false /* promiseStateChanged */); } else if (v instanceof PendingAppWidgetHostView && info instanceof LauncherAppWidgetInfo && updates.contains(info)) { diff --git a/src/com/android/launcher3/allapps/AllAppsStore.java b/src/com/android/launcher3/allapps/AllAppsStore.java index 3ae0a18137..00bdb70c4a 100644 --- a/src/com/android/launcher3/allapps/AllAppsStore.java +++ b/src/com/android/launcher3/allapps/AllAppsStore.java @@ -24,7 +24,6 @@ import android.view.ViewGroup; import com.android.launcher3.BubbleTextView; import com.android.launcher3.model.data.AppInfo; import com.android.launcher3.model.data.ItemInfo; -import com.android.launcher3.model.data.PromiseAppInfo; import com.android.launcher3.util.ComponentKey; import com.android.launcher3.util.PackageUserKey; @@ -145,10 +144,17 @@ public class AllAppsStore { }); } - public void updatePromiseAppProgress(PromiseAppInfo app) { + /** + * Sets the AppInfo's associated icon's progress bar. + * + * If this app is installed and supports incremental downloads, the progress bar will be updated + * the app's total download progress. Otherwise, the progress bar will be updated to the app's + * installation progress. + */ + public void updateProgressBar(AppInfo app) { updateAllIcons((child) -> { if (child.getTag() == app) { - child.applyProgressLevel(app.level); + child.applyProgressLevel(app.getProgressLevel()); } }); } diff --git a/src/com/android/launcher3/folder/PreviewItemManager.java b/src/com/android/launcher3/folder/PreviewItemManager.java index 7f8a15c927..9ae7faf988 100644 --- a/src/com/android/launcher3/folder/PreviewItemManager.java +++ b/src/com/android/launcher3/folder/PreviewItemManager.java @@ -39,6 +39,7 @@ import androidx.annotation.NonNull; import com.android.launcher3.Utilities; import com.android.launcher3.graphics.PreloadIconDrawable; +import com.android.launcher3.model.data.ItemInfoWithIcon; import com.android.launcher3.model.data.WorkspaceItemInfo; import com.android.launcher3.views.ActivityContext; @@ -394,9 +395,10 @@ public class PreviewItemManager { } private void setDrawable(PreviewItemDrawingParams p, WorkspaceItemInfo item) { - if (item.hasPromiseIconUi()) { + if (item.hasPromiseIconUi() || (item.runtimeStatusFlags + & ItemInfoWithIcon.FLAG_SHOW_DOWNLOAD_PROGRESS_MASK) != 0) { PreloadIconDrawable drawable = newPendingIcon(mContext, item); - drawable.setLevel(item.getInstallProgress()); + drawable.setLevel(item.getProgressLevel()); p.drawable = drawable; } else { p.drawable = newIcon(mContext, item); diff --git a/src/com/android/launcher3/graphics/PreloadIconDrawable.java b/src/com/android/launcher3/graphics/PreloadIconDrawable.java index e85b056376..9971990267 100644 --- a/src/com/android/launcher3/graphics/PreloadIconDrawable.java +++ b/src/com/android/launcher3/graphics/PreloadIconDrawable.java @@ -117,6 +117,8 @@ public class PreloadIconDrawable extends FastBitmapDrawable { mIndicatorColor = IconPalette.getPreloadProgressColor(context, mIconColor); setInternalProgress(0); + + setIsDisabled(!info.isAppStartable()); } @Override @@ -266,14 +268,12 @@ public class PreloadIconDrawable extends FastBitmapDrawable { mIconScale = SMALL_SCALE; mScaledTrackPath.reset(); mTrackAlpha = MAX_PAINT_ALPHA; - setIsDisabled(true); } if (progress < 1 && progress > 0) { mPathMeasure.getSegment(0, progress * mTrackLength, mScaledProgressPath, true); mIconScale = SMALL_SCALE; mTrackAlpha = MAX_PAINT_ALPHA; - setIsDisabled(true); } else if (progress >= 1) { setIsDisabled(mItem.isDisabled()); mScaledTrackPath.set(mScaledProgressPath); diff --git a/src/com/android/launcher3/model/AddWorkspaceItemsTask.java b/src/com/android/launcher3/model/AddWorkspaceItemsTask.java index c236fa6dec..56dbbd33da 100644 --- a/src/com/android/launcher3/model/AddWorkspaceItemsTask.java +++ b/src/com/android/launcher3/model/AddWorkspaceItemsTask.java @@ -34,6 +34,7 @@ import com.android.launcher3.model.data.ItemInfo; import com.android.launcher3.model.data.LauncherAppWidgetInfo; import com.android.launcher3.model.data.WorkspaceItemInfo; import com.android.launcher3.pm.InstallSessionHelper; +import com.android.launcher3.pm.PackageInstallInfo; import com.android.launcher3.util.GridOccupancy; import com.android.launcher3.util.IntArray; import com.android.launcher3.util.PackageManagerHelper; @@ -132,7 +133,9 @@ public class AddWorkspaceItemsTask extends BaseModelUpdateTask { continue; } } else { - workspaceInfo.setInstallProgress((int) sessionInfo.getProgress()); + workspaceInfo.setProgressLevel( + (int) (sessionInfo.getProgress() * 100), + PackageInstallInfo.STATUS_INSTALLING); } if (hasActivity) { diff --git a/src/com/android/launcher3/model/AllAppsList.java b/src/com/android/launcher3/model/AllAppsList.java index 2695e66591..8d5cf7422f 100644 --- a/src/com/android/launcher3/model/AllAppsList.java +++ b/src/com/android/launcher3/model/AllAppsList.java @@ -21,11 +21,11 @@ import static com.android.launcher3.model.data.AppInfo.EMPTY_ARRAY; import android.content.ComponentName; import android.content.Context; +import android.content.Intent; import android.content.pm.ApplicationInfo; import android.content.pm.LauncherActivityInfo; import android.content.pm.LauncherApps; import android.os.LocaleList; -import android.os.Process; import android.os.UserHandle; import android.util.Log; @@ -37,7 +37,6 @@ import com.android.launcher3.compat.AlphabeticIndexCompat; import com.android.launcher3.icons.IconCache; import com.android.launcher3.model.BgDataModel.Callbacks; import com.android.launcher3.model.data.AppInfo; -import com.android.launcher3.model.data.PromiseAppInfo; import com.android.launcher3.pm.PackageInstallInfo; import com.android.launcher3.util.FlagOp; import com.android.launcher3.util.ItemInfoMatcher; @@ -150,7 +149,7 @@ public class AllAppsList { .getApplicationInfo(installInfo.packageName, installInfo.user, 0); // only if not yet installed if (applicationInfo == null) { - PromiseAppInfo info = new PromiseAppInfo(installInfo); + AppInfo info = new AppInfo(installInfo); mIconCache.getTitleAndIcon(info, info.usingLowResIcon()); info.sectionName = mIndex.computeSectionName(info.title); @@ -159,24 +158,26 @@ public class AllAppsList { } } - public PromiseAppInfo updatePromiseInstallInfo(PackageInstallInfo installInfo) { - UserHandle user = Process.myUserHandle(); - for (int i=0; i < data.size(); i++) { + /** Updates the given PackageInstallInfo's associated AppInfo's installation info. */ + public List updatePromiseInstallInfo(PackageInstallInfo installInfo) { + List updatedAppInfos = new ArrayList<>(); + UserHandle user = installInfo.user; + for (int i = data.size() - 1; i >= 0; i--) { final AppInfo appInfo = data.get(i); final ComponentName tgtComp = appInfo.getTargetComponent(); if (tgtComp != null && tgtComp.getPackageName().equals(installInfo.packageName) - && appInfo.user.equals(user) - && appInfo instanceof PromiseAppInfo) { - final PromiseAppInfo promiseAppInfo = (PromiseAppInfo) appInfo; - if (installInfo.state == PackageInstallInfo.STATUS_INSTALLING) { - promiseAppInfo.level = installInfo.progress; - return promiseAppInfo; + && appInfo.user.equals(user)) { + if (installInfo.state == PackageInstallInfo.STATUS_INSTALLED_DOWNLOADING + || installInfo.state == PackageInstallInfo.STATUS_INSTALLING) { + appInfo.setProgressLevel(installInfo); + + updatedAppInfos.add(appInfo); } else if (installInfo.state == PackageInstallInfo.STATUS_FAILED) { removeApp(i); } } } - return null; + return updatedAppInfos; } private void removeApp(int index) { @@ -268,8 +269,14 @@ public class AllAppsList { if (applicationInfo == null) { add(new AppInfo(context, info, user), info); } else { + Intent launchIntent = AppInfo.makeLaunchIntent(info); + mIconCache.getTitleAndIcon(applicationInfo, info, true /* useLowResIcon */); applicationInfo.sectionName = mIndex.computeSectionName(applicationInfo.title); + applicationInfo.setProgressLevel( + PackageManagerHelper.getLoadingProgress(info), + PackageInstallInfo.STATUS_INSTALLED_DOWNLOADING); + applicationInfo.intent = launchIntent; mDataChanged = true; } diff --git a/src/com/android/launcher3/model/BgDataModel.java b/src/com/android/launcher3/model/BgDataModel.java index c217a475a1..2d860a41d3 100644 --- a/src/com/android/launcher3/model/BgDataModel.java +++ b/src/com/android/launcher3/model/BgDataModel.java @@ -39,7 +39,6 @@ import com.android.launcher3.model.data.AppInfo; import com.android.launcher3.model.data.FolderInfo; import com.android.launcher3.model.data.ItemInfo; import com.android.launcher3.model.data.LauncherAppWidgetInfo; -import com.android.launcher3.model.data.PromiseAppInfo; import com.android.launcher3.model.data.WorkspaceItemInfo; import com.android.launcher3.pm.UserCache; import com.android.launcher3.shortcuts.ShortcutKey; @@ -459,7 +458,11 @@ public class BgDataModel { void preAddApps(); void bindAppsAdded(IntArray newScreens, ArrayList addNotAnimated, ArrayList addAnimated); - void bindPromiseAppProgressUpdated(PromiseAppInfo app); + + /** + * Binds updated incremental download progress + */ + void bindIncrementalDownloadProgressUpdated(AppInfo app); void bindWorkspaceItemsChanged(List updated); void bindWidgetsRestored(ArrayList widgets); void bindRestoreItemsChange(HashSet updates); diff --git a/src/com/android/launcher3/model/LoaderCursor.java b/src/com/android/launcher3/model/LoaderCursor.java index 532834eeb8..19d9af98dc 100644 --- a/src/com/android/launcher3/model/LoaderCursor.java +++ b/src/com/android/launcher3/model/LoaderCursor.java @@ -35,11 +35,13 @@ import android.text.TextUtils; import android.util.Log; import android.util.LongSparseArray; +import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; import com.android.launcher3.InvariantDeviceProfile; import com.android.launcher3.LauncherAppState; import com.android.launcher3.LauncherSettings; +import com.android.launcher3.LauncherSettings.Favorites; import com.android.launcher3.Utilities; import com.android.launcher3.Workspace; import com.android.launcher3.config.FeatureFlags; @@ -92,6 +94,9 @@ public class LoaderCursor extends CursorWrapper { private final int restoredIndex; private final int intentIndex; + @Nullable + private LauncherActivityInfo mActivityInfo; + // Properties loaded per iteration public long serialNumber; public UserHandle user; @@ -132,6 +137,8 @@ public class LoaderCursor extends CursorWrapper { public boolean moveToNext() { boolean result = super.moveToNext(); if (result) { + mActivityInfo = null; + // Load common properties. itemType = getInt(itemTypeIndex); container = getInt(containerIndex); @@ -245,6 +252,10 @@ public class LoaderCursor extends CursorWrapper { return info; } + public LauncherActivityInfo getLauncherActivityInfo() { + return mActivityInfo; + } + /** * Make an WorkspaceItemInfo object for a shortcut that is an application. */ @@ -264,25 +275,25 @@ public class LoaderCursor extends CursorWrapper { Intent newIntent = new Intent(Intent.ACTION_MAIN, null); newIntent.addCategory(Intent.CATEGORY_LAUNCHER); newIntent.setComponent(componentName); - LauncherActivityInfo lai = mContext.getSystemService(LauncherApps.class) + mActivityInfo = mContext.getSystemService(LauncherApps.class) .resolveActivity(newIntent, user); - if ((lai == null) && !allowMissingTarget) { + if ((mActivityInfo == null) && !allowMissingTarget) { Log.d(TAG, "Missing activity found in getShortcutInfo: " + componentName); return null; } final WorkspaceItemInfo info = new WorkspaceItemInfo(); - info.itemType = LauncherSettings.Favorites.ITEM_TYPE_APPLICATION; + info.itemType = Favorites.ITEM_TYPE_APPLICATION; info.user = user; info.intent = newIntent; - mIconCache.getTitleAndIcon(info, lai, useLowResIcon); + mIconCache.getTitleAndIcon(info, mActivityInfo, useLowResIcon); if (mIconCache.isDefaultIcon(info.bitmap, user)) { loadIcon(info); } - if (lai != null) { - AppInfo.updateRuntimeFlagsForActivityTarget(info, lai); + if (mActivityInfo != null) { + AppInfo.updateRuntimeFlagsForActivityTarget(info, mActivityInfo); } // from the db diff --git a/src/com/android/launcher3/model/LoaderTask.java b/src/com/android/launcher3/model/LoaderTask.java index 8e085ce52d..f74c8b5c1c 100644 --- a/src/com/android/launcher3/model/LoaderTask.java +++ b/src/com/android/launcher3/model/LoaderTask.java @@ -69,6 +69,7 @@ import com.android.launcher3.logging.FileLog; import com.android.launcher3.model.data.AppInfo; import com.android.launcher3.model.data.FolderInfo; import com.android.launcher3.model.data.ItemInfo; +import com.android.launcher3.model.data.ItemInfoWithIcon; import com.android.launcher3.model.data.LauncherAppWidgetInfo; import com.android.launcher3.model.data.PackageItemInfo; import com.android.launcher3.model.data.WorkspaceItemInfo; @@ -591,11 +592,24 @@ public class LoaderTask implements Runnable { if (c.restoreFlag != 0 && !TextUtils.isEmpty(targetPkg)) { tempPackageKey.update(targetPkg, c.user); SessionInfo si = installingPkgs.get(tempPackageKey); - if (si == null) { - info.status &= ~WorkspaceItemInfo.FLAG_INSTALL_SESSION_ACTIVE; - } else { - info.setInstallProgress((int) (si.getProgress() * 100)); - } + LauncherActivityInfo activityInfo = + c.getLauncherActivityInfo(); + if (si == null) { + info.runtimeStatusFlags &= + ~ItemInfoWithIcon.FLAG_INSTALL_SESSION_ACTIVE; + } else if (activityInfo == null) { + int installProgress = (int) (si.getProgress() * 100); + + info.setProgressLevel( + installProgress, + PackageInstallInfo.STATUS_INSTALLING); + } else { + info.setProgressLevel( + PackageManagerHelper + .getLoadingProgress(activityInfo), + PackageInstallInfo + .STATUS_INSTALLED_DOWNLOADING); + } } c.checkAndAddItem(info, mBgDataModel); diff --git a/src/com/android/launcher3/model/PackageIncrementalDownloadUpdatedTask.java b/src/com/android/launcher3/model/PackageIncrementalDownloadUpdatedTask.java new file mode 100644 index 0000000000..e3e87693b1 --- /dev/null +++ b/src/com/android/launcher3/model/PackageIncrementalDownloadUpdatedTask.java @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.launcher3.model; + +import android.content.ComponentName; +import android.os.UserHandle; + +import com.android.launcher3.LauncherAppState; +import com.android.launcher3.model.data.AppInfo; +import com.android.launcher3.model.data.ItemInfoWithIcon; +import com.android.launcher3.model.data.WorkspaceItemInfo; +import com.android.launcher3.pm.PackageInstallInfo; + +import java.util.ArrayList; +import java.util.List; + +/** + * Handles updates due to incremental download progress updates. + */ +public class PackageIncrementalDownloadUpdatedTask extends BaseModelUpdateTask { + + private final UserHandle mUser; + private final int mProgress; + private final String mPackageName; + + public PackageIncrementalDownloadUpdatedTask( + String packageName, UserHandle user, float progress) { + mUser = user; + mProgress = 1 - progress > 0.001 ? (int) (100 * progress) : 100; + mPackageName = packageName; + } + + @Override + public void execute(LauncherAppState app, BgDataModel dataModel, AllAppsList appsList) { + PackageInstallInfo downloadInfo = new PackageInstallInfo( + mPackageName, + PackageInstallInfo.STATUS_INSTALLED_DOWNLOADING, + mProgress, + mUser); + + synchronized (appsList) { + List updatedAppInfos = appsList.updatePromiseInstallInfo(downloadInfo); + if (!updatedAppInfos.isEmpty()) { + for (AppInfo appInfo : updatedAppInfos) { + appInfo.runtimeStatusFlags &= ~ItemInfoWithIcon.FLAG_INSTALL_SESSION_ACTIVE; + scheduleCallbackTask( + c -> c.bindIncrementalDownloadProgressUpdated(appInfo)); + } + } + bindApplicationsIfNeeded(); + } + + final ArrayList updatedWorkspaceItems = new ArrayList<>(); + synchronized (dataModel) { + dataModel.forAllWorkspaceItemInfos(mUser, si -> { + ComponentName cn = si.getTargetComponent(); + if ((cn != null) && cn.getPackageName().equals(mPackageName)) { + si.runtimeStatusFlags &= ~ItemInfoWithIcon.FLAG_INSTALL_SESSION_ACTIVE; + si.setProgressLevel(downloadInfo); + updatedWorkspaceItems.add(si); + } + }); + } + bindUpdatedWorkspaceItems(updatedWorkspaceItems); + } +} diff --git a/src/com/android/launcher3/model/PackageInstallStateChangedTask.java b/src/com/android/launcher3/model/PackageInstallStateChangedTask.java index 8369c48e5c..8215edd90b 100644 --- a/src/com/android/launcher3/model/PackageInstallStateChangedTask.java +++ b/src/com/android/launcher3/model/PackageInstallStateChangedTask.java @@ -20,14 +20,15 @@ import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import com.android.launcher3.LauncherAppState; +import com.android.launcher3.model.data.AppInfo; import com.android.launcher3.model.data.ItemInfo; +import com.android.launcher3.model.data.ItemInfoWithIcon; import com.android.launcher3.model.data.LauncherAppWidgetInfo; -import com.android.launcher3.model.data.PromiseAppInfo; -import com.android.launcher3.model.data.WorkspaceItemInfo; import com.android.launcher3.pm.PackageInstallInfo; import com.android.launcher3.util.InstantAppResolver; import java.util.HashSet; +import java.util.List; /** * Handles changes due to a sessions updates for a currently installing app. @@ -59,9 +60,11 @@ public class PackageInstallStateChangedTask extends BaseModelUpdateTask { } synchronized (apps) { - PromiseAppInfo updated = apps.updatePromiseInstallInfo(mInstallInfo); - if (updated != null) { - scheduleCallbackTask(c -> c.bindPromiseAppProgressUpdated(updated)); + List updatedAppInfos = apps.updatePromiseInstallInfo(mInstallInfo); + if (!updatedAppInfos.isEmpty()) { + for (AppInfo appInfo : updatedAppInfos) { + scheduleCallbackTask(c -> c.bindIncrementalDownloadProgressUpdated(appInfo)); + } } bindApplicationsIfNeeded(); } @@ -71,11 +74,13 @@ public class PackageInstallStateChangedTask extends BaseModelUpdateTask { dataModel.forAllWorkspaceItemInfos(mInstallInfo.user, si -> { ComponentName cn = si.getTargetComponent(); if (si.hasPromiseIconUi() && (cn != null) - && mInstallInfo.packageName.equals(cn.getPackageName())) { - si.setInstallProgress(mInstallInfo.progress); + && cn.getPackageName().equals(mInstallInfo.packageName)) { + int installProgress = mInstallInfo.progress; + + si.setProgressLevel(installProgress, PackageInstallInfo.STATUS_INSTALLING); if (mInstallInfo.state == PackageInstallInfo.STATUS_FAILED) { // Mark this info as broken. - si.status &= ~WorkspaceItemInfo.FLAG_INSTALL_SESSION_ACTIVE; + si.runtimeStatusFlags &= ~ItemInfoWithIcon.FLAG_INSTALL_SESSION_ACTIVE; } updates.add(si); } diff --git a/src/com/android/launcher3/model/data/AppInfo.java b/src/com/android/launcher3/model/data/AppInfo.java index aee1f2a65b..39247c221f 100644 --- a/src/com/android/launcher3/model/data/AppInfo.java +++ b/src/com/android/launcher3/model/data/AppInfo.java @@ -28,10 +28,13 @@ import android.os.Process; import android.os.UserHandle; import android.os.UserManager; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; import com.android.launcher3.LauncherSettings; import com.android.launcher3.Utilities; +import com.android.launcher3.pm.PackageInstallInfo; import com.android.launcher3.util.ComponentKey; import com.android.launcher3.util.PackageManagerHelper; @@ -104,13 +107,37 @@ public class AppInfo extends ItemInfoWithIcon { this.intent = intent; } + public AppInfo(@NonNull PackageInstallInfo installInfo) { + componentName = installInfo.componentName; + intent = new Intent(Intent.ACTION_MAIN) + .addCategory(Intent.CATEGORY_LAUNCHER) + .setComponent(componentName) + .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK + | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED); + user = installInfo.user; + } + @Override protected String dumpProperties() { return super.dumpProperties() + " componentName=" + componentName; } public WorkspaceItemInfo makeWorkspaceItem() { - return new WorkspaceItemInfo(this); + WorkspaceItemInfo workspaceItemInfo = new WorkspaceItemInfo(this); + + if ((runtimeStatusFlags & FLAG_INSTALL_SESSION_ACTIVE) != 0) { + // We need to update the component name when the apk is installed + workspaceItemInfo.status |= WorkspaceItemInfo.FLAG_AUTOINSTALL_ICON; + // Since the user is manually placing it on homescreen, it should not be auto-removed + // later + workspaceItemInfo.status |= WorkspaceItemInfo.FLAG_RESTORE_STARTED; + workspaceItemInfo.status |= FLAG_INSTALL_SESSION_ACTIVE; + } + if ((runtimeStatusFlags & FLAG_INCREMENTAL_DOWNLOAD_ACTIVE) != 0) { + workspaceItemInfo.runtimeStatusFlags |= FLAG_INCREMENTAL_DOWNLOAD_ACTIVE; + } + + return workspaceItemInfo; } public ComponentKey toComponentKey() { @@ -129,6 +156,12 @@ public class AppInfo extends ItemInfoWithIcon { | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED); } + @Nullable + @Override + public ComponentName getTargetComponent() { + return componentName; + } + public static void updateRuntimeFlagsForActivityTarget( ItemInfoWithIcon info, LauncherActivityInfo lai) { ApplicationInfo appInfo = lai.getApplicationInfo(); @@ -143,6 +176,11 @@ public class AppInfo extends ItemInfoWithIcon { // The icon for a non-primary user is badged, hence it's not exactly an adaptive icon. info.runtimeStatusFlags |= FLAG_ADAPTIVE_ICON; } + + // Sets the progress level, installation and incremental download flags. + info.setProgressLevel( + PackageManagerHelper.getLoadingProgress(lai), + PackageInstallInfo.STATUS_INSTALLED); } @Override diff --git a/src/com/android/launcher3/model/data/ItemInfoWithIcon.java b/src/com/android/launcher3/model/data/ItemInfoWithIcon.java index d95f94f79f..b8a71d33e0 100644 --- a/src/com/android/launcher3/model/data/ItemInfoWithIcon.java +++ b/src/com/android/launcher3/model/data/ItemInfoWithIcon.java @@ -16,7 +16,15 @@ package com.android.launcher3.model.data; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; + +import androidx.annotation.Nullable; + import com.android.launcher3.icons.BitmapInfo; +import com.android.launcher3.pm.PackageInstallInfo; +import com.android.launcher3.util.PackageManagerHelper; /** * Represents an ItemInfo which also holds an icon. @@ -87,12 +95,35 @@ public abstract class ItemInfoWithIcon extends ItemInfo { */ public static final int FLAG_ICON_BADGED = 1 << 9; + /** + * The icon is being installed. If {@link WorkspaceItemInfo#FLAG_RESTORED_ICON} or + * {@link WorkspaceItemInfo#FLAG_AUTOINSTALL_ICON} is set, then the icon is either being + * installed or is in a broken state. + */ + public static final int FLAG_INSTALL_SESSION_ACTIVE = 1 << 10; + + /** + * This icon is still being downloaded. + */ + public static final int FLAG_INCREMENTAL_DOWNLOAD_ACTIVE = 1 << 11; + + public static final int FLAG_SHOW_DOWNLOAD_PROGRESS_MASK = FLAG_INSTALL_SESSION_ACTIVE + | FLAG_INCREMENTAL_DOWNLOAD_ACTIVE; + /** * 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. */ public int runtimeStatusFlags = 0; + /** + * The download progress of the package that this shortcut represents. For legacy apps, this + * will always be the installation progress. For apps that support incremental downloads, this + * will only match be the installation progress until the app is installed, then this will the + * total download progress. + */ + private int mProgressLevel = 100; + protected ItemInfoWithIcon() { } protected ItemInfoWithIcon(ItemInfoWithIcon info) { @@ -113,6 +144,72 @@ public abstract class ItemInfoWithIcon extends ItemInfo { return bitmap.isLowRes(); } + /** + * Returns whether the app this shortcut represents is able to be started. For legacy apps, + * this returns whether it is fully installed. For apps that support incremental downloads, + * this returns whether the app is either fully downloaded or has installed and is downloading + * incrementally. + */ + public boolean isAppStartable() { + return ((runtimeStatusFlags & FLAG_INSTALL_SESSION_ACTIVE) == 0) + && (((runtimeStatusFlags & FLAG_INCREMENTAL_DOWNLOAD_ACTIVE) != 0) + || mProgressLevel == 100); + } + + /** + * Returns the download progress for the app this shortcut represents. If this app is not yet + * installed or does not support incremental downloads, this will return the installation + * progress. + */ + public int getProgressLevel() { + if ((runtimeStatusFlags & FLAG_SHOW_DOWNLOAD_PROGRESS_MASK) != 0) { + return mProgressLevel; + } + return 100; + } + + /** + * Sets the download progress for the app this shortcut represents. If this app is not yet + * installed or does not support incremental downloads, this will set + * {@code FLAG_INSTALL_SESSION_ACTIVE}. If this app is downloading incrementally, this will + * set {@code FLAG_INCREMENTAL_DOWNLOAD_ACTIVE}. Otherwise, this will remove both flags. + */ + public void setProgressLevel(PackageInstallInfo installInfo) { + setProgressLevel(installInfo.progress, installInfo.state); + } + + /** + * Sets the download progress for the app this shortcut represents. + */ + public void setProgressLevel(int progress, int status) { + if (status == PackageInstallInfo.STATUS_INSTALLING) { + mProgressLevel = progress; + runtimeStatusFlags = progress < 100 + ? runtimeStatusFlags | FLAG_INSTALL_SESSION_ACTIVE + : runtimeStatusFlags & ~FLAG_INSTALL_SESSION_ACTIVE; + } else if (status == PackageInstallInfo.STATUS_INSTALLED_DOWNLOADING) { + mProgressLevel = progress; + runtimeStatusFlags = runtimeStatusFlags & ~FLAG_INSTALL_SESSION_ACTIVE; + runtimeStatusFlags = progress < 100 + ? runtimeStatusFlags | FLAG_INCREMENTAL_DOWNLOAD_ACTIVE + : runtimeStatusFlags & ~FLAG_INCREMENTAL_DOWNLOAD_ACTIVE; + } else { + mProgressLevel = status == PackageInstallInfo.STATUS_INSTALLED ? 100 : 0; + runtimeStatusFlags = runtimeStatusFlags & ~FLAG_INSTALL_SESSION_ACTIVE; + runtimeStatusFlags = runtimeStatusFlags & ~FLAG_INCREMENTAL_DOWNLOAD_ACTIVE; + } + } + + /** Creates an intent to that launches the app store at this app's page. */ + @Nullable + public Intent getMarketIntent(Context context) { + ComponentName componentName = getTargetComponent(); + + return componentName != null + ? new PackageManagerHelper(context).getMarketIntent(componentName.getPackageName()) + : null; + } + /** * @return a copy of this */ diff --git a/src/com/android/launcher3/model/data/PromiseAppInfo.java b/src/com/android/launcher3/model/data/PromiseAppInfo.java deleted file mode 100644 index b6231ede19..0000000000 --- a/src/com/android/launcher3/model/data/PromiseAppInfo.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.launcher3.model.data; - -import android.content.Context; -import android.content.Intent; - -import androidx.annotation.NonNull; - -import com.android.launcher3.pm.PackageInstallInfo; -import com.android.launcher3.util.PackageManagerHelper; - -public class PromiseAppInfo extends AppInfo { - - public int level = 0; - - public PromiseAppInfo(@NonNull PackageInstallInfo installInfo) { - componentName = installInfo.componentName; - intent = new Intent(Intent.ACTION_MAIN) - .addCategory(Intent.CATEGORY_LAUNCHER) - .setComponent(componentName) - .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK - | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED); - } - - @Override - public WorkspaceItemInfo makeWorkspaceItem() { - WorkspaceItemInfo shortcut = new WorkspaceItemInfo(this); - shortcut.setInstallProgress(level); - // We need to update the component name when the apk is installed - shortcut.status |= WorkspaceItemInfo.FLAG_AUTOINSTALL_ICON; - // Since the user is manually placing it on homescreen, it should not be auto-removed later - shortcut.status |= WorkspaceItemInfo.FLAG_RESTORE_STARTED; - return shortcut; - } - - public Intent getMarketIntent(Context context) { - return new PackageManagerHelper(context).getMarketIntent(componentName.getPackageName()); - } -} diff --git a/src/com/android/launcher3/model/data/WorkspaceItemInfo.java b/src/com/android/launcher3/model/data/WorkspaceItemInfo.java index 1e1d093b13..690e904a02 100644 --- a/src/com/android/launcher3/model/data/WorkspaceItemInfo.java +++ b/src/com/android/launcher3/model/data/WorkspaceItemInfo.java @@ -57,21 +57,15 @@ public class WorkspaceItemInfo extends ItemInfoWithIcon { */ public static final int FLAG_AUTOINSTALL_ICON = 1 << 1; - /** - * The icon is being installed. If {@link #FLAG_RESTORED_ICON} or {@link #FLAG_AUTOINSTALL_ICON} - * is set, then the icon is either being installed or is in a broken state. - */ - public static final int FLAG_INSTALL_SESSION_ACTIVE = 1 << 2; - /** * Indicates that the widget restore has started. */ - public static final int FLAG_RESTORE_STARTED = 1 << 3; + public static final int FLAG_RESTORE_STARTED = 1 << 2; /** * Web UI supported. */ - public static final int FLAG_SUPPORTS_WEB_UI = 1 << 4; + public static final int FLAG_SUPPORTS_WEB_UI = 1 << 3; /** * The intent used to start the application. @@ -98,11 +92,6 @@ public class WorkspaceItemInfo extends ItemInfoWithIcon { */ @NonNull private String[] personKeys = Utilities.EMPTY_STRING_ARRAY; - /** - * The installation progress [0-100] of the package that this shortcut represents. - */ - private int mInstallProgress; - public WorkspaceItemInfo() { itemType = LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT; @@ -114,7 +103,6 @@ public class WorkspaceItemInfo extends ItemInfoWithIcon { intent = new Intent(info.intent); iconResource = info.iconResource; status = info.status; - mInstallProgress = info.mInstallProgress; personKeys = info.personKeys.clone(); } @@ -168,15 +156,6 @@ public class WorkspaceItemInfo extends ItemInfoWithIcon { return isPromise() && !hasStatusFlag(FLAG_SUPPORTS_WEB_UI); } - public int getInstallProgress() { - return mInstallProgress; - } - - public void setInstallProgress(int progress) { - mInstallProgress = progress; - status |= FLAG_INSTALL_SESSION_ACTIVE; - } - public void updateFromDeepShortcutInfo(ShortcutInfo shortcutInfo, Context context) { // {@link ShortcutInfo#getActivity} can change during an update. Recreate the intent intent = ShortcutKey.makeIntent(shortcutInfo); diff --git a/src/com/android/launcher3/pm/PackageInstallInfo.java b/src/com/android/launcher3/pm/PackageInstallInfo.java index 7997d16756..fad904f968 100644 --- a/src/com/android/launcher3/pm/PackageInstallInfo.java +++ b/src/com/android/launcher3/pm/PackageInstallInfo.java @@ -25,7 +25,8 @@ public final class PackageInstallInfo { public static final int STATUS_INSTALLED = 0; public static final int STATUS_INSTALLING = 1; - public static final int STATUS_FAILED = 2; + public static final int STATUS_INSTALLED_DOWNLOADING = 2; + public static final int STATUS_FAILED = 3; public final ComponentName componentName; public final String packageName; @@ -56,5 +57,4 @@ public final class PackageInstallInfo { public static PackageInstallInfo fromState(int state, String packageName, UserHandle user) { return new PackageInstallInfo(packageName, state, 0 /* progress */, user); } - } diff --git a/src/com/android/launcher3/secondarydisplay/SecondaryDisplayLauncher.java b/src/com/android/launcher3/secondarydisplay/SecondaryDisplayLauncher.java index b496608ac5..026634529f 100644 --- a/src/com/android/launcher3/secondarydisplay/SecondaryDisplayLauncher.java +++ b/src/com/android/launcher3/secondarydisplay/SecondaryDisplayLauncher.java @@ -35,8 +35,8 @@ import com.android.launcher3.allapps.AllAppsContainerView; import com.android.launcher3.model.BgDataModel; import com.android.launcher3.model.data.AppInfo; import com.android.launcher3.model.data.ItemInfo; +import com.android.launcher3.model.data.ItemInfoWithIcon; import com.android.launcher3.model.data.LauncherAppWidgetInfo; -import com.android.launcher3.model.data.PromiseAppInfo; import com.android.launcher3.model.data.WorkspaceItemInfo; import com.android.launcher3.popup.PopupContainerWithArrow; import com.android.launcher3.popup.PopupDataProvider; @@ -215,8 +215,8 @@ public class SecondaryDisplayLauncher extends BaseDraggingActivity ArrayList addAnimated) { } @Override - public void bindPromiseAppProgressUpdated(PromiseAppInfo app) { - mAppsView.getAppsStore().updatePromiseAppProgress(app); + public void bindIncrementalDownloadProgressUpdated(AppInfo app) { + mAppsView.getAppsStore().updateProgressBar(app); } @Override @@ -315,9 +315,11 @@ public class SecondaryDisplayLauncher extends BaseDraggingActivity if (tag instanceof ItemInfo) { ItemInfo item = (ItemInfo) tag; Intent intent; - if (item instanceof PromiseAppInfo) { - PromiseAppInfo promiseAppInfo = (PromiseAppInfo) item; - intent = promiseAppInfo.getMarketIntent(this); + if (item instanceof ItemInfoWithIcon + && (((ItemInfoWithIcon) item).runtimeStatusFlags + & ItemInfoWithIcon.FLAG_INSTALL_SESSION_ACTIVE) != 0) { + ItemInfoWithIcon appInfo = (ItemInfoWithIcon) item; + intent = appInfo.getMarketIntent(this); } else { intent = item.getIntent(); } diff --git a/src/com/android/launcher3/touch/ItemClickHandler.java b/src/com/android/launcher3/touch/ItemClickHandler.java index 9b9cb0a61b..41587357f5 100644 --- a/src/com/android/launcher3/touch/ItemClickHandler.java +++ b/src/com/android/launcher3/touch/ItemClickHandler.java @@ -49,8 +49,8 @@ import com.android.launcher3.logging.StatsLogManager; import com.android.launcher3.model.data.AppInfo; import com.android.launcher3.model.data.FolderInfo; import com.android.launcher3.model.data.ItemInfo; +import com.android.launcher3.model.data.ItemInfoWithIcon; import com.android.launcher3.model.data.LauncherAppWidgetInfo; -import com.android.launcher3.model.data.PromiseAppInfo; import com.android.launcher3.model.data.RemoteActionItemInfo; import com.android.launcher3.model.data.WorkspaceItemInfo; import com.android.launcher3.pm.InstallSessionHelper; @@ -231,8 +231,12 @@ public class ItemClickHandler { ? shortcut.getIntent().getComponent().getPackageName() : shortcut.getIntent().getPackage(); if (!TextUtils.isEmpty(packageName)) { - onClickPendingAppItem(v, launcher, packageName, - shortcut.hasStatusFlag(WorkspaceItemInfo.FLAG_INSTALL_SESSION_ACTIVE)); + onClickPendingAppItem( + v, + launcher, + packageName, + (shortcut.runtimeStatusFlags + & ItemInfoWithIcon.FLAG_INSTALL_SESSION_ACTIVE) != 0); return; } } @@ -266,9 +270,12 @@ public class ItemClickHandler { TestLogging.recordEvent( TestProtocol.SEQUENCE_MAIN, "start: startAppShortcutOrInfoActivity"); Intent intent; - if (item instanceof PromiseAppInfo) { - PromiseAppInfo promiseAppInfo = (PromiseAppInfo) item; - intent = promiseAppInfo.getMarketIntent(launcher); + if (item instanceof ItemInfoWithIcon + && (((ItemInfoWithIcon) item).runtimeStatusFlags + & ItemInfoWithIcon.FLAG_INSTALL_SESSION_ACTIVE) != 0) { + ItemInfoWithIcon appInfo = (ItemInfoWithIcon) item; + intent = new PackageManagerHelper(launcher) + .getMarketIntent(appInfo.getTargetComponent().getPackageName()); } else { intent = item.getIntent(); } diff --git a/src/com/android/launcher3/util/PackageManagerHelper.java b/src/com/android/launcher3/util/PackageManagerHelper.java index 523545af43..7b264275d4 100644 --- a/src/com/android/launcher3/util/PackageManagerHelper.java +++ b/src/com/android/launcher3/util/PackageManagerHelper.java @@ -45,10 +45,11 @@ import android.widget.Toast; import com.android.launcher3.PendingAddItemInfo; import com.android.launcher3.R; +import com.android.launcher3.Utilities; import com.android.launcher3.model.data.AppInfo; import com.android.launcher3.model.data.ItemInfo; +import com.android.launcher3.model.data.ItemInfoWithIcon; import com.android.launcher3.model.data.LauncherAppWidgetInfo; -import com.android.launcher3.model.data.PromiseAppInfo; import com.android.launcher3.model.data.WorkspaceItemInfo; import java.net.URISyntaxException; @@ -200,9 +201,12 @@ public class PackageManagerHelper { * Starts the details activity for {@code info} */ public void startDetailsActivityForInfo(ItemInfo info, Rect sourceBounds, Bundle opts) { - if (info instanceof PromiseAppInfo) { - PromiseAppInfo promiseAppInfo = (PromiseAppInfo) info; - mContext.startActivity(promiseAppInfo.getMarketIntent(mContext)); + if (info instanceof ItemInfoWithIcon + && (((ItemInfoWithIcon) info).runtimeStatusFlags + & ItemInfoWithIcon.FLAG_INSTALL_SESSION_ACTIVE) != 0) { + ItemInfoWithIcon appInfo = (ItemInfoWithIcon) info; + mContext.startActivity(new PackageManagerHelper(mContext) + .getMarketIntent(appInfo.getTargetComponent().getPackageName())); return; } ComponentName componentName = null; @@ -319,4 +323,12 @@ public class PackageManagerHelper { } return false; } + + /** Returns the incremental download progress for the given shortcut's app. */ + public static int getLoadingProgress(LauncherActivityInfo info) { + if (Utilities.ATLEAST_S) { + return (int) (100 * info.getLoadingProgress()); + } + return 100; + } }