diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index c56de07b2c..e6a8bea15d 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -63,6 +63,8 @@
+
+
@@ -206,6 +208,12 @@
+
+
+
+
+
+
sBgWorkspaceScreens = new ArrayList();
+ // sPendingPackages is a set of packages which could be on sdcard and are not available yet
+ static final HashMap> sPendingPackages = new HashMap<>();
+
// only access in worker thread >
private IconCache mIconCache;
@@ -1826,6 +1837,9 @@ public class LauncherModel extends BroadcastReceiver
final PackageManager manager = context.getPackageManager();
final AppWidgetManager widgets = AppWidgetManager.getInstance(context);
final boolean isSafeMode = manager.isSafeMode();
+ final LauncherAppsCompat launcherApps = LauncherAppsCompat.getInstance(context);
+ final boolean isSdCardReady = context.registerReceiver(null,
+ new IntentFilter(StartupReceiver.SYESTEM_READY)) != null;
LauncherAppState app = LauncherAppState.getInstance();
DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
@@ -1919,6 +1933,7 @@ public class LauncherModel extends BroadcastReceiver
try {
int itemType = c.getInt(itemTypeIndex);
boolean restored = 0 != c.getInt(restoredIndex);
+ boolean allowMissingTarget = false;
switch (itemType) {
case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:
@@ -1935,30 +1950,51 @@ public class LauncherModel extends BroadcastReceiver
try {
intent = Intent.parseUri(intentDescription, 0);
ComponentName cn = intent.getComponent();
- if (cn != null && !isValidPackageActivity(context, cn, user)) {
- if (restored) {
- // might be installed later
+ if (cn != null && cn.getPackageName() != null) {
+ boolean validPkg = launcherApps.isPackageEnabledForProfile(
+ cn.getPackageName(), user);
+ boolean validComponent = validPkg &&
+ launcherApps.isActivityEnabledForProfile(cn, user);
+
+ if (validComponent) {
+ if (restored) {
+ // no special handling necessary for this item
+ restoredRows.add(id);
+ 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;
+ } else if (restored) {
+ // Package is not yet available but might be
+ // installed later.
Launcher.addDumpLog(TAG,
"package not yet restored: " + cn, true);
- } else {
- if (!mAppsCanBeOnRemoveableStorage) {
- // Log the invalid package, and remove it
- Launcher.addDumpLog(TAG,
- "Invalid package removed: " + cn, true);
- itemsToRemove.add(id);
- } else {
- // If apps can be on external storage, then we just
- // leave them for the user to remove (maybe add
- // visual treatment to it)
- Launcher.addDumpLog(TAG,
- "Invalid package found: " + cn, true);
- }
+ } 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 {
+ // SdCard is not ready yet. Package might get available,
+ // once it is ready.
+ Launcher.addDumpLog(TAG, "Invalid package: " + cn
+ + " (check again later)", true);
+ HashSet pkgs = sPendingPackages.get(user);
+ if (pkgs == null) {
+ pkgs = new HashSet<>();
+ sPendingPackages.put(user, pkgs);
+ }
+ pkgs.add(cn.getPackageName());
+ allowMissingTarget = true;
+ // Add the icon on the workspace anyway.
}
- } else if (restored) {
- // no special handling necessary for this restored item
- restoredRows.add(id);
- restored = false;
}
} catch (URISyntaxException e) {
Launcher.addDumpLog(TAG,
@@ -1980,8 +2016,8 @@ public class LauncherModel extends BroadcastReceiver
}
} else if (itemType ==
LauncherSettings.Favorites.ITEM_TYPE_APPLICATION) {
- info = getShortcutInfo(manager, intent, user, context, c, iconIndex,
- titleIndex, mLabelCache);
+ info = getShortcutInfo(manager, intent, user, context, c,
+ iconIndex, titleIndex, mLabelCache, allowMissingTarget);
} else {
info = getShortcutInfo(c, context, iconTypeIndex,
iconPackageIndex, iconResourceIndex, iconIndex,
@@ -2198,6 +2234,12 @@ public class LauncherModel extends BroadcastReceiver
}
}
+ if (!isSdCardReady && !sPendingPackages.isEmpty()) {
+ context.registerReceiver(new AppsAvailabilityCheck(),
+ new IntentFilter(StartupReceiver.SYESTEM_READY),
+ null, sWorker);
+ }
+
if (loadedOldDb) {
long maxScreenId = 0;
// If we're importing we use the old screen order.
@@ -2743,6 +2785,33 @@ public class LauncherModel extends BroadcastReceiver
sWorker.post(task);
}
+ private class AppsAvailabilityCheck extends BroadcastReceiver {
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ synchronized (sBgLock) {
+ final LauncherAppsCompat launcherApps = LauncherAppsCompat
+ .getInstance(mApp.getContext());
+ ArrayList packagesRemoved;
+ for (Entry> entry : sPendingPackages.entrySet()) {
+ UserHandleCompat user = entry.getKey();
+ packagesRemoved = new ArrayList<>();
+ for (String pkg : entry.getValue()) {
+ if (!launcherApps.isPackageEnabledForProfile(pkg, user)) {
+ 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));
+ }
+ }
+ sPendingPackages.clear();
+ }
+ }
+ }
+
private class PackageUpdatedTask implements Runnable {
int mOp;
String[] mPackages;
@@ -3006,7 +3075,7 @@ public class LauncherModel extends BroadcastReceiver
*/
public ShortcutInfo getShortcutInfo(PackageManager manager, Intent intent,
UserHandleCompat user, Context context) {
- return getShortcutInfo(manager, intent, user, context, null, -1, -1, null);
+ return getShortcutInfo(manager, intent, user, context, null, -1, -1, null, false);
}
/**
@@ -3016,7 +3085,7 @@ public class LauncherModel extends BroadcastReceiver
*/
public ShortcutInfo getShortcutInfo(PackageManager manager, Intent intent,
UserHandleCompat user, Context context, Cursor c, int iconIndex, int titleIndex,
- HashMap