Merge "Fix bug where All Apps wasn't always getting updated"
diff --git a/Android.mk b/Android.mk
index 980d0e2..abcca40 100644
--- a/Android.mk
+++ b/Android.mk
@@ -14,8 +14,6 @@
 # limitations under the License.
 #
 
-ifneq ($(TARGET_SIMULATOR),true)
-
 LOCAL_PATH := $(call my-dir)
 include $(CLEAR_VARS)
 
@@ -36,5 +34,3 @@
 include $(BUILD_PACKAGE)
 
 include $(call all-makefiles-under,$(LOCAL_PATH))
-
-endif
diff --git a/res/drawable-hdpi/default_widget_preview.9.png b/res/drawable-hdpi/default_widget_preview.9.png
deleted file mode 100644
index 833daff..0000000
--- a/res/drawable-hdpi/default_widget_preview.9.png
+++ /dev/null
Binary files differ
diff --git a/res/values/config.xml b/res/values/config.xml
index f03ded7..fca0acc 100644
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -47,7 +47,7 @@
 
 <!-- Workspace -->
     <!-- The transition duration for the background of the drop targets -->
-    <integer name="config_dropTargetBgTransitionDuration">200</integer>
+    <integer name="config_dropTargetBgTransitionDuration">100</integer>
 
     <integer name="config_crosshairsFadeInTime">600</integer>
 
diff --git a/src/com/android/launcher2/AllAppsList.java b/src/com/android/launcher2/AllAppsList.java
index 4c9bc5e..051b0bd 100644
--- a/src/com/android/launcher2/AllAppsList.java
+++ b/src/com/android/launcher2/AllAppsList.java
@@ -91,7 +91,7 @@
 
         if (matches.size() > 0) {
             for (ResolveInfo info : matches) {
-                add(new ApplicationInfo(context.getPackageManager(), info, mIconCache));
+                add(new ApplicationInfo(context.getPackageManager(), info, mIconCache, null));
             }
         }
     }
@@ -142,10 +142,10 @@
                         info.activityInfo.applicationInfo.packageName,
                         info.activityInfo.name);
                 if (applicationInfo == null) {
-                    add(new ApplicationInfo(context.getPackageManager(), info, mIconCache));
+                    add(new ApplicationInfo(context.getPackageManager(), info, mIconCache, null));
                 } else {
                     mIconCache.remove(applicationInfo.componentName);
-                    mIconCache.getTitleAndIcon(applicationInfo, info);
+                    mIconCache.getTitleAndIcon(applicationInfo, info, null);
                     modified.add(applicationInfo);
                 }
             }
diff --git a/src/com/android/launcher2/ApplicationInfo.java b/src/com/android/launcher2/ApplicationInfo.java
index 1d948b7..1fc1d1f 100644
--- a/src/com/android/launcher2/ApplicationInfo.java
+++ b/src/com/android/launcher2/ApplicationInfo.java
@@ -19,12 +19,13 @@
 import android.content.ComponentName;
 import android.content.Intent;
 import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
 import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.ResolveInfo;
 import android.graphics.Bitmap;
 import android.util.Log;
 
 import java.util.ArrayList;
+import java.util.HashMap;
 
 /**
  * Represents an app in AllAppsView.
@@ -38,11 +39,6 @@
     CharSequence title;
 
     /**
-     * A bitmap of the application's text in the bubble.
-     */
-    Bitmap titleBitmap;
-
-    /**
      * The intent used to start the application.
      */
     Intent intent;
@@ -71,7 +67,8 @@
     /**
      * Must not hold the Context.
      */
-    public ApplicationInfo(PackageManager pm, ResolveInfo info, IconCache iconCache) {
+    public ApplicationInfo(PackageManager pm, ResolveInfo info, IconCache iconCache,
+            HashMap<Object, CharSequence> labelCache) {
         final String packageName = info.activityInfo.applicationInfo.packageName;
 
         this.componentName = new ComponentName(packageName, info.activityInfo.name);
@@ -93,9 +90,9 @@
             Log.d(TAG, "PackageManager.getApplicationInfo failed for " + packageName);
         }
 
-        iconCache.getTitleAndIcon(this, info);
+        iconCache.getTitleAndIcon(this, info, labelCache);
     }
