diff options
author | Sunny Goyal <sunnygoyal@google.com> | 2014-09-05 07:42:31 +0000 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2014-09-05 07:42:32 +0000 |
commit | 1c13ff569170bec075ab9961fbc0eb1ca395696b (patch) | |
tree | 8291513e3e8c9a072e23cce1f4dd9f0c95fb86ae | |
parent | 66205ce9ceb46a821c9a2d93745226d67f1b119a (diff) | |
parent | 349426234e8c5a0e5bcf2c8d94dbb9844b5f724a (diff) | |
download | android_packages_apps_Trebuchet-1c13ff569170bec075ab9961fbc0eb1ca395696b.tar.gz android_packages_apps_Trebuchet-1c13ff569170bec075ab9961fbc0eb1ca395696b.tar.bz2 android_packages_apps_Trebuchet-1c13ff569170bec075ab9961fbc0eb1ca395696b.zip |
Merge "Handling label and icon from SessionInfo." into ub-now-porkchop
-rw-r--r-- | src/com/android/launcher3/AutoInstallsLayout.java | 2 | ||||
-rw-r--r-- | src/com/android/launcher3/BubbleTextView.java | 49 | ||||
-rw-r--r-- | src/com/android/launcher3/IconCache.java | 52 | ||||
-rw-r--r-- | src/com/android/launcher3/ItemInfo.java | 4 | ||||
-rw-r--r-- | src/com/android/launcher3/Launcher.java | 6 | ||||
-rw-r--r-- | src/com/android/launcher3/LauncherAppState.java | 2 | ||||
-rw-r--r-- | src/com/android/launcher3/LauncherModel.java | 131 | ||||
-rw-r--r-- | src/com/android/launcher3/PreloadIconDrawable.java | 6 | ||||
-rw-r--r-- | src/com/android/launcher3/ShortcutInfo.java | 98 | ||||
-rw-r--r-- | src/com/android/launcher3/Workspace.java | 129 | ||||
-rw-r--r-- | src/com/android/launcher3/compat/PackageInstallerCompat.java | 6 | ||||
-rw-r--r-- | src/com/android/launcher3/compat/PackageInstallerCompatV16.java | 8 | ||||
-rw-r--r-- | src/com/android/launcher3/compat/PackageInstallerCompatVL.java | 30 |
13 files changed, 317 insertions, 206 deletions
diff --git a/src/com/android/launcher3/AutoInstallsLayout.java b/src/com/android/launcher3/AutoInstallsLayout.java index 4ea7b3d78..931501c6a 100644 --- a/src/com/android/launcher3/AutoInstallsLayout.java +++ b/src/com/android/launcher3/AutoInstallsLayout.java @@ -298,7 +298,7 @@ public class AutoInstallsLayout implements WorkspaceLoader { return -1; } - mValues.put(Favorites.RESTORED, 1); + mValues.put(Favorites.RESTORED, ShortcutInfo.FLAG_AUTOINTALL_ICON); final Intent intent = new Intent(Intent.ACTION_MAIN, null) .addCategory(Intent.CATEGORY_LAUNCHER) .setComponent(new ComponentName(packageName, className)) diff --git a/src/com/android/launcher3/BubbleTextView.java b/src/com/android/launcher3/BubbleTextView.java index d83f81dab..a368796bd 100644 --- a/src/com/android/launcher3/BubbleTextView.java +++ b/src/com/android/launcher3/BubbleTextView.java @@ -26,7 +26,6 @@ import android.graphics.Canvas; import android.graphics.Region; import android.graphics.drawable.Drawable; import android.util.AttributeSet; -import android.util.Log; import android.util.SparseArray; import android.util.TypedValue; import android.view.KeyEvent; @@ -50,10 +49,6 @@ public class BubbleTextView extends TextView { private static final int SHADOW_SMALL_COLOUR = 0xCC000000; static final float PADDING_V = 3.0f; - private static final String TAG = "BubbleTextView"; - - private static final boolean DEBUG = false; - private HolographicOutlineHelper mOutlineHelper; private Bitmap mPressedBackground; @@ -118,6 +113,11 @@ public class BubbleTextView extends TextView { public void applyFromShortcutInfo(ShortcutInfo info, IconCache iconCache, boolean setDefaultPadding) { + applyFromShortcutInfo(info, iconCache, setDefaultPadding, false); + } + + public void applyFromShortcutInfo(ShortcutInfo info, IconCache iconCache, + boolean setDefaultPadding, boolean promiseStateChanged) { Bitmap b = info.getIcon(iconCache); LauncherAppState app = LauncherAppState.getInstance(); @@ -135,8 +135,8 @@ public class BubbleTextView extends TextView { setText(info.title); setTag(info); - if (info.wasPromise) { - applyState(); + if (promiseStateChanged || info.isPromise()) { + applyState(promiseStateChanged); } } @@ -377,31 +377,13 @@ public class BubbleTextView extends TextView { mLongPressHelper.cancelLongPress(); } - public void applyState() { + public void applyState(boolean promiseStateChanged) { if (getTag() instanceof ShortcutInfo) { ShortcutInfo info = (ShortcutInfo) getTag(); - final int state = info.getState(); - - final int progressLevel; - if (DEBUG) Log.d(TAG, "applying icon state: " + state); - - switch(state) { - case ShortcutInfo.PACKAGE_STATE_DEFAULT: - progressLevel = 100; - break; - - case ShortcutInfo.PACKAGE_STATE_INSTALLING: - setText(R.string.package_state_installing); - progressLevel = info.getProgress(); - break; - - case ShortcutInfo.PACKAGE_STATE_ERROR: - case ShortcutInfo.PACKAGE_STATE_UNKNOWN: - default: - progressLevel = 0; - setText(R.string.package_state_unknown); - break; - } + final boolean isPromise = info.isPromise(); + final int progressLevel = isPromise ? + ((info.hasStatusFlag(ShortcutInfo.FLAG_INSTALL_SESSION_ACTIVE) ? + info.getInstallProgress() : 0)) : 100; Drawable[] drawables = getCompoundDrawables(); Drawable top = drawables[1]; @@ -415,12 +397,9 @@ public class BubbleTextView extends TextView { } preloadDrawable.setLevel(progressLevel); - if ((state == ShortcutInfo.PACKAGE_STATE_DEFAULT) && info.wasPromise) { - // Clear the promise flag as it is no longer different than a normal shortcut, - // once the animation has been run. - info.wasPromise = !preloadDrawable.maybePerformFinishedAnimation(); + if (promiseStateChanged) { + preloadDrawable.maybePerformFinishedAnimation(); } - } } } diff --git a/src/com/android/launcher3/IconCache.java b/src/com/android/launcher3/IconCache.java index 76a85caae..75be83638 100644 --- a/src/com/android/launcher3/IconCache.java +++ b/src/com/android/launcher3/IconCache.java @@ -30,6 +30,7 @@ import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.drawable.Drawable; +import android.text.TextUtils; import android.util.Log; import com.android.launcher3.compat.LauncherActivityInfoCompat; @@ -254,18 +255,16 @@ public class IconCache { return getIcon(intent, null, user, true); } - public Bitmap getIcon(Intent intent, String title, UserHandleCompat user, boolean usePkgIcon) { + private Bitmap getIcon(Intent intent, String title, UserHandleCompat user, boolean usePkgIcon) { synchronized (mCache) { - LauncherActivityInfoCompat launcherActInfo = - mLauncherApps.resolveActivity(intent, user); ComponentName component = intent.getComponent(); - // null info means not installed, but if we have a component from the intent then // we should still look in the cache for restored app icons. if (component == null) { return getDefaultIcon(user); } + LauncherActivityInfoCompat launcherActInfo = mLauncherApps.resolveActivity(intent, user); CacheEntry entry = cacheLocked(component, launcherActInfo, null, user, usePkgIcon); if (title != null) { entry.title = title; @@ -275,6 +274,32 @@ public class IconCache { } } + /** + * Fill in "shortcutInfo" with the icon and label for "info." + */ + public void getTitleAndIcon(ShortcutInfo shortcutInfo, Intent intent, UserHandleCompat user, + boolean usePkgIcon) { + synchronized (mCache) { + ComponentName component = intent.getComponent(); + // null info means not installed, but if we have a component from the intent then + // we should still look in the cache for restored app icons. + if (component == null) { + shortcutInfo.setIcon(getDefaultIcon(user)); + shortcutInfo.title = ""; + shortcutInfo.usingFallbackIcon = true; + } else { + LauncherActivityInfoCompat launcherActInfo = + mLauncherApps.resolveActivity(intent, user); + CacheEntry entry = cacheLocked(component, launcherActInfo, null, user, usePkgIcon); + + shortcutInfo.setIcon(entry.icon); + shortcutInfo.title = entry.title; + shortcutInfo.usingFallbackIcon = isDefaultIcon(entry.icon, user); + } + } + } + + public Bitmap getDefaultIcon(UserHandleCompat user) { if (!mDefaultIcons.containsKey(user)) { mDefaultIcons.put(user, makeDefaultIcon(user)); @@ -332,10 +357,11 @@ public class IconCache { if (usePackageIcon) { CacheEntry packageEntry = getEntryForPackage( componentName.getPackageName(), user); - if (packageEntry != null && packageEntry.icon != null) { + if (packageEntry != null) { if (DEBUG) Log.d(TAG, "using package default icon for " + componentName.toShortString()); entry.icon = packageEntry.icon; + entry.title = packageEntry.title; } } if (entry.icon == null) { @@ -350,6 +376,21 @@ public class IconCache { } /** + * Adds a default package entry in the cache. This entry is not persisted and will be removed + * when the cache is flushed. + */ + public void cachePackageInstallInfo(String packageName, UserHandleCompat user, + Bitmap icon, CharSequence title) { + CacheEntry entry = getEntryForPackage(packageName, user); + if (!TextUtils.isEmpty(title)) { + entry.title = title; + } + if (icon != null) { + entry.icon = Utilities.createIconBitmap(icon, mContext); + } + } + + /** * Gets an entry for the package, which can be used as a fallback entry for various components. */ private CacheEntry getEntryForPackage(String packageName, UserHandleCompat user) { @@ -358,6 +399,7 @@ public class IconCache { CacheEntry entry = mCache.get(cacheKey); if (entry == null) { entry = new CacheEntry(); + entry.title = ""; mCache.put(cacheKey, entry); try { diff --git a/src/com/android/launcher3/ItemInfo.java b/src/com/android/launcher3/ItemInfo.java index 8f96f74eb..09b77f756 100644 --- a/src/com/android/launcher3/ItemInfo.java +++ b/src/com/android/launcher3/ItemInfo.java @@ -146,10 +146,6 @@ public class ItemInfo { throw new RuntimeException("Unexpected Intent"); } - protected Intent getRestoredIntent() { - throw new RuntimeException("Unexpected Intent"); - } - /** * Write the fields of this item to the DB * diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java index ffce116b9..309ab46c9 100644 --- a/src/com/android/launcher3/Launcher.java +++ b/src/com/android/launcher3/Launcher.java @@ -2600,9 +2600,11 @@ public class Launcher extends Activity } // Check for abandoned promise - if (shortcut.isAbandoned() && v instanceof BubbleTextView) { + if ((v instanceof BubbleTextView) + && shortcut.isPromise() + && !shortcut.hasStatusFlag(ShortcutInfo.FLAG_INSTALL_SESSION_ACTIVE)) { showBrokenAppInstallDialog( - shortcut.getRestoredIntent().getComponent().getPackageName(), + shortcut.getTargetComponent().getPackageName(), new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { startAppShortcutOrInfoActivity(v); diff --git a/src/com/android/launcher3/LauncherAppState.java b/src/com/android/launcher3/LauncherAppState.java index 4ab4e4bea..2657b6e65 100644 --- a/src/com/android/launcher3/LauncherAppState.java +++ b/src/com/android/launcher3/LauncherAppState.java @@ -161,7 +161,7 @@ public class LauncherAppState implements DeviceProfile.DeviceProfileCallbacks { return mModel; } - IconCache getIconCache() { + public IconCache getIconCache() { return mIconCache; } diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java index 5e8e2ad0e..b44433d8d 100644 --- a/src/com/android/launcher3/LauncherModel.java +++ b/src/com/android/launcher3/LauncherModel.java @@ -54,12 +54,14 @@ import android.util.Pair; import com.android.launcher3.compat.AppWidgetManagerCompat; import com.android.launcher3.compat.LauncherActivityInfoCompat; import com.android.launcher3.compat.LauncherAppsCompat; +import com.android.launcher3.compat.PackageInstallerCompat; import com.android.launcher3.compat.PackageInstallerCompat.PackageInstallInfo; import com.android.launcher3.compat.UserHandleCompat; import com.android.launcher3.compat.UserManagerCompat; import java.lang.ref.WeakReference; import java.net.URISyntaxException; +import java.security.InvalidParameterException; import java.text.Collator; import java.util.ArrayList; import java.util.Arrays; @@ -359,7 +361,7 @@ public class LauncherModel extends BroadcastReceiver Iterator<AppInfo> iter = allAppsApps.iterator(); while (iter.hasNext()) { ItemInfo a = iter.next(); - if (LauncherModel.appWasRestored(ctx, a.getIntent(), a.user)) { + if (LauncherModel.appWasPromise(ctx, a.getIntent(), a.user)) { restoredAppsFinal.add((AppInfo) a); } } @@ -428,7 +430,7 @@ public class LauncherModel extends BroadcastReceiver if (LauncherModel.shortcutExists(context, name, launchIntent)) { // Only InstallShortcutReceiver sends us shortcutInfos, ignore them if (a instanceof AppInfo && - LauncherModel.appWasRestored(context, launchIntent, a.user)) { + LauncherModel.appWasPromise(context, launchIntent, a.user)) { restoredAppsFinal.add((AppInfo) a); } continue; @@ -884,33 +886,14 @@ public class LauncherModel extends BroadcastReceiver } /** - * Returns true if the shortcuts already exists in the database. - * we identify a shortcut by the component name of the intent - * and the user. + * Returns true if the promise shortcuts with the same package name exists on the workspace. */ - static boolean appWasRestored(Context context, Intent intent, UserHandleCompat user) { - final ContentResolver cr = context.getContentResolver(); + static boolean appWasPromise(Context context, Intent intent, UserHandleCompat user) { final ComponentName component = intent.getComponent(); if (component == null) { return false; } - String componentName = component.flattenToString(); - String shortName = component.flattenToShortString(); - long serialNumber = UserManagerCompat.getInstance(context) - .getSerialNumberForUser(user); - final String where = "(intent glob \"*component=" + componentName + "*\" or " + - "intent glob \"*component=" + shortName + "*\")" + - "and restored = 1 and profileId = " + serialNumber; - Cursor c = cr.query(LauncherSettings.Favorites.CONTENT_URI, - new String[]{"intent", "restored", "profileId"}, where, null, null); - boolean result = false; - try { - result = c.moveToFirst(); - } finally { - c.close(); - } - Log.d(TAG, "shortcutWasRestored is " + result + " for " + componentName); - return result; + return !getItemsByPackageName(component.getPackageName(), user).isEmpty(); } /** @@ -1077,19 +1060,23 @@ public class LauncherModel extends BroadcastReceiver | ((int) screen & 0xFF) << 16 | (localCellX & 0xFF) << 8 | (localCellY & 0xFF); } - /** - * Removes all the items from the database corresponding to the specified package. - */ - static void deletePackageFromDatabase(Context context, final String pn, - final UserHandleCompat user) { + private static ArrayList<ItemInfo> getItemsByPackageName( + final String pn, final UserHandleCompat user) { ItemInfoFilter filter = new ItemInfoFilter() { @Override public boolean filterItem(ItemInfo parent, ItemInfo info, ComponentName cn) { return cn.getPackageName().equals(pn) && info.user.equals(user); } }; - ArrayList<ItemInfo> infos = filterItemInfos(sBgItemsIdMap.values(), filter); - deleteItemsFromDatabase(context, infos); + return filterItemInfos(sBgItemsIdMap.values(), filter); + } + + /** + * Removes all the items from the database corresponding to the specified package. + */ + static void deletePackageFromDatabase(Context context, final String pn, + final UserHandleCompat user) { + deleteItemsFromDatabase(context, getItemsByPackageName(pn, user)); } /** @@ -1898,6 +1885,7 @@ public class LauncherModel extends BroadcastReceiver synchronized (sBgLock) { clearSBgDataStructures(); + PackageInstallerCompat.getInstance(mContext).updateActiveSessionCache(); final ArrayList<Long> itemsToRemove = new ArrayList<Long>(); final ArrayList<Long> restoredRows = new ArrayList<Long>(); @@ -1971,6 +1959,7 @@ public class LauncherModel extends BroadcastReceiver intentDescription = c.getString(intentIndex); long serialNumber = c.getInt(profileIdIndex); user = mUserManager.getUserForSerialNumber(serialNumber); + int promiseType = c.getInt(restoredIndex); if (user == null) { // User has been deleted remove the item. itemsToRemove.add(id); @@ -1992,12 +1981,34 @@ public class LauncherModel extends BroadcastReceiver restored = false; } } else if (validPkg) { - // The app is installed but the component is no - // longer available. - Launcher.addDumpLog(TAG, - "Invalid component removed: " + cn, true); - itemsToRemove.add(id); - continue; + intent = null; + if ((promiseType & ShortcutInfo.FLAG_AUTOINTALL_ICON) != 0) { + // We allow auto install apps to have their intent + // updated after an install. + intent = manager.getLaunchIntentForPackage( + cn.getPackageName()); + if (intent != null) { + ContentValues values = new ContentValues(); + values.put(LauncherSettings.Favorites.INTENT, + intent.toUri(0)); + String where = BaseColumns._ID + "= ?"; + String[] args = {Long.toString(id)}; + contentResolver.update(contentUri, values, where, args); + } + } + + if (intent == null) { + // The app is installed but the component is no + // longer available. + Launcher.addDumpLog(TAG, + "Invalid component removed: " + cn, true); + itemsToRemove.add(id); + continue; + } else { + // no special handling necessary for this item + restoredRows.add(id); + restored = false; + } } else if (restored) { // Package is not yet available but might be // installed later. @@ -2036,7 +2047,7 @@ public class LauncherModel extends BroadcastReceiver Launcher.addDumpLog(TAG, "constructing info for partially restored package", true); - info = getRestoredItemInfo(c, titleIndex, intent); + info = getRestoredItemInfo(c, titleIndex, intent, promiseType); intent = getRestoredItemIntent(c, context, intent); } else { // Don't restore items for other profiles. @@ -2299,7 +2310,7 @@ public class LauncherModel extends BroadcastReceiver selectionBuilder.append(")"); ContentValues values = new ContentValues(); values.put(LauncherSettings.Favorites.RESTORED, 0); - updater.update(LauncherSettings.Favorites.CONTENT_URI, + updater.update(LauncherSettings.Favorites.CONTENT_URI_NO_NOTIFICATION, values, selectionBuilder.toString(), null); } catch (RemoteException e) { Log.w(TAG, "Could not update restored rows"); @@ -2879,7 +2890,7 @@ public class LauncherModel extends BroadcastReceiver packagesRemoved.toArray(new String[packagesRemoved.size()]), user)); } } - sPendingPackages.clear(); + sPendingPackages.clear(); } } } @@ -3101,21 +3112,31 @@ public class LauncherModel extends BroadcastReceiver * Make an ShortcutInfo object for a restored application or shortcut item that points * to a package that is not yet installed on the system. */ - public ShortcutInfo getRestoredItemInfo(Cursor cursor, int titleIndex, Intent intent) { + public ShortcutInfo getRestoredItemInfo(Cursor cursor, int titleIndex, Intent intent, + int promiseType) { final ShortcutInfo info = new ShortcutInfo(); - if (cursor != null) { - info.title = cursor.getString(titleIndex); + info.user = UserHandleCompat.myUserHandle(); + mIconCache.getTitleAndIcon(info, intent, info.user, true); + + if ((promiseType & ShortcutInfo.FLAG_RESTORED_ICON) != 0) { + String title = (cursor != null) ? cursor.getString(titleIndex) : null; + if (!TextUtils.isEmpty(title)) { + info.title = title; + } + info.status = ShortcutInfo.FLAG_RESTORED_ICON; + } else if ((promiseType & ShortcutInfo.FLAG_AUTOINTALL_ICON) != 0) { + if (TextUtils.isEmpty(info.title)) { + info.title = (cursor != null) ? cursor.getString(titleIndex) : ""; + } + info.status = ShortcutInfo.FLAG_AUTOINTALL_ICON; } else { - info.title = ""; + throw new InvalidParameterException("Invalid restoreType " + promiseType); } - info.user = UserHandleCompat.myUserHandle(); + info.contentDescription = mUserManager.getBadgedLabelForUser( info.title.toString(), info.user); - info.setIcon(mIconCache.getIcon(intent, info.title.toString(), info.user, false)); info.itemType = LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT; - info.restoredIntent = intent; - info.wasPromise = true; - info.setState(ShortcutInfo.PACKAGE_STATE_UNKNOWN); + info.promisedIntent = intent; return info; } @@ -3230,20 +3251,14 @@ public class LauncherModel extends BroadcastReceiver for (ItemInfo i : infos) { if (i instanceof ShortcutInfo) { ShortcutInfo info = (ShortcutInfo) i; - ComponentName cn = info.intent.getComponent(); - if (info.restoredIntent != null) { - cn = info.restoredIntent.getComponent(); - } + ComponentName cn = info.getTargetComponent(); if (cn != null && f.filterItem(null, info, cn)) { filtered.add(info); } } else if (i instanceof FolderInfo) { FolderInfo info = (FolderInfo) i; for (ShortcutInfo s : info.contents) { - ComponentName cn = s.intent.getComponent(); - if (s.restoredIntent != null) { - cn = s.restoredIntent.getComponent(); - } + ComponentName cn = s.getTargetComponent(); if (cn != null && f.filterItem(info, s, cn)) { filtered.add(s); } @@ -3287,7 +3302,7 @@ public class LauncherModel extends BroadcastReceiver return true; } // placeholder shortcuts get special treatment, let them through too. - if (info.getRestoredIntent() != null) { + if (info.isPromise()) { return true; } } diff --git a/src/com/android/launcher3/PreloadIconDrawable.java b/src/com/android/launcher3/PreloadIconDrawable.java index 1b2d5a4e3..2972c4f9b 100644 --- a/src/com/android/launcher3/PreloadIconDrawable.java +++ b/src/com/android/launcher3/PreloadIconDrawable.java @@ -189,11 +189,10 @@ class PreloadIconDrawable extends Drawable { /** * Runs the finish animation if it is has not been run after last level change. - * @return true if the animation was run. */ - public boolean maybePerformFinishedAnimation() { + public void maybePerformFinishedAnimation() { if (mAnimationProgress > ANIMATION_PROGRESS_STOPPED) { - return false; + return; } if (mAnimator != null) { mAnimator.cancel(); @@ -202,7 +201,6 @@ class PreloadIconDrawable extends Drawable { mAnimator = ObjectAnimator.ofFloat(this, "animationProgress", ANIMATION_PROGRESS_STARTED, ANIMATION_PROGRESS_COMPLETED); mAnimator.start(); - return true; } public void setAnimationProgress(float progress) { diff --git a/src/com/android/launcher3/ShortcutInfo.java b/src/com/android/launcher3/ShortcutInfo.java index 612b0a5aa..9abfb7f86 100644 --- a/src/com/android/launcher3/ShortcutInfo.java +++ b/src/com/android/launcher3/ShortcutInfo.java @@ -16,6 +16,7 @@ package com.android.launcher3; +import android.content.ComponentName; import android.content.ContentValues; import android.content.Context; import android.content.Intent; @@ -32,17 +33,26 @@ import java.util.Arrays; */ public class ShortcutInfo extends ItemInfo { - /** {@link #mState} meaning this package is not installed, and there is no other information. */ - public static final int PACKAGE_STATE_UNKNOWN = -2; + public static final int DEFAULT = 0; - /** {@link #mState} meaning this package is not installed, because installation failed. */ - public static final int PACKAGE_STATE_ERROR = -1; + /** + * The shortcut was restored from a backup and it not ready to be used. This is automatically + * set during backup/restore + */ + public static final int FLAG_RESTORED_ICON = 1; - /** {@link #mState} meaning this package is installed. This is the typical case. */ - public static final int PACKAGE_STATE_DEFAULT = 0; + /** + * The icon was added as an auto-install app, and is not ready to be used. This flag can't + * be present along with {@link #FLAG_RESTORED_ICON}, and is set during default layout + * parsing. + */ + public static final int FLAG_AUTOINTALL_ICON = 2; - /** {@link #mState} meaning some external entity has promised to install this package. */ - public static final int PACKAGE_STATE_INSTALLING = 1; + /** + * The icon is being installed. If {@link FLAG_RESTORED_ICON} or {@link FLAG_AUTOINTALL_ICON} + * is set, then the icon is either being installed or is in a broken state. + */ + public static final int FLAG_INSTALL_SESSION_ACTIVE = 4; /** * The intent used to start the application. @@ -78,29 +88,29 @@ public class ShortcutInfo extends ItemInfo { */ boolean isDisabled = false; - /** - * The installation state of the package that this shortcut represents. - */ - protected int mState; + int status; /** * The installation progress [0-100] of the package that this shortcut represents. */ - protected int mProgress; + private int mInstallProgress; + /** + * Refer {@link AppInfo#firstInstallTime}. + */ long firstInstallTime; - int flags = 0; /** - * If this shortcut is a placeholder, then intent will be a market intent for the package, and - * this will hold the original intent from the database. Otherwise, null. + * TODO move this to {@link status} */ - Intent restoredIntent; + int flags = 0; /** - * This is set once to indicate that it was a promise info at some point of its life. + * If this shortcut is a placeholder, then intent will be a market intent for the package, and + * this will hold the original intent from the database. Otherwise, null. + * Refer {@link #FLAG_RESTORE_PENDING}, {@link #FLAG_INSTALL_PENDING} */ - boolean wasPromise = false; + Intent promisedIntent; ShortcutInfo() { itemType = LauncherSettings.BaseLauncherColumns.ITEM_TYPE_SHORTCUT; @@ -110,21 +120,6 @@ public class ShortcutInfo extends ItemInfo { return intent; } - protected Intent getRestoredIntent() { - return restoredIntent; - } - - /** - * Overwrite placeholder data with restored data, or do nothing if this is not a placeholder. - */ - public void restore() { - if (restoredIntent != null) { - intent = restoredIntent; - restoredIntent = null; - mState = PACKAGE_STATE_DEFAULT; - } - } - ShortcutInfo(Intent intent, CharSequence title, CharSequence contentDescription, Bitmap icon, UserHandleCompat user) { this(); @@ -149,6 +144,7 @@ public class ShortcutInfo extends ItemInfo { flags = info.flags; firstInstallTime = info.firstInstallTime; user = info.user; + status = info.status; } /** TODO: Remove this. It's only called by ApplicationInfo.makeShortcut. */ @@ -184,7 +180,7 @@ public class ShortcutInfo extends ItemInfo { String titleStr = title != null ? title.toString() : null; values.put(LauncherSettings.BaseLauncherColumns.TITLE, titleStr); - String uri = restoredIntent != null ? restoredIntent.toUri(0) + String uri = promisedIntent != null ? promisedIntent.toUri(0) : (intent != null ? intent.toUri(0) : null); values.put(LauncherSettings.BaseLauncherColumns.INTENT, uri); @@ -224,36 +220,26 @@ public class ShortcutInfo extends ItemInfo { } } - public boolean isPromise() { - return restoredIntent != null; + public ComponentName getTargetComponent() { + return promisedIntent != null ? promisedIntent.getComponent() : intent.getComponent(); } - public boolean isPromiseFor(String pkgName) { - return restoredIntent != null - && pkgName != null - && pkgName.equals(restoredIntent.getComponent().getPackageName()); + public boolean hasStatusFlag(int flag) { + return (status & flag) != 0; } - public boolean isAbandoned() { - return isPromise() - && (mState == PACKAGE_STATE_ERROR - || mState == PACKAGE_STATE_UNKNOWN); - } - - public int getProgress() { - return mProgress; - } - public void setProgress(int progress) { - mProgress = progress; + public final boolean isPromise() { + return hasStatusFlag(FLAG_RESTORED_ICON | FLAG_AUTOINTALL_ICON); } - public void setState(int state) { - mState = state; + public int getInstallProgress() { + return mInstallProgress; } - public int getState() { - return mState; + public void setInstallProgress(int progress) { + mInstallProgress = progress; + status |= FLAG_INSTALL_SESSION_ACTIVE; } } diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java index 2e966de0b..f7a0df681 100644 --- a/src/com/android/launcher3/Workspace.java +++ b/src/com/android/launcher3/Workspace.java @@ -31,7 +31,10 @@ import android.appwidget.AppWidgetHostView; import android.appwidget.AppWidgetProviderInfo; import android.content.ComponentName; import android.content.Context; +import android.content.Intent; import android.content.SharedPreferences; +import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; import android.content.res.Resources; import android.content.res.TypedArray; import android.graphics.Bitmap; @@ -65,6 +68,7 @@ import android.widget.TextView; import com.android.launcher3.FolderIcon.FolderRingAnimator; import com.android.launcher3.Launcher.CustomContentCallbacks; import com.android.launcher3.LauncherSettings.Favorites; +import com.android.launcher3.compat.PackageInstallerCompat; import com.android.launcher3.compat.PackageInstallerCompat.PackageInstallInfo; import com.android.launcher3.compat.UserHandleCompat; @@ -72,6 +76,7 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; +import java.util.Map; import java.util.Set; import java.util.concurrent.atomic.AtomicInteger; @@ -4746,26 +4751,6 @@ public class Workspace extends SmoothPagedView stripEmptyScreens(); } - private void updateShortcut(HashMap<ComponentName, AppInfo> appsMap, ItemInfo info, - View child) { - ComponentName cn = info.getIntent().getComponent(); - if (info.getRestoredIntent() != null) { - cn = info.getRestoredIntent().getComponent(); - } - if (cn != null) { - AppInfo appInfo = appsMap.get(cn); - if ((appInfo != null) && LauncherModel.isShortcutInfoUpdateable(info)) { - ShortcutInfo shortcutInfo = (ShortcutInfo) info; - BubbleTextView shortcut = (BubbleTextView) child; - shortcutInfo.restore(); - shortcutInfo.updateIcon(mIconCache); - shortcutInfo.title = appInfo.title.toString(); - shortcutInfo.contentDescription = appInfo.contentDescription; - shortcut.applyFromShortcutInfo(shortcutInfo, mIconCache, true); - } - } - } - interface ItemOperator { /** * Process the next itemInfo, possibly with side-effect on {@link ItemOperator#value}. @@ -4824,13 +4809,83 @@ public class Workspace extends SmoothPagedView pkgNames.add(ai.componentName.getPackageName()); } + final HashMap<UserHandleCompat, HashSet<ComponentName>> iconsToRemove = + new HashMap<UserHandleCompat, HashSet<ComponentName>>(); mapOverItems(MAP_RECURSE, new ItemOperator() { @Override public boolean evaluate(ItemInfo info, View v, View parent) { - if (info instanceof ShortcutInfo) { - updateShortcut(appsMap, info, v); - if (parent != null) { - parent.invalidate(); + if (info instanceof ShortcutInfo && v instanceof BubbleTextView) { + ShortcutInfo shortcutInfo = (ShortcutInfo) info; + ComponentName cn = shortcutInfo.getTargetComponent(); + AppInfo appInfo = appsMap.get(cn); + if (cn != null && LauncherModel.isShortcutInfoUpdateable(info) + && pkgNames.contains(cn.getPackageName())) { + boolean promiseStateChanged = false; + boolean infoUpdated = false; + if (shortcutInfo.isPromise()) { + if (shortcutInfo.hasStatusFlag(ShortcutInfo.FLAG_AUTOINTALL_ICON)) { + // Auto install icon + PackageManager pm = getContext().getPackageManager(); + ResolveInfo matched = pm.resolveActivity( + new Intent(Intent.ACTION_MAIN) + .setComponent(cn).addCategory(Intent.CATEGORY_LAUNCHER), + PackageManager.MATCH_DEFAULT_ONLY); + if (matched == null) { + // Try to find the best match activity. + Intent intent = pm.getLaunchIntentForPackage( + cn.getPackageName()); + if (intent != null) { + cn = intent.getComponent(); + appInfo = appsMap.get(cn); + } + + if ((intent == null) || (appsMap == null)) { + // Could not find a default activity. Remove this item. + HashSet<ComponentName> cnSet = iconsToRemove + .get(shortcutInfo.user); + if (cnSet == null) { + cnSet = new HashSet<>(); + iconsToRemove.put(shortcutInfo.user, cnSet); + } + cnSet.add(shortcutInfo.getTargetComponent()); + + // process next shortcut. + return false; + } + shortcutInfo.promisedIntent = intent; + } + } + + // Restore the shortcut. + shortcutInfo.intent = shortcutInfo.promisedIntent; + shortcutInfo.promisedIntent = null; + shortcutInfo.status &= ~ShortcutInfo.FLAG_RESTORED_ICON + & ~ShortcutInfo.FLAG_AUTOINTALL_ICON + & ~ShortcutInfo.FLAG_INSTALL_SESSION_ACTIVE; + + promiseStateChanged = true; + infoUpdated = true; + shortcutInfo.updateIcon(mIconCache); + LauncherModel.updateItemInDatabase(getContext(), shortcutInfo); + } + + + if (appInfo != null) { + shortcutInfo.updateIcon(mIconCache); + shortcutInfo.title = appInfo.title.toString(); + shortcutInfo.contentDescription = appInfo.contentDescription; + infoUpdated = true; + } + + if (infoUpdated) { + BubbleTextView shortcut = (BubbleTextView) v; + shortcut.applyFromShortcutInfo(shortcutInfo, + mIconCache, true, promiseStateChanged); + + if (parent != null) { + parent.invalidate(); + } + } } } // process all the shortcuts @@ -4838,6 +4893,12 @@ public class Workspace extends SmoothPagedView } }); + if (!iconsToRemove.isEmpty()) { + for (Map.Entry<UserHandleCompat, HashSet<ComponentName>> entry : + iconsToRemove.entrySet()) { + removeItemsByComponentName(entry.getValue(), entry.getKey()); + } + } restorePendingWidgets(pkgNames); } @@ -4855,12 +4916,18 @@ public class Workspace extends SmoothPagedView mapOverItems(MAP_RECURSE, new ItemOperator() { @Override public boolean evaluate(ItemInfo info, View v, View parent) { - if (info instanceof ShortcutInfo - && ((ShortcutInfo) info).isPromiseFor(installInfo.packageName) - && v instanceof BubbleTextView) { - ((ShortcutInfo) info).setProgress(installInfo.progress); - ((ShortcutInfo) info).setState(installInfo.state); - ((BubbleTextView)v).applyState(); + if (info instanceof ShortcutInfo && v instanceof BubbleTextView) { + ShortcutInfo si = (ShortcutInfo) info; + ComponentName cn = si.getTargetComponent(); + if (si.isPromise() && (cn != null) + && installInfo.packageName.equals(cn.getPackageName())) { + si.setInstallProgress(installInfo.progress); + if (installInfo.state == PackageInstallerCompat.STATUS_FAILED) { + // Mark this info as broken. + si.status &= ~ShortcutInfo.FLAG_INSTALL_SESSION_ACTIVE; + } + ((BubbleTextView)v).applyState(false); + } } else if (v instanceof PendingAppWidgetHostView && info instanceof LauncherAppWidgetInfo && ((LauncherAppWidgetInfo) info).providerName.getPackageName() @@ -4874,7 +4941,7 @@ public class Workspace extends SmoothPagedView } }); - if (installInfo.state == ShortcutInfo.PACKAGE_STATE_DEFAULT) { + if (installInfo.state == PackageInstallerCompat.STATUS_INSTALLED) { completedPackages.add(installInfo.packageName); } } diff --git a/src/com/android/launcher3/compat/PackageInstallerCompat.java b/src/com/android/launcher3/compat/PackageInstallerCompat.java index 89a2157eb..0ae52bd23 100644 --- a/src/com/android/launcher3/compat/PackageInstallerCompat.java +++ b/src/com/android/launcher3/compat/PackageInstallerCompat.java @@ -22,6 +22,10 @@ import com.android.launcher3.Utilities; public abstract class PackageInstallerCompat { + public static final int STATUS_INSTALLED = 0; + public static final int STATUS_INSTALLING = 1; + public static final int STATUS_FAILED = 2; + private static final Object sInstanceLock = new Object(); private static PackageInstallerCompat sInstance; @@ -38,6 +42,8 @@ public abstract class PackageInstallerCompat { } } + public abstract void updateActiveSessionCache(); + public abstract void onPause(); public abstract void onResume(); diff --git a/src/com/android/launcher3/compat/PackageInstallerCompatV16.java b/src/com/android/launcher3/compat/PackageInstallerCompatV16.java index 6a2a02e48..4cc6fc12f 100644 --- a/src/com/android/launcher3/compat/PackageInstallerCompatV16.java +++ b/src/com/android/launcher3/compat/PackageInstallerCompatV16.java @@ -22,7 +22,6 @@ import android.text.TextUtils; import android.util.Log; import com.android.launcher3.LauncherAppState; -import com.android.launcher3.ShortcutInfo; import org.json.JSONException; import org.json.JSONObject; @@ -77,6 +76,9 @@ public class PackageInstallerCompatV16 extends PackageInstallerCompat { @Override public void onStop() { } + @Override + public void updateActiveSessionCache() { } + private void replayUpdates() { if (DEBUG) Log.d(TAG, "updates resumed"); LauncherAppState app = LauncherAppState.getInstanceNoCreate(); @@ -107,7 +109,7 @@ public class PackageInstallerCompatV16 extends PackageInstallerCompat { PackageInstallInfo installInfo = new PackageInstallInfo(packageName); installInfo.progress = progress; installInfo.state = state; - if (state == ShortcutInfo.PACKAGE_STATE_DEFAULT) { + if (state == STATUS_INSTALLED) { // no longer necessary to track this package editor.remove(packageName); if (DEBUG) Log.d(TAG, "no longer tracking " + packageName); @@ -123,7 +125,7 @@ public class PackageInstallerCompatV16 extends PackageInstallerCompat { if (!mUseQueue) { if (mReplayPending) { replayUpdates(); - } else { + } else if (state != STATUS_INSTALLED) { LauncherAppState app = LauncherAppState.getInstanceNoCreate(); ArrayList<PackageInstallInfo> update = new ArrayList<PackageInstallInfo>(); update.add(installInfo); diff --git a/src/com/android/launcher3/compat/PackageInstallerCompatVL.java b/src/com/android/launcher3/compat/PackageInstallerCompatVL.java index c78ab9900..5d016a838 100644 --- a/src/com/android/launcher3/compat/PackageInstallerCompatVL.java +++ b/src/com/android/launcher3/compat/PackageInstallerCompatVL.java @@ -23,8 +23,8 @@ import android.content.pm.PackageInstaller.SessionInfo; import android.util.Log; import android.util.SparseArray; +import com.android.launcher3.IconCache; import com.android.launcher3.LauncherAppState; -import com.android.launcher3.ShortcutInfo; import java.util.ArrayList; @@ -35,12 +35,14 @@ public class PackageInstallerCompatVL extends PackageInstallerCompat { private final SparseArray<SessionInfo> mPendingReplays = new SparseArray<SessionInfo>(); private final PackageInstaller mInstaller; + private final IconCache mCache; private boolean mResumed; private boolean mBound; PackageInstallerCompatVL(Context context) { mInstaller = context.getPackageManager().getPackageInstaller(); + mCache = LauncherAppState.getInstance().getIconCache(); mResumed = false; mBound = false; @@ -53,6 +55,22 @@ public class PackageInstallerCompatVL extends PackageInstallerCompat { } @Override + public void updateActiveSessionCache() { + UserHandleCompat user = UserHandleCompat.myUserHandle(); + for (SessionInfo info : mInstaller.getAllSessions()) { + addSessionInfoToCahce(info, user); + } + } + + private void addSessionInfoToCahce(SessionInfo info, UserHandleCompat user) { + String packageName = info.getAppPackageName(); + if (packageName != null) { + mCache.cachePackageInstallInfo(packageName, user, info.getAppIcon(), + info.getAppLabel()); + } + } + + @Override public void onStop() { mInstaller.removeSessionCallback(mCallback); } @@ -98,14 +116,14 @@ public class PackageInstallerCompatVL extends PackageInstallerCompat { } ArrayList<PackageInstallInfo> updates = new ArrayList<PackageInstallInfo>(); - if (newInfo != null) { + if ((newInfo != null) && (newInfo.state != STATUS_INSTALLED)) { updates.add(newInfo); } - for (int i = mPendingReplays.size() - 1; i > 0; i--) { + for (int i = mPendingReplays.size() - 1; i >= 0; i--) { SessionInfo session = mPendingReplays.valueAt(i); if (session.getAppPackageName() != null) { updates.add(new PackageInstallInfo(session.getAppPackageName(), - ShortcutInfo.PACKAGE_STATE_INSTALLING, + STATUS_INSTALLING, (int) (session.getProgress() * 100))); } } @@ -121,6 +139,7 @@ public class PackageInstallerCompatVL extends PackageInstallerCompat { public void onCreated(int sessionId) { SessionInfo session = mInstaller.getSessionInfo(sessionId); if (session != null) { + addSessionInfoToCahce(session, UserHandleCompat.myUserHandle()); mPendingReplays.put(sessionId, session); replayUpdates(null); } @@ -135,8 +154,7 @@ public class PackageInstallerCompatVL extends PackageInstallerCompat { // need to store this record for future updates, as the app list will get // refreshed on resume. replayUpdates(new PackageInstallInfo(session.getAppPackageName(), - success ? ShortcutInfo.PACKAGE_STATE_DEFAULT - : ShortcutInfo.PACKAGE_STATE_ERROR, 0)); + success ? STATUS_INSTALLED : STATUS_FAILED, 0)); } } |