am 1c13ff56: Merge "Handling label and icon from SessionInfo." into ub-now-porkchop
* commit '1c13ff569170bec075ab9961fbc0eb1ca395696b': Handling label and icon from SessionInfo.
This commit is contained in:
@@ -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))
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
*
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user