-    
+
     public ApplicationInfo(ApplicationInfo info) {
         super(info);
         componentName = info.componentName;
@@ -129,8 +126,8 @@
             ArrayList<ApplicationInfo> list) {
         Log.d(tag, label + " size=" + list.size());
         for (ApplicationInfo info: list) {
-            Log.d(tag, "   title=\"" + info.title + "\" titleBitmap=" + info.titleBitmap
-                    + " iconBitmap=" + info.iconBitmap + " firstInstallTime="
+            Log.d(tag, "   title=\"" + info.title + "\" iconBitmap="
+                    + info.iconBitmap + " firstInstallTime="
                     + info.firstInstallTime);
         }
     }
diff --git a/src/com/android/launcher2/AppsCustomizePagedView.java b/src/com/android/launcher2/AppsCustomizePagedView.java
index f5874bf..12fe971 100644
--- a/src/com/android/launcher2/AppsCustomizePagedView.java
+++ b/src/com/android/launcher2/AppsCustomizePagedView.java
@@ -833,19 +833,25 @@
         // Generate a preview image if we couldn't load one
         if (drawable == null) {
             Resources resources = mLauncher.getResources();
+            int bitmapWidth;
+            int bitmapHeight;
 
-            // Specify the dimensions of the bitmap
-            if (info.minWidth >= info.minHeight) {
-                expectedWidth = cellWidth;
-                expectedHeight = mWidgetPreviewIconPaddedDimension;
+            // Specify the dimensions of the bitmap (since we are using a default preview bg with 
+            // the full icon, we only imply the aspect ratio of the widget)
+            if (cellHSpan == cellVSpan) {
+                bitmapWidth = bitmapHeight = cellWidth;
+                expectedWidth = expectedHeight = mWidgetPreviewIconPaddedDimension;
+            } else if (cellHSpan >= cellVSpan) {
+                bitmapWidth = expectedWidth = cellWidth;
+                bitmapHeight = expectedHeight = mWidgetPreviewIconPaddedDimension;
             } else {
                 // Note that in vertical widgets, we might not have enough space due to the text
                 // label, so be conservative and use the width as a height bound
-                expectedWidth = mWidgetPreviewIconPaddedDimension;
-                expectedHeight = cellWidth;
+                bitmapWidth = expectedWidth = mWidgetPreviewIconPaddedDimension;
+                bitmapHeight = expectedHeight = cellWidth;
             }
 
-            preview = Bitmap.createBitmap(expectedWidth, expectedHeight, Config.ARGB_8888);
+            preview = Bitmap.createBitmap(bitmapWidth, bitmapHeight, Config.ARGB_8888);
             renderDrawableToBitmap(mDefaultWidgetBackground, preview, 0, 0, expectedWidth,
                     expectedHeight, 1f,1f);
 
diff --git a/src/com/android/launcher2/DeleteDropTarget.java b/src/com/android/launcher2/DeleteDropTarget.java
index afa2654..c8c6faa 100644
--- a/src/com/android/launcher2/DeleteDropTarget.java
+++ b/src/com/android/launcher2/DeleteDropTarget.java
@@ -113,6 +113,7 @@
         }
 
         mActive = isVisible;
+        mDrawable.resetTransition();
         setVisibility(isVisible ? View.VISIBLE : View.GONE);
         if (mText.getText().length() > 0) {
             mText.setText(isUninstall ? R.string.delete_target_uninstall_label
@@ -135,7 +136,9 @@
     public void onDragExit(DragObject d) {
         super.onDragExit(d);
 
-        mDrawable.resetTransition();
+        if (!d.dragComplete) {
+            mDrawable.resetTransition();
+        }
     }
 
     public void onDrop(DragObject d) {
diff --git a/src/com/android/launcher2/DragController.java b/src/com/android/launcher2/DragController.java
index f6058a0..5aecede 100644
--- a/src/com/android/launcher2/DragController.java
+++ b/src/com/android/launcher2/DragController.java
@@ -110,6 +110,9 @@
     private int mLastTouch[] = new int[2];
     private int mDistanceSinceScroll = 0;
 
+    private int mTmpPoint[] = new int[2];
+    private Rect mDragLayerRect = new Rect();
+
     /**
      * Interface to receive notifications when a drag starts or stops
      */
@@ -385,6 +388,16 @@
     }
 
     /**
+     * Clamps the position to the drag layer bounds.
+     */
+    private int[] getClampedDragLayerPos(float x, float y) {
+        mLauncher.getDragLayer().getLocalVisibleRect(mDragLayerRect);
+        mTmpPoint[0] = (int) Math.max(mDragLayerRect.left, Math.min(x, mDragLayerRect.right - 1));
+        mTmpPoint[1] = (int) Math.max(mDragLayerRect.top, Math.min(y, mDragLayerRect.bottom - 1));
+        return mTmpPoint;
+    }
+
+    /**
      * Call this from a drag source view.
      */
     public boolean onInterceptTouchEvent(MotionEvent ev) {
@@ -394,8 +407,9 @@
         }
         final int action = ev.getAction();
 
-        final int dragLayerX = (int) ev.getX();
-        final int dragLayerY = (int) ev.getY();
+        final int[] dragLayerPos = getClampedDragLayerPos(ev.getX(), ev.getY());
+        final int dragLayerX = dragLayerPos[0];
+        final int dragLayerY = dragLayerPos[1];
 
         switch (action) {
             case MotionEvent.ACTION_MOVE:
@@ -506,8 +520,9 @@
         }
 
         final int action = ev.getAction();
-        final int dragLayerX = (int) ev.getX();
-        final int dragLayerY = (int) ev.getY();
+        final int[] dragLayerPos = getClampedDragLayerPos(ev.getX(), ev.getY());
+        final int dragLayerX = dragLayerPos[0];
+        final int dragLayerY = dragLayerPos[1];
 
         switch (action) {
         case MotionEvent.ACTION_DOWN:
diff --git a/src/com/android/launcher2/DragView.java b/src/com/android/launcher2/DragView.java
index aff3d42..1c75e47 100644
--- a/src/com/android/launcher2/DragView.java
+++ b/src/com/android/launcher2/DragView.java
@@ -179,12 +179,6 @@
         canvas.drawBitmap(mBitmap, 0.0f, 0.0f, mPaint);
     }
 
-    @Override
-    protected void onDetachedFromWindow() {
-        super.onDetachedFromWindow();
-        mBitmap.recycle();
-    }
-
     public void setPaint(Paint paint) {
         mPaint = paint;
         invalidate();
diff --git a/src/com/android/launcher2/Folder.java b/src/com/android/launcher2/Folder.java
index 788d4b9..78df80f 100644
--- a/src/com/android/launcher2/Folder.java
+++ b/src/com/android/launcher2/Folder.java
@@ -54,14 +54,12 @@
 public class Folder extends LinearLayout implements DragSource, View.OnClickListener,
         View.OnLongClickListener, DropTarget, FolderListener, TextView.OnEditorActionListener {
 
-    protected DragController mDragController;
-
-    protected Launcher mLauncher;
-
-    protected FolderInfo mInfo;
-
     private static final String TAG = "Launcher.Folder";
 
+    protected DragController mDragController;
+    protected Launcher mLauncher;
+    protected FolderInfo mInfo;
+
     static final int STATE_NONE = -1;
     static final int STATE_SMALL = 0;
     static final int STATE_ANIMATING = 1;
@@ -132,6 +130,8 @@
         if (sHintText == null) {
             sHintText = res.getString(R.string.folder_hint_text);
         }
+
+        mLauncher = (Launcher) context;
     }
 
     @Override
@@ -286,10 +286,6 @@
         mDragController = dragController;
     }
 
-    void setLauncher(Launcher launcher) {
-        mLauncher = launcher;
-    }
-
     void setFolderIcon(FolderIcon icon) {
         mFolderIcon = icon;
     }
diff --git a/src/com/android/launcher2/FolderIcon.java b/src/com/android/launcher2/FolderIcon.java
index 283c295..952916d 100644
--- a/src/com/android/launcher2/FolderIcon.java
+++ b/src/com/android/launcher2/FolderIcon.java
@@ -127,7 +127,6 @@
 
         Folder folder = Folder.fromXml(launcher);
         folder.setDragController(launcher.getDragController());
-        folder.setLauncher(launcher);
         folder.setFolderIcon(icon);
         folder.bind(folderInfo);
         icon.mFolder = folder;
diff --git a/src/com/android/launcher2/FolderInfo.java b/src/com/android/launcher2/FolderInfo.java
index b5b5b29..3ae31d2 100644
--- a/src/com/android/launcher2/FolderInfo.java
+++ b/src/com/android/launcher2/FolderInfo.java
@@ -99,6 +99,12 @@
         }
     }
 
+    @Override
+    void unbind() {
+        super.unbind();
+        listeners.clear();
+    }
+
     interface FolderListener {
         public void onAdd(ShortcutInfo item);
         public void onRemove(ShortcutInfo item);
diff --git a/src/com/android/launcher2/IconCache.java b/src/com/android/launcher2/IconCache.java
index 22691a5..2977383 100644
--- a/src/com/android/launcher2/IconCache.java
+++ b/src/com/android/launcher2/IconCache.java
@@ -40,7 +40,6 @@
     private static class CacheEntry {
         public Bitmap icon;
         public String title;
-        public Bitmap titleBitmap;
     }
 
     private final Bitmap mDefaultIcon;
@@ -126,15 +125,12 @@
     /**
      * Fill in "application" with the icon and label for "info."
      */
-    public void getTitleAndIcon(ApplicationInfo application, ResolveInfo info) {
+    public void getTitleAndIcon(ApplicationInfo application, ResolveInfo info,
+            HashMap<Object, CharSequence> labelCache) {
         synchronized (mCache) {
-            CacheEntry entry = cacheLocked(application.componentName, info);
-            if (entry.titleBitmap == null) {
-                entry.titleBitmap = mBubble.createTextBitmap(entry.title);
-            }
+            CacheEntry entry = cacheLocked(application.componentName, info, labelCache);
 
             application.title = entry.title;
-            application.titleBitmap = entry.titleBitmap;
             application.iconBitmap = entry.icon;
         }
     }
@@ -148,7 +144,7 @@
                 return mDefaultIcon;
             }
 
-            CacheEntry entry = cacheLocked(component, resolveInfo);
+            CacheEntry entry = cacheLocked(component, resolveInfo, null);
             return entry.icon;
         }
     }
@@ -159,7 +155,7 @@
                 return null;
             }
 
