Split ApplicationInfo into ApplicationInfo which is used for AllAppsView and ShortcutInfo which is
used for the workspace.

Consolidate the three icon resampling functions into one.

Ensure that the icons stored in LauncherProvider are the right size, so we don't have to resample
them each time we load them.
diff --git a/src/com/android/launcher2/AllAppsList.java b/src/com/android/launcher2/AllAppsList.java
index 00e9ea8..9d4c5b0 100644
--- a/src/com/android/launcher2/AllAppsList.java
+++ b/src/com/android/launcher2/AllAppsList.java
@@ -44,10 +44,13 @@
     /** The list of apps that have been modified since the last notify() call. */
     public ArrayList<ApplicationInfo> modified = new ArrayList<ApplicationInfo>();
 
+    private IconCache mIconCache;
+
     /**
      * Boring constructor.
      */
-    public AllAppsList() {
+    public AllAppsList(IconCache iconCache) {
+        mIconCache = iconCache;
     }
 
     /**
@@ -82,9 +85,8 @@
         final List<ResolveInfo> matches = findActivitiesForPackage(context, packageName);
 
         if (matches.size() > 0) {
-            Utilities.BubbleText bubble = new Utilities.BubbleText(context);
             for (ResolveInfo info : matches) {
-                ApplicationInfo item = AppInfoCache.cache(info, context, bubble);
+                ApplicationInfo item = new ApplicationInfo(info, mIconCache);
                 data.add(item);
                 added.add(item);
             }
@@ -105,9 +107,9 @@
             }
         }
         // This is more aggressive than it needs to be.
-        AppInfoCache.flush();
+        mIconCache.flush();
     }
-    
+
     /**
      * Add and remove icons for this package which has been updated.
      */
@@ -122,7 +124,7 @@
                 if (packageName.equals(component.getPackageName())) {
                     if (!findActivity(matches, component)) {
                         removed.add(applicationInfo);
-                        AppInfoCache.remove(component);
+                        mIconCache.remove(component);
                         data.remove(i);
                     }
                 }
@@ -130,7 +132,6 @@
 
             // Find enabled activities and add them to the adapter
             // Also updates existing activities with new labels/icons
-            Utilities.BubbleText bubble = new Utilities.BubbleText(context);
             int count = matches.size();
             for (int i = 0; i < count; i++) {
                 final ResolveInfo info = matches.get(i);
@@ -138,11 +139,12 @@
                         info.activityInfo.applicationInfo.packageName,
                         info.activityInfo.name);
                 if (applicationInfo == null) {
-                    applicationInfo = AppInfoCache.cache(info, context, bubble);
+                    applicationInfo = new ApplicationInfo(info, mIconCache);
                     data.add(applicationInfo);
                     added.add(applicationInfo);
                 } else {
-                    AppInfoCache.update(info, applicationInfo, context, bubble);
+                    mIconCache.remove(applicationInfo.componentName);
+                    mIconCache.getTitleAndIcon(applicationInfo, info);
                     modified.add(applicationInfo);
                 }
             }
