Merge "Split ApplicationInfo into ApplicationInfo which is used for AllAppsView and ShortcutInfo which is used for the workspace."
diff --git a/res/layout-land/workspace_screen.xml b/res/layout-land/workspace_screen.xml
index 5349aa4..2483f51 100644
--- a/res/layout-land/workspace_screen.xml
+++ b/res/layout-land/workspace_screen.xml
@@ -23,8 +23,8 @@
 
     launcher:cellWidth="@dimen/workspace_cell_width"
     launcher:cellHeight="@dimen/workspace_cell_height"
-    launcher:longAxisStartPadding="@dimen/button_bar_height"
-    launcher:longAxisEndPadding="@dimen/button_bar_height"
+    launcher:longAxisStartPadding="65dip"
+    launcher:longAxisEndPadding="65dip"
     launcher:shortAxisStartPadding="0dip"
     launcher:shortAxisEndPadding="0dip"
     launcher:shortAxisCells="4"
diff --git a/res/layout-port/workspace_screen.xml b/res/layout-port/workspace_screen.xml
index 522d345..b43375b 100644
--- a/res/layout-port/workspace_screen.xml
+++ b/res/layout-port/workspace_screen.xml
@@ -23,7 +23,7 @@
 
     launcher:cellWidth="@dimen/workspace_cell_width"
     launcher:cellHeight="@dimen/workspace_cell_height"
-    launcher:longAxisStartPadding="0dip"
+    launcher:longAxisStartPadding="8dip"
     launcher:longAxisEndPadding="@dimen/button_bar_height"
     launcher:shortAxisStartPadding="0dip"
     launcher:shortAxisEndPadding="0dip"
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);
                     }
                 }
             }