-            CacheEntry entry = cacheLocked(component, resolveInfo);
+            CacheEntry entry = cacheLocked(component, resolveInfo, null);
             return entry.icon;
         }
     }
@@ -168,14 +164,22 @@
         return mDefaultIcon == icon;
     }
 
-    private CacheEntry cacheLocked(ComponentName componentName, ResolveInfo info) {
+    private CacheEntry cacheLocked(ComponentName componentName, ResolveInfo info,
+            HashMap<Object, CharSequence> labelCache) {
         CacheEntry entry = mCache.get(componentName);
         if (entry == null) {
             entry = new CacheEntry();
 
             mCache.put(componentName, entry);
 
-            entry.title = info.loadLabel(mPackageManager).toString();
+            if (labelCache != null && labelCache.containsKey(info)) {
+                entry.title = labelCache.get(info).toString();
+            } else {
+                entry.title = info.loadLabel(mPackageManager).toString();
+                if (labelCache != null) {
+                    labelCache.put(info, entry.title);
+                }
+            }
             if (entry.title == null) {
                 entry.title = info.activityInfo.name;
             }
diff --git a/src/com/android/launcher2/InfoDropTarget.java b/src/com/android/launcher2/InfoDropTarget.java
index c7812e3..02e3f01 100644
--- a/src/com/android/launcher2/InfoDropTarget.java
+++ b/src/com/android/launcher2/InfoDropTarget.java
@@ -97,6 +97,7 @@
         }
 
         mActive = isVisible;
+        mDrawable.resetTransition();
         setVisibility(isVisible ? View.VISIBLE : View.GONE);
     }
 
@@ -115,6 +116,8 @@
     public void onDragExit(DragObject d) {
         super.onDragExit(d);
 
-        mDrawable.resetTransition();
+        if (!d.dragComplete) {
+            mDrawable.resetTransition();
+        }
     }
 }
