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; + } }