summaryrefslogtreecommitdiffstats
path: root/src/com/android/launcher3/LauncherModel.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/com/android/launcher3/LauncherModel.java')
-rw-r--r--src/com/android/launcher3/LauncherModel.java1160
1 files changed, 744 insertions, 416 deletions
diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java
index 007fd7a4a..c64506d80 100644
--- a/src/com/android/launcher3/LauncherModel.java
+++ b/src/com/android/launcher3/LauncherModel.java
@@ -19,12 +19,19 @@ package com.android.launcher3;
import android.app.SearchManager;
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProviderInfo;
-import android.content.*;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.ContentProviderClient;
+import android.content.ContentProviderOperation;
+import android.content.ContentResolver;
+import android.content.ContentValues;
+import android.content.Context;
+import android.content.Intent;
import android.content.Intent.ShortcutIconResource;
-import android.content.pm.ActivityInfo;
-import android.content.pm.PackageInfo;
+import android.content.IntentFilter;
+import android.content.SharedPreferences;
import android.content.pm.PackageManager;
-import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.ProviderInfo;
import android.content.pm.ResolveInfo;
import android.content.res.Configuration;
import android.content.res.Resources;
@@ -44,10 +51,17 @@ import android.text.TextUtils;
import android.util.Log;
import android.util.Pair;
-import com.android.launcher3.InstallWidgetReceiver.WidgetMimeTypeHandlerData;
+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;
@@ -58,6 +72,7 @@ import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
+import java.util.Map.Entry;
import java.util.Set;
import java.util.TreeMap;
import java.util.concurrent.atomic.AtomicBoolean;
@@ -67,14 +82,17 @@ import java.util.concurrent.atomic.AtomicBoolean;
* LauncherModel object held in a static. Also provide APIs for updating the database state
* for the Launcher.
*/
-public class LauncherModel extends BroadcastReceiver {
+public class LauncherModel extends BroadcastReceiver
+ implements LauncherAppsCompat.OnAppsChangedCallbackCompat {
static final boolean DEBUG_LOADERS = false;
+ private static final boolean DEBUG_RECEIVER = false;
+ private static final boolean REMOVE_UNRESTORED_ICONS = true;
+
static final String TAG = "Launcher.Model";
// true = use a "More Apps" folder for non-workspace apps on upgrade
// false = strew non-workspace apps across the workspace on upgrade
public static final boolean UPGRADE_USE_MORE_APPS_FOLDER = false;
-
public static final int LOADER_FLAG_NONE = 0;
public static final int LOADER_FLAG_CLEAR_WORKSPACE = 1 << 0;
public static final int LOADER_FLAG_MIGRATE_SHORTCUTS = 1 << 1;
@@ -97,6 +115,7 @@ public class LauncherModel extends BroadcastReceiver {
private static final int MAIN_THREAD_NORMAL_RUNNABLE = 0;
private static final int MAIN_THREAD_BINDING_RUNNABLE = 1;
+ private static final String MIGRATE_AUTHORITY = "com.android.launcher2.settings";
private static final HandlerThread sWorkerThread = new HandlerThread("launcher-loader");
static {
@@ -149,13 +168,19 @@ public class LauncherModel extends BroadcastReceiver {
// sBgWorkspaceScreens is the ordered set of workspace screens.
static final ArrayList<Long> sBgWorkspaceScreens = new ArrayList<Long>();
+ // sPendingPackages is a set of packages which could be on sdcard and are not available yet
+ static final HashMap<UserHandleCompat, HashSet<String>> sPendingPackages =
+ new HashMap<UserHandleCompat, HashSet<String>>();
+
// </ only access in worker thread >
private IconCache mIconCache;
- private Bitmap mDefaultIcon;
protected int mPreviousConfigMcc;
+ private final LauncherAppsCompat mLauncherApps;
+ private final UserManagerCompat mUserManager;
+
public interface Callbacks {
public boolean setLoadOnResume();
public int getCurrentWorkspaceScreen();
@@ -173,8 +198,11 @@ public class LauncherModel extends BroadcastReceiver {
ArrayList<ItemInfo> addAnimated,
ArrayList<AppInfo> addedApps);
public void bindAppsUpdated(ArrayList<AppInfo> apps);
+ public void bindAppsRestored(ArrayList<AppInfo> apps);
+ public void updatePackageState(ArrayList<PackageInstallInfo> installInfo);
+ public void updatePackageBadge(String packageName);
public void bindComponentsRemoved(ArrayList<String> packageNames,
- ArrayList<AppInfo> appInfos);
+ ArrayList<AppInfo> appInfos, UserHandleCompat user);
public void bindPackagesUpdated(ArrayList<Object> widgetsAndShortcuts);
public void bindSearchablesChanged();
public boolean isAllAppsButtonRank(int rank);
@@ -188,11 +216,26 @@ public class LauncherModel extends BroadcastReceiver {
LauncherModel(LauncherAppState app, IconCache iconCache, AppFilter appFilter) {
Context context = app.getContext();
- ContentResolver contentResolver = context.getContentResolver();
mAppsCanBeOnRemoveableStorage = Environment.isExternalStorageRemovable();
- mOldContentProviderExists = (contentResolver.acquireContentProviderClient(
- LauncherSettings.Favorites.OLD_CONTENT_URI) != null);
+ String oldProvider = context.getString(R.string.old_launcher_provider_uri);
+ // This may be the same as MIGRATE_AUTHORITY, or it may be replaced by a different
+ // resource string.
+ String redirectAuthority = Uri.parse(oldProvider).getAuthority();
+ ProviderInfo providerInfo =
+ context.getPackageManager().resolveContentProvider(MIGRATE_AUTHORITY, 0);
+ ProviderInfo redirectProvider =
+ context.getPackageManager().resolveContentProvider(redirectAuthority, 0);
+
+ Log.d(TAG, "Old launcher provider: " + oldProvider);
+ mOldContentProviderExists = (providerInfo != null) && (redirectProvider != null);
+
+ if (mOldContentProviderExists) {
+ Log.d(TAG, "Old launcher provider exists.");
+ } else {
+ Log.d(TAG, "Old launcher provider does not exist.");
+ }
+
mApp = app;
mBgAllAppsList = new AllAppsList(iconCache, appFilter);
mIconCache = iconCache;
@@ -200,6 +243,8 @@ public class LauncherModel extends BroadcastReceiver {
final Resources res = context.getResources();
Configuration config = res.getConfiguration();
mPreviousConfigMcc = config.mcc;
+ mLauncherApps = LauncherAppsCompat.getInstance(context);
+ mUserManager = UserManagerCompat.getInstance(context);
}
/** Runs the specified runnable immediately if called from the main thread, otherwise it is
@@ -292,6 +337,32 @@ public class LauncherModel extends BroadcastReceiver {
return null;
}
+ public void setPackageState(final ArrayList<PackageInstallInfo> installInfo) {
+ // Process the updated package state
+ Runnable r = new Runnable() {
+ public void run() {
+ Callbacks callbacks = mCallbacks != null ? mCallbacks.get() : null;
+ if (callbacks != null) {
+ callbacks.updatePackageState(installInfo);
+ }
+ }
+ };
+ mHandler.post(r);
+ }
+
+ public void updatePackageBadge(final String packageName) {
+ // Process the updated package badge
+ Runnable r = new Runnable() {
+ public void run() {
+ Callbacks callbacks = mCallbacks != null ? mCallbacks.get() : null;
+ if (callbacks != null) {
+ callbacks.updatePackageBadge(packageName);
+ }
+ }
+ };
+ mHandler.post(r);
+ }
+
public void addAppsToAllApps(final Context ctx, final ArrayList<AppInfo> allAppsApps) {
final Callbacks callbacks = mCallbacks != null ? mCallbacks.get() : null;
@@ -306,7 +377,7 @@ public class LauncherModel extends BroadcastReceiver {
Iterator<AppInfo> iter = allAppsApps.iterator();
while (iter.hasNext()) {
ItemInfo a = iter.next();
- if (LauncherModel.appWasRestored(ctx, a.getIntent())) {
+ if (LauncherModel.appWasPromise(ctx, a.getIntent(), a.user)) {
restoredAppsFinal.add((AppInfo) a);
}
}
@@ -322,7 +393,8 @@ public class LauncherModel extends BroadcastReceiver {
for (AppInfo info : restoredAppsFinal) {
final Intent intent = info.getIntent();
if (intent != null) {
- mIconCache.deletePreloadedIcon(intent.getComponent());
+ mIconCache.deletePreloadedIcon(intent.getComponent(),
+ info.user);
}
}
callbacks.bindAppsUpdated(restoredAppsFinal);
@@ -374,7 +446,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)) {
+ LauncherModel.appWasPromise(context, launchIntent, a.user)) {
restoredAppsFinal.add((AppInfo) a);
}
continue;
@@ -464,15 +536,6 @@ public class LauncherModel extends BroadcastReceiver {
runOnWorkerThread(r);
}
- public Bitmap getFallbackIcon() {
- if (mDefaultIcon == null) {
- final Context context = LauncherAppState.getInstance().getContext();
- mDefaultIcon = Utilities.createIconBitmap(
- mIconCache.getFullResDefaultActivityIcon(), context);
- }
- return Bitmap.createBitmap(mDefaultIcon);
- }
-
public void unbindItemInfosAndClearQueuedBindRunnables() {
if (sWorkerThread.getThreadId() == Process.myTid()) {
throw new RuntimeException("Expected unbindLauncherItemInfos() to be called from the " +
@@ -480,7 +543,9 @@ public class LauncherModel extends BroadcastReceiver {
}
// Clear any deferred bind runnables
- mDeferredBindRunnables.clear();
+ synchronized (mDeferredBindRunnables) {
+ mDeferredBindRunnables.clear();
+ }
// Remove any queued bind runnables
mHandler.cancelAllRunnablesOfType(MAIN_THREAD_BINDING_RUNNABLE);
// Unbind all the workspace items
@@ -796,7 +861,7 @@ public class LauncherModel extends BroadcastReceiver {
*/
static void updateItemInDatabase(Context context, final ItemInfo item) {
final ContentValues values = new ContentValues();
- item.onAddToDatabase(values);
+ item.onAddToDatabase(context, values);
item.updateValuesWithCoordinates(values, item.cellX, item.cellY);
updateItemInDatabaseHelper(context, values, item, "updateItemInDatabase");
}
@@ -807,9 +872,26 @@ public class LauncherModel extends BroadcastReceiver {
*/
static boolean shortcutExists(Context context, String title, Intent intent) {
final ContentResolver cr = context.getContentResolver();
+ final Intent intentWithPkg, intentWithoutPkg;
+
+ if (intent.getComponent() != null) {
+ // If component is not null, an intent with null package will produce
+ // the same result and should also be a match.
+ if (intent.getPackage() != null) {
+ intentWithPkg = intent;
+ intentWithoutPkg = new Intent(intent).setPackage(null);
+ } else {
+ intentWithPkg = new Intent(intent).setPackage(
+ intent.getComponent().getPackageName());
+ intentWithoutPkg = intent;
+ }
+ } else {
+ intentWithPkg = intent;
+ intentWithoutPkg = intent;
+ }
Cursor c = cr.query(LauncherSettings.Favorites.CONTENT_URI,
- new String[] { "title", "intent" }, "title=? and intent=?",
- new String[] { title, intent.toUri(0) }, null);
+ new String[] { "title", "intent" }, "title=? and (intent=? or intent=?)",
+ new String[] { title, intentWithPkg.toUri(0), intentWithoutPkg.toUri(0) }, null);
boolean result = false;
try {
result = c.moveToFirst();
@@ -820,27 +902,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.
+ * Returns true if the promise shortcuts with the same package name exists on the workspace.
*/
- static boolean appWasRestored(Context context, Intent intent) {
- 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();
- final String where = "intent glob \"*component=" + componentName + "*\" and restored = 1";
- Cursor c = cr.query(LauncherSettings.Favorites.CONTENT_URI,
- new String[]{"intent", "restored"}, 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();
}
/**
@@ -852,8 +921,10 @@ public class LauncherModel extends BroadcastReceiver {
final ContentResolver cr = context.getContentResolver();
Cursor c = cr.query(LauncherSettings.Favorites.CONTENT_URI, new String[] {
LauncherSettings.Favorites.ITEM_TYPE, LauncherSettings.Favorites.CONTAINER,
- LauncherSettings.Favorites.SCREEN, LauncherSettings.Favorites.CELLX, LauncherSettings.Favorites.CELLY,
- LauncherSettings.Favorites.SPANX, LauncherSettings.Favorites.SPANY }, null, null, null);
+ LauncherSettings.Favorites.SCREEN,
+ LauncherSettings.Favorites.CELLX, LauncherSettings.Favorites.CELLY,
+ LauncherSettings.Favorites.SPANX, LauncherSettings.Favorites.SPANY,
+ LauncherSettings.Favorites.PROFILE_ID }, null, null, null);
final int itemTypeIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ITEM_TYPE);
final int containerIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CONTAINER);
@@ -862,7 +933,8 @@ public class LauncherModel extends BroadcastReceiver {
final int cellYIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLY);
final int spanXIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SPANX);
final int spanYIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SPANY);
-
+ final int profileIdIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.PROFILE_ID);
+ UserManagerCompat userManager = UserManagerCompat.getInstance(context);
try {
while (c.moveToNext()) {
ItemInfo item = new ItemInfo();
@@ -873,8 +945,12 @@ public class LauncherModel extends BroadcastReceiver {
item.container = c.getInt(containerIndex);
item.itemType = c.getInt(itemTypeIndex);
item.screenId = c.getInt(screenIndex);
-
- items.add(item);
+ long serialNumber = c.getInt(profileIdIndex);
+ item.user = userManager.getUserForSerialNumber(serialNumber);
+ // Skip if user has been deleted.
+ if (item.user != null) {
+ items.add(item);
+ }
}
} catch (Exception e) {
items.clear();
@@ -947,12 +1023,13 @@ public class LauncherModel extends BroadcastReceiver {
final ContentValues values = new ContentValues();
final ContentResolver cr = context.getContentResolver();
- item.onAddToDatabase(values);
+ item.onAddToDatabase(context, values);
item.id = LauncherAppState.getLauncherProvider().generateNewItemId();
values.put(LauncherSettings.Favorites._ID, item.id);
item.updateValuesWithCoordinates(values, item.cellX, item.cellY);
+ final StackTraceElement[] stackTrace = new Throwable().getStackTrace();
Runnable r = new Runnable() {
public void run() {
cr.insert(notify ? LauncherSettings.Favorites.CONTENT_URI :
@@ -960,7 +1037,7 @@ public class LauncherModel extends BroadcastReceiver {
// Lock on mBgLock *after* the db operation
synchronized (sBgLock) {
- checkItemInfoLocked(item.id, item, null);
+ checkItemInfoLocked(item.id, item, stackTrace);
sBgItemsIdMap.put(item.id, item);
switch (item.itemType) {
case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:
@@ -999,45 +1076,77 @@ public class LauncherModel extends BroadcastReceiver {
| ((int) screen & 0xFF) << 16 | (localCellX & 0xFF) << 8 | (localCellY & 0xFF);
}
+ 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);
+ }
+ };
+ 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));
+ }
+
/**
* Removes the specified item from the database
* @param context
* @param item
*/
static void deleteItemFromDatabase(Context context, final ItemInfo item) {
+ ArrayList<ItemInfo> items = new ArrayList<ItemInfo>();
+ items.add(item);
+ deleteItemsFromDatabase(context, items);
+ }
+
+ /**
+ * Removes the specified items from the database
+ * @param context
+ * @param item
+ */
+ static void deleteItemsFromDatabase(Context context, final ArrayList<ItemInfo> items) {
final ContentResolver cr = context.getContentResolver();
- final Uri uriToDelete = LauncherSettings.Favorites.getContentUri(item.id, false);
Runnable r = new Runnable() {
public void run() {
- cr.delete(uriToDelete, null, null);
+ for (ItemInfo item : items) {
+ final Uri uri = LauncherSettings.Favorites.getContentUri(item.id, false);
+ cr.delete(uri, null, null);
- // Lock on mBgLock *after* the db operation
- synchronized (sBgLock) {
- switch (item.itemType) {
- case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:
- sBgFolders.remove(item.id);
- for (ItemInfo info: sBgItemsIdMap.values()) {
- if (info.container == item.id) {
- // We are deleting a folder which still contains items that
- // think they are contained by that folder.
- String msg = "deleting a folder (" + item + ") which still " +
- "contains items (" + info + ")";
- Log.e(TAG, msg);
+ // Lock on mBgLock *after* the db operation
+ synchronized (sBgLock) {
+ switch (item.itemType) {
+ case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:
+ sBgFolders.remove(item.id);
+ for (ItemInfo info: sBgItemsIdMap.values()) {
+ if (info.container == item.id) {
+ // We are deleting a folder which still contains items that
+ // think they are contained by that folder.
+ String msg = "deleting a folder (" + item + ") which still " +
+ "contains items (" + info + ")";
+ Log.e(TAG, msg);
+ }
}
- }
- sBgWorkspaceItems.remove(item);
- break;
- case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:
- case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:
- sBgWorkspaceItems.remove(item);
- break;
- case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET:
- sBgAppWidgets.remove((LauncherAppWidgetInfo) item);
- break;
+ sBgWorkspaceItems.remove(item);
+ break;
+ case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:
+ case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:
+ sBgWorkspaceItems.remove(item);
+ break;
+ case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET:
+ sBgAppWidgets.remove((LauncherAppWidgetInfo) item);
+ break;
+ }
+ sBgItemsIdMap.remove(item.id);
+ sBgDbIconCache.remove(item);
}
- sBgItemsIdMap.remove(item.id);
- sBgDbIconCache.remove(item);
}
}
};
@@ -1136,74 +1245,67 @@ public class LauncherModel extends BroadcastReceiver {
}
}
- /**
- * Call from the handler for ACTION_PACKAGE_ADDED, ACTION_PACKAGE_REMOVED and
- * ACTION_PACKAGE_CHANGED.
- */
@Override
- public void onReceive(Context context, Intent intent) {
- if (DEBUG_LOADERS) Log.d(TAG, "onReceive intent=" + intent);
-
- final String action = intent.getAction();
+ public void onPackageChanged(String packageName, UserHandleCompat user) {
+ int op = PackageUpdatedTask.OP_UPDATE;
+ enqueuePackageUpdated(new PackageUpdatedTask(op, new String[] { packageName },
+ user));
+ }
- if (Intent.ACTION_PACKAGE_CHANGED.equals(action)
- || Intent.ACTION_PACKAGE_REMOVED.equals(action)
- || Intent.ACTION_PACKAGE_ADDED.equals(action)) {
- final String packageName = intent.getData().getSchemeSpecificPart();
- final boolean replacing = intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);
+ @Override
+ public void onPackageRemoved(String packageName, UserHandleCompat user) {
+ int op = PackageUpdatedTask.OP_REMOVE;
+ enqueuePackageUpdated(new PackageUpdatedTask(op, new String[] { packageName },
+ user));
+ }
- int op = PackageUpdatedTask.OP_NONE;
+ @Override
+ public void onPackageAdded(String packageName, UserHandleCompat user) {
+ int op = PackageUpdatedTask.OP_ADD;
+ enqueuePackageUpdated(new PackageUpdatedTask(op, new String[] { packageName },
+ user));
+ }
- if (packageName == null || packageName.length() == 0) {
- // they sent us a bad intent
- return;
+ @Override
+ public void onPackagesAvailable(String[] packageNames, UserHandleCompat user,
+ boolean replacing) {
+ if (!replacing) {
+ enqueuePackageUpdated(new PackageUpdatedTask(PackageUpdatedTask.OP_ADD, packageNames,
+ user));
+ if (mAppsCanBeOnRemoveableStorage) {
+ // Only rebind if we support removable storage. It catches the
+ // case where
+ // apps on the external sd card need to be reloaded
+ startLoaderFromBackground();
}
+ } else {
+ // If we are replacing then just update the packages in the list
+ enqueuePackageUpdated(new PackageUpdatedTask(PackageUpdatedTask.OP_UPDATE,
+ packageNames, user));
+ }
+ }
- if (Intent.ACTION_PACKAGE_CHANGED.equals(action)) {
- op = PackageUpdatedTask.OP_UPDATE;
- } else if (Intent.ACTION_PACKAGE_REMOVED.equals(action)) {
- if (!replacing) {
- op = PackageUpdatedTask.OP_REMOVE;
- }
- // else, we are replacing the package, so a PACKAGE_ADDED will be sent
- // later, we will update the package at this time
- } else if (Intent.ACTION_PACKAGE_ADDED.equals(action)) {
- if (!replacing) {
- op = PackageUpdatedTask.OP_ADD;
- } else {
- op = PackageUpdatedTask.OP_UPDATE;
- }
- }
+ @Override
+ public void onPackagesUnavailable(String[] packageNames, UserHandleCompat user,
+ boolean replacing) {
+ if (!replacing) {
+ enqueuePackageUpdated(new PackageUpdatedTask(
+ PackageUpdatedTask.OP_UNAVAILABLE, packageNames,
+ user));
+ }
- if (op != PackageUpdatedTask.OP_NONE) {
- enqueuePackageUpdated(new PackageUpdatedTask(op, new String[] { packageName }));
- }
+ }
- } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals(action)) {
- final boolean replacing = intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);
- String[] packages = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
- if (!replacing) {
- enqueuePackageUpdated(new PackageUpdatedTask(PackageUpdatedTask.OP_ADD, packages));
- if (mAppsCanBeOnRemoveableStorage) {
- // Only rebind if we support removable storage. It catches the case where
- // apps on the external sd card need to be reloaded
- startLoaderFromBackground();
- }
- } else {
- // If we are replacing then just update the packages in the list
- enqueuePackageUpdated(new PackageUpdatedTask(PackageUpdatedTask.OP_UPDATE,
- packages));
- }
- } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action)) {
- final boolean replacing = intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);
- if (!replacing) {
- String[] packages = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
- enqueuePackageUpdated(new PackageUpdatedTask(
- PackageUpdatedTask.OP_UNAVAILABLE, packages));
- }
- // else, we are replacing the packages, so ignore this event and wait for
- // EXTERNAL_APPLICATIONS_AVAILABLE to update the packages at that time
- } else if (Intent.ACTION_LOCALE_CHANGED.equals(action)) {
+ /**
+ * Call from the handler for ACTION_PACKAGE_ADDED, ACTION_PACKAGE_REMOVED and
+ * ACTION_PACKAGE_CHANGED.
+ */
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (DEBUG_RECEIVER) Log.d(TAG, "onReceive intent=" + intent);
+
+ final String action = intent.getAction();
+ if (Intent.ACTION_LOCALE_CHANGED.equals(action)) {
// If we have changed locale we need to clear out the labels in all apps/workspace.
forceReload();
} else if (Intent.ACTION_CONFIGURATION_CHANGED.equals(action)) {
@@ -1229,7 +1331,7 @@ public class LauncherModel extends BroadcastReceiver {
}
}
- private void forceReload() {
+ void forceReload() {
resetLoadedState(true, true);
// Do this here because if the launcher activity is running it will be restarted.
@@ -1284,6 +1386,10 @@ public class LauncherModel extends BroadcastReceiver {
return isLaunching;
}
+ public boolean isCurrentCallbacks(Callbacks callbacks) {
+ return (mCallbacks != null && mCallbacks.get() == callbacks);
+ }
+
public void startLoader(boolean isLaunching, int synchronousBindPage) {
startLoader(isLaunching, synchronousBindPage, LOADER_FLAG_NONE);
}
@@ -1296,7 +1402,9 @@ public class LauncherModel extends BroadcastReceiver {
// Clear any deferred bind-runnables from the synchronized load process
// We must do this before any loading/binding is scheduled below.
- mDeferredBindRunnables.clear();
+ synchronized (mDeferredBindRunnables) {
+ mDeferredBindRunnables.clear();
+ }
// Don't bother to start the thread if we know it's not going to do anything
if (mCallbacks != null && mCallbacks.get() != null) {
@@ -1318,10 +1426,15 @@ public class LauncherModel extends BroadcastReceiver {
void bindRemainingSynchronousPages() {
// Post the remaining side pages to be loaded
if (!mDeferredBindRunnables.isEmpty()) {
- for (final Runnable r : mDeferredBindRunnables) {
+ Runnable[] deferredBindRunnables = null;
+ synchronized (mDeferredBindRunnables) {
+ deferredBindRunnables = mDeferredBindRunnables.toArray(
+ new Runnable[mDeferredBindRunnables.size()]);
+ mDeferredBindRunnables.clear();
+ }
+ for (final Runnable r : deferredBindRunnables) {
mHandler.post(r, MAIN_THREAD_BINDING_RUNNABLE);
}
- mDeferredBindRunnables.clear();
}
}
@@ -1630,7 +1743,7 @@ public class LauncherModel extends BroadcastReceiver {
ArrayList<ItemInfo> added = new ArrayList<ItemInfo>();
synchronized (sBgLock) {
for (AppInfo app : mBgAllAppsList.data) {
- tmpInfos = getItemInfoForComponentName(app.componentName);
+ tmpInfos = getItemInfoForComponentName(app.componentName, app.user);
if (tmpInfos.isEmpty()) {
// We are missing an application icon, so add this to the workspace
added.add(app);
@@ -1760,6 +1873,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.SYSTEM_READY)) != null;
LauncherAppState app = LauncherAppState.getInstance();
DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
@@ -1778,22 +1894,23 @@ public class LauncherModel extends BroadcastReceiver {
} else {
// Make sure the default workspace is loaded
Launcher.addDumpLog(TAG, "loadWorkspace: loading default favorites", false);
- LauncherAppState.getLauncherProvider().loadDefaultFavoritesIfNecessary(0);
+ LauncherAppState.getLauncherProvider().loadDefaultFavoritesIfNecessary();
}
- // Check if we need to do any upgrade-path logic
- // (Includes having just imported default favorites)
- boolean loadedOldDb = LauncherAppState.getLauncherProvider().justLoadedOldDb();
+ // This code path is for our old migration code and should no longer be exercised
+ boolean loadedOldDb = false;
// Log to disk
Launcher.addDumpLog(TAG, "11683562 - loadedOldDb: " + loadedOldDb, true);
synchronized (sBgLock) {
clearSBgDataStructures();
+ final HashSet<String> installingPkgs = PackageInstallerCompat
+ .getInstance(mContext).updateAndGetActiveSessionCache();
final ArrayList<Long> itemsToRemove = new ArrayList<Long>();
final ArrayList<Long> restoredRows = new ArrayList<Long>();
- final Uri contentUri = LauncherSettings.Favorites.CONTENT_URI;
+ final Uri contentUri = LauncherSettings.Favorites.CONTENT_URI_NO_NOTIFICATION;
if (DEBUG_LOADERS) Log.d(TAG, "loading model from " + contentUri);
final Cursor c = contentResolver.query(contentUri, null, null, null, null);
@@ -1835,6 +1952,8 @@ public class LauncherModel extends BroadcastReceiver {
LauncherSettings.Favorites.SPANY);
final int restoredIndex = c.getColumnIndexOrThrow(
LauncherSettings.Favorites.RESTORED);
+ final int profileIdIndex = c.getColumnIndexOrThrow(
+ LauncherSettings.Favorites.PROFILE_ID);
//final int uriIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.URI);
//final int displayModeIndex = c.getColumnIndexOrThrow(
// LauncherSettings.Favorites.DISPLAY_MODE);
@@ -1845,43 +1964,119 @@ public class LauncherModel extends BroadcastReceiver {
int container;
long id;
Intent intent;
+ UserHandleCompat user;
while (!mStopped && c.moveToNext()) {
AtomicBoolean deleteOnInvalidPlacement = new AtomicBoolean(false);
try {
int itemType = c.getInt(itemTypeIndex);
boolean restored = 0 != c.getInt(restoredIndex);
+ boolean allowMissingTarget = false;
switch (itemType) {
case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:
case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:
id = c.getLong(idIndex);
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);
+ continue;
+ }
try {
intent = Intent.parseUri(intentDescription, 0);
ComponentName cn = intent.getComponent();
- if (cn != null && !isValidPackageComponent(manager, cn)) {
- if (restored) {
- // might be installed later
- Launcher.addDumpLog(TAG,
- "package not yet restored: " + cn, true);
- } else {
- if (!mAppsCanBeOnRemoveableStorage) {
- // Log the invalid package, and remove it
+ 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) {
+ 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 package removed: " + cn, true);
+ "Invalid component removed: " + cn, true);
itemsToRemove.add(id);
+ continue;
} else {
- // If apps can be on external storage, then we just
- // leave them for the user to remove (maybe add
- // visual treatment to it)
+ // 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.
+ Launcher.addDumpLog(TAG,
+ "package not yet restored: " + cn, true);
+
+ if ((promiseType & ShortcutInfo.FLAG_RESTORE_STARTED) != 0) {
+ // Restore has started once.
+ } else if (installingPkgs.contains(cn.getPackageName())) {
+ // App restore has started. Update the flag
+ promiseType |= ShortcutInfo.FLAG_RESTORE_STARTED;
+ ContentValues values = new ContentValues();
+ values.put(LauncherSettings.Favorites.RESTORED,
+ promiseType);
+ String where = BaseColumns._ID + "= ?";
+ String[] args = {Long.toString(id)};
+ contentResolver.update(contentUri, values, where, args);
+
+ } else if (REMOVE_UNRESTORED_ICONS) {
Launcher.addDumpLog(TAG,
- "Invalid package found: " + cn, true);
+ "Unrestored package removed: " + cn, true);
+ 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 {
+ // SdCard is not ready yet. Package might get available,
+ // once it is ready.
+ Launcher.addDumpLog(TAG, "Invalid package: " + cn
+ + " (check again later)", true);
+ HashSet<String> pkgs = sPendingPackages.get(user);
+ if (pkgs == null) {
+ pkgs = new HashSet<String>();
+ 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
+ } else if (cn == null) {
+ // For shortcuts with no component, keep them as they are
restoredRows.add(id);
restored = false;
}
@@ -1892,15 +2087,21 @@ public class LauncherModel extends BroadcastReceiver {
}
if (restored) {
- Launcher.addDumpLog(TAG,
- "constructing info for partially restored package",
- true);
- info = getRestoredItemInfo(c, titleIndex, intent);
- intent = getRestoredItemIntent(c, context, intent);
+ if (user.equals(UserHandleCompat.myUserHandle())) {
+ Launcher.addDumpLog(TAG,
+ "constructing info for partially restored package",
+ true);
+ info = getRestoredItemInfo(c, titleIndex, intent, promiseType);
+ intent = getRestoredItemIntent(c, context, intent);
+ } else {
+ // Don't restore items for other profiles.
+ itemsToRemove.add(id);
+ continue;
+ }
} else if (itemType ==
LauncherSettings.Favorites.ITEM_TYPE_APPLICATION) {
- info = getShortcutInfo(manager, intent, 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,
@@ -1929,6 +2130,9 @@ public class LauncherModel extends BroadcastReceiver {
info.cellY = c.getInt(cellYIndex);
info.spanX = 1;
info.spanY = 1;
+ info.intent.putExtra(ItemInfo.EXTRA_PROFILE, serialNumber);
+ info.isDisabled = isSafeMode
+ && !Utilities.isSystemApp(context, intent);
// check & update map of what's occupied
deleteOnInvalidPlacement.set(false);
@@ -2005,31 +2209,79 @@ public class LauncherModel extends BroadcastReceiver {
// Read all Launcher-specific widget details
int appWidgetId = c.getInt(appWidgetIdIndex);
String savedProvider = c.getString(appWidgetProviderIndex);
-
id = c.getLong(idIndex);
+ final ComponentName component =
+ ComponentName.unflattenFromString(savedProvider);
+
+ final int restoreStatus = c.getInt(restoredIndex);
+ final boolean isIdValid = (restoreStatus &
+ LauncherAppWidgetInfo.FLAG_ID_NOT_VALID) == 0;
- final AppWidgetProviderInfo provider =
- widgets.getAppWidgetInfo(appWidgetId);
+ final boolean wasProviderReady = (restoreStatus &
+ LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY) == 0;
- if (!isSafeMode && (provider == null || provider.provider == null ||
- provider.provider.getPackageName() == null)) {
- String log = "Deleting widget that isn't installed anymore: id="
- + id + " appWidgetId=" + appWidgetId;
+ final AppWidgetProviderInfo provider = isIdValid
+ ? widgets.getAppWidgetInfo(appWidgetId)
+ : findAppWidgetProviderInfoWithComponent(context, component);
+
+ final boolean isProviderReady = isValidProvider(provider);
+ if (!isSafeMode && wasProviderReady && !isProviderReady) {
+ String log = "Deleting widget that isn't installed anymore: "
+ + "id=" + id + " appWidgetId=" + appWidgetId;
Log.e(TAG, log);
Launcher.addDumpLog(TAG, log, false);
itemsToRemove.add(id);
} else {
- appWidgetInfo = new LauncherAppWidgetInfo(appWidgetId,
- provider.provider);
+ if (isProviderReady) {
+ appWidgetInfo = new LauncherAppWidgetInfo(appWidgetId,
+ provider.provider);
+ int[] minSpan =
+ Launcher.getMinSpanForWidget(context, provider);
+ appWidgetInfo.minSpanX = minSpan[0];
+ appWidgetInfo.minSpanY = minSpan[1];
+
+ int status = restoreStatus;
+ if (!wasProviderReady) {
+ // If provider was not previously ready, update the
+ // status and UI flag.
+
+ // Id would be valid only if the widget restore broadcast was received.
+ if (isIdValid) {
+ status = LauncherAppWidgetInfo.RESTORE_COMPLETED;
+ } else {
+ status &= ~LauncherAppWidgetInfo
+ .FLAG_PROVIDER_NOT_READY;
+ }
+ }
+ appWidgetInfo.restoreStatus = status;
+ } else {
+ Log.v(TAG, "Widget restore pending id=" + id
+ + " appWidgetId=" + appWidgetId
+ + " status =" + restoreStatus);
+ appWidgetInfo = new LauncherAppWidgetInfo(appWidgetId,
+ component);
+ appWidgetInfo.restoreStatus = restoreStatus;
+
+ if ((restoreStatus & LauncherAppWidgetInfo.FLAG_RESTORE_STARTED) != 0) {
+ // Restore has started once.
+ } else if (installingPkgs.contains(component.getPackageName())) {
+ // App restore has started. Update the flag
+ appWidgetInfo.restoreStatus |=
+ LauncherAppWidgetInfo.FLAG_RESTORE_STARTED;
+ } else if (REMOVE_UNRESTORED_ICONS) {
+ Launcher.addDumpLog(TAG,
+ "Unrestored widget removed: " + component, true);
+ itemsToRemove.add(id);
+ continue;
+ }
+ }
+
appWidgetInfo.id = id;
appWidgetInfo.screenId = c.getInt(screenIndex);
appWidgetInfo.cellX = c.getInt(cellXIndex);
appWidgetInfo.cellY = c.getInt(cellYIndex);
appWidgetInfo.spanX = c.getInt(spanXIndex);
appWidgetInfo.spanY = c.getInt(spanYIndex);
- int[] minSpan = Launcher.getMinSpanForWidget(context, provider);
- appWidgetInfo.minSpanX = minSpan[0];
- appWidgetInfo.minSpanY = minSpan[1];
container = c.getInt(containerIndex);
if (container != LauncherSettings.Favorites.CONTAINER_DESKTOP &&
@@ -2049,13 +2301,17 @@ public class LauncherModel extends BroadcastReceiver {
}
break;
}
- String providerName = provider.provider.flattenToString();
- if (!providerName.equals(savedProvider)) {
+
+ String providerName = appWidgetInfo.providerName.flattenToString();
+ if (!providerName.equals(savedProvider) ||
+ (appWidgetInfo.restoreStatus != restoreStatus)) {
ContentValues values = new ContentValues();
values.put(LauncherSettings.Favorites.APPWIDGET_PROVIDER,
providerName);
+ values.put(LauncherSettings.Favorites.RESTORED,
+ appWidgetInfo.restoreStatus);
String where = BaseColumns._ID + "= ?";
- String[] args = {Integer.toString(c.getInt(idIndex))};
+ String[] args = {Long.toString(id)};
contentResolver.update(contentUri, values, where, args);
}
sBgItemsIdMap.put(appWidgetInfo.id, appWidgetInfo);
@@ -2081,7 +2337,7 @@ public class LauncherModel extends BroadcastReceiver {
if (itemsToRemove.size() > 0) {
ContentProviderClient client = contentResolver.acquireContentProviderClient(
- LauncherSettings.Favorites.CONTENT_URI);
+ contentUri);
// Remove dead items
for (long id : itemsToRemove) {
if (DEBUG_LOADERS) {
@@ -2099,7 +2355,7 @@ public class LauncherModel extends BroadcastReceiver {
if (restoredRows.size() > 0) {
ContentProviderClient updater = contentResolver.acquireContentProviderClient(
- LauncherSettings.Favorites.CONTENT_URI);
+ contentUri);
// Update restored items that no longer require special handling
try {
StringBuilder selectionBuilder = new StringBuilder();
@@ -2109,13 +2365,19 @@ 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");
}
}
+ if (!isSdCardReady && !sPendingPackages.isEmpty()) {
+ context.registerReceiver(new AppsAvailabilityCheck(),
+ new IntentFilter(StartupReceiver.SYSTEM_READY),
+ null, sWorker);
+ }
+
if (loadedOldDb) {
long maxScreenId = 0;
// If we're importing we use the old screen order.
@@ -2189,7 +2451,12 @@ public class LauncherModel extends BroadcastReceiver {
line += " | ";
}
for (int x = 0; x < countX; x++) {
- line += ((occupied.get(screenId)[x][y] != null) ? "#" : ".");
+ ItemInfo[][] screen = occupied.get(screenId);
+ if (x < screen.length && y < screen[x].length) {
+ line += (screen[x][y] != null) ? "#" : ".";
+ } else {
+ line += "!";
+ }
}
}
Log.d(TAG, "[ " + line + " ]");
@@ -2343,7 +2610,9 @@ public class LauncherModel extends BroadcastReceiver {
}
};
if (postOnMainThread) {
- deferredBindRunnables.add(r);
+ synchronized (deferredBindRunnables) {
+ deferredBindRunnables.add(r);
+ }
} else {
runOnMainThread(r, MAIN_THREAD_BINDING_RUNNABLE);
}
@@ -2360,7 +2629,9 @@ public class LauncherModel extends BroadcastReceiver {
}
};
if (postOnMainThread) {
- deferredBindRunnables.add(r);
+ synchronized (deferredBindRunnables) {
+ deferredBindRunnables.add(r);
+ }
} else {
runOnMainThread(r, MAIN_THREAD_BINDING_RUNNABLE);
}
@@ -2482,7 +2753,9 @@ public class LauncherModel extends BroadcastReceiver {
// Load all the remaining pages (if we are loading synchronously, we want to defer this
// work until after the first render)
- mDeferredBindRunnables.clear();
+ synchronized (mDeferredBindRunnables) {
+ mDeferredBindRunnables.clear();
+ }
bindWorkspaceItems(oldCallbacks, otherWorkspaceItems, otherAppWidgets, otherFolders,
(isLoadingSynchronously ? mDeferredBindRunnables : null));
@@ -2504,7 +2777,9 @@ public class LauncherModel extends BroadcastReceiver {
}
};
if (isLoadingSynchronously) {
- mDeferredBindRunnables.add(r);
+ synchronized (mDeferredBindRunnables) {
+ mDeferredBindRunnables.add(r);
+ }
} else {
runOnMainThread(r, MAIN_THREAD_BINDING_RUNNABLE);
}
@@ -2570,42 +2845,42 @@ public class LauncherModel extends BroadcastReceiver {
return;
}
- final PackageManager packageManager = mContext.getPackageManager();
final Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);
mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);
+ final List<UserHandleCompat> profiles = mUserManager.getUserProfiles();
+
// Clear the list of apps
mBgAllAppsList.clear();
+ for (UserHandleCompat user : profiles) {
+ // Query for the set of apps
+ final long qiaTime = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0;
+ List<LauncherActivityInfoCompat> apps = mLauncherApps.getActivityList(null, user);
+ if (DEBUG_LOADERS) {
+ Log.d(TAG, "getActivityList took "
+ + (SystemClock.uptimeMillis()-qiaTime) + "ms for user " + user);
+ Log.d(TAG, "getActivityList got " + apps.size() + " apps for user " + user);
+ }
+ // Fail if we don't have any apps
+ if (apps == null || apps.isEmpty()) {
+ return;
+ }
+ // Sort the applications by name
+ final long sortTime = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0;
+ Collections.sort(apps,
+ new LauncherModel.ShortcutNameComparator(mLabelCache));
+ if (DEBUG_LOADERS) {
+ Log.d(TAG, "sort took "
+ + (SystemClock.uptimeMillis()-sortTime) + "ms");
+ }
- // Query for the set of apps
- final long qiaTime = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0;
- List<ResolveInfo> apps = packageManager.queryIntentActivities(mainIntent, 0);
- if (DEBUG_LOADERS) {
- Log.d(TAG, "queryIntentActivities took "
- + (SystemClock.uptimeMillis()-qiaTime) + "ms");
- Log.d(TAG, "queryIntentActivities got " + apps.size() + " apps");
- }
- // Fail if we don't have any apps
- if (apps == null || apps.isEmpty()) {
- return;
- }
- // Sort the applications by name
- final long sortTime = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0;
- Collections.sort(apps,
- new LauncherModel.ShortcutNameComparator(packageManager, mLabelCache));
- if (DEBUG_LOADERS) {
- Log.d(TAG, "sort took "
- + (SystemClock.uptimeMillis()-sortTime) + "ms");
- }
-
- // Create the ApplicationInfos
- for (int i = 0; i < apps.size(); i++) {
- ResolveInfo app = apps.get(i);
- // This builds the icon bitmaps.
- mBgAllAppsList.add(new AppInfo(packageManager, app,
- mIconCache, mLabelCache));
+ // Create the ApplicationInfos
+ for (int i = 0; i < apps.size(); i++) {
+ LauncherActivityInfoCompat app = apps.get(i);
+ // This builds the icon bitmaps.
+ mBgAllAppsList.add(new AppInfo(mContext, app, user, mIconCache, mLabelCache));
+ }
}
-
// Huh? Shouldn't this be inside the Runnable below?
final ArrayList<AppInfo> added = mBgAllAppsList.added;
mBgAllAppsList.added = new ArrayList<AppInfo>();
@@ -2648,9 +2923,95 @@ 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<String> packagesRemoved;
+ for (Entry<UserHandleCompat, HashSet<String>> entry : sPendingPackages.entrySet()) {
+ UserHandleCompat user = entry.getKey();
+ packagesRemoved = new ArrayList<String>();
+ 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();
+ }
+ }
+ }
+
+ /**
+ * Workaround to re-check unrestored items, in-case they were installed but the Package-ADD
+ * runnable was missed by the launcher.
+ */
+ public void recheckRestoredItems(final Context context) {
+ Runnable r = new Runnable() {
+
+ @Override
+ public void run() {
+ LauncherAppsCompat launcherApps = LauncherAppsCompat.getInstance(context);
+ HashSet<String> installedPackages = new HashSet<String>();
+ UserHandleCompat user = UserHandleCompat.myUserHandle();
+ synchronized(sBgLock) {
+ for (ItemInfo info : sBgItemsIdMap.values()) {
+ if (info instanceof ShortcutInfo) {
+ ShortcutInfo si = (ShortcutInfo) info;
+ if (si.isPromise() && si.getTargetComponent() != null
+ && launcherApps.isPackageEnabledForProfile(
+ si.getTargetComponent().getPackageName(), user)) {
+ installedPackages.add(si.getTargetComponent().getPackageName());
+ }
+ } else if (info instanceof LauncherAppWidgetInfo) {
+ LauncherAppWidgetInfo widget = (LauncherAppWidgetInfo) info;
+ if (widget.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY)
+ && launcherApps.isPackageEnabledForProfile(
+ widget.providerName.getPackageName(), user)) {
+ installedPackages.add(widget.providerName.getPackageName());
+ }
+ }
+ }
+ }
+
+ if (!installedPackages.isEmpty()) {
+ final ArrayList<AppInfo> restoredApps = new ArrayList<AppInfo>();
+ for (String pkg : installedPackages) {
+ for (LauncherActivityInfoCompat info : launcherApps.getActivityList(pkg, user)) {
+ restoredApps.add(new AppInfo(context, info, user, mIconCache, null));
+ }
+ }
+
+ final Callbacks callbacks = mCallbacks != null ? mCallbacks.get() : null;
+ if (!restoredApps.isEmpty()) {
+ mHandler.post(new Runnable() {
+ public void run() {
+ Callbacks cb = mCallbacks != null ? mCallbacks.get() : null;
+ if (callbacks == cb && cb != null) {
+ callbacks.bindAppsRestored(restoredApps);
+ }
+ }
+ });
+ }
+
+ }
+ }
+ };
+ sWorker.post(r);
+ }
+
private class PackageUpdatedTask implements Runnable {
int mOp;
String[] mPackages;
+ UserHandleCompat mUser;
public static final int OP_NONE = 0;
public static final int OP_ADD = 1;
@@ -2659,9 +3020,10 @@ public class LauncherModel extends BroadcastReceiver {
public static final int OP_UNAVAILABLE = 4; // external media unmounted
- public PackageUpdatedTask(int op, String[] packages) {
+ public PackageUpdatedTask(int op, String[] packages, UserHandleCompat user) {
mOp = op;
mPackages = packages;
+ mUser = user;
}
public void run() {
@@ -2673,14 +3035,14 @@ public class LauncherModel extends BroadcastReceiver {
case OP_ADD:
for (int i=0; i<N; i++) {
if (DEBUG_LOADERS) Log.d(TAG, "mAllAppsList.addPackage " + packages[i]);
- mIconCache.remove(packages[i]);
- mBgAllAppsList.addPackage(context, packages[i]);
+ mIconCache.remove(packages[i], mUser);
+ mBgAllAppsList.addPackage(context, packages[i], mUser);
}
break;
case OP_UPDATE:
for (int i=0; i<N; i++) {
if (DEBUG_LOADERS) Log.d(TAG, "mAllAppsList.updatePackage " + packages[i]);
- mBgAllAppsList.updatePackage(context, packages[i]);
+ mBgAllAppsList.updatePackage(context, packages[i], mUser);
WidgetPreviewLoader.removePackageFromDb(
mApp.getWidgetPreviewCacheDb(), packages[i]);
}
@@ -2689,7 +3051,7 @@ public class LauncherModel extends BroadcastReceiver {
case OP_UNAVAILABLE:
for (int i=0; i<N; i++) {
if (DEBUG_LOADERS) Log.d(TAG, "mAllAppsList.removePackage " + packages[i]);
- mBgAllAppsList.removePackage(packages[i]);
+ mBgAllAppsList.removePackage(packages[i], mUser);
WidgetPreviewLoader.removePackageFromDb(
mApp.getWidgetPreviewCacheDb(), packages[i]);
}
@@ -2735,11 +3097,12 @@ public class LauncherModel extends BroadcastReceiver {
// Update the launcher db to reflect the changes
for (AppInfo a : modifiedFinal) {
ArrayList<ItemInfo> infos =
- getItemInfoForComponentName(a.componentName);
+ getItemInfoForComponentName(a.componentName, mUser);
for (ItemInfo i : infos) {
if (isShortcutInfoUpdateable(i)) {
ShortcutInfo info = (ShortcutInfo) i;
info.title = a.title.toString();
+ info.contentDescription = a.contentDescription;
updateItemInDatabase(context, info);
}
}
@@ -2764,24 +3127,19 @@ public class LauncherModel extends BroadcastReceiver {
// Mark disabled packages in the broadcast to be removed
final PackageManager pm = context.getPackageManager();
for (int i=0; i<N; i++) {
- if (isPackageDisabled(pm, packages[i])) {
+ if (isPackageDisabled(context, packages[i], mUser)) {
removedPackageNames.add(packages[i]);
}
}
}
// Remove all the components associated with this package
for (String pn : removedPackageNames) {
- ArrayList<ItemInfo> infos = getItemInfoForPackageName(pn);
- for (ItemInfo i : infos) {
- deleteItemFromDatabase(context, i);
- }
+ deletePackageFromDatabase(context, pn, mUser);
}
// Remove all the specific components
for (AppInfo a : removedApps) {
- ArrayList<ItemInfo> infos = getItemInfoForComponentName(a.componentName);
- for (ItemInfo i : infos) {
- deleteItemFromDatabase(context, i);
- }
+ ArrayList<ItemInfo> infos = getItemInfoForComponentName(a.componentName, mUser);
+ deleteItemsFromDatabase(context, infos);
}
if (!removedPackageNames.isEmpty() || !removedApps.isEmpty()) {
// Remove any queued items from the install queue
@@ -2794,14 +3152,14 @@ public class LauncherModel extends BroadcastReceiver {
public void run() {
Callbacks cb = mCallbacks != null ? mCallbacks.get() : null;
if (callbacks == cb && cb != null) {
- callbacks.bindComponentsRemoved(removedPackageNames, removedApps);
+ callbacks.bindComponentsRemoved(removedPackageNames, removedApps, mUser);
}
}
});
}
final ArrayList<Object> widgetsAndShortcuts =
- getSortedWidgetsAndShortcuts(context);
+ getSortedWidgetsAndShortcuts(context);
mHandler.post(new Runnable() {
@Override
public void run() {
@@ -2828,55 +3186,70 @@ public class LauncherModel extends BroadcastReceiver {
public static ArrayList<Object> getSortedWidgetsAndShortcuts(Context context) {
PackageManager packageManager = context.getPackageManager();
final ArrayList<Object> widgetsAndShortcuts = new ArrayList<Object>();
- widgetsAndShortcuts.addAll(AppWidgetManager.getInstance(context).getInstalledProviders());
+ widgetsAndShortcuts.addAll(AppWidgetManagerCompat.getInstance(context).getAllProviders());
+
Intent shortcutsIntent = new Intent(Intent.ACTION_CREATE_SHORTCUT);
widgetsAndShortcuts.addAll(packageManager.queryIntentActivities(shortcutsIntent, 0));
- Collections.sort(widgetsAndShortcuts,
- new LauncherModel.WidgetAndShortcutNameComparator(packageManager));
+ Collections.sort(widgetsAndShortcuts, new WidgetAndShortcutNameComparator(context));
return widgetsAndShortcuts;
}
- private static boolean isPackageDisabled(PackageManager pm, String packageName) {
- try {
- PackageInfo pi = pm.getPackageInfo(packageName, 0);
- return !pi.applicationInfo.enabled;
- } catch (NameNotFoundException e) {
- // Fall through
- }
- return false;
+ private static boolean isPackageDisabled(Context context, String packageName,
+ UserHandleCompat user) {
+ final LauncherAppsCompat launcherApps = LauncherAppsCompat.getInstance(context);
+ return !launcherApps.isPackageEnabledForProfile(packageName, user);
}
- public static boolean isValidPackageComponent(PackageManager pm, ComponentName cn) {
+ public static boolean isValidPackageActivity(Context context, ComponentName cn,
+ UserHandleCompat user) {
if (cn == null) {
return false;
}
- if (isPackageDisabled(pm, cn.getPackageName())) {
+ final LauncherAppsCompat launcherApps = LauncherAppsCompat.getInstance(context);
+ if (!launcherApps.isPackageEnabledForProfile(cn.getPackageName(), user)) {
return false;
}
+ return launcherApps.isActivityEnabledForProfile(cn, user);
+ }
- try {
- // Check the activity
- PackageInfo pi = pm.getPackageInfo(cn.getPackageName(), 0);
- return (pm.getActivityInfo(cn, 0) != null);
- } catch (NameNotFoundException e) {
+ public static boolean isValidPackage(Context context, String packageName,
+ UserHandleCompat user) {
+ if (packageName == null) {
return false;
}
+ final LauncherAppsCompat launcherApps = LauncherAppsCompat.getInstance(context);
+ return launcherApps.isPackageEnabledForProfile(packageName, user);
}
/**
* Make an ShortcutInfo object for a restored application or shortcut item that points
* to a package that is not yet installed on the system.
*/
- public ShortcutInfo getRestoredItemInfo(Cursor cursor, int titleIndex, Intent intent) {
+ public ShortcutInfo getRestoredItemInfo(Cursor cursor, int titleIndex, Intent intent,
+ int promiseType) {
final ShortcutInfo info = new ShortcutInfo();
- if (cursor != null) {
- info.title = cursor.getString(titleIndex);
+ info.user = UserHandleCompat.myUserHandle();
+ mIconCache.getTitleAndIcon(info, intent, info.user, true);
+
+ if ((promiseType & ShortcutInfo.FLAG_RESTORED_ICON) != 0) {
+ String title = (cursor != null) ? cursor.getString(titleIndex) : null;
+ if (!TextUtils.isEmpty(title)) {
+ info.title = title;
+ }
+ info.status = ShortcutInfo.FLAG_RESTORED_ICON;
+ } else if ((promiseType & ShortcutInfo.FLAG_AUTOINTALL_ICON) != 0) {
+ if (TextUtils.isEmpty(info.title)) {
+ info.title = (cursor != null) ? cursor.getString(titleIndex) : "";
+ }
+ info.status = ShortcutInfo.FLAG_AUTOINTALL_ICON;
} else {
- info.title = "";
+ throw new InvalidParameterException("Invalid restoreType " + promiseType);
}
- info.setIcon(mIconCache.getIcon(intent, info.title.toString()));
+
+ info.contentDescription = mUserManager.getBadgedLabelForUser(
+ info.title.toString(), info.user);
info.itemType = LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT;
- info.restoredIntent = intent;
+ info.promisedIntent = intent;
return info;
}
@@ -2885,25 +3258,26 @@ public class LauncherModel extends BroadcastReceiver {
* to the market page for the item.
*/
private Intent getRestoredItemIntent(Cursor c, Context context, Intent intent) {
- final boolean debug = false;
ComponentName componentName = intent.getComponent();
- Intent marketIntent = new Intent(Intent.ACTION_VIEW);
- Uri marketUri = new Uri.Builder()
+ return getMarketIntent(componentName.getPackageName());
+ }
+
+ static Intent getMarketIntent(String packageName) {
+ return new Intent(Intent.ACTION_VIEW)
+ .setData(new Uri.Builder()
.scheme("market")
.authority("details")
- .appendQueryParameter("id", componentName.getPackageName())
- .build();
- if (debug) Log.d(TAG, "manufactured intent uri: " + marketUri.toString());
- marketIntent.setData(marketUri);
- return marketIntent;
+ .appendQueryParameter("id", packageName)
+ .build());
}
/**
* This is called from the code that adds shortcuts from the intent receiver. This
* doesn't have a Cursor, but
*/
- public ShortcutInfo getShortcutInfo(PackageManager manager, Intent intent, Context context) {
- return getShortcutInfo(manager, intent, context, null, -1, -1, null);
+ public ShortcutInfo getShortcutInfo(PackageManager manager, Intent intent,
+ UserHandleCompat user, Context context) {
+ return getShortcutInfo(manager, intent, user, context, null, -1, -1, null, false);
}
/**
@@ -2911,54 +3285,37 @@ public class LauncherModel extends BroadcastReceiver {
*
* If c is not null, then it will be used to fill in missing data like the title and icon.
*/
- public ShortcutInfo getShortcutInfo(PackageManager manager, Intent intent, Context context,
- Cursor c, int iconIndex, int titleIndex, HashMap<Object, CharSequence> labelCache) {
+ public ShortcutInfo getShortcutInfo(PackageManager manager, Intent intent,
+ UserHandleCompat user, Context context, Cursor c, int iconIndex, int titleIndex,
+ HashMap<Object, CharSequence> labelCache, boolean allowMissingTarget) {
+ if (user == null) {
+ Log.d(TAG, "Null user found in getShortcutInfo");
+ return null;
+ }
+
ComponentName componentName = intent.getComponent();
- final ShortcutInfo info = new ShortcutInfo();
- if (componentName != null && !isValidPackageComponent(manager, componentName)) {
- Log.d(TAG, "Invalid package found in getShortcutInfo: " + componentName);
+ if (componentName == null) {
+ Log.d(TAG, "Missing component found in getShortcutInfo: " + componentName);
+ return null;
+ }
+
+ Intent newIntent = new Intent(intent.getAction(), null);
+ newIntent.addCategory(Intent.CATEGORY_LAUNCHER);
+ newIntent.setComponent(componentName);
+ LauncherActivityInfoCompat lai = mLauncherApps.resolveActivity(newIntent, user);
+ if ((lai == null) && !allowMissingTarget) {
+ Log.d(TAG, "Missing activity found in getShortcutInfo: " + componentName);
return null;
- } else {
- try {
- PackageInfo pi = manager.getPackageInfo(componentName.getPackageName(), 0);
- info.initFlagsAndFirstInstallTime(pi);
- } catch (NameNotFoundException e) {
- Log.d(TAG, "getPackInfo failed for package " +
- componentName.getPackageName());
- }
}
- // TODO: See if the PackageManager knows about this case. If it doesn't
- // then return null & delete this.
+ final ShortcutInfo info = new ShortcutInfo();
// the resource -- This may implicitly give us back the fallback icon,
// but don't worry about that. All we're doing with usingFallbackIcon is
// to avoid saving lots of copies of that in the database, and most apps
// have icons anyway.
+ Bitmap icon = mIconCache.getIcon(componentName, lai, labelCache);
- // Attempt to use queryIntentActivities to get the ResolveInfo (with IntentFilter info) and
- // if that fails, or is ambiguious, fallback to the standard way of getting the resolve info
- // via resolveActivity().
- Bitmap icon = null;
- ResolveInfo resolveInfo = null;
- ComponentName oldComponent = intent.getComponent();
- Intent newIntent = new Intent(intent.getAction(), null);
- newIntent.addCategory(Intent.CATEGORY_LAUNCHER);
- newIntent.setPackage(oldComponent.getPackageName());
- List<ResolveInfo> infos = manager.queryIntentActivities(newIntent, 0);
- for (ResolveInfo i : infos) {
- ComponentName cn = new ComponentName(i.activityInfo.packageName,
- i.activityInfo.name);
- if (cn.equals(oldComponent)) {
- resolveInfo = i;
- }
- }
- if (resolveInfo == null) {
- resolveInfo = manager.resolveActivity(intent, 0);
- }
- if (resolveInfo != null) {
- icon = mIconCache.getIcon(componentName, resolveInfo, labelCache);
- }
// the db
if (icon == null) {
if (c != null) {
@@ -2967,21 +3324,21 @@ public class LauncherModel extends BroadcastReceiver {
}
// the fallback icon
if (icon == null) {
- icon = getFallbackIcon();
+ icon = mIconCache.getDefaultIcon(user);
info.usingFallbackIcon = true;
}
info.setIcon(icon);
+ // From the cache.
+ if (labelCache != null) {
+ info.title = labelCache.get(componentName);
+ }
+
// from the resource
- if (resolveInfo != null) {
- ComponentName key = LauncherModel.getComponentNameFromResolveInfo(resolveInfo);
- if (labelCache != null && labelCache.containsKey(key)) {
- info.title = labelCache.get(key);
- } else {
- info.title = resolveInfo.activityInfo.loadLabel(manager);
- if (labelCache != null) {
- labelCache.put(key, info.title);
- }
+ if (info.title == null && lai != null) {
+ info.title = lai.getLabel();
+ if (labelCache != null) {
+ labelCache.put(componentName, info.title);
}
}
// from the db
@@ -2995,6 +3352,9 @@ public class LauncherModel extends BroadcastReceiver {
info.title = componentName.getClassName();
}
info.itemType = LauncherSettings.Favorites.ITEM_TYPE_APPLICATION;
+ info.user = user;
+ info.contentDescription = mUserManager.getBadgedLabelForUser(
+ info.title.toString(), info.user);
return info;
}
@@ -3004,14 +3364,14 @@ public class LauncherModel extends BroadcastReceiver {
for (ItemInfo i : infos) {
if (i instanceof ShortcutInfo) {
ShortcutInfo info = (ShortcutInfo) i;
- ComponentName cn = info.intent.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();
+ ComponentName cn = s.getTargetComponent();
if (cn != null && f.filterItem(info, s, cn)) {
filtered.add(s);
}
@@ -3027,21 +3387,16 @@ public class LauncherModel extends BroadcastReceiver {
return new ArrayList<ItemInfo>(filtered);
}
- private ArrayList<ItemInfo> getItemInfoForPackageName(final String pn) {
+ private ArrayList<ItemInfo> getItemInfoForComponentName(final ComponentName cname,
+ final UserHandleCompat user) {
ItemInfoFilter filter = new ItemInfoFilter() {
@Override
public boolean filterItem(ItemInfo parent, ItemInfo info, ComponentName cn) {
- return cn.getPackageName().equals(pn);
- }
- };
- return filterItemInfos(sBgItemsIdMap.values(), filter);
- }
-
- private ArrayList<ItemInfo> getItemInfoForComponentName(final ComponentName cname) {
- ItemInfoFilter filter = new ItemInfoFilter() {
- @Override
- public boolean filterItem(ItemInfo parent, ItemInfo info, ComponentName cn) {
- return cn.equals(cname);
+ if (info.user == null) {
+ return cn.equals(cname);
+ } else {
+ return cn.equals(cname) && info.user.equals(user);
+ }
}
};
return filterItemInfos(sBgItemsIdMap.values(), filter);
@@ -3060,7 +3415,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;
}
}
@@ -3076,6 +3431,8 @@ public class LauncherModel extends BroadcastReceiver {
Bitmap icon = null;
final ShortcutInfo info = new ShortcutInfo();
+ // Non-app shortcuts are only supported for current user.
+ info.user = UserHandleCompat.myUserHandle();
info.itemType = LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT;
// TODO: If there's an explicit component and we can't install that, delete it.
@@ -3106,14 +3463,14 @@ public class LauncherModel extends BroadcastReceiver {
}
// the fallback icon
if (icon == null) {
- icon = getFallbackIcon();
+ icon = mIconCache.getDefaultIcon(info.user);
info.usingFallbackIcon = true;
}
break;
case LauncherSettings.Favorites.ICON_TYPE_BITMAP:
icon = getIconFromCursor(c, iconIndex, context);
if (icon == null) {
- icon = getFallbackIcon();
+ icon = mIconCache.getDefaultIcon(info.user);
info.customIcon = false;
info.usingFallbackIcon = true;
} else {
@@ -3121,7 +3478,7 @@ public class LauncherModel extends BroadcastReceiver {
}
break;
default:
- icon = getFallbackIcon();
+ icon = mIconCache.getDefaultIcon(info.user);
info.usingFallbackIcon = true;
info.customIcon = false;
break;
@@ -3160,7 +3517,7 @@ public class LauncherModel extends BroadcastReceiver {
/**
* Attempts to find an AppWidgetProviderInfo that matches the given component.
*/
- AppWidgetProviderInfo findAppWidgetProviderInfoWithComponent(Context context,
+ static AppWidgetProviderInfo findAppWidgetProviderInfoWithComponent(Context context,
ComponentName component) {
List<AppWidgetProviderInfo> widgets =
AppWidgetManager.getInstance(context).getInstalledProviders();
@@ -3172,44 +3529,6 @@ public class LauncherModel extends BroadcastReceiver {
return null;
}
- /**
- * Returns a list of all the widgets that can handle configuration with a particular mimeType.
- */
- List<WidgetMimeTypeHandlerData> resolveWidgetsForMimeType(Context context, String mimeType) {
- final PackageManager packageManager = context.getPackageManager();
- final List<WidgetMimeTypeHandlerData> supportedConfigurationActivities =
- new ArrayList<WidgetMimeTypeHandlerData>();
-
- final Intent supportsIntent =
- new Intent(InstallWidgetReceiver.ACTION_SUPPORTS_CLIPDATA_MIMETYPE);
- supportsIntent.setType(mimeType);
-
- // Create a set of widget configuration components that we can test against
- final List<AppWidgetProviderInfo> widgets =
- AppWidgetManager.getInstance(context).getInstalledProviders();
- final HashMap<ComponentName, AppWidgetProviderInfo> configurationComponentToWidget =
- new HashMap<ComponentName, AppWidgetProviderInfo>();
- for (AppWidgetProviderInfo info : widgets) {
- configurationComponentToWidget.put(info.configure, info);
- }
-
- // Run through each of the intents that can handle this type of clip data, and cross
- // reference them with the components that are actual configuration components
- final List<ResolveInfo> activities = packageManager.queryIntentActivities(supportsIntent,
- PackageManager.MATCH_DEFAULT_ONLY);
- for (ResolveInfo info : activities) {
- final ActivityInfo activityInfo = info.activityInfo;
- final ComponentName infoComponent = new ComponentName(activityInfo.packageName,
- activityInfo.name);
- if (configurationComponentToWidget.containsKey(infoComponent)) {
- supportedConfigurationActivities.add(
- new InstallWidgetReceiver.WidgetMimeTypeHandlerData(info,
- configurationComponentToWidget.get(infoComponent)));
- }
- }
- return supportedConfigurationActivities;
- }
-
ShortcutInfo infoFromShortcutIntent(Context context, Intent data, Bitmap fallbackIcon) {
Intent intent = data.getParcelableExtra(Intent.EXTRA_SHORTCUT_INTENT);
String name = data.getStringExtra(Intent.EXTRA_SHORTCUT_NAME);
@@ -3238,7 +3557,8 @@ public class LauncherModel extends BroadcastReceiver {
iconResource.packageName);
final int id = resources.getIdentifier(iconResource.resourceName, null, null);
icon = Utilities.createIconBitmap(
- mIconCache.getFullResIcon(resources, id), context);
+ mIconCache.getFullResIcon(resources, id),
+ context);
} catch (Exception e) {
Log.w(TAG, "Could not load shortcut icon: " + extra);
}
@@ -3247,17 +3567,22 @@ public class LauncherModel extends BroadcastReceiver {
final ShortcutInfo info = new ShortcutInfo();
+ // Only support intents for current user for now. Intents sent from other
+ // users wouldn't get here without intent forwarding anyway.
+ info.user = UserHandleCompat.myUserHandle();
if (icon == null) {
if (fallbackIcon != null) {
icon = fallbackIcon;
} else {
- icon = getFallbackIcon();
+ icon = mIconCache.getDefaultIcon(info.user);
info.usingFallbackIcon = true;
}
}
info.setIcon(icon);
info.title = name;
+ info.contentDescription = mUserManager.getBadgedLabelForUser(
+ info.title.toString(), info.user);
info.intent = intent;
info.customIcon = customIcon;
info.iconResource = iconResource;
@@ -3323,12 +3648,18 @@ public class LauncherModel extends BroadcastReceiver {
final Collator collator = Collator.getInstance();
return new Comparator<AppInfo>() {
public final int compare(AppInfo a, AppInfo b) {
- int result = collator.compare(a.title.toString().trim(),
- b.title.toString().trim());
- if (result == 0) {
- result = a.componentName.compareTo(b.componentName);
+ if (a.user.equals(b.user)) {
+ int result = collator.compare(a.title.toString().trim(),
+ b.title.toString().trim());
+ if (result == 0) {
+ result = a.componentName.compareTo(b.componentName);
+ }
+ return result;
+ } else {
+ // TODO Need to figure out rules for sorting
+ // profiles, this puts work second.
+ return a.user.toString().compareTo(b.user.toString());
}
- return result;
}
};
}
@@ -3340,14 +3671,6 @@ public class LauncherModel extends BroadcastReceiver {
return 0;
}
};
- public static final Comparator<AppWidgetProviderInfo> getWidgetNameComparator() {
- final Collator collator = Collator.getInstance();
- return new Comparator<AppWidgetProviderInfo>() {
- public final int compare(AppWidgetProviderInfo a, AppWidgetProviderInfo b) {
- return collator.compare(a.label.toString().trim(), b.label.toString().trim());
- }
- };
- }
static ComponentName getComponentNameFromResolveInfo(ResolveInfo info) {
if (info.activityInfo != null) {
return new ComponentName(info.activityInfo.packageName, info.activityInfo.name);
@@ -3355,35 +3678,32 @@ public class LauncherModel extends BroadcastReceiver {
return new ComponentName(info.serviceInfo.packageName, info.serviceInfo.name);
}
}
- public static class ShortcutNameComparator implements Comparator<ResolveInfo> {
+ public static class ShortcutNameComparator implements Comparator<LauncherActivityInfoCompat> {
private Collator mCollator;
- private PackageManager mPackageManager;
private HashMap<Object, CharSequence> mLabelCache;
ShortcutNameComparator(PackageManager pm) {
- mPackageManager = pm;
mLabelCache = new HashMap<Object, CharSequence>();
mCollator = Collator.getInstance();
}
- ShortcutNameComparator(PackageManager pm, HashMap<Object, CharSequence> labelCache) {
- mPackageManager = pm;
+ ShortcutNameComparator(HashMap<Object, CharSequence> labelCache) {
mLabelCache = labelCache;
mCollator = Collator.getInstance();
}
- public final int compare(ResolveInfo a, ResolveInfo b) {
- CharSequence labelA, labelB;
- ComponentName keyA = LauncherModel.getComponentNameFromResolveInfo(a);
- ComponentName keyB = LauncherModel.getComponentNameFromResolveInfo(b);
+ public final int compare(LauncherActivityInfoCompat a, LauncherActivityInfoCompat b) {
+ String labelA, labelB;
+ ComponentName keyA = a.getComponentName();
+ ComponentName keyB = b.getComponentName();
if (mLabelCache.containsKey(keyA)) {
- labelA = mLabelCache.get(keyA);
+ labelA = mLabelCache.get(keyA).toString();
} else {
- labelA = a.loadLabel(mPackageManager).toString().trim();
+ labelA = a.getLabel().toString().trim();
mLabelCache.put(keyA, labelA);
}
if (mLabelCache.containsKey(keyB)) {
- labelB = mLabelCache.get(keyB);
+ labelB = mLabelCache.get(keyB).toString();
} else {
- labelB = b.loadLabel(mPackageManager).toString().trim();
+ labelB = b.getLabel().toString().trim();
mLabelCache.put(keyB, labelB);
}
@@ -3391,11 +3711,14 @@ public class LauncherModel extends BroadcastReceiver {
}
};
public static class WidgetAndShortcutNameComparator implements Comparator<Object> {
- private Collator mCollator;
- private PackageManager mPackageManager;
- private HashMap<Object, String> mLabelCache;
- WidgetAndShortcutNameComparator(PackageManager pm) {
- mPackageManager = pm;
+ private final AppWidgetManagerCompat mManager;
+ private final PackageManager mPackageManager;
+ private final HashMap<Object, String> mLabelCache;
+ private final Collator mCollator;
+
+ WidgetAndShortcutNameComparator(Context context) {
+ mManager = AppWidgetManagerCompat.getInstance(context);
+ mPackageManager = context.getPackageManager();
mLabelCache = new HashMap<Object, String>();
mCollator = Collator.getInstance();
}
@@ -3404,23 +3727,28 @@ public class LauncherModel extends BroadcastReceiver {
if (mLabelCache.containsKey(a)) {
labelA = mLabelCache.get(a);
} else {
- labelA = (a instanceof AppWidgetProviderInfo) ?
- ((AppWidgetProviderInfo) a).label :
- ((ResolveInfo) a).loadLabel(mPackageManager).toString().trim();
+ labelA = (a instanceof AppWidgetProviderInfo)
+ ? mManager.loadLabel((AppWidgetProviderInfo) a)
+ : ((ResolveInfo) a).loadLabel(mPackageManager).toString().trim();
mLabelCache.put(a, labelA);
}
if (mLabelCache.containsKey(b)) {
labelB = mLabelCache.get(b);
} else {
- labelB = (b instanceof AppWidgetProviderInfo) ?
- ((AppWidgetProviderInfo) b).label :
- ((ResolveInfo) b).loadLabel(mPackageManager).toString().trim();
+ labelB = (b instanceof AppWidgetProviderInfo)
+ ? mManager.loadLabel((AppWidgetProviderInfo) b)
+ : ((ResolveInfo) b).loadLabel(mPackageManager).toString().trim();
mLabelCache.put(b, labelB);
}
return mCollator.compare(labelA, labelB);
}
};
+ static boolean isValidProvider(AppWidgetProviderInfo provider) {
+ return (provider != null) && (provider.provider != null)
+ && (provider.provider.getPackageName() != null);
+ }
+
public void dumpState() {
Log.d(TAG, "mCallbacks=" + mCallbacks);
AppInfo.dumpApplicationInfoList(TAG, "mAllAppsList.data", mBgAllAppsList.data);