diff --git a/src/com/android/launcher2/ItemInfo.java b/src/com/android/launcher2/ItemInfo.java
index 3a1c29a..8d46624 100644
--- a/src/com/android/launcher2/ItemInfo.java
+++ b/src/com/android/launcher2/ItemInfo.java
@@ -144,7 +144,13 @@
             values.put(LauncherSettings.Favorites.ICON, data);
         }
     }
-    
+
+    /**
+     * It is very important that sub-classes implement this if they contain any references
+     * to the activity (anything in the view hierarchy etc.). If not, leaks can result since
+     * ItemInfo objects persist across rotation and can hence leak by holding stale references
+     * to the old view hierarchy / activity.
+     */
     void unbind() {
     }
 
diff --git a/src/com/android/launcher2/Launcher.java b/src/com/android/launcher2/Launcher.java
index 530f49c..4e69ee8 100644
--- a/src/com/android/launcher2/Launcher.java
+++ b/src/com/android/launcher2/Launcher.java
@@ -221,8 +221,6 @@
 
     private static LocaleConfiguration sLocaleConfiguration = null;
 
-    private ArrayList<ItemInfo> mDesktopItems = new ArrayList<ItemInfo>();
-
     private static HashMap<Long, FolderInfo> sFolders = new HashMap<Long, FolderInfo>();
 
     // Hotseats (quick-launch icons next to AllApps)
