am 65d0a198: am 1c13ff56: Merge "Handling label and icon from SessionInfo." into ub-now-porkchop

* commit '65d0a198314ce49119d7448de206c273ccc97c6d':
  Handling label and icon from SessionInfo.
This commit is contained in:
Sunny Goyal
2014-09-08 13:48:41 +00:00
committed by Android Git Automerger
13 changed files with 319 additions and 208 deletions
@@ -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))
+14 -35
View File
@@ -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();
}
}
}
}
+47 -5
View File
@@ -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) {
@@ -349,6 +375,21 @@ public class IconCache {
return entry;
}
/**
* 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.
*/
@@ -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 {
-4
View File
@@ -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
*
+4 -2
View File
@@ -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);
@@ -161,7 +161,7 @@ public class LauncherAppState implements DeviceProfile.DeviceProfileCallbacks {
return mModel;
}
IconCache getIconCache() {
public IconCache getIconCache() {
return mIconCache;
}
+74 -59
View File
@@ -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);
} else {
info.title = "";
}
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 {
throw new InvalidParameterException("Invalid restoreType " + promiseType);
}
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;
}
}
@@ -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) {
+43 -57
View File
@@ -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;
/**
* TODO move this to {@link status}
*/
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.
* Refer {@link #FLAG_RESTORE_PENDING}, {@link #FLAG_INSTALL_PENDING}
*/
Intent restoredIntent;
/**
* This is set once to indicate that it was a promise info at some point of its life.
*/
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 final boolean isPromise() {
return hasStatusFlag(FLAG_RESTORED_ICON | FLAG_AUTOINTALL_ICON);
}
public int getProgress() {
return mProgress;
public int getInstallProgress() {
return mInstallProgress;
}
public void setProgress(int progress) {
mProgress = progress;
}
public void setState(int state) {
mState = state;
}
public int getState() {
return mState;
public void setInstallProgress(int progress) {
mInstallProgress = progress;
status |= FLAG_INSTALL_SESSION_ACTIVE;
}
}
+98 -31
View File
@@ -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);
}
}
@@ -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();
@@ -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);
@@ -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;
@@ -52,6 +54,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));
}
}