Merge "Keeping icons in disabled state when SD-card is unmounted" into ub-now-queens
This commit is contained in:
@@ -40,6 +40,8 @@
|
||||
<string name="folder_name"></string>
|
||||
<!-- Displayed when user selects a shortcut for an app that was uninstalled [CHAR_LIMIT=none]-->
|
||||
<string name="activity_not_found">App isn\'t installed.</string>
|
||||
<!-- Displayed when user selects a shortcut for an app that is current not available [CHAR_LIMIT=none]-->
|
||||
<string name="activity_not_available">App isn\'t available</string>
|
||||
<!-- SafeMode shortcut error string -->
|
||||
<string name="safemode_shortcut_error">Downloaded app disabled in Safe mode</string>
|
||||
<!-- Labels for the tabs in the customize drawer -->
|
||||
|
||||
@@ -105,7 +105,7 @@ class AllAppsList {
|
||||
/**
|
||||
* Remove the apps for the given apk identified by packageName.
|
||||
*/
|
||||
public void removePackage(String packageName, UserHandleCompat user) {
|
||||
public void removePackage(String packageName, UserHandleCompat user, boolean clearCache) {
|
||||
final List<AppInfo> data = this.data;
|
||||
for (int i = data.size() - 1; i >= 0; i--) {
|
||||
AppInfo info = data.get(i);
|
||||
@@ -115,7 +115,9 @@ class AllAppsList {
|
||||
data.remove(i);
|
||||
}
|
||||
}
|
||||
mIconCache.remove(packageName, user);
|
||||
if (clearCache) {
|
||||
mIconCache.remove(packageName, user);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -122,7 +122,7 @@ public class BubbleTextView extends TextView {
|
||||
LauncherAppState app = LauncherAppState.getInstance();
|
||||
|
||||
FastBitmapDrawable iconDrawable = Utilities.createIconDrawable(b);
|
||||
iconDrawable.setGhostModeEnabled(info.isDisabled);
|
||||
iconDrawable.setGhostModeEnabled(info.isDisabled != 0);
|
||||
|
||||
setCompoundDrawables(null, iconDrawable, null, null);
|
||||
if (setDefaultPadding) {
|
||||
|
||||
@@ -2590,6 +2590,16 @@ public class Launcher extends Activity
|
||||
|
||||
// Open shortcut
|
||||
final ShortcutInfo shortcut = (ShortcutInfo) tag;
|
||||
|
||||
if (shortcut.isDisabled != 0) {
|
||||
int error = R.string.activity_not_available;
|
||||
if ((shortcut.isDisabled & ShortcutInfo.FLAG_DISABLED_SAFEMODE) != 0) {
|
||||
error = R.string.safemode_shortcut_error;
|
||||
}
|
||||
Toast.makeText(this, error, Toast.LENGTH_SHORT).show();
|
||||
return;
|
||||
}
|
||||
|
||||
final Intent intent = shortcut.intent;
|
||||
|
||||
// Check for special shortcuts
|
||||
@@ -4766,24 +4776,30 @@ public class Launcher extends Activity
|
||||
* we only remove specific components from the workspace, where as
|
||||
* package-removal should clear all items by package name.
|
||||
*
|
||||
* @param reason if non-zero, the icons are not permanently removed, rather marked as disabled.
|
||||
* Implementation of the method from LauncherModel.Callbacks.
|
||||
*/
|
||||
@Override
|
||||
public void bindComponentsRemoved(final ArrayList<String> packageNames,
|
||||
final ArrayList<AppInfo> appInfos, final UserHandleCompat user) {
|
||||
final ArrayList<AppInfo> appInfos, final UserHandleCompat user, final int reason) {
|
||||
Runnable r = new Runnable() {
|
||||
public void run() {
|
||||
bindComponentsRemoved(packageNames, appInfos, user);
|
||||
bindComponentsRemoved(packageNames, appInfos, user, reason);
|
||||
}
|
||||
};
|
||||
if (waitUntilResume(r)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!packageNames.isEmpty()) {
|
||||
mWorkspace.removeItemsByPackageName(packageNames, user);
|
||||
}
|
||||
if (!appInfos.isEmpty()) {
|
||||
mWorkspace.removeItemsByApplicationInfo(appInfos, user);
|
||||
if (reason == 0) {
|
||||
if (!packageNames.isEmpty()) {
|
||||
mWorkspace.removeItemsByPackageName(packageNames, user);
|
||||
}
|
||||
if (!appInfos.isEmpty()) {
|
||||
mWorkspace.removeItemsByApplicationInfo(appInfos, user);
|
||||
}
|
||||
} else {
|
||||
mWorkspace.disableShortcutsByPackageName(packageNames, user, reason);
|
||||
}
|
||||
|
||||
// Notify the drag controller
|
||||
|
||||
@@ -202,7 +202,7 @@ public class LauncherModel extends BroadcastReceiver
|
||||
public void updatePackageState(ArrayList<PackageInstallInfo> installInfo);
|
||||
public void updatePackageBadge(String packageName);
|
||||
public void bindComponentsRemoved(ArrayList<String> packageNames,
|
||||
ArrayList<AppInfo> appInfos, UserHandleCompat user);
|
||||
ArrayList<AppInfo> appInfos, UserHandleCompat user, int reason);
|
||||
public void bindPackagesUpdated(ArrayList<Object> widgetsAndShortcuts);
|
||||
public void bindSearchablesChanged();
|
||||
public boolean isAllAppsButtonRank(int rank);
|
||||
@@ -1981,6 +1981,7 @@ public class LauncherModel extends BroadcastReceiver
|
||||
long serialNumber = c.getInt(profileIdIndex);
|
||||
user = mUserManager.getUserForSerialNumber(serialNumber);
|
||||
int promiseType = c.getInt(restoredIndex);
|
||||
int disabledState = 0;
|
||||
if (user == null) {
|
||||
// User has been deleted remove the item.
|
||||
itemsToRemove.add(id);
|
||||
@@ -2054,14 +2055,13 @@ public class LauncherModel extends BroadcastReceiver
|
||||
itemsToRemove.add(id);
|
||||
continue;
|
||||
}
|
||||
} else if (isSdCardReady) {
|
||||
// Do not wait for external media load anymore.
|
||||
// Log the invalid package, and remove it
|
||||
Launcher.addDumpLog(TAG,
|
||||
"Invalid package removed: " + cn, true);
|
||||
itemsToRemove.add(id);
|
||||
continue;
|
||||
} else {
|
||||
} else if (launcherApps.isAppEnabled(
|
||||
manager, cn.getPackageName(),
|
||||
PackageManager.GET_UNINSTALLED_PACKAGES)) {
|
||||
// Package is present but not available.
|
||||
allowMissingTarget = true;
|
||||
disabledState = ShortcutInfo.FLAG_DISABLED_NOT_AVAILABLE;
|
||||
} else if (!isSdCardReady) {
|
||||
// SdCard is not ready yet. Package might get available,
|
||||
// once it is ready.
|
||||
Launcher.addDumpLog(TAG, "Invalid package: " + cn
|
||||
@@ -2074,6 +2074,14 @@ public class LauncherModel extends BroadcastReceiver
|
||||
pkgs.add(cn.getPackageName());
|
||||
allowMissingTarget = true;
|
||||
// Add the icon on the workspace anyway.
|
||||
|
||||
} else {
|
||||
// Do not wait for external media load anymore.
|
||||
// Log the invalid package, and remove it
|
||||
Launcher.addDumpLog(TAG,
|
||||
"Invalid package removed: " + cn, true);
|
||||
itemsToRemove.add(id);
|
||||
continue;
|
||||
}
|
||||
} else if (cn == null) {
|
||||
// For shortcuts with no component, keep them as they are
|
||||
@@ -2131,8 +2139,10 @@ public class LauncherModel extends BroadcastReceiver
|
||||
info.spanX = 1;
|
||||
info.spanY = 1;
|
||||
info.intent.putExtra(ItemInfo.EXTRA_PROFILE, serialNumber);
|
||||
info.isDisabled = isSafeMode
|
||||
&& !Utilities.isSystemApp(context, intent);
|
||||
info.isDisabled = disabledState;
|
||||
if (isSafeMode && !Utilities.isSystemApp(context, intent)) {
|
||||
info.isDisabled |= ShortcutInfo.FLAG_DISABLED_SAFEMODE;
|
||||
}
|
||||
|
||||
// check & update map of what's occupied
|
||||
deleteOnInvalidPlacement.set(false);
|
||||
@@ -2930,20 +2940,34 @@ public class LauncherModel extends BroadcastReceiver
|
||||
synchronized (sBgLock) {
|
||||
final LauncherAppsCompat launcherApps = LauncherAppsCompat
|
||||
.getInstance(mApp.getContext());
|
||||
ArrayList<String> packagesRemoved;
|
||||
final PackageManager manager = context.getPackageManager();
|
||||
final ArrayList<String> packagesRemoved = new ArrayList<String>();
|
||||
final ArrayList<String> packagesUnavailable = new ArrayList<String>();
|
||||
for (Entry<UserHandleCompat, HashSet<String>> entry : sPendingPackages.entrySet()) {
|
||||
UserHandleCompat user = entry.getKey();
|
||||
packagesRemoved = new ArrayList<String>();
|
||||
packagesRemoved.clear();
|
||||
packagesUnavailable.clear();
|
||||
for (String pkg : entry.getValue()) {
|
||||
if (!launcherApps.isPackageEnabledForProfile(pkg, user)) {
|
||||
Launcher.addDumpLog(TAG, "Package not found: " + pkg, true);
|
||||
packagesRemoved.add(pkg);
|
||||
boolean packageOnSdcard = launcherApps.isAppEnabled(
|
||||
manager, pkg, PackageManager.GET_UNINSTALLED_PACKAGES);
|
||||
if (packageOnSdcard) {
|
||||
Launcher.addDumpLog(TAG, "Package found on sd-card: " + pkg, true);
|
||||
packagesUnavailable.add(pkg);
|
||||
} else {
|
||||
Launcher.addDumpLog(TAG, "Package not found: " + pkg, true);
|
||||
packagesRemoved.add(pkg);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!packagesRemoved.isEmpty()) {
|
||||
enqueuePackageUpdated(new PackageUpdatedTask(PackageUpdatedTask.OP_REMOVE,
|
||||
packagesRemoved.toArray(new String[packagesRemoved.size()]), user));
|
||||
}
|
||||
if (!packagesUnavailable.isEmpty()) {
|
||||
enqueuePackageUpdated(new PackageUpdatedTask(PackageUpdatedTask.OP_UNAVAILABLE,
|
||||
packagesUnavailable.toArray(new String[packagesUnavailable.size()]), user));
|
||||
}
|
||||
}
|
||||
sPendingPackages.clear();
|
||||
}
|
||||
@@ -2991,9 +3015,10 @@ public class LauncherModel extends BroadcastReceiver
|
||||
break;
|
||||
case OP_REMOVE:
|
||||
case OP_UNAVAILABLE:
|
||||
boolean clearCache = mOp == OP_REMOVE;
|
||||
for (int i=0; i<N; i++) {
|
||||
if (DEBUG_LOADERS) Log.d(TAG, "mAllAppsList.removePackage " + packages[i]);
|
||||
mBgAllAppsList.removePackage(packages[i], mUser);
|
||||
mBgAllAppsList.removePackage(packages[i], mUser, clearCache);
|
||||
WidgetPreviewLoader.removePackageFromDb(
|
||||
mApp.getWidgetPreviewCacheDb(), packages[i]);
|
||||
}
|
||||
@@ -3041,7 +3066,7 @@ public class LauncherModel extends BroadcastReceiver
|
||||
ArrayList<ItemInfo> infos =
|
||||
getItemInfoForComponentName(a.componentName, mUser);
|
||||
for (ItemInfo i : infos) {
|
||||
if (isShortcutInfoUpdateable(i)) {
|
||||
if (i instanceof ShortcutInfo && isShortcutAppTarget((ShortcutInfo) i)) {
|
||||
ShortcutInfo info = (ShortcutInfo) i;
|
||||
info.title = a.title.toString();
|
||||
info.contentDescription = a.contentDescription;
|
||||
@@ -3064,7 +3089,7 @@ public class LauncherModel extends BroadcastReceiver
|
||||
if (mOp == OP_ADD || mOp == OP_UPDATE) {
|
||||
final ArrayList<ShortcutInfo> iconsChanged = new ArrayList<ShortcutInfo>();
|
||||
HashSet<String> packageSet = new HashSet<String>(Arrays.asList(packages));
|
||||
// We need to iteration over the items here, so that we can avoid new Bitmap
|
||||
// We need to iterate over the items here, so that we can avoid new Bitmap
|
||||
// creation on the UI thread.
|
||||
synchronized (sBgLock) {
|
||||
for (ItemInfo info : sBgWorkspaceItems) {
|
||||
@@ -3099,28 +3124,35 @@ public class LauncherModel extends BroadcastReceiver
|
||||
|
||||
final ArrayList<String> removedPackageNames =
|
||||
new ArrayList<String>();
|
||||
if (mOp == OP_REMOVE) {
|
||||
if (mOp == OP_REMOVE || mOp == OP_UNAVAILABLE) {
|
||||
// Mark all packages in the broadcast to be removed
|
||||
removedPackageNames.addAll(Arrays.asList(packages));
|
||||
} else if (mOp == OP_UPDATE) {
|
||||
// Mark disabled packages in the broadcast to be removed
|
||||
final PackageManager pm = context.getPackageManager();
|
||||
for (int i=0; i<N; i++) {
|
||||
if (isPackageDisabled(context, packages[i], mUser)) {
|
||||
removedPackageNames.add(packages[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Remove all the components associated with this package
|
||||
for (String pn : removedPackageNames) {
|
||||
deletePackageFromDatabase(context, pn, mUser);
|
||||
}
|
||||
// Remove all the specific components
|
||||
for (AppInfo a : removedApps) {
|
||||
ArrayList<ItemInfo> infos = getItemInfoForComponentName(a.componentName, mUser);
|
||||
deleteItemsFromDatabase(context, infos);
|
||||
}
|
||||
|
||||
if (!removedPackageNames.isEmpty() || !removedApps.isEmpty()) {
|
||||
final int removeReason;
|
||||
if (mOp == OP_UNAVAILABLE) {
|
||||
removeReason = ShortcutInfo.FLAG_DISABLED_NOT_AVAILABLE;
|
||||
} else {
|
||||
// Remove all the components associated with this package
|
||||
for (String pn : removedPackageNames) {
|
||||
deletePackageFromDatabase(context, pn, mUser);
|
||||
}
|
||||
// Remove all the specific components
|
||||
for (AppInfo a : removedApps) {
|
||||
ArrayList<ItemInfo> infos = getItemInfoForComponentName(a.componentName, mUser);
|
||||
deleteItemsFromDatabase(context, infos);
|
||||
}
|
||||
removeReason = 0;
|
||||
}
|
||||
|
||||
// Remove any queued items from the install queue
|
||||
String spKey = LauncherAppState.getSharedPreferencesKey();
|
||||
SharedPreferences sp =
|
||||
@@ -3131,7 +3163,8 @@ public class LauncherModel extends BroadcastReceiver
|
||||
public void run() {
|
||||
Callbacks cb = mCallbacks != null ? mCallbacks.get() : null;
|
||||
if (callbacks == cb && cb != null) {
|
||||
callbacks.bindComponentsRemoved(removedPackageNames, removedApps, mUser);
|
||||
callbacks.bindComponentsRemoved(
|
||||
removedPackageNames, removedApps, mUser, removeReason);
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -3381,24 +3414,18 @@ public class LauncherModel extends BroadcastReceiver
|
||||
return filterItemInfos(sBgItemsIdMap.values(), filter);
|
||||
}
|
||||
|
||||
public static boolean isShortcutInfoUpdateable(ItemInfo i) {
|
||||
if (i instanceof ShortcutInfo) {
|
||||
ShortcutInfo info = (ShortcutInfo) i;
|
||||
// We need to check for ACTION_MAIN otherwise getComponent() might
|
||||
// return null for some shortcuts (for instance, for shortcuts to
|
||||
// web pages.)
|
||||
Intent intent = info.intent;
|
||||
ComponentName name = intent.getComponent();
|
||||
if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION &&
|
||||
Intent.ACTION_MAIN.equals(intent.getAction()) && name != null) {
|
||||
return true;
|
||||
}
|
||||
// placeholder shortcuts get special treatment, let them through too.
|
||||
if (info.isPromise()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
/**
|
||||
* @return true if the ShortcutInfo points to an app shortcut target, i.e. it has been added by
|
||||
* dragging from AllApps list.
|
||||
*/
|
||||
public static boolean isShortcutAppTarget(ShortcutInfo info) {
|
||||
// We need to check for ACTION_MAIN otherwise getComponent() might
|
||||
// return null for some shortcuts (for instance, for shortcuts to
|
||||
// web pages.)
|
||||
Intent intent = info.promisedIntent != null ? info.promisedIntent : info.intent;
|
||||
ComponentName name = intent.getComponent();
|
||||
return info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION &&
|
||||
Intent.ACTION_MAIN.equals(intent.getAction()) && name != null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -87,11 +87,21 @@ public class ShortcutInfo extends ItemInfo {
|
||||
*/
|
||||
private Bitmap mIcon;
|
||||
|
||||
/**
|
||||
* Indicates that the icon is disabled due to safe mode restrictions.
|
||||
*/
|
||||
public static final int FLAG_DISABLED_SAFEMODE = 1;
|
||||
|
||||
/**
|
||||
* Indicates that the icon is disabled as the app is not available.
|
||||
*/
|
||||
public static final int FLAG_DISABLED_NOT_AVAILABLE = 2;
|
||||
|
||||
/**
|
||||
* Could be disabled, if the the app is installed but unavailable (eg. in safe mode or when
|
||||
* sd-card is not available).
|
||||
*/
|
||||
boolean isDisabled = false;
|
||||
int isDisabled = DEFAULT;
|
||||
|
||||
int status;
|
||||
|
||||
|
||||
@@ -4629,6 +4629,34 @@ public class Workspace extends SmoothPagedView
|
||||
});
|
||||
}
|
||||
|
||||
public void disableShortcutsByPackageName(final ArrayList<String> packages,
|
||||
final UserHandleCompat user, final int reason) {
|
||||
final HashSet<String> packageNames = new HashSet<String>();
|
||||
packageNames.addAll(packages);
|
||||
|
||||
mapOverItems(MAP_RECURSE, new ItemOperator() {
|
||||
@Override
|
||||
public boolean evaluate(ItemInfo info, View v, View parent) {
|
||||
if (info instanceof ShortcutInfo && v instanceof BubbleTextView) {
|
||||
ShortcutInfo shortcutInfo = (ShortcutInfo) info;
|
||||
ComponentName cn = shortcutInfo.getTargetComponent();
|
||||
if (user.equals(shortcutInfo.user) && cn != null
|
||||
&& packageNames.contains(cn.getPackageName())) {
|
||||
shortcutInfo.isDisabled |= reason;
|
||||
BubbleTextView shortcut = (BubbleTextView) v;
|
||||
shortcut.applyFromShortcutInfo(shortcutInfo, mIconCache, true, false);
|
||||
|
||||
if (parent != null) {
|
||||
parent.invalidate();
|
||||
}
|
||||
}
|
||||
}
|
||||
// process all the shortcuts
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Removes ALL items that match a given package name, this is usually called when a package
|
||||
// has been removed and we want to remove all components (widgets, shortcuts, apps) that
|
||||
// belong to that package.
|
||||
@@ -4859,7 +4887,6 @@ public class Workspace extends SmoothPagedView
|
||||
ComponentName cn = shortcutInfo.getTargetComponent();
|
||||
AppInfo appInfo = appsMap.get(cn);
|
||||
if (user.equals(shortcutInfo.user) && cn != null
|
||||
&& LauncherModel.isShortcutInfoUpdateable(info)
|
||||
&& pkgNames.contains(cn.getPackageName())) {
|
||||
boolean promiseStateChanged = false;
|
||||
boolean infoUpdated = false;
|
||||
@@ -4904,8 +4931,14 @@ public class Workspace extends SmoothPagedView
|
||||
LauncherModel.updateItemInDatabase(getContext(), shortcutInfo);
|
||||
}
|
||||
|
||||
if ((shortcutInfo.isDisabled & ShortcutInfo.FLAG_DISABLED_NOT_AVAILABLE) != 0) {
|
||||
// Since package was just updated, the target must be available now.
|
||||
shortcutInfo.isDisabled &= ~ShortcutInfo.FLAG_DISABLED_NOT_AVAILABLE;
|
||||
infoUpdated = true;
|
||||
}
|
||||
|
||||
if (appInfo != null) {
|
||||
// Only update the icon and labels if the shortcuts points to an app target
|
||||
if ((appInfo != null) && LauncherModel.isShortcutAppTarget(shortcutInfo)) {
|
||||
shortcutInfo.updateIcon(mIconCache);
|
||||
shortcutInfo.title = appInfo.title.toString();
|
||||
shortcutInfo.contentDescription = appInfo.contentDescription;
|
||||
|
||||
@@ -19,8 +19,10 @@ package com.android.launcher3.compat;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.PackageManager.NameNotFoundException;
|
||||
import android.graphics.Rect;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
|
||||
import com.android.launcher3.Utilities;
|
||||
@@ -73,4 +75,13 @@ public abstract class LauncherAppsCompat {
|
||||
public abstract boolean isPackageEnabledForProfile(String packageName, UserHandleCompat user);
|
||||
public abstract boolean isActivityEnabledForProfile(ComponentName component,
|
||||
UserHandleCompat user);
|
||||
|
||||
public boolean isAppEnabled(PackageManager pm, String packageName, int flags) {
|
||||
try {
|
||||
ApplicationInfo info = pm.getApplicationInfo(packageName, flags);
|
||||
return info != null && info.enabled;
|
||||
} catch (NameNotFoundException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -22,7 +22,6 @@ import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.content.pm.ActivityInfo;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.PackageManager.NameNotFoundException;
|
||||
import android.content.pm.ResolveInfo;
|
||||
@@ -112,12 +111,7 @@ public class LauncherAppsCompatV16 extends LauncherAppsCompat {
|
||||
}
|
||||
|
||||
public boolean isPackageEnabledForProfile(String packageName, UserHandleCompat user) {
|
||||
try {
|
||||
PackageInfo info = mPm.getPackageInfo(packageName, 0);
|
||||
return info != null && info.applicationInfo.enabled;
|
||||
} catch (NameNotFoundException e) {
|
||||
return false;
|
||||
}
|
||||
return isAppEnabled(mPm, packageName, 0);
|
||||
}
|
||||
|
||||
public boolean isActivityEnabledForProfile(ComponentName component, UserHandleCompat user) {
|
||||
@@ -198,8 +192,13 @@ public class LauncherAppsCompatV16 extends LauncherAppsCompat {
|
||||
callback.onPackagesAvailable(packages, user, replacing);
|
||||
}
|
||||
} else if (Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action)) {
|
||||
final boolean replacing = intent.getBooleanExtra(Intent.EXTRA_REPLACING,
|
||||
Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT);
|
||||
// This intent is broadcasted when moving a package or mounting/un-mounting
|
||||
// external storage.
|
||||
// However on Kitkat this is also sent when a package is being updated, and
|
||||
// contains an extra Intent.EXTRA_REPLACING=true for that case.
|
||||
// Using false as default for Intent.EXTRA_REPLACING gives correct value on
|
||||
// lower devices as the intent is not sent when the app is updating/replacing.
|
||||
final boolean replacing = intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);
|
||||
String[] packages = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
|
||||
for (OnAppsChangedCallbackCompat callback : getCallbacks()) {
|
||||
callback.onPackagesUnavailable(packages, user, replacing);
|
||||
|
||||
Reference in New Issue
Block a user