diff --git a/src/com/android/launcher2/AppInfoCache.java b/src/com/android/launcher2/AppInfoCache.java
deleted file mode 100644
index a2d9830..0000000
--- a/src/com/android/launcher2/AppInfoCache.java
+++ /dev/null
@@ -1,177 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.launcher2;
-
-import android.content.ComponentName;
-import android.content.ContentResolver;
-import android.content.ContentValues;
-import android.content.Intent;
-import android.content.Context;
-import android.content.pm.ActivityInfo;
-import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
-import android.content.res.Resources;
-import android.database.Cursor;
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.graphics.drawable.Drawable;
-import android.graphics.drawable.BitmapDrawable;
-import android.net.Uri;
-import android.util.Log;
-import android.os.Process;
-
-import java.lang.ref.WeakReference;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-
-/**
- * Cache of application icons.  Icons can be made from any thread.
- */
-public class AppInfoCache {
-    private static final String TAG = "Launcher.AppInfoCache";
-
-    private static final int INITIAL_ICON_CACHE_CAPACITY = 50;
-
-    private static final HashMap<ComponentName, ApplicationInfo> sCache =
-            new HashMap<ComponentName, ApplicationInfo>(INITIAL_ICON_CACHE_CAPACITY);
-
-    /**
-     * no public constructor.
-     */
-    private AppInfoCache() {
-    }
-
-    /**
-     * For the given ResolveInfo, return an ApplicationInfo and cache the result for later.
-     */
-    public static ApplicationInfo cache(ResolveInfo info, Context context,
-            Utilities.BubbleText bubble) {
-        synchronized (sCache) {
-            ComponentName componentName = new ComponentName(
-                    info.activityInfo.applicationInfo.packageName,
-                    info.activityInfo.name);
-            ApplicationInfo application = sCache.get(componentName);
-
-            if (application == null) {
-                application = new ApplicationInfo();
-                application.container = ItemInfo.NO_ID;
-
-                updateTitleAndIcon(info, application, context, bubble);
-
-                application.setActivity(componentName,
-                        Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
-
-                sCache.put(componentName, application);
-            }
-
-            return application;
-        }
-    }
-
-    /**
-     * Update the entry in the in the cache with its new metadata.
-     */
-    public static void update(ResolveInfo info, ApplicationInfo applicationInfo, Context context,
-            Utilities.BubbleText bubble) {
-        synchronized (sCache) {
-            updateTitleAndIcon(info, applicationInfo, context, bubble);
-
-            ComponentName componentName = new ComponentName(
-                    info.activityInfo.applicationInfo.packageName, info.activityInfo.name);
-            sCache.put(componentName, applicationInfo);
-        }
-    }
-
-    /**
-     * Remove any records for the supplied ComponentName.
-     */
-    public static void remove(ComponentName componentName) {
-        synchronized (sCache) {
-            sCache.remove(componentName);
-        }
-    }
-
-    /**
-     * Empty out the cache.
-     */
-    public static void flush() {
-        synchronized (sCache) {
-            sCache.clear();
-        }
-    }
-
-    /**
-     * Get the icon for the supplied ApplicationInfo.  If that activity already
-     * exists in the cache, use that.
-     */
-    public static Drawable getIconDrawable(PackageManager packageManager, ApplicationInfo info) {
-        final ResolveInfo resolveInfo = packageManager.resolveActivity(info.intent, 0);
-        if (resolveInfo == null) {
-            return null;
-        }
-
-        ComponentName componentName = new ComponentName(
-                resolveInfo.activityInfo.applicationInfo.packageName,
-                resolveInfo.activityInfo.name);
-        ApplicationInfo cached;
-        synchronized (sCache) {
-            cached = sCache.get(componentName);
-            if (cached != null) {
-                if (cached.icon == null) {
-                    cached.icon = resolveInfo.activityInfo.loadIcon(packageManager);
-                }
-                return cached.icon;
-            } else {
-                return resolveInfo.activityInfo.loadIcon(packageManager);
-            }
-        }
-    }
-
-    /**
-     * Go through the cache and disconnect any of the callbacks in the drawables or we
-     * leak the previous Home screen on orientation change.
-     */
-    public static void unbindDrawables() {
-        synchronized (sCache) {
-            for (ApplicationInfo appInfo: sCache.values()) {
-                if (appInfo.icon != null) {
-                    appInfo.icon.setCallback(null);
-                }
-            }
-        }
-    }
-
-    /**
-     * Update the title and icon.  Don't keep a reference to the context!
-     */
-    private static void updateTitleAndIcon(ResolveInfo info, ApplicationInfo application,
-            Context context, Utilities.BubbleText bubble) {
-        final PackageManager packageManager = context.getPackageManager();
-
-        application.title = info.loadLabel(packageManager);
-        if (application.title == null) {
-            application.title = info.activityInfo.name;
-        }
-
-        application.iconBitmap = Utilities.createAllAppsBitmap(
-                info.activityInfo.loadIcon(packageManager), context);
-
-        application.titleBitmap = bubble.createTextBitmap(application.title.toString());
-    }
-}
-
diff --git a/src/com/android/launcher2/ApplicationInfo.java b/src/com/android/launcher2/ApplicationInfo.java
index 0fe84e7..f50b889 100644
--- a/src/com/android/launcher2/ApplicationInfo.java
+++ b/src/com/android/launcher2/ApplicationInfo.java
@@ -18,7 +18,9 @@
 
 import android.content.ComponentName;
 import android.content.ContentValues;
+import android.content.Context;
 import android.content.Intent;
+import android.content.pm.ResolveInfo;
 import android.graphics.Bitmap;
 import android.graphics.drawable.Drawable;
 import android.util.Log;
@@ -26,8 +28,7 @@
 import java.util.ArrayList;
 
 /**
- * Represents a launchable application. An application is made of a name (or title),
- * an intent and an icon.
+ * Represents an app in AllAppsView.
  */
 class ApplicationInfo extends ItemInfo {
 
@@ -47,48 +48,37 @@
     Intent intent;
 
     /**
-     * The application icon.
-     */
-    Drawable icon;
-
-    /**
      * A bitmap version of the application icon.
      */
     Bitmap iconBitmap;
 
-    /**
-     * When set to true, indicates that the icon has been resized.
-     */
-    boolean filtered;
+    ComponentName componentName;
 
-    /**
-     * Indicates whether the icon comes from an application's resource (if false)
-     * or from a custom Bitmap (if true.)
-     */
-    boolean customIcon;
-
-    /**
-     * If isShortcut=true and customIcon=false, this contains a reference to the
-     * shortcut icon as an application's resource.
-     */
-    Intent.ShortcutIconResource iconResource;
 
     ApplicationInfo() {
         itemType = LauncherSettings.BaseLauncherColumns.ITEM_TYPE_SHORTCUT;
     }
+
+    /**
+     * Must not hold the Context.
+     */
+    public ApplicationInfo(ResolveInfo info, IconCache iconCache) {
+        this.componentName = new ComponentName(
+                info.activityInfo.applicationInfo.packageName,
+                info.activityInfo.name);
+
+        this.container = ItemInfo.NO_ID;
+        this.setActivity(componentName,
+                Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
+
+        iconCache.getTitleAndIcon(this, info);
+    }
     
     public ApplicationInfo(ApplicationInfo info) {
         super(info);
+        componentName = info.componentName;
         title = info.title.toString();
         intent = new Intent(info.intent);
-        if (info.iconResource != null) {
-            iconResource = new Intent.ShortcutIconResource();
-            iconResource.packageName = info.iconResource.packageName;
-            iconResource.resourceName = info.iconResource.resourceName;
-        }
-        icon = info.icon;
-        filtered = info.filtered;
-        customIcon = info.customIcon;
     }
 
     /**
@@ -107,51 +97,20 @@
     }
 
     @Override
-    void onAddToDatabase(ContentValues values) {
-        super.onAddToDatabase(values);
-
-        String titleStr = title != null ? title.toString() : null;
-        values.put(LauncherSettings.BaseLauncherColumns.TITLE, titleStr);
-
-        String uri = intent != null ? intent.toUri(0) : null;
-        values.put(LauncherSettings.BaseLauncherColumns.INTENT, uri);
-
-        if (customIcon) {
-            values.put(LauncherSettings.BaseLauncherColumns.ICON_TYPE,
-                    LauncherSettings.BaseLauncherColumns.ICON_TYPE_BITMAP);
-            Bitmap bitmap = ((FastBitmapDrawable) icon).getBitmap();
-            writeBitmap(values, bitmap);
-        } else {
-            values.put(LauncherSettings.BaseLauncherColumns.ICON_TYPE,
-                    LauncherSettings.BaseLauncherColumns.ICON_TYPE_RESOURCE);
-            if (iconResource != null) {
-                values.put(LauncherSettings.BaseLauncherColumns.ICON_PACKAGE,
-                        iconResource.packageName);
-                values.put(LauncherSettings.BaseLauncherColumns.ICON_RESOURCE,
-                        iconResource.resourceName);
-            }
-        }
-    }
-
-    @Override
     public String toString() {
         return title.toString();
     }
 
-    @Override
-    void unbind() {
-        super.unbind();
-        icon.setCallback(null);
-    }
-
-
     public static void dumpApplicationInfoList(String tag, String label,
             ArrayList<ApplicationInfo> list) {
         Log.d(tag, label + " size=" + list.size());
         for (ApplicationInfo info: list) {
             Log.d(tag, "   title=\"" + info.title + "\" titleBitmap=" + info.titleBitmap
-                    + " icon=" + info.icon + " iconBitmap=" + info.iconBitmap
-                    + " filtered=" + info.filtered + " customIcon=" + info.customIcon);
+                    + " iconBitmap=" + info.iconBitmap);
         }
     }
+
+    public ShortcutInfo makeShortcut() {
+        return new ShortcutInfo(this);
+    }
 }
diff --git a/src/com/android/launcher2/DeleteZone.java b/src/com/android/launcher2/DeleteZone.java
index ec4bc53..fabeb4a 100644
--- a/src/com/android/launcher2/DeleteZone.java
+++ b/src/com/android/launcher2/DeleteZone.java
@@ -101,9 +101,9 @@
             if (source instanceof UserFolder) {
                 final UserFolder userFolder = (UserFolder) source;
                 final UserFolderInfo userFolderInfo = (UserFolderInfo) userFolder.getInfo();
-                // item must be an ApplicationInfo otherwise it couldn't have been in the folder
+                // Item must be a ShortcutInfo otherwise it couldn't have been in the folder
                 // in the first place.
-                userFolderInfo.remove((ApplicationInfo)item);
+                userFolderInfo.remove((ShortcutInfo)item);
             }
         }
         if (item instanceof UserFolderInfo) {
diff --git a/src/com/android/launcher2/FastBitmapDrawable.java b/src/com/android/launcher2/FastBitmapDrawable.java
index db2c01c..850535e 100644
--- a/src/com/android/launcher2/FastBitmapDrawable.java
+++ b/src/com/android/launcher2/FastBitmapDrawable.java
@@ -67,6 +67,10 @@
         return mBitmap.getHeight();
     }
 
+    public void setBitmap(Bitmap b) {
+        mBitmap = b;
+    }
+
     public Bitmap getBitmap() {
         return mBitmap;
     }
diff --git a/src/com/android/launcher2/Folder.java b/src/com/android/launcher2/Folder.java
index 4f66ad0..7c35f79 100644
--- a/src/com/android/launcher2/Folder.java
+++ b/src/com/android/launcher2/Folder.java
@@ -46,7 +46,7 @@
     /**
      * Which item is being dragged
      */
-    protected ApplicationInfo mDragItem;
+    protected ShortcutInfo mDragItem;
     private boolean mCloneInfo;
 
     /**
@@ -74,7 +74,7 @@
     }
     
     public void onItemClick(AdapterView parent, View v, int position, long id) {
-        ApplicationInfo app = (ApplicationInfo) parent.getItemAtPosition(position);
+        ShortcutInfo app = (ShortcutInfo) parent.getItemAtPosition(position);
         mLauncher.startActivitySafely(app.intent);
     }
 
@@ -93,9 +93,9 @@
             return false;
         }
 
-        ApplicationInfo app = (ApplicationInfo) parent.getItemAtPosition(position);
+        ShortcutInfo app = (ShortcutInfo) parent.getItemAtPosition(position);
         if (mCloneInfo) {
-            app = new ApplicationInfo(app);
+            app = new ShortcutInfo(app);
         }
 
         mDragController.startDrag(view, this, app, DragController.DRAG_ACTION_COPY);
@@ -118,7 +118,7 @@
 
     /**
      * Sets the adapter used to populate the content area. The adapter must only
-     * contains ApplicationInfo items.
+     * contains ShortcutInfo items.
      *
      * @param adapter The list of applications to display in the folder.
      */
diff --git a/src/com/android/launcher2/FolderIcon.java b/src/com/android/launcher2/FolderIcon.java
index 85fc3a7..826336c 100644
--- a/src/com/android/launcher2/FolderIcon.java
+++ b/src/com/android/launcher2/FolderIcon.java
@@ -48,7 +48,6 @@
 
         final Resources resources = launcher.getResources();
         Drawable d = resources.getDrawable(R.drawable.ic_launcher_folder);
-        d = Utilities.createIconThumbnail(d, launcher);
         icon.mCloseIcon = d;
         icon.mOpenIcon = resources.getDrawable(R.drawable.ic_launcher_folder_open);
         icon.setCompoundDrawablesWithIntrinsicBounds(null, d, null, null);
@@ -77,8 +76,13 @@
 
     public void onDrop(DragSource source, int x, int y, int xOffset, int yOffset,
             DragView dragView, Object dragInfo) {
-        final ApplicationInfo item = (ApplicationInfo) dragInfo;
-        // TODO: update open folder that is looking at this data
+        ShortcutInfo item;
+        if (dragInfo instanceof ApplicationInfo) {
+            // Came from all apps -- make a copy
+            item = ((ApplicationInfo)dragInfo).makeShortcut();
+        } else {
+            item = (ShortcutInfo)dragInfo;
+        }
         mInfo.add(item);
         LauncherModel.addOrMoveItemInDatabase(mLauncher, item, mInfo.id, 0, 0, 0);
     }
diff --git a/src/com/android/launcher2/IconCache.java b/src/com/android/launcher2/IconCache.java
new file mode 100644
index 0000000..847cab7
--- /dev/null
+++ b/src/com/android/launcher2/IconCache.java
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher2;
+
+import android.content.ComponentName;
+import android.content.ContentResolver;
+import android.content.ContentValues;
+import android.content.Intent;
+import android.content.Context;
+import android.content.pm.ActivityInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.res.Resources;
+import android.database.Cursor;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.BitmapDrawable;
+import android.net.Uri;
+import android.util.Log;
+import android.os.Process;
+
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+
+/**
+ * Cache of application icons.  Icons can be made from any thread.
+ */
+public class IconCache {
+    private static final String TAG = "Launcher.IconCache";
+
+    private static final int INITIAL_ICON_CACHE_CAPACITY = 50;
+
+    private static class CacheEntry {
+        public Bitmap icon;
+        public String title;
+        public Bitmap titleBitmap;
+    }
+
+    private LauncherApplication mContext;
+    private PackageManager mPackageManager;
+    private Utilities.BubbleText mBubble;
+    private final HashMap<ComponentName, CacheEntry> mCache =
+            new HashMap<ComponentName, CacheEntry>(INITIAL_ICON_CACHE_CAPACITY);
+
+    public IconCache(LauncherApplication context) {
+        mContext = context;
+        mPackageManager = context.getPackageManager();
+        mBubble = new Utilities.BubbleText(context);
+    }
+
+    /**
+     * Remove any records for the supplied ComponentName.
+     */
+    public void remove(ComponentName componentName) {
+        synchronized (mCache) {
+            mCache.remove(componentName);
+        }
+    }
+
+    /**
+     * Empty out the cache.
+     */
+    public void flush() {
+        synchronized (mCache) {
+            mCache.clear();
+        }
+    }
+
+    /**
+     * Fill in "application" with the icon and label for "info."
+     */
+    public void getTitleAndIcon(ApplicationInfo application, ResolveInfo info) {
+        synchronized (mCache) {
+            CacheEntry entry = cacheLocked(application.componentName, info);
+
+            application.title = entry.title;
+            application.titleBitmap = entry.titleBitmap;
+            application.iconBitmap = entry.icon;
+        }
+    }
+
+    public Bitmap getIcon(Intent intent) {
+        final ResolveInfo resolveInfo = mPackageManager.resolveActivity(intent, 0);
+        ComponentName component = intent.getComponent();
+
+        if (resolveInfo == null || component == null) {
+            return null;
+        }
+
+        CacheEntry entry = cacheLocked(component, resolveInfo);
+        return entry.icon;
+    }
+
+    public Bitmap getIcon(ComponentName component, ResolveInfo resolveInfo) {
+        if (resolveInfo == null || component == null) {
+            return null;
+        }
+
+        CacheEntry entry = cacheLocked(component, resolveInfo);
+        return entry.icon;
+    }
+
+    private CacheEntry cacheLocked(ComponentName componentName, ResolveInfo info) {
+        CacheEntry entry = mCache.get(componentName);
+        if (entry == null) {
+            entry = new CacheEntry();
+
+            entry.title = info.loadLabel(mPackageManager).toString();
+            if (entry.title == null) {
+                entry.title = info.activityInfo.name;
+            }
+            entry.titleBitmap = mBubble.createTextBitmap(entry.title.toString());
+            entry.icon = Utilities.createIconBitmap(
+                    info.activityInfo.loadIcon(mPackageManager), mContext);
+
+            mCache.put(componentName, entry);
+        }
+        return entry;
+    }
+}
+
diff --git a/src/com/android/launcher2/InstallShortcutReceiver.java b/src/com/android/launcher2/InstallShortcutReceiver.java
index 45ff24e..9a2f73f 100644
--- a/src/com/android/launcher2/InstallShortcutReceiver.java
+++ b/src/com/android/launcher2/InstallShortcutReceiver.java
@@ -63,7 +63,8 @@
             // different places)
             boolean duplicate = data.getBooleanExtra(Launcher.EXTRA_SHORTCUT_DUPLICATE, true);
             if (duplicate || !LauncherModel.shortcutExists(context, name, intent)) {
-                Launcher.addShortcut(context, data, cell, true);
+                ((LauncherApplication)context.getApplicationContext()).getModel()
+                        .addShortcut(context, data, cell, true);
                 Toast.makeText(context, context.getString(R.string.shortcut_installed, name),
                         Toast.LENGTH_SHORT).show();
             } else {
diff --git a/src/com/android/launcher2/ItemInfo.java b/src/com/android/launcher2/ItemInfo.java
index f04880d..ca2ea86 100644
--- a/src/com/android/launcher2/ItemInfo.java
+++ b/src/com/android/launcher2/ItemInfo.java
@@ -112,21 +112,26 @@
         }
     }
 
+    static byte[] flattenBitmap(Bitmap bitmap) {
+        // Try go guesstimate how much space the icon will take when serialized
+        // to avoid unnecessary allocations/copies during the write.
+        int size = bitmap.getWidth() * bitmap.getHeight() * 4;
+        ByteArrayOutputStream out = new ByteArrayOutputStream(size);
+        try {
+            bitmap.compress(Bitmap.CompressFormat.PNG, 100, out);
+            out.flush();
+            out.close();
+            return out.toByteArray();
+        } catch (IOException e) {
+            Log.w("Favorite", "Could not write icon");
+            return null;
+        }
+    }
+
     static void writeBitmap(ContentValues values, Bitmap bitmap) {
         if (bitmap != null) {
-            // Try go guesstimate how much space the icon will take when serialized
-            // to avoid unnecessary allocations/copies during the write.
-            int size = bitmap.getWidth() * bitmap.getHeight() * 4;
-            ByteArrayOutputStream out = new ByteArrayOutputStream(size);
-            try {
-                bitmap.compress(Bitmap.CompressFormat.PNG, 100, out);
-                out.flush();
-                out.close();
-
-                values.put(LauncherSettings.Favorites.ICON, out.toByteArray());
-            } catch (IOException e) {
-                Log.w("Favorite", "Could not write icon");
-            }
+            byte[] data = flattenBitmap(bitmap);
+            values.put(LauncherSettings.Favorites.ICON, data);
         }
     }
     
diff --git a/src/com/android/launcher2/Launcher.java b/src/com/android/launcher2/Launcher.java
index 646203c..089e551 100644
--- a/src/com/android/launcher2/Launcher.java
+++ b/src/com/android/launcher2/Launcher.java
@@ -191,6 +191,7 @@
     private Bundle mSavedInstanceState;
 
     private LauncherModel mModel;
+    private IconCache mIconCache;
 
     private ArrayList<ItemInfo> mDesktopItems = new ArrayList<ItemInfo>();
     private static HashMap<Long, FolderInfo> mFolders = new HashMap<Long, FolderInfo>();
@@ -202,7 +203,9 @@
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
 
-        mModel = ((LauncherApplication)getApplication()).setLauncher(this);
+        LauncherApplication app = ((LauncherApplication)getApplication());
+        mModel = app.setLauncher(this);
+        mIconCache = app.getIconCache();
         mDragController = new DragController(this);
         mInflater = getLayoutInflater();
 
@@ -271,7 +274,7 @@
             localeConfiguration.mnc = mnc;
 
             writeConfiguration(this, localeConfiguration);
-            AppInfoCache.flush();
+            mIconCache.flush();
         }
     }
 