@@ -1098,8 +1096,6 @@
                 screen, cellXY[0], cellXY[1], false);
 
         if (!mRestoring) {
-            mDesktopItems.add(launcherInfo);
-
             // Perform actual inflation because we're live
             launcherInfo.hostView = mAppWidgetHost.createView(this, appWidgetId, appWidgetInfo);
 
@@ -1228,7 +1224,6 @@
     }
 
     public void removeAppWidget(LauncherAppWidgetInfo launcherInfo) {
-        mDesktopItems.remove(launcherInfo);
         removeWidgetToAutoAdvance(launcherInfo.hostView);
         launcherInfo.hostView = null;
     }
@@ -1314,6 +1309,9 @@
         super.onSaveInstanceState(outState);
 
         outState.putInt(RUNTIME_STATE, mState.ordinal());
+        // We close any open folder since it will not be re-opened, and we need to make sure
+        // this state is reflected.
+        closeFolder();
 
         if (mAddScreen > -1 && mWaitingForResult) {
             outState.putInt(RUNTIME_STATE_PENDING_ADD_SCREEN, mAddScreen);
@@ -1356,7 +1354,7 @@
         TextKeyListener.getInstance().release();
 
 
-        unbindDesktopItems();
+        unbindWorkspaceItems();
 
         getContentResolver().unregisterContentObserver(mWidgetObserver);
         unregisterReceiver(mCloseSystemDialogsReceiver);
@@ -1740,11 +1738,8 @@
      * Go through the and disconnect any of the callbacks in the drawables and the views or we
      * leak the previous Home screen on orientation change.
      */
-    private void unbindDesktopItems() {
-        for (ItemInfo item: mDesktopItems) {
-            item.unbind();
-        }
-        mDesktopItems.clear();
+    private void unbindWorkspaceItems() {
+        LauncherModel.unbindWorkspaceItems();
     }
 
     /**
@@ -2712,6 +2707,10 @@
             }
         } catch (NameNotFoundException e) {
             // Do nothing
+        } catch (Resources.NotFoundException nfe) {
+            // This can happen if the activity defines an invalid drawable
+            Log.w(TAG, "Failed to load toolbar icon from " + activityName.flattenToShortString(),
+                    nfe);
         }
         return null;
     }
@@ -3013,9 +3012,8 @@
             });
         }
 
-        // This wasn't being called before which resulted in a leak of AppWidgetHostViews (through
-        // mDesktopItems -> AppWidgetInfo -> hostView).
-        unbindDesktopItems();
+        // This wasn't being called before which resulted in a leak of AppWidgetHostViews
+        unbindWorkspaceItems();
     }
 
     /**
@@ -3031,7 +3029,6 @@
 
         for (int i=start; i<end; i++) {
             final ItemInfo item = shortcuts.get(i);
-            mDesktopItems.add(item);
             switch (item.itemType) {
                 case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:
                 case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:
@@ -3093,8 +3090,6 @@
 
         workspace.requestLayout();
 
-        mDesktopItems.add(item);
-
         if (DEBUG_WIDGETS) {
             Log.d(TAG, "bound widget id="+item.appWidgetId+" in "
                     + (SystemClock.uptimeMillis()-start) + "ms");
@@ -3266,7 +3261,6 @@
         Log.d(TAG, "mRestoring=" + mRestoring);
         Log.d(TAG, "mWaitingForResult=" + mWaitingForResult);
         Log.d(TAG, "mSavedInstanceState=" + mSavedInstanceState);
-        Log.d(TAG, "mDesktopItems.size=" + mDesktopItems.size());
         Log.d(TAG, "sFolders.size=" + sFolders.size());
         mModel.dumpState();
 
diff --git a/src/com/android/launcher2/LauncherModel.java b/src/com/android/launcher2/LauncherModel.java
index a177b31..1a097b5 100644
--- a/src/com/android/launcher2/LauncherModel.java
+++ b/src/com/android/launcher2/LauncherModel.java
@@ -98,7 +98,7 @@
     // sItems is passed to bindItems, which expects a list of all folders and shortcuts created by
     //       LauncherModel that are directly on the home screen (however, no widgets or shortcuts
     //       within folders).
-    static final ArrayList<ItemInfo> sItems = new ArrayList<ItemInfo>();
+    static final ArrayList<ItemInfo> sWorkspaceItems = new ArrayList<ItemInfo>();
 
     // sAppWidgets is all LauncherAppWidgetInfo created by LauncherModel. Passed to bindAppWidget()
     static final ArrayList<LauncherAppWidgetInfo> sAppWidgets =
@@ -148,6 +148,12 @@
         return Bitmap.createBitmap(mDefaultIcon);
     }
 
+    public static void unbindWorkspaceItems() {
+        for (ItemInfo item: sWorkspaceItems) {
+            item.unbind();
+        }
+    }
+
     /**
      * Adds an item to the DB if it was not created previously, or move it to a new
      * <container, screen, cellX, cellY>
@@ -197,11 +203,11 @@
                     // as in Workspace.onDrop. Here, we just add/remove them from the list of items
                     // that are on the desktop, as appropriate
                     if (modelItem.container == LauncherSettings.Favorites.CONTAINER_DESKTOP) {
-                        if (!sItems.contains(modelItem)) {
-                            sItems.add(modelItem);
+                        if (!sWorkspaceItems.contains(modelItem)) {
+                            sWorkspaceItems.add(modelItem);
                         }
                     } else {
-                        sItems.remove(modelItem);
+                        sWorkspaceItems.remove(modelItem);
                     }
                 }
             });
@@ -374,13 +380,13 @@
                     case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:
                         sFolders.put(item.id, (FolderInfo) item);
                         if (item.container == LauncherSettings.Favorites.CONTAINER_DESKTOP) {
-                            sItems.add(item);
+                            sWorkspaceItems.add(item);
                         }
                         break;
                     case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:
                     case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:
                         if (item.container == LauncherSettings.Favorites.CONTAINER_DESKTOP) {
-                            sItems.add(item);
+                            sWorkspaceItems.add(item);
                         }
                         break;
                     case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET:
@@ -456,11 +462,11 @@
                     switch (item.itemType) {
                         case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:
                             sFolders.remove(item.id);
-                            sItems.remove(item);
+                            sWorkspaceItems.remove(item);
                             break;
                         case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:
                         case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:
-                            sItems.remove(item);
+                            sWorkspaceItems.remove(item);
                             break;
                         case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET:
                             sAppWidgets.remove((LauncherAppWidgetInfo) item);
@@ -482,7 +488,7 @@
                     cr.delete(LauncherSettings.Favorites.getContentUri(info.id, false), null, null);
                     sItemsIdMap.remove(info.id);
                     sFolders.remove(info.id);
-                    sItems.remove(info);
+                    sWorkspaceItems.remove(info);
 
                     cr.delete(LauncherSettings.Favorites.CONTENT_URI,
                             LauncherSettings.Favorites.CONTAINER + "=" + info.id, null);
@@ -630,10 +636,12 @@
         private boolean mIsLaunching;
         private boolean mStopped;
         private boolean mLoadAndBindStepFinished;
+        private HashMap<Object, CharSequence> mLabelCache;
 
         LoaderTask(Context context, boolean isLaunching) {
             mContext = context;
             mIsLaunching = isLaunching;
+            mLabelCache = new HashMap<Object, CharSequence>();
         }
 
         boolean isLaunching() {
@@ -819,7 +827,7 @@
             final AppWidgetManager widgets = AppWidgetManager.getInstance(context);
             final boolean isSafeMode = manager.isSafeMode();
 
-            sItems.clear();
+            sWorkspaceItems.clear();
             sAppWidgets.clear();
             sFolders.clear();
             sItemsIdMap.clear();
@@ -888,7 +896,7 @@
 
                             if (itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION) {
                                 info = getShortcutInfo(manager, intent, context, c, iconIndex,
-                                        titleIndex);
+                                        titleIndex, mLabelCache);
                             } else {
                                 info = getShortcutInfo(c, context, iconTypeIndex,
                                         iconPackageIndex, iconResourceIndex, iconIndex,
@@ -911,7 +919,7 @@
 
                                 switch (container) {
                                 case LauncherSettings.Favorites.CONTAINER_DESKTOP:
-                                    sItems.add(info);
+                                    sWorkspaceItems.add(info);
                                     break;
                                 default:
                                     // Item is in a user folder
@@ -955,7 +963,7 @@
                             }
                             switch (container) {
                                 case LauncherSettings.Favorites.CONTAINER_DESKTOP:
-                                    sItems.add(folderInfo);
+                                    sWorkspaceItems.add(folderInfo);
                                     break;
                             }
 
@@ -1072,7 +1080,7 @@
                 }
             });
             // Add the items to the workspace.
-            N = sItems.size();
+            N = sWorkspaceItems.size();
             for (int i=0; i<N; i+=ITEMS_CHUNK) {
                 final int start = i;
                 final int chunkSize = (i+ITEMS_CHUNK <= N) ? ITEMS_CHUNK : (N-i);
@@ -1080,7 +1088,7 @@
                     public void run() {
                         Callbacks callbacks = tryGetCallbacks(oldCallbacks);
                         if (callbacks != null) {
-                            callbacks.bindItems(sItems, start, start+chunkSize);
+                            callbacks.bindItems(sWorkspaceItems, start, start+chunkSize);
                         }
                     }
                 });
@@ -1249,7 +1257,7 @@
 
                     final long sortTime = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0;
                     Collections.sort(apps,
-                            new ResolveInfo.DisplayNameComparator(packageManager));
+                            new LauncherModel.ShortcutNameComparator(packageManager, mLabelCache));
                     if (DEBUG_LOADERS) {
                         Log.d(TAG, "sort took "
                                 + (SystemClock.uptimeMillis()-sortTime) + "ms");
@@ -1261,7 +1269,8 @@
                 startIndex = i;
                 for (int j=0; i<N && j<batchSize; j++) {
                     // This builds the icon bitmaps.
-                    mAllAppsList.add(new ApplicationInfo(packageManager, apps.get(i), mIconCache));
+                    mAllAppsList.add(new ApplicationInfo(packageManager, apps.get(i),
+                            mIconCache, mLabelCache));
                     i++;
                 }
 
@@ -1317,7 +1326,7 @@
             Log.d(TAG, "mLoaderTask.mIsLaunching=" + mIsLaunching);
             Log.d(TAG, "mLoaderTask.mStopped=" + mStopped);
             Log.d(TAG, "mLoaderTask.mLoadAndBindStepFinished=" + mLoadAndBindStepFinished);
-            Log.d(TAG, "mItems size=" + sItems.size());
+            Log.d(TAG, "mItems size=" + sWorkspaceItems.size());
         }
     }
 
@@ -1446,7 +1455,7 @@
      * doesn't have a Cursor, but
      */
     public ShortcutInfo getShortcutInfo(PackageManager manager, Intent intent, Context context) {
-        return getShortcutInfo(manager, intent, context, null, -1, -1);
+        return getShortcutInfo(manager, intent, context, null, -1, -1, null);
     }
 
     /**
@@ -1455,7 +1464,7 @@
      * If c is not null, then it will be used to fill in missing data like the title and icon.
      */
     public ShortcutInfo getShortcutInfo(PackageManager manager, Intent intent, Context context,
-            Cursor c, int iconIndex, int titleIndex) {
+            Cursor c, int iconIndex, int titleIndex, HashMap<Object, CharSequence> labelCache) {
         Bitmap icon = null;
         final ShortcutInfo info = new ShortcutInfo();
 
@@ -1490,7 +1499,14 @@
 
         // from the resource
         if (resolveInfo != null) {
-            info.title = resolveInfo.activityInfo.loadLabel(manager);
+            if (labelCache != null && labelCache.containsKey(resolveInfo)) {
+                info.title = labelCache.get(resolveInfo);
+            } else {
+                info.title = resolveInfo.activityInfo.loadLabel(manager);
+                if (labelCache != null) {
+                    labelCache.put(resolveInfo, info.title);
+                }
+            }
         }
         // from the db
         if (info.title == null) {
@@ -1770,17 +1786,31 @@
     };
     public static class ShortcutNameComparator implements Comparator<ResolveInfo> {
         private PackageManager mPackageManager;
-        private HashMap<Object, String> mLabelCache;
+        private HashMap<Object, CharSequence> mLabelCache;
         ShortcutNameComparator(PackageManager pm) {
             mPackageManager = pm;
-            mLabelCache = new HashMap<Object, String>();
+            mLabelCache = new HashMap<Object, CharSequence>();
+        }
+        ShortcutNameComparator(PackageManager pm, HashMap<Object, CharSequence> labelCache) {
+            mPackageManager = pm;
+            mLabelCache = labelCache;
         }
         public final int compare(ResolveInfo a, ResolveInfo b) {
-            String labelA, labelB;
-            if (mLabelCache.containsKey(a)) labelA = mLabelCache.get(a);
-            else labelA = a.loadLabel(mPackageManager).toString();
-            if (mLabelCache.containsKey(b)) labelB = mLabelCache.get(b);
-            else labelB = b.loadLabel(mPackageManager).toString();
+            CharSequence labelA, labelB;
+            if (mLabelCache.containsKey(a)) {
+                labelA = mLabelCache.get(a);
+            } else {
+                labelA = a.loadLabel(mPackageManager).toString();
+
+                mLabelCache.put(a, labelA);
+            }
+            if (mLabelCache.containsKey(b)) {
+                labelB = mLabelCache.get(b);
+            } else {
+                labelB = b.loadLabel(mPackageManager).toString();
+
+                mLabelCache.put(b, labelB);
+            }
             return sCollator.compare(labelA, labelB);
         }
     };
@@ -1793,14 +1823,22 @@
         }
         public final int compare(Object a, Object b) {
             String labelA, labelB;
-            if (mLabelCache.containsKey(a)) labelA = mLabelCache.get(a);
-            else labelA = (a instanceof AppWidgetProviderInfo) ?
+            if (mLabelCache.containsKey(a)) {
+                labelA = mLabelCache.get(a);
+            } else {
+                labelA = (a instanceof AppWidgetProviderInfo) ?
                     ((AppWidgetProviderInfo) a).label :
                     ((ResolveInfo) a).loadLabel(mPackageManager).toString();
-            if (mLabelCache.containsKey(b)) labelB = mLabelCache.get(b);
-            else labelB = (b instanceof AppWidgetProviderInfo) ?
+                mLabelCache.put(a, labelA);
+            }
+            if (mLabelCache.containsKey(b)) {
+                labelB = mLabelCache.get(b);
+            } else {
+                labelB = (b instanceof AppWidgetProviderInfo) ?
                     ((AppWidgetProviderInfo) b).label :
                     ((ResolveInfo) b).loadLabel(mPackageManager).toString();
+                mLabelCache.put(b, labelB);
+            }
             return sCollator.compare(labelA, labelB);
         }
     };
diff --git a/src/com/android/launcher2/PagedViewIcon.java b/src/com/android/launcher2/PagedViewIcon.java
index a48a4ef..3ae978d 100644
--- a/src/com/android/launcher2/PagedViewIcon.java
+++ b/src/com/android/launcher2/PagedViewIcon.java
@@ -103,16 +103,6 @@
         setTag(info);
     }
 
