From 56d8291af6a28c6ba64113120efdf84a785e816c Mon Sep 17 00:00:00 2001 From: Joe Onorato Date: Sun, 7 Mar 2010 14:32:10 -0500 Subject: Apps on SD card don't confuse the launcher any more. They show up properly after reboots, mounting and unmounting. Change-Id: Icd861dcd8ac6401c597e2f9c8e2c66dff1cf9c61 --- src/com/android/launcher2/LauncherModel.java | 357 +++++++++++++++------------ src/com/android/launcher2/ShortcutInfo.java | 17 +- src/com/android/launcher2/Utilities.java | 24 ++ 3 files changed, 238 insertions(+), 160 deletions(-) diff --git a/src/com/android/launcher2/LauncherModel.java b/src/com/android/launcher2/LauncherModel.java index 228b7a59f..00b17549b 100644 --- a/src/com/android/launcher2/LauncherModel.java +++ b/src/com/android/launcher2/LauncherModel.java @@ -45,6 +45,7 @@ import java.lang.ref.WeakReference; import java.net.URISyntaxException; import java.text.Collator; import java.util.ArrayList; +import java.util.Arrays; import java.util.Comparator; import java.util.Collections; import java.util.HashMap; @@ -96,7 +97,7 @@ public class LauncherModel extends BroadcastReceiver { app.getPackageManager().getDefaultActivityIcon(), app); } - public Bitmap getDefaultIcon() { + public Bitmap getFallbackIcon() { return Bitmap.createBitmap(mDefaultIcon); } @@ -291,8 +292,6 @@ public class LauncherModel extends BroadcastReceiver { * ACTION_PACKAGE_CHANGED. */ public void onReceive(Context context, Intent intent) { - Log.d(TAG, "onReceive intent=" + intent); - // Use the app as the context. context = mApp; @@ -335,6 +334,53 @@ public class LauncherModel extends BroadcastReceiver { mAllAppsList.updatePackage(context, packageName); } } + + if (mAllAppsList.added.size() > 0) { + added = mAllAppsList.added; + mAllAppsList.added = new ArrayList(); + } + if (mAllAppsList.removed.size() > 0) { + removed = mAllAppsList.removed; + mAllAppsList.removed = new ArrayList(); + for (ApplicationInfo info: removed) { + mIconCache.remove(info.intent.getComponent()); + } + } + if (mAllAppsList.modified.size() > 0) { + modified = mAllAppsList.modified; + mAllAppsList.modified = new ArrayList(); + } + + final Callbacks callbacks = mCallbacks != null ? mCallbacks.get() : null; + if (callbacks == null) { + Log.w(TAG, "Nobody to tell about the new app. Launcher is probably loading."); + return; + } + + if (added != null) { + final ArrayList addedFinal = added; + mHandler.post(new Runnable() { + public void run() { + callbacks.bindAppsAdded(addedFinal); + } + }); + } + if (modified != null) { + final ArrayList modifiedFinal = modified; + mHandler.post(new Runnable() { + public void run() { + callbacks.bindAppsUpdated(modifiedFinal); + } + }); + } + if (removed != null) { + final ArrayList removedFinal = removed; + mHandler.post(new Runnable() { + public void run() { + callbacks.bindAppsRemoved(removedFinal); + } + }); + } } else { if (Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals(action)) { String packages[] = intent.getStringArrayExtra( @@ -342,63 +388,20 @@ public class LauncherModel extends BroadcastReceiver { if (packages == null || packages.length == 0) { return; } - Log.d(TAG, "they're back! " + packages); + setAllAppsDirty(); + setWorkspaceDirty(); + startLoader(context, false); } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action)) { String packages[] = intent.getStringArrayExtra( Intent.EXTRA_CHANGED_PACKAGE_LIST); if (packages == null || packages.length == 0) { return; } - Log.d(TAG, "they're gone! " + packages); - } - } - - if (mAllAppsList.added.size() > 0) { - added = mAllAppsList.added; - mAllAppsList.added = new ArrayList(); - } - if (mAllAppsList.removed.size() > 0) { - removed = mAllAppsList.removed; - mAllAppsList.removed = new ArrayList(); - for (ApplicationInfo info: removed) { - mIconCache.remove(info.intent.getComponent()); + setAllAppsDirty(); + setWorkspaceDirty(); + startLoader(context, false); } } - if (mAllAppsList.modified.size() > 0) { - modified = mAllAppsList.modified; - mAllAppsList.modified = new ArrayList(); - } - - final Callbacks callbacks = mCallbacks != null ? mCallbacks.get() : null; - if (callbacks == null) { - Log.w(TAG, "Nobody to tell about the new app. Launcher is probably loading."); - return; - } - - if (added != null) { - final ArrayList addedFinal = added; - mHandler.post(new Runnable() { - public void run() { - callbacks.bindAppsAdded(addedFinal); - } - }); - } - if (modified != null) { - final ArrayList modifiedFinal = modified; - mHandler.post(new Runnable() { - public void run() { - callbacks.bindAppsUpdated(modifiedFinal); - } - }); - } - if (removed != null) { - final ArrayList removedFinal = removed; - mHandler.post(new Runnable() { - public void run() { - callbacks.bindAppsRemoved(removedFinal); - } - }); - } } } @@ -648,12 +651,6 @@ public class LauncherModel extends BroadcastReceiver { final AppWidgetManager widgets = AppWidgetManager.getInstance(context); final boolean isSafeMode = manager.isSafeMode(); - /* TODO - if (mLocaleChanged) { - updateShortcutLabels(contentResolver, manager); - } - */ - mItems.clear(); mAppWidgets.clear(); mFolders.clear(); @@ -718,24 +715,18 @@ public class LauncherModel extends BroadcastReceiver { } if (itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION) { - info = getShortcutInfo(manager, intent, context); + info = getShortcutInfo(manager, intent, context, c, iconIndex, + titleIndex); } else { info = getShortcutInfo(c, context, iconTypeIndex, - iconPackageIndex, iconResourceIndex, iconIndex); - } - - if (info == null) { - info = new ShortcutInfo(); - info.setIcon(getDefaultIcon()); + iconPackageIndex, iconResourceIndex, iconIndex, + titleIndex); } if (info != null) { - if (itemType - != LauncherSettings.Favorites.ITEM_TYPE_APPLICATION) { - info.title = c.getString(titleIndex); - } - info.intent = intent; + updateSavedIcon(context, info, c, iconIndex); + info.intent = intent; info.id = c.getLong(idIndex); container = c.getInt(containerIndex); info.container = container; @@ -754,6 +745,15 @@ public class LauncherModel extends BroadcastReceiver { folderInfo.add(info); break; } + } else { + // Failed to load the shortcut, probably because the + // activity manager couldn't resolve it (maybe the app + // was uninstalled), or the db row was somehow screwed up. + // Delete it. + id = c.getLong(idIndex); + Log.e(TAG, "Error loading shortcut " + id + ", removing it"); + contentResolver.delete(LauncherSettings.Favorites.getContentUri( + id, false), null, null); } break; @@ -1085,24 +1085,62 @@ public class LauncherModel extends BroadcastReceiver { } /** - * Make an ShortcutInfo object for a sortcut that is an application. + * 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) { - final ResolveInfo resolveInfo = manager.resolveActivity(intent, 0); + public ShortcutInfo getShortcutInfo(PackageManager manager, Intent intent, Context context) { + return getShortcutInfo(manager, intent, context); + } + + /** + * Make an ShortcutInfo object for a shortcut that is an application. + * + * 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) { + Bitmap icon = null; + final ShortcutInfo info = new ShortcutInfo(); - if (resolveInfo == null) { + ComponentName componentName = intent.getComponent(); + if (componentName == null) { return null; } - final ShortcutInfo info = new ShortcutInfo(); - final ActivityInfo activityInfo = resolveInfo.activityInfo; - info.setIcon(mIconCache.getIcon(intent.getComponent(), resolveInfo)); - if (info.title == null || info.title.length() == 0) { - info.title = activityInfo.loadLabel(manager); + // 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. + final ResolveInfo resolveInfo = manager.resolveActivity(intent, 0); + if (resolveInfo != null) { + icon = mIconCache.getIcon(componentName, resolveInfo); + } + // the db + if (icon == null) { + if (c != null) { + icon = getIconFromCursor(c, iconIndex); + } } + // the fallback icon + if (icon == null) { + icon = getFallbackIcon(); + info.usingFallbackIcon = true; + } + info.setIcon(icon); + + // from the resource + if (resolveInfo != null) { + info.title = resolveInfo.activityInfo.loadLabel(manager); + } + // from the db + if (info.title == null) { + if (c != null) { + info.title = c.getString(titleIndex); + } + } + // fall back to the class name of the activity if (info.title == null) { - info.title = activityInfo.name; + info.title = componentName.getClassName(); } info.itemType = LauncherSettings.Favorites.ITEM_TYPE_APPLICATION; return info; @@ -1112,47 +1150,75 @@ public class LauncherModel extends BroadcastReceiver { * Make an ShortcutInfo object for a shortcut that isn't an application. */ private ShortcutInfo getShortcutInfo(Cursor c, Context context, - int iconTypeIndex, int iconPackageIndex, int iconResourceIndex, int iconIndex) { + int iconTypeIndex, int iconPackageIndex, int iconResourceIndex, int iconIndex, + int titleIndex) { + Bitmap icon = null; final ShortcutInfo info = new ShortcutInfo(); info.itemType = LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT; + info.title = c.getString(titleIndex); + int iconType = c.getInt(iconTypeIndex); switch (iconType) { case LauncherSettings.Favorites.ICON_TYPE_RESOURCE: String packageName = c.getString(iconPackageIndex); String resourceName = c.getString(iconResourceIndex); PackageManager packageManager = context.getPackageManager(); + info.customIcon = false; + // the resource try { Resources resources = packageManager.getResourcesForApplication(packageName); - final int id = resources.getIdentifier(resourceName, null, null); - info.setIcon(Utilities.createIconBitmap(resources.getDrawable(id), context)); + if (resources != null) { + final int id = resources.getIdentifier(resourceName, null, null); + icon = Utilities.createIconBitmap(resources.getDrawable(id), context); + } } catch (Exception e) { - info.setIcon(getDefaultIcon()); + // drop this. we have other places to look for icons + } + // the db + if (icon == null) { + icon = getIconFromCursor(c, iconIndex); + } + // the fallback icon + if (icon == null) { + icon = getFallbackIcon(); + info.usingFallbackIcon = true; } - info.iconResource = new Intent.ShortcutIconResource(); - info.iconResource.packageName = packageName; - info.iconResource.resourceName = resourceName; - info.customIcon = false; break; case LauncherSettings.Favorites.ICON_TYPE_BITMAP: - byte[] data = c.getBlob(iconIndex); - try { - Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length); - info.setIcon(bitmap); - } catch (Exception e) { - info.setIcon(getDefaultIcon()); + icon = getIconFromCursor(c, iconIndex); + if (icon == null) { + icon = getFallbackIcon(); + info.customIcon = false; + info.usingFallbackIcon = true; + } else { + info.customIcon = true; } - info.customIcon = true; + info.setIcon(icon); break; default: - info.setIcon(getDefaultIcon()); + info.setIcon(getFallbackIcon()); + info.usingFallbackIcon = true; info.customIcon = false; break; } return info; } + Bitmap getIconFromCursor(Cursor c, int iconIndex) { + if (false) { + Log.d(TAG, "getIconFromCursor app=" + + c.getString(c.getColumnIndexOrThrow(LauncherSettings.Favorites.TITLE))); + } + byte[] data = c.getBlob(iconIndex); + try { + return BitmapFactory.decodeByteArray(data, 0, data.length); + } catch (Exception e) { + return null; + } + } + ShortcutInfo addShortcut(Context context, Intent data, CellLayout.CellInfo cellInfo, boolean notify) { @@ -1193,12 +1259,14 @@ public class LauncherModel extends BroadcastReceiver { } } + final ShortcutInfo info = new ShortcutInfo(); + if (icon == null) { - icon = getDefaultIcon(); + icon = getFallbackIcon(); + info.usingFallbackIcon = true; } - - final ShortcutInfo info = new ShortcutInfo(); info.setIcon(icon); + info.title = name; info.intent = intent; info.customIcon = customIcon; @@ -1237,6 +1305,37 @@ public class LauncherModel extends BroadcastReceiver { } } + void updateSavedIcon(Context context, ShortcutInfo info, Cursor c, int iconIndex) { + // If this icon doesn't have a custom icon, check to see + // what's stored in the DB, and if it doesn't match what + // we're going to show, store what we are going to show back + // into the DB. We do this so when we're loading, if the + // package manager can't find an icon (for example because + // the app is on SD) then we can use that instead. + if (info.onExternalStorage && !info.customIcon && !info.usingFallbackIcon) { + boolean needSave; + byte[] data = c.getBlob(iconIndex); + try { + if (data != null) { + Bitmap saved = BitmapFactory.decodeByteArray(data, 0, data.length); + Bitmap loaded = info.getIcon(mIconCache); + needSave = !saved.sameAs(loaded); + } else { + needSave = true; + } + } catch (Exception e) { + needSave = true; + } + if (needSave) { + Log.d(TAG, "going to save icon bitmap for info=" + info); + // This is slower than is ideal, but this only happens either + // after the froyo OTA or when the app is updated with a new + // icon. + updateItemInDatabase(context, info); + } + } + } + /** * Return an existing UserFolderInfo object if we have encountered this ID previously, * or make a new one. @@ -1267,64 +1366,6 @@ public class LauncherModel extends BroadcastReceiver { return (LiveFolderInfo) folderInfo; } - private static void updateShortcutLabels(ContentResolver resolver, PackageManager manager) { - final Cursor c = resolver.query(LauncherSettings.Favorites.CONTENT_URI, - new String[] { LauncherSettings.Favorites._ID, LauncherSettings.Favorites.TITLE, - LauncherSettings.Favorites.INTENT, LauncherSettings.Favorites.ITEM_TYPE }, - null, null, null); - - final int idIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites._ID); - final int intentIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.INTENT); - final int itemTypeIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ITEM_TYPE); - final int titleIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.TITLE); - - // boolean changed = false; - - try { - while (c.moveToNext()) { - try { - if (c.getInt(itemTypeIndex) != - LauncherSettings.Favorites.ITEM_TYPE_APPLICATION) { - continue; - } - - final String intentUri = c.getString(intentIndex); - if (intentUri != null) { - final Intent shortcut = Intent.parseUri(intentUri, 0); - if (Intent.ACTION_MAIN.equals(shortcut.getAction())) { - final ComponentName name = shortcut.getComponent(); - if (name != null) { - final ActivityInfo activityInfo = manager.getActivityInfo(name, 0); - final String title = c.getString(titleIndex); - String label = getLabel(manager, activityInfo); - - if (title == null || !title.equals(label)) { - final ContentValues values = new ContentValues(); - values.put(LauncherSettings.Favorites.TITLE, label); - - resolver.update( - LauncherSettings.Favorites.CONTENT_URI_NO_NOTIFICATION, - values, "_id=?", - new String[] { String.valueOf(c.getLong(idIndex)) }); - - // changed = true; - } - } - } - } - } catch (URISyntaxException e) { - // Ignore - } catch (PackageManager.NameNotFoundException e) { - // Ignore - } - } - } finally { - c.close(); - } - - // if (changed) resolver.notifyChange(Settings.Favorites.CONTENT_URI, null); - } - private static String getLabel(PackageManager manager, ActivityInfo activityInfo) { String label = activityInfo.loadLabel(manager).toString(); if (label == null) { diff --git a/src/com/android/launcher2/ShortcutInfo.java b/src/com/android/launcher2/ShortcutInfo.java index cb73ac05b..6e2d767d8 100644 --- a/src/com/android/launcher2/ShortcutInfo.java +++ b/src/com/android/launcher2/ShortcutInfo.java @@ -47,6 +47,17 @@ class ShortcutInfo extends ItemInfo { */ boolean customIcon; + /** + * Indicates whether we're using the default fallback icon instead of something from the + * app. + */ + boolean usingFallbackIcon; + + /** + * Indicates whether the shortcut is on external storage and may go away at any time. + */ + boolean onExternalStorage; + /** * If isShortcut=true and customIcon=false, this contains a reference to the * shortcut icon as an application's resource. @@ -122,9 +133,11 @@ class ShortcutInfo extends ItemInfo { if (customIcon) { values.put(LauncherSettings.BaseLauncherColumns.ICON_TYPE, LauncherSettings.BaseLauncherColumns.ICON_TYPE_BITMAP); - Bitmap bitmap = this.mIcon; - writeBitmap(values, bitmap); + writeBitmap(values, mIcon); } else { + if (onExternalStorage && !usingFallbackIcon) { + writeBitmap(values, mIcon); + } values.put(LauncherSettings.BaseLauncherColumns.ICON_TYPE, LauncherSettings.BaseLauncherColumns.ICON_TYPE_RESOURCE); if (iconResource != null) { diff --git a/src/com/android/launcher2/Utilities.java b/src/com/android/launcher2/Utilities.java index 7bc1e8255..757e48e30 100644 --- a/src/com/android/launcher2/Utilities.java +++ b/src/com/android/launcher2/Utilities.java @@ -22,6 +22,8 @@ import android.graphics.drawable.PaintDrawable; import android.graphics.Bitmap; import android.graphics.BlurMaskFilter; import android.graphics.Canvas; +import android.graphics.ColorMatrix; +import android.graphics.ColorMatrixColorFilter; import android.graphics.Paint; import android.graphics.PaintFlagsDrawFilter; import android.graphics.PixelFormat; @@ -57,6 +59,7 @@ final class Utilities { private static final Paint sBlurPaint = new Paint(); private static final Paint sGlowColorPressedPaint = new Paint(); private static final Paint sGlowColorFocusedPaint = new Paint(); + private static final Paint sDisabledPaint = new Paint(); private static final Rect sBounds = new Rect(); private static final Rect sOldBounds = new Rect(); private static final Canvas sCanvas = new Canvas(); @@ -214,6 +217,22 @@ final class Utilities { } } + static Bitmap drawDisabledBitmap(Bitmap bitmap, Context context) { + synchronized (sCanvas) { // we share the statics :-( + if (sIconWidth == -1) { + initStatics(context); + } + final Bitmap disabled = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), + Bitmap.Config.ARGB_8888); + final Canvas canvas = sCanvas; + canvas.setBitmap(disabled); + + canvas.drawBitmap(bitmap, 0.0f, 0.0f, sDisabledPaint); + + return disabled; + } + } + private static void initStatics(Context context) { final Resources resources = context.getResources(); final DisplayMetrics metrics = resources.getDisplayMetrics(); @@ -227,6 +246,11 @@ final class Utilities { sGlowColorPressedPaint.setMaskFilter(TableMaskFilter.CreateClipTable(0, 30)); sGlowColorFocusedPaint.setColor(0xffff8e00); sGlowColorFocusedPaint.setMaskFilter(TableMaskFilter.CreateClipTable(0, 30)); + + ColorMatrix cm = new ColorMatrix(); + cm.setSaturation(0.2f); + sDisabledPaint.setColorFilter(new ColorMatrixColorFilter(cm)); + sDisabledPaint.setAlpha(0x88); } static class BubbleText { -- cgit v1.2.3