@@ -615,7 +618,7 @@
      *
      * @return A View inflated from R.layout.application.
      */
-    View createShortcut(ApplicationInfo info) {
+    View createShortcut(ShortcutInfo info) {
         return createShortcut(R.layout.application,
                 (ViewGroup) mWorkspace.getChildAt(mWorkspace.getCurrentScreen()), info);
     }
@@ -629,18 +632,12 @@
      *
      * @return A View inflated from layoutResId.
      */
-    View createShortcut(int layoutResId, ViewGroup parent, ApplicationInfo info) {
+    View createShortcut(int layoutResId, ViewGroup parent, ShortcutInfo info) {
         TextView favorite = (TextView) mInflater.inflate(layoutResId, parent, false);
 
-        if (info.icon == null) {
-            info.icon = AppInfoCache.getIconDrawable(getPackageManager(), info);
-        }
-        if (!info.filtered) {
-            info.icon = Utilities.createIconThumbnail(info.icon, this);
-            info.filtered = true;
-        }
-
-        favorite.setCompoundDrawablesWithIntrinsicBounds(null, info.icon, null, null);
+        favorite.setCompoundDrawablesWithIntrinsicBounds(null,
+                new FastBitmapDrawable(info.getIcon(mIconCache)),
+                null, null);
         favorite.setText(info.title);
         favorite.setTag(info);
         favorite.setOnClickListener(this);
@@ -658,39 +655,17 @@
         cellInfo.screen = mWorkspace.getCurrentScreen();
         if (!findSingleSlot(cellInfo)) return;
 
-        final ApplicationInfo info = infoFromApplicationIntent(context, data);
+        final ShortcutInfo info = mModel.getShortcutInfo(context.getPackageManager(),
+                data, context);
+
         if (info != null) {
-            mWorkspace.addApplicationShortcut(info, cellInfo, isWorkspaceLocked());
-        }
-    }
-
-    private static ApplicationInfo infoFromApplicationIntent(Context context, Intent data) {
-        ComponentName component = data.getComponent();
-        PackageManager packageManager = context.getPackageManager();
-        ActivityInfo activityInfo = null;
-        try {
-            activityInfo = packageManager.getActivityInfo(component, 0 /* no flags */);
-        } catch (NameNotFoundException e) {
-            Log.e(TAG, "Couldn't find ActivityInfo for selected application", e);
-        }
-
-        if (activityInfo != null) {
-            ApplicationInfo itemInfo = new ApplicationInfo();
-
-            itemInfo.title = activityInfo.loadLabel(packageManager);
-            if (itemInfo.title == null) {
-                itemInfo.title = activityInfo.name;
-            }
-
-            itemInfo.setActivity(component, Intent.FLAG_ACTIVITY_NEW_TASK |
+            info.setActivity(data.getComponent(), Intent.FLAG_ACTIVITY_NEW_TASK |
                     Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
-            itemInfo.icon = activityInfo.loadIcon(packageManager);
-            itemInfo.container = ItemInfo.NO_ID;
-
-            return itemInfo;
+            info.container = ItemInfo.NO_ID;
+            mWorkspace.addApplicationShortcut(info, cellInfo, isWorkspaceLocked());
+        } else {
+            Log.e(TAG, "Couldn't find ActivityInfo for selected application: " + data);
         }
-
-        return null;
     }
 
     /**
@@ -703,7 +678,7 @@
         cellInfo.screen = mWorkspace.getCurrentScreen();
         if (!findSingleSlot(cellInfo)) return;
 
-        final ApplicationInfo info = addShortcut(this, data, cellInfo, false);
+        final ShortcutInfo info = mModel.addShortcut(this, data, cellInfo, false);
 
         if (!mRestoring) {
             final View view = createShortcut(info);
@@ -770,61 +745,6 @@
         return mAppWidgetHost;
     }
 
-    static ApplicationInfo addShortcut(Context context, Intent data,
-            CellLayout.CellInfo cellInfo, boolean notify) {
-
-        final ApplicationInfo info = infoFromShortcutIntent(context, data);
-        LauncherModel.addItemToDatabase(context, info, LauncherSettings.Favorites.CONTAINER_DESKTOP,
-                cellInfo.screen, cellInfo.cellX, cellInfo.cellY, notify);
-
-        return info;
-    }
-
-    private static ApplicationInfo infoFromShortcutIntent(Context context, Intent data) {
-        Intent intent = data.getParcelableExtra(Intent.EXTRA_SHORTCUT_INTENT);
-        String name = data.getStringExtra(Intent.EXTRA_SHORTCUT_NAME);
-        Parcelable bitmap = data.getParcelableExtra(Intent.EXTRA_SHORTCUT_ICON);
-
-        Drawable icon = null;
-        boolean filtered = false;
-        boolean customIcon = false;
-        ShortcutIconResource iconResource = null;
-
-        if (bitmap != null && bitmap instanceof Bitmap) {
-            icon = new FastBitmapDrawable(Utilities.createBitmapThumbnail((Bitmap) bitmap, context));
-            filtered = true;
-            customIcon = true;
-        } else {
-            Parcelable extra = data.getParcelableExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE);
-            if (extra != null && extra instanceof ShortcutIconResource) {
-                try {
-                    iconResource = (ShortcutIconResource) extra;
-                    final PackageManager packageManager = context.getPackageManager();
-                    Resources resources = packageManager.getResourcesForApplication(
-                            iconResource.packageName);
-                    final int id = resources.getIdentifier(iconResource.resourceName, null, null);
-                    icon = resources.getDrawable(id);
-                } catch (Exception e) {
-                    Log.w(TAG, "Could not load shortcut icon: " + extra);
-                }
-            }
-        }
-
-        if (icon == null) {
-            icon = context.getPackageManager().getDefaultActivityIcon();
-        }
-
-        final ApplicationInfo info = new ApplicationInfo();
-        info.icon = icon;
-        info.filtered = filtered;
-        info.title = name;
-        info.intent = intent;
-        info.customIcon = customIcon;
-        info.iconResource = iconResource;
-
-        return info;
-    }
-
     void closeSystemDialogs() {
         getWindow().closeAllPanels();
 
@@ -936,7 +856,6 @@
         mModel.stopLoader();
 
         unbindDesktopItems();
-        AppInfoCache.unbindDrawables();
 
         getContentResolver().unregisterContentObserver(mWidgetObserver);
         
@@ -1163,7 +1082,6 @@
         String name = data.getStringExtra(LiveFolders.EXTRA_LIVE_FOLDER_NAME);
 
         Drawable icon = null;
-        boolean filtered = false;
         Intent.ShortcutIconResource iconResource = null;
 
         Parcelable extra = data.getParcelableExtra(LiveFolders.EXTRA_LIVE_FOLDER_ICON);
@@ -1185,8 +1103,7 @@
         }
 
         final LiveFolderInfo info = new LiveFolderInfo();
-        info.icon = icon;
-        info.filtered = filtered;
+        info.icon = Utilities.createIconBitmap(icon, context);
         info.title = name;
         info.iconResource = iconResource;
         info.uri = data.getData();
@@ -1338,9 +1255,9 @@
      */
     public void onClick(View v) {
         Object tag = v.getTag();
-        if (tag instanceof ApplicationInfo) {
+        if (tag instanceof ShortcutInfo) {
             // Open shortcut
-            final Intent intent = ((ApplicationInfo) tag).intent;
+            final Intent intent = ((ShortcutInfo)tag).intent;
             int[] pos = new int[2];
             v.getLocationOnScreen(pos);
             intent.setSourceBounds(
@@ -2011,7 +1928,7 @@
             switch (item.itemType) {
                 case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:
                 case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:
-                    final View shortcut = createShortcut((ApplicationInfo) item);
+                    final View shortcut = createShortcut((ShortcutInfo)item);
                     workspace.addInScreen(shortcut, item.screen, item.cellX, item.cellY, 1, 1,
                             false);
                     break;
diff --git a/src/com/android/launcher2/LauncherApplication.java b/src/com/android/launcher2/LauncherApplication.java
index a72e53a..183dbf5 100644
--- a/src/com/android/launcher2/LauncherApplication.java
+++ b/src/com/android/launcher2/LauncherApplication.java
@@ -25,11 +25,8 @@
 import dalvik.system.VMRuntime;
 
 public class LauncherApplication extends Application {
-    public final LauncherModel mModel;
-
-    public LauncherApplication() {
-        mModel = new LauncherModel(this);
-    }
+    public LauncherModel mModel;
+    public IconCache mIconCache;
 
     @Override
     public void onCreate() {
@@ -37,6 +34,9 @@
 
         super.onCreate();
 
+        mIconCache = new IconCache(this);
+        mModel = new LauncherModel(this, mIconCache);
+
         // Register intent receivers
         IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
         filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
@@ -79,4 +79,12 @@
         mModel.initialize(launcher);
         return mModel;
     }
+
+    IconCache getIconCache() {
+        return mIconCache;
+    }
+
+    LauncherModel getModel() {
+        return mModel;
+    }
 }
diff --git a/src/com/android/launcher2/LauncherModel.java b/src/com/android/launcher2/LauncherModel.java
index 7eb240f..16e5c3b 100644
--- a/src/com/android/launcher2/LauncherModel.java
+++ b/src/com/android/launcher2/LauncherModel.java
@@ -24,6 +24,7 @@
 import android.content.ContentResolver;
 import android.content.ContentValues;
 import android.content.Intent;
+import android.content.Intent.ShortcutIconResource;
 import android.content.Context;
 import android.content.pm.ActivityInfo;
 import android.content.pm.PackageManager;
@@ -34,6 +35,7 @@
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
 import android.net.Uri;
+import android.os.Parcelable;
 import android.os.RemoteException;
 import android.util.Log;
 import android.os.Process;
@@ -65,7 +67,10 @@
     private boolean mBeforeFirstLoad = true;
     private WeakReference<Callbacks> mCallbacks;
 
-    private AllAppsList mAllAppsList = new AllAppsList();
+    private AllAppsList mAllAppsList;
+    private IconCache mIconCache;
+
+    private Bitmap mDefaultIcon;
 
     public interface Callbacks {
         public int getCurrentWorkspaceScreen();
@@ -80,8 +85,17 @@
         public void bindPackageRemoved(String packageName, ArrayList<ApplicationInfo> apps);
     }
 
-    LauncherModel(LauncherApplication app) {
+    LauncherModel(LauncherApplication app, IconCache iconCache) {
         mApp = app;
+        mAllAppsList = new AllAppsList(iconCache);
+        mIconCache = iconCache;
+
+        mDefaultIcon = Utilities.createIconBitmap(
+                app.getPackageManager().getDefaultActivityIcon(), app);
+    }
+
+    public Bitmap getDefaultIcon() {
+        return Bitmap.createBitmap(mDefaultIcon);
     }
 
     /**
@@ -323,7 +337,7 @@
                 removed = mAllAppsList.removed;
                 mAllAppsList.removed = new ArrayList<ApplicationInfo>();
                 for (ApplicationInfo info: removed) {
-                    AppInfoCache.remove(info.intent.getComponent());
+                    mIconCache.remove(info.intent.getComponent());
                 }
             }
             if (mAllAppsList.modified.size() > 0) {
@@ -658,7 +672,7 @@
                     final int displayModeIndex = c.getColumnIndexOrThrow(
                             LauncherSettings.Favorites.DISPLAY_MODE);
 
-                    ApplicationInfo info;
+                    ShortcutInfo info;
                     String intentDescription;
                     LauncherAppWidgetInfo appWidgetInfo;
                     int container;
@@ -680,15 +694,15 @@
                                 }
 
                                 if (itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION) {
-                                    info = getApplicationInfo(manager, intent, context);
+                                    info = getShortcutInfo(manager, intent, context);
                                 } else {
-                                    info = getApplicationInfoShortcut(c, context, iconTypeIndex,
+                                    info = getShortcutInfo(c, context, iconTypeIndex,
                                             iconPackageIndex, iconResourceIndex, iconIndex);
                                 }
 
                                 if (info == null) {
-                                    info = new ApplicationInfo();
-                                    info.icon = manager.getDefaultActivityIcon();
+                                    info = new ShortcutInfo();
+                                    info.setIcon(getDefaultIcon());
                                 }
 
                                 if (info != null) {
@@ -973,9 +987,7 @@
                     return;
                 }
 
-                final Context context = mContext;
-                final PackageManager packageManager = context.getPackageManager();
-
+                final PackageManager packageManager = mContext.getPackageManager();
                 final List<ResolveInfo> apps = packageManager.queryIntentActivities(mainIntent, 0);
 
                 synchronized (mLock) {
@@ -986,10 +998,9 @@
                         long t = SystemClock.uptimeMillis();
 
                         int N = apps.size();
-                        Utilities.BubbleText bubble = new Utilities.BubbleText(context);
                         for (int i=0; i<N && !mStopped; i++) {
                             // This builds the icon bitmaps.
-                            mAllAppsList.add(AppInfoCache.cache(apps.get(i), context, bubble));
+                            mAllAppsList.add(new ApplicationInfo(apps.get(i), mIconCache));
                         }
                         Collections.sort(mAllAppsList.data, APP_NAME_COMPARATOR);
                         Collections.sort(mAllAppsList.added, APP_NAME_COMPARATOR);
@@ -1050,9 +1061,9 @@
     }
 
     /**
-     * Make an ApplicationInfo object for an application.
+     * Make an ShortcutInfo object for a sortcut that is an application.
      */
-    private static ApplicationInfo getApplicationInfo(PackageManager manager, Intent intent,
+    public ShortcutInfo getShortcutInfo(PackageManager manager, Intent intent,
                                                       Context context) {
         final ResolveInfo resolveInfo = manager.resolveActivity(intent, 0);
 
@@ -1060,26 +1071,26 @@
             return null;
         }
 
-        final ApplicationInfo info = new ApplicationInfo();
+        final ShortcutInfo info = new ShortcutInfo();
         final ActivityInfo activityInfo = resolveInfo.activityInfo;
-        info.icon = Utilities.createIconThumbnail(activityInfo.loadIcon(manager), context);
+        info.setIcon(mIconCache.getIcon(intent.getComponent(), resolveInfo));
         if (info.title == null || info.title.length() == 0) {
             info.title = activityInfo.loadLabel(manager);
         }
         if (info.title == null) {
-            info.title = "";
+            info.title = activityInfo.name;
         }
         info.itemType = LauncherSettings.Favorites.ITEM_TYPE_APPLICATION;
         return info;
     }
 
     /**
-     * Make an ApplicationInfo object for a sortcut
+     * Make an ShortcutInfo object for a shortcut that isn't an application.
      */
-    private static ApplicationInfo getApplicationInfoShortcut(Cursor c, Context context,
+    private ShortcutInfo getShortcutInfo(Cursor c, Context context,
             int iconTypeIndex, int iconPackageIndex, int iconResourceIndex, int iconIndex) {
 
-        final ApplicationInfo info = new ApplicationInfo();
+        final ShortcutInfo info = new ShortcutInfo();
         info.itemType = LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT;
 
         int iconType = c.getInt(iconTypeIndex);
@@ -1091,9 +1102,9 @@
             try {
                 Resources resources = packageManager.getResourcesForApplication(packageName);
                 final int id = resources.getIdentifier(resourceName, null, null);
-                info.icon = Utilities.createIconThumbnail(resources.getDrawable(id), context);
+                info.setIcon(Utilities.createIconBitmap(resources.getDrawable(id), context));
             } catch (Exception e) {
-                info.icon = packageManager.getDefaultActivityIcon();
+                info.setIcon(getDefaultIcon());
             }
             info.iconResource = new Intent.ShortcutIconResource();
             info.iconResource.packageName = packageName;
@@ -1104,23 +1115,74 @@
             byte[] data = c.getBlob(iconIndex);
             try {
                 Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
-                info.icon = new FastBitmapDrawable(
-                        Utilities.createBitmapThumbnail(bitmap, context));
+                info.setIcon(bitmap);
             } catch (Exception e) {
-                packageManager = context.getPackageManager();
-                info.icon = packageManager.getDefaultActivityIcon();
+                info.setIcon(getDefaultIcon());
             }
-            info.filtered = true;
             info.customIcon = true;
             break;
         default:
-            info.icon = context.getPackageManager().getDefaultActivityIcon();
+            info.setIcon(getDefaultIcon());
             info.customIcon = false;
             break;
         }
         return info;
     }
 
+    ShortcutInfo addShortcut(Context context, Intent data,
+            CellLayout.CellInfo cellInfo, boolean notify) {
+
+        final ShortcutInfo info = infoFromShortcutIntent(context, data);
+        addItemToDatabase(context, info, LauncherSettings.Favorites.CONTAINER_DESKTOP,
+                cellInfo.screen, cellInfo.cellX, cellInfo.cellY, notify);
+
+        return info;
+    }
+
+    private ShortcutInfo infoFromShortcutIntent(Context context, Intent data) {
+        Intent intent = data.getParcelableExtra(Intent.EXTRA_SHORTCUT_INTENT);
+        String name = data.getStringExtra(Intent.EXTRA_SHORTCUT_NAME);
+        Parcelable bitmap = data.getParcelableExtra(Intent.EXTRA_SHORTCUT_ICON);
+
+        Bitmap icon = null;
+        boolean filtered = false;
+        boolean customIcon = false;
+        ShortcutIconResource iconResource = null;
+
+        if (bitmap != null && bitmap instanceof Bitmap) {
+            icon = Utilities.createIconBitmap(new FastBitmapDrawable((Bitmap)bitmap), context);
+            filtered = true;
+            customIcon = true;
+        } else {
+            Parcelable extra = data.getParcelableExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE);
+            if (extra != null && extra instanceof ShortcutIconResource) {
+                try {
+                    iconResource = (ShortcutIconResource) extra;
+                    final PackageManager packageManager = context.getPackageManager();
+                    Resources resources = packageManager.getResourcesForApplication(
+                            iconResource.packageName);
+                    final int id = resources.getIdentifier(iconResource.resourceName, null, null);
+                    icon = Utilities.createIconBitmap(resources.getDrawable(id), context);
+                } catch (Exception e) {
+                    Log.w(TAG, "Could not load shortcut icon: " + extra);
+                }
+            }
+        }
+
+        if (icon == null) {
+            icon = getDefaultIcon();
+        }
+
+        final ShortcutInfo info = new ShortcutInfo();
+        info.setIcon(icon);
+        info.title = name;
+        info.intent = intent;
+        info.customIcon = customIcon;
+        info.iconResource = iconResource;
+
+        return info;
+    }
+
     private static void loadLiveFolderIcon(Context context, Cursor c, int iconTypeIndex,
             int iconPackageIndex, int iconResourceIndex, LiveFolderInfo liveFolderInfo) {
 
@@ -1133,18 +1195,21 @@
             try {
                 Resources resources = packageManager.getResourcesForApplication(packageName);
                 final int id = resources.getIdentifier(resourceName, null, null);
-                liveFolderInfo.icon = resources.getDrawable(id);
+                liveFolderInfo.icon = Utilities.createIconBitmap(resources.getDrawable(id),
+                        context);
             } catch (Exception e) {
-                liveFolderInfo.icon =
-                        context.getResources().getDrawable(R.drawable.ic_launcher_folder);
+                liveFolderInfo.icon = Utilities.createIconBitmap(
+                        context.getResources().getDrawable(R.drawable.ic_launcher_folder),
+                        context);
             }
             liveFolderInfo.iconResource = new Intent.ShortcutIconResource();
             liveFolderInfo.iconResource.packageName = packageName;
             liveFolderInfo.iconResource.resourceName = resourceName;
             break;
         default:
-            liveFolderInfo.icon =
-                    context.getResources().getDrawable(R.drawable.ic_launcher_folder);
+            liveFolderInfo.icon = Utilities.createIconBitmap(
+                    context.getResources().getDrawable(R.drawable.ic_launcher_folder),
+                    context);
         }
     }
 
diff --git a/src/com/android/launcher2/LauncherProvider.java b/src/com/android/launcher2/LauncherProvider.java
index f03e50c..4a08029 100644
--- a/src/com/android/launcher2/LauncherProvider.java
+++ b/src/com/android/launcher2/LauncherProvider.java
@@ -34,9 +34,12 @@
 import android.content.pm.ActivityInfo;
 import android.database.sqlite.SQLiteOpenHelper;
 import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteStatement;
 import android.database.sqlite.SQLiteQueryBuilder;
 import android.database.Cursor;
 import android.database.SQLException;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
 import android.util.Log;
 import android.util.Xml;
 import android.util.AttributeSet;
@@ -61,7 +64,7 @@
 
     private static final String DATABASE_NAME = "launcher.db";
     
-    private static final int DATABASE_VERSION = 7;
+    private static final int DATABASE_VERSION = 8;
 
     static final String AUTHORITY = "com.android.launcher2.settings";
     
@@ -392,6 +395,14 @@
                 version = 7;
             }
 
+            if (version < 8) {
+                // Version 8 (froyo) has the icons all normalized.  This should
+                // already be the case in practice, but we now rely on it and don't
+                // resample the images each time.
+                normalizeIcons(db);
+                version = 8;
+            }
+
             if (version != DATABASE_VERSION) {
                 Log.w(TAG, "Destroying all old data.");
                 db.execSQL("DROP TABLE IF EXISTS " + TABLE_FAVORITES);
@@ -466,6 +477,60 @@
             return true;
         }
 
+        private void normalizeIcons(SQLiteDatabase db) {
+            Log.d(TAG, "normalizing icons");
+
+            Cursor c = null;
+            try {
+                boolean logged = false;
+                final ContentValues values = new ContentValues();
+                final ContentResolver cr = mContext.getContentResolver();
+                final SQLiteStatement update = db.compileStatement("UPDATE favorites "
+                        + "WHERE _id=? SET icon=?");
+
+                c = db.rawQuery("SELECT _id, icon FROM favorites WHERE iconType=" +
+                        Favorites.ICON_TYPE_BITMAP, null);
+
+                final int idIndex = c.getColumnIndexOrThrow(Favorites._ID);
+                final int iconIndex = c.getColumnIndexOrThrow(Favorites.ICON);
+
+                while (c.moveToNext()) {
+                    long id = c.getLong(idIndex);
+                    byte[] data = c.getBlob(iconIndex);
+                    try {
+                        Bitmap bitmap = Utilities.resampleIconBitmap(
+                                BitmapFactory.decodeByteArray(data, 0, data.length),
+                                mContext);
+                        if (bitmap != null) {
+                            update.bindLong(1, id);
+                            data = ItemInfo.flattenBitmap(bitmap);
+                            if (data != null) {
+                                update.bindBlob(2, data);
+                                update.execute();
+                            }
+                            bitmap.recycle();
+                            bitmap = null;
+                        }
+                    } catch (Exception e) {
+                        if (!logged) {
+                            Log.e(TAG, "Failed normalizing icon " + id, e);
+                        } else {
+                            Log.e(TAG, "Also failed normalizing icon " + id);
+                        }
+                        logged = true;
+                    }
+                }
+            } catch (SQLException ex) {
+                Log.w(TAG, "Problem while allocating appWidgetIds for existing widgets", ex);
+            } finally {
+                db.endTransaction();
+                if (c != null) {
+                    c.close();
+                }
+            }
+            
+        }
+
         /**
          * Upgrade existing clock and photo frame widgets into their new widget
          * equivalents.
diff --git a/src/com/android/launcher2/LiveFolderAdapter.java b/src/com/android/launcher2/LiveFolderAdapter.java
index b0e9eff..58b43e3 100644
--- a/src/com/android/launcher2/LiveFolderAdapter.java
+++ b/src/com/android/launcher2/LiveFolderAdapter.java
@@ -141,7 +141,12 @@
 
             if (icon == null) {
                 final Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
-                icon = new FastBitmapDrawable(Utilities.createBitmapThumbnail(bitmap, mContext));
+                final Bitmap resampled = Utilities.resampleIconBitmap(bitmap, mContext);
+                if (bitmap != resampled) {
+                    // If we got back a different object, we don't need the old one any more.
+                    bitmap.recycle();
+                }
+                icon = new FastBitmapDrawable(resampled);
                 mCustomIcons.put(holder.id, new SoftReference<Drawable>(icon));
             }
         } else if (holder.iconResourceIndex != -1 && holder.iconPackageIndex != -1) {
@@ -154,7 +159,8 @@
                             cursor.getString(holder.iconPackageIndex));
                     final int id = resources.getIdentifier(resource,
                             null, null);
-                    icon = Utilities.createIconThumbnail(resources.getDrawable(id), mContext);
+                    icon = new FastBitmapDrawable(
+                            Utilities.createIconBitmap(resources.getDrawable(id), mContext));
                     mIcons.put(resource, icon);
                 } catch (Exception e) {
                     // Ignore
diff --git a/src/com/android/launcher2/LiveFolderIcon.java b/src/com/android/launcher2/LiveFolderIcon.java
index 55f100c..f80928b 100644
--- a/src/com/android/launcher2/LiveFolderIcon.java
+++ b/src/com/android/launcher2/LiveFolderIcon.java
@@ -21,7 +21,7 @@
 import android.util.AttributeSet;
 import android.view.ViewGroup;
 import android.view.LayoutInflater;
-import android.graphics.drawable.Drawable;
+import android.graphics.Bitmap;
 
 public class LiveFolderIcon extends FolderIcon {
     public LiveFolderIcon(Context context, AttributeSet attrs) {
@@ -39,13 +39,12 @@
                 LayoutInflater.from(launcher).inflate(resId, group, false);
 
         final Resources resources = launcher.getResources();
-        Drawable d = folderInfo.icon;
-        if (d == null) {
-            d = Utilities.createIconThumbnail(resources.getDrawable(R.drawable.ic_launcher_folder),
+        Bitmap b = folderInfo.icon;
+        if (b == null) {
+            b = Utilities.createIconBitmap(resources.getDrawable(R.drawable.ic_launcher_folder),
                     launcher);
-            folderInfo.filtered = true;
         }
-        icon.setCompoundDrawablesWithIntrinsicBounds(null, d, null, null);
+        icon.setCompoundDrawablesWithIntrinsicBounds(null, new FastBitmapDrawable(b), null, null);
         icon.setText(folderInfo.title);
         icon.setTag(folderInfo);
         icon.setOnClickListener(launcher);
diff --git a/src/com/android/launcher2/LiveFolderInfo.java b/src/com/android/launcher2/LiveFolderInfo.java
index 5b1217c..7d0a0f5 100644
--- a/src/com/android/launcher2/LiveFolderInfo.java
+++ b/src/com/android/launcher2/LiveFolderInfo.java
@@ -19,6 +19,7 @@
 import android.content.ContentValues;
 import android.content.Intent;
 import android.graphics.drawable.Drawable;
+import android.graphics.Bitmap;
 import android.net.Uri;
 
 class LiveFolderInfo extends FolderInfo {
@@ -41,12 +42,7 @@
     /**
      * The live folder icon.
      */
-    Drawable icon;
-
-    /**
-     * When set to true, indicates that the icon has been resized.
-     */
-    boolean filtered;
+    Bitmap icon;
 
     /**
      * Reference to the live folder icon as an application's resource.
diff --git a/src/com/android/launcher2/ShortcutInfo.java b/src/com/android/launcher2/ShortcutInfo.java
new file mode 100644
index 0000000..cb73ac0
--- /dev/null
+++ b/src/com/android/launcher2/ShortcutInfo.java
@@ -0,0 +1,159 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher2;
+
+import android.content.ComponentName;
+import android.content.ContentValues;
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.Bitmap;
+import android.graphics.drawable.Drawable;
+import android.util.Log;
+
+import java.util.ArrayList;
+
+/**
+ * Represents a launchable icon on the workspaces and in folders.
+ */
+class ShortcutInfo extends ItemInfo {
+
+    /**
+     * The application name.
+     */
+    CharSequence title;
+
+    /**
+     * The intent used to start the application.
+     */
+    Intent intent;
+
+    /**
+     * Indicates whether the icon comes from an application's resource (if false)
+     * or from a custom Bitmap (if true.)
+     */
+    boolean customIcon;
+
+    /**
+     * If isShortcut=true and customIcon=false, this contains a reference to the
+     * shortcut icon as an application's resource.
+     */
+    Intent.ShortcutIconResource iconResource;
+
+    /**
+     * The application icon.
+     */
+    private Bitmap mIcon;
+
+    ShortcutInfo() {
+        itemType = LauncherSettings.BaseLauncherColumns.ITEM_TYPE_SHORTCUT;
+    }
+    
+    public ShortcutInfo(ShortcutInfo info) {
+        super(info);
+        title = info.title.toString();
+        intent = new Intent(info.intent);
+        if (info.iconResource != null) {
+            iconResource = new Intent.ShortcutIconResource();
+            iconResource.packageName = info.iconResource.packageName;
+            iconResource.resourceName = info.iconResource.resourceName;
+        }
+        mIcon = info.mIcon; // TODO: should make a copy here.  maybe we don't need this ctor at all
+        customIcon = info.customIcon;
+    }
+
+    /** TODO: Remove this.  It's only called by ApplicationInfo.makeShortcut. */
+    public ShortcutInfo(ApplicationInfo info) {
+        super(info);
+        title = info.title.toString();
+        intent = new Intent(info.intent);
+        customIcon = false;
+    }
+
+    public void setIcon(Bitmap b) {
+        mIcon = b;
+    }
+
+    public Bitmap getIcon(IconCache iconCache) {
+        if (mIcon == null) {
+            mIcon = iconCache.getIcon(this.intent);
+        }
+        return mIcon;
+    }
+
+    /**
+     * Creates the application intent based on a component name and various launch flags.
+     * Sets {@link #itemType} to {@link LauncherSettings.BaseLauncherColumns#ITEM_TYPE_APPLICATION}.
+     *
+     * @param className the class name of the component representing the intent
+     * @param launchFlags the launch flags
+     */
+    final void setActivity(ComponentName className, int launchFlags) {
+        intent = new Intent(Intent.ACTION_MAIN);
+        intent.addCategory(Intent.CATEGORY_LAUNCHER);
+        intent.setComponent(className);
+        intent.setFlags(launchFlags);
+        itemType = LauncherSettings.BaseLauncherColumns.ITEM_TYPE_APPLICATION;
+    }
+
+    @Override
+    void onAddToDatabase(ContentValues values) {
+        super.onAddToDatabase(values);
+
+        String titleStr = title != null ? title.toString() : null;
+        values.put(LauncherSettings.BaseLauncherColumns.TITLE, titleStr);
+
+        String uri = intent != null ? intent.toUri(0) : null;
+        values.put(LauncherSettings.BaseLauncherColumns.INTENT, uri);
+
+        if (customIcon) {
+            values.put(LauncherSettings.BaseLauncherColumns.ICON_TYPE,
+                    LauncherSettings.BaseLauncherColumns.ICON_TYPE_BITMAP);
+            Bitmap bitmap = this.mIcon;
+            writeBitmap(values, bitmap);
+        } else {
+            values.put(LauncherSettings.BaseLauncherColumns.ICON_TYPE,
+                    LauncherSettings.BaseLauncherColumns.ICON_TYPE_RESOURCE);
+            if (iconResource != null) {
+                values.put(LauncherSettings.BaseLauncherColumns.ICON_PACKAGE,
+                        iconResource.packageName);
+                values.put(LauncherSettings.BaseLauncherColumns.ICON_RESOURCE,
+                        iconResource.resourceName);
+            }
+        }
+    }
+
+    @Override
+    public String toString() {
+        return title.toString();
+    }
+
+    @Override
+    void unbind() {
+        super.unbind();
+    }
+
+
+    public static void dumpShortcutInfoList(String tag, String label,
+            ArrayList<ShortcutInfo> list) {
+        Log.d(tag, label + " size=" + list.size());
+        for (ShortcutInfo info: list) {
+            Log.d(tag, "   title=\"" + info.title + " icon=" + info.mIcon
+                    + " customIcon=" + info.customIcon);
+        }
+    }
+}
+
diff --git a/src/com/android/launcher2/ApplicationsAdapter.java b/src/com/android/launcher2/ShortcutsAdapter.java
similarity index 73%
rename from src/com/android/launcher2/ApplicationsAdapter.java
rename to src/com/android/launcher2/ShortcutsAdapter.java
index 129103a..212b5d6 100644
--- a/src/com/android/launcher2/ApplicationsAdapter.java
+++ b/src/com/android/launcher2/ShortcutsAdapter.java
@@ -29,34 +29,29 @@
 /**
  * GridView adapter to show the list of applications and shortcuts
  */
-public class ApplicationsAdapter  extends ArrayAdapter<ApplicationInfo> {
+public class ShortcutsAdapter  extends ArrayAdapter<ShortcutInfo> {
     private final LayoutInflater mInflater;
     private final PackageManager mPackageManager;
+    private final IconCache mIconCache;
 
-    public ApplicationsAdapter(Context context, ArrayList<ApplicationInfo> apps) {
+    public ShortcutsAdapter(Context context, ArrayList<ShortcutInfo> apps) {
         super(context, 0, apps);
         mPackageManager = context.getPackageManager();
         mInflater = LayoutInflater.from(context);
+        mIconCache = ((LauncherApplication)context.getApplicationContext()).getIconCache();
     }
 
     @Override
     public View getView(int position, View convertView, ViewGroup parent) {
-        final ApplicationInfo info = getItem(position);
+        final ShortcutInfo info = getItem(position);
 
         if (convertView == null) {
             convertView = mInflater.inflate(R.layout.application_boxed, parent, false);
         }
 
-        if (info.icon == null) {
-            info.icon = AppInfoCache.getIconDrawable(mPackageManager, info);
-        }
-        if (!info.filtered) {
-            info.icon = Utilities.createIconThumbnail(info.icon, getContext());
-            info.filtered = true;
-        }
-
         final TextView textView = (TextView) convertView;
-        textView.setCompoundDrawablesWithIntrinsicBounds(null, info.icon, null, null);
+        textView.setCompoundDrawablesWithIntrinsicBounds(null,
+                new FastBitmapDrawable(info.getIcon(mIconCache)), null, null);
         textView.setText(info.title);
 
         return convertView;
diff --git a/src/com/android/launcher2/UserFolder.java b/src/com/android/launcher2/UserFolder.java
index 16fe616..1489492 100644
--- a/src/com/android/launcher2/UserFolder.java
+++ b/src/com/android/launcher2/UserFolder.java
@@ -46,13 +46,14 @@
 
     public void onDrop(DragSource source, int x, int y, int xOffset, int yOffset,
             DragView dragView, Object dragInfo) {
-        ApplicationInfo item = (ApplicationInfo) dragInfo;
-        if (item.container == NO_ID) {
+        ShortcutInfo item;
+        if (dragInfo instanceof ApplicationInfo) {
             // Came from all apps -- make a copy
-            item = new ApplicationInfo((ApplicationInfo)item);
+            item = ((ApplicationInfo)dragInfo).makeShortcut();
+        } else {
+            item = (ShortcutInfo)dragInfo;
         }
-        //noinspection unchecked
-        ((ArrayAdapter<ApplicationInfo>) mContent.getAdapter()).add((ApplicationInfo) dragInfo);
+        ((ShortcutsAdapter)mContent.getAdapter()).add(item);
         LauncherModel.addOrMoveItemInDatabase(mLauncher, item, mInfo.id, 0, 0, 0);
     }
 
@@ -71,16 +72,14 @@
     @Override
     public void onDropCompleted(View target, boolean success) {
         if (success) {
-            //noinspection unchecked
-            ArrayAdapter<ApplicationInfo> adapter =
-                    (ArrayAdapter<ApplicationInfo>) mContent.getAdapter();
+            ShortcutsAdapter adapter = (ShortcutsAdapter)mContent.getAdapter();
             adapter.remove(mDragItem);
         }
     }
 
     void bind(FolderInfo info) {
         super.bind(info);
-        setContentAdapter(new ApplicationsAdapter(mContext, ((UserFolderInfo) info).contents));
+        setContentAdapter(new ShortcutsAdapter(mContext, ((UserFolderInfo) info).contents));
     }
 
     // When the folder opens, we need to refresh the GridView's selection by
diff --git a/src/com/android/launcher2/UserFolderInfo.java b/src/com/android/launcher2/UserFolderInfo.java
index 75b19ee..0b8841c 100644
--- a/src/com/android/launcher2/UserFolderInfo.java
+++ b/src/com/android/launcher2/UserFolderInfo.java
@@ -27,7 +27,7 @@
     /**
      * The apps and shortcuts 
      */
-    ArrayList<ApplicationInfo> contents = new ArrayList<ApplicationInfo>();
+    ArrayList<ShortcutInfo> contents = new ArrayList<ShortcutInfo>();
     
     UserFolderInfo() {
         itemType = LauncherSettings.Favorites.ITEM_TYPE_USER_FOLDER;
@@ -38,7 +38,7 @@
      * 
      * @param item
      */
-    public void add(ApplicationInfo item) {
+    public void add(ShortcutInfo item) {
         contents.add(item);
     }
     
@@ -47,7 +47,7 @@
      * 
      * @param item
      */
-    public void remove(ApplicationInfo item) {
+    public void remove(ShortcutInfo item) {
         contents.remove(item);
     }
     
diff --git a/src/com/android/launcher2/Utilities.java b/src/com/android/launcher2/Utilities.java
index 30108af..93ff97a 100644
--- a/src/com/android/launcher2/Utilities.java
+++ b/src/com/android/launcher2/Utilities.java
@@ -85,87 +85,6 @@
         return bitmap;
     }
 
-    /**
-     * Returns a Drawable representing the thumbnail of the specified Drawable.
-     * The size of the thumbnail is defined by the dimension
-     * android.R.dimen.launcher_application_icon_size.
-     *
-     * @param icon The icon to get a thumbnail of.
-     * @param context The application's context.
-     *
-     * @return A thumbnail for the specified icon or the icon itself if the
-     *         thumbnail could not be created.
-     */
-    static Drawable createIconThumbnail(Drawable icon, Context context) {
-        synchronized (sCanvas) { // we share the statics :-(
-            if (sIconWidth == -1) {
-                initStatics(context);
-            }
-
-            int width = sIconWidth;
-            int height = sIconHeight;
-
-            if (icon instanceof PaintDrawable) {
-                PaintDrawable painter = (PaintDrawable) icon;
-                painter.setIntrinsicWidth(width);
-                painter.setIntrinsicHeight(height);
-            } else if (icon instanceof BitmapDrawable) {
-                // Ensure the bitmap has a density.
-                BitmapDrawable bitmapDrawable = (BitmapDrawable) icon;
-                Bitmap bitmap = bitmapDrawable.getBitmap();
-                if (bitmap.getDensity() == Bitmap.DENSITY_NONE) {
-                    bitmapDrawable.setTargetDensity(context.getResources().getDisplayMetrics());
-                }
-            }
-            int iconWidth = icon.getIntrinsicWidth();
-            int iconHeight = icon.getIntrinsicHeight();
-
-            if (iconWidth > 0 && iconHeight > 0) {
-                if (width < iconWidth || height < iconHeight) {
-                    final float ratio = (float) iconWidth / iconHeight;
-
-                    if (iconWidth > iconHeight) {
-                        height = (int) (width / ratio);
-                    } else if (iconHeight > iconWidth) {
-                        width = (int) (height * ratio);
-                    }
-
-                    final Bitmap.Config c = icon.getOpacity() != PixelFormat.OPAQUE ?
-                                Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565;
-                    final Bitmap thumb = Bitmap.createBitmap(sIconWidth, sIconHeight, c);
-                    final Canvas canvas = sCanvas;
-                    canvas.setBitmap(thumb);
-                    // Copy the old bounds to restore them later
-                    // If we were to do oldBounds = icon.getBounds(),
-                    // the call to setBounds() that follows would
-                    // change the same instance and we would lose the
-                    // old bounds
-                    sOldBounds.set(icon.getBounds());
-                    final int x = (sIconWidth - width) / 2;
-                    final int y = (sIconHeight - height) / 2;
-                    icon.setBounds(x, y, x + width, y + height);
-                    icon.draw(canvas);
-                    icon.setBounds(sOldBounds);
-                    icon = new FastBitmapDrawable(thumb);
-                } else if (iconWidth < width && iconHeight < height) {
-                    final Bitmap.Config c = Bitmap.Config.ARGB_8888;
-                    final Bitmap thumb = Bitmap.createBitmap(sIconWidth, sIconHeight, c);
-                    final Canvas canvas = sCanvas;
-                    canvas.setBitmap(thumb);
-                    sOldBounds.set(icon.getBounds());
-                    final int x = (width - iconWidth) / 2;
-                    final int y = (height - iconHeight) / 2;
-                    icon.setBounds(x, y, x + iconWidth, y + iconHeight);
-                    icon.draw(canvas);
-                    icon.setBounds(sOldBounds);
-                    icon = new FastBitmapDrawable(thumb);
-                }
-            }
-
-            return icon;
-        }
-    }
-
     static int sColors[] = { 0xffff0000, 0xff00ff00, 0xff0000ff };
     static int sColorIndex = 0;
 
@@ -173,7 +92,7 @@
      * Returns a bitmap suitable for the all apps view.  The bitmap will be a power
      * of two sized ARGB_8888 bitmap that can be used as a gl texture.
      */
-    static Bitmap createAllAppsBitmap(Drawable icon, Context context) {
+    static Bitmap createIconBitmap(Drawable icon, Context context) {
         synchronized (sCanvas) { // we share the statics :-(
             if (sIconWidth == -1) {
                 initStatics(context);
@@ -279,55 +198,17 @@
      * @return A thumbnail for the specified bitmap or the bitmap itself if the
      *         thumbnail could not be created.
      */
-    static Bitmap createBitmapThumbnail(Bitmap bitmap, Context context) {
+    static Bitmap resampleIconBitmap(Bitmap bitmap, Context context) {
         synchronized (sCanvas) { // we share the statics :-(
             if (sIconWidth == -1) {
                 initStatics(context);
             }
 
-            int width = sIconWidth;
-            int height = sIconHeight;
-
-            final int bitmapWidth = bitmap.getWidth();
-            final int bitmapHeight = bitmap.getHeight();
-
-            if (width > 0 && height > 0) {
-                if (width < bitmapWidth || height < bitmapHeight) {
-                    final float ratio = (float) bitmapWidth / bitmapHeight;
-
-                    if (bitmapWidth > bitmapHeight) {
-                        height = (int) (width / ratio);
-                    } else if (bitmapHeight > bitmapWidth) {
-                        width = (int) (height * ratio);
-                    }
-
-                    final Bitmap.Config c = (width == sIconWidth && height == sIconHeight) ?
-                            bitmap.getConfig() : Bitmap.Config.ARGB_8888;
-                    final Bitmap thumb = Bitmap.createBitmap(sIconWidth, sIconHeight, c);
-                    final Canvas canvas = sCanvas;
-                    final Paint paint = sPaint;
-                    canvas.setBitmap(thumb);
-                    paint.setDither(false);
-                    paint.setFilterBitmap(true);
-                    sBounds.set((sIconWidth - width) / 2, (sIconHeight - height) / 2, width, height);
-                    sOldBounds.set(0, 0, bitmapWidth, bitmapHeight);
-                    canvas.drawBitmap(bitmap, sOldBounds, sBounds, paint);
-                    return thumb;
-                } else if (bitmapWidth < width || bitmapHeight < height) {
-                    final Bitmap.Config c = Bitmap.Config.ARGB_8888;
-                    final Bitmap thumb = Bitmap.createBitmap(sIconWidth, sIconHeight, c);
-                    final Canvas canvas = sCanvas;
-                    final Paint paint = sPaint;
-                    canvas.setBitmap(thumb);
-                    paint.setDither(false);
-                    paint.setFilterBitmap(true);
-                    canvas.drawBitmap(bitmap, (sIconWidth - bitmapWidth) / 2,
-                            (sIconHeight - bitmapHeight) / 2, paint);
-                    return thumb;
-                }
+            if (bitmap.getWidth() == sIconWidth && bitmap.getHeight() == sIconHeight) {
+                return bitmap;
+            } else {
+                return createIconBitmap(new BitmapDrawable(bitmap), context);
             }
-
-            return bitmap;
         }
     }
 
diff --git a/src/com/android/launcher2/Workspace.java b/src/com/android/launcher2/Workspace.java
index 2c95bee..1d2d75e 100644
--- a/src/com/android/launcher2/Workspace.java
+++ b/src/com/android/launcher2/Workspace.java
@@ -90,6 +90,7 @@
     private OnLongClickListener mLongClickListener;
 
     private Launcher mLauncher;
+    private IconCache mIconCache;
     private DragController mDragController;
     
     /**
@@ -142,9 +143,12 @@
      * Initializes various states for this workspace.
      */
     private void initWorkspace() {
-        mScroller = new Scroller(getContext());
+        Context context = getContext();
+        mScroller = new Scroller(context);
         mCurrentScreen = mDefaultScreen;
         Launcher.setScreen(mCurrentScreen);
+        LauncherApplication app = (LauncherApplication)context.getApplicationContext();
+        mIconCache = app.getIconCache();
 
         final ViewConfiguration configuration = ViewConfiguration.get(getContext());
         mTouchSlop = configuration.getScaledTouchSlop();
@@ -880,11 +884,11 @@
         }
     }
 
-    void addApplicationShortcut(ApplicationInfo info, CellLayout.CellInfo cellInfo) {
+    void addApplicationShortcut(ShortcutInfo info, CellLayout.CellInfo cellInfo) {
         addApplicationShortcut(info, cellInfo, false);
     }
 
-    void addApplicationShortcut(ApplicationInfo info, CellLayout.CellInfo cellInfo,
+    void addApplicationShortcut(ShortcutInfo info, CellLayout.CellInfo cellInfo,
             boolean insertAtFirst) {
         final CellLayout layout = (CellLayout) getChildAt(cellInfo.screen);
         final int[] result = new int[2];
@@ -950,10 +954,9 @@
         case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:
             if (info.container == NO_ID) {
                 // Came from all apps -- make a copy
-                info = new ApplicationInfo((ApplicationInfo) info);
+                info = new ShortcutInfo((ShortcutInfo)info);
             }
-            view = mLauncher.createShortcut(R.layout.application, cellLayout,
-                    (ApplicationInfo) info);
+            view = mLauncher.createShortcut(R.layout.application, cellLayout, (ShortcutInfo)info);
             break;
         case LauncherSettings.Favorites.ITEM_TYPE_USER_FOLDER:
             view = FolderIcon.fromXml(R.layout.folder_icon, mLauncher,
@@ -1183,8 +1186,8 @@
                         final View view = layout.getChildAt(j);
                         Object tag = view.getTag();
         
-                        if (tag instanceof ApplicationInfo) {
-                            final ApplicationInfo info = (ApplicationInfo) tag;
+                        if (tag instanceof ShortcutInfo) {
+                            final ShortcutInfo info = (ShortcutInfo) tag;
                             // We need to check for ACTION_MAIN otherwise getComponent() might
                             // return null for some shortcuts (for instance, for shortcuts to
                             // web pages.)
@@ -1199,14 +1202,13 @@
                             }
                         } else if (tag instanceof UserFolderInfo) {
                             final UserFolderInfo info = (UserFolderInfo) tag;
-                            final ArrayList<ApplicationInfo> contents = info.contents;
-                            final ArrayList<ApplicationInfo> toRemove =
-                                    new ArrayList<ApplicationInfo>(1);
+                            final ArrayList<ShortcutInfo> contents = info.contents;
+                            final ArrayList<ShortcutInfo> toRemove = new ArrayList<ShortcutInfo>(1);
                             final int contentsCount = contents.size();
                             boolean removedFromFolder = false;
         
                             for (int k = 0; k < contentsCount; k++) {
-                                final ApplicationInfo appInfo = contents.get(k);
+                                final ShortcutInfo appInfo = contents.get(k);
                                 final Intent intent = appInfo.intent;
                                 final ComponentName name = intent.getComponent();
         
@@ -1277,8 +1279,8 @@
             for (int j = 0; j < childCount; j++) {
                 final View view = layout.getChildAt(j);
                 Object tag = view.getTag();
-                if (tag instanceof ApplicationInfo) {
-                    ApplicationInfo info = (ApplicationInfo) tag;
+                if (tag instanceof ShortcutInfo) {
+                    ShortcutInfo info = (ShortcutInfo)tag;
                     // We need to check for ACTION_MAIN otherwise getComponent() might
                     // return null for some shortcuts (for instance, for shortcuts to
                     // web pages.)
@@ -1288,14 +1290,9 @@
                             Intent.ACTION_MAIN.equals(intent.getAction()) && name != null &&
                             packageName.equals(name.getPackageName())) {
 
-                        final Drawable icon = AppInfoCache.getIconDrawable(pm, info);
-                        if (icon != null && icon != info.icon) {
-                            info.icon.setCallback(null);
-                            info.icon = Utilities.createIconThumbnail(icon, mContext);
-                            info.filtered = true;
-                            ((TextView) view).setCompoundDrawablesWithIntrinsicBounds(null,
-                                    info.icon, null, null);
-                        }
+                        info.setIcon(mIconCache.getIcon(info.intent));
+                        ((TextView) view).setCompoundDrawablesWithIntrinsicBounds(null,
+                                new FastBitmapDrawable(info.getIcon(mIconCache)), null, null);
                     }
                 }
             }