-    public void applyFromResolveInfo(ResolveInfo info, PackageManager packageManager,
-            IconCache modelIconCache, HolographicOutlineHelper holoOutlineHelper) {
-        mHolographicOutlineHelper = holoOutlineHelper;
-        ComponentName cn = new ComponentName(info.activityInfo.packageName, info.activityInfo.name);
-        mIcon = modelIconCache.getIcon(cn, info);
-        setCompoundDrawablesWithIntrinsicBounds(null, new FastBitmapDrawable(mIcon), null, null);
-        setText(info.loadLabel(packageManager));
-        setTag(info);
-    }
-
     public void setHolographicOutline(Bitmap holoOutline) {
         mHolographicOutline = holoOutline;
         getHolographicOutlineView().invalidate();
@@ -120,8 +110,8 @@
 
     @Override
     public void setAlpha(float alpha) {
-        final float viewAlpha = mHolographicOutlineHelper.viewAlphaInterpolator(alpha);
-        final float holographicAlpha = mHolographicOutlineHelper.highlightAlphaInterpolator(alpha);
+        final float viewAlpha = HolographicOutlineHelper.viewAlphaInterpolator(alpha);
+        final float holographicAlpha = HolographicOutlineHelper.highlightAlphaInterpolator(alpha);
         int newViewAlpha = (int) (viewAlpha * 255);
         int newHolographicAlpha = (int) (holographicAlpha * 255);
         if ((mAlpha != newViewAlpha) || (mHolographicAlpha != newHolographicAlpha)) {
diff --git a/src/com/android/launcher2/SearchDropTargetBar.java b/src/com/android/launcher2/SearchDropTargetBar.java
index 4bfb40a..e4cf361 100644
--- a/src/com/android/launcher2/SearchDropTargetBar.java
+++ b/src/com/android/launcher2/SearchDropTargetBar.java
@@ -33,7 +33,7 @@
 public class SearchDropTargetBar extends FrameLayout implements DragController.DragListener {
 
     private static final int sTransitionInDuration = 275;
-    private static final int sTransitionOutDuration = 100;
+    private static final int sTransitionOutDuration = 125;
 
     private ObjectAnimator mDropTargetBarFadeInAnim;
     private ObjectAnimator mDropTargetBarFadeOutAnim;