am bcff7eda: am 9dc25f06: Merge "Fixing concurrent modification exception when iterating through new apps list. (Bug 6621553)" into jb-dev

* commit 'bcff7eda3731b7af254a1d5182766683ea1d46e3':
  Fixing concurrent modification exception when iterating through new apps list. (Bug 6621553)
diff --git a/Android.mk b/Android.mk
index abcca40..8a3d276 100644
--- a/Android.mk
+++ b/Android.mk
@@ -22,7 +22,7 @@
 LOCAL_STATIC_JAVA_LIBRARIES := android-common android-support-v13
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src) $(call all-renderscript-files-under, src)
-
+LOCAL_SDK_VERSION := 16
 
 LOCAL_PACKAGE_NAME := Launcher2
 LOCAL_CERTIFICATE := shared
diff --git a/res/drawable-hdpi/default_widget_preview_holo.9.png b/res/drawable-hdpi/default_widget_preview_holo.9.png
deleted file mode 100644
index 0b4a634..0000000
--- a/res/drawable-hdpi/default_widget_preview_holo.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/default_widget_preview_holo.9.png b/res/drawable-mdpi/default_widget_preview_holo.9.png
deleted file mode 100644
index 0bfdaef..0000000
--- a/res/drawable-mdpi/default_widget_preview_holo.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/default_widget_preview_holo.9.png b/res/drawable-xhdpi/default_widget_preview_holo.9.png
deleted file mode 100644
index 42d57d8..0000000
--- a/res/drawable-xhdpi/default_widget_preview_holo.9.png
+++ /dev/null
Binary files differ
diff --git a/res/values-sw720dp/dimens.xml b/res/values-sw720dp/dimens.xml
index 7daccd0..4750ae2 100644
--- a/res/values-sw720dp/dimens.xml
+++ b/res/values-sw720dp/dimens.xml
@@ -42,9 +42,6 @@
     <integer name="apps_customize_maxCellCountY">-1</integer>
     <dimen name="all_apps_button_vertical_padding">4dip</dimen>
 
-    <!-- roughly a status bar (for determining how many rows of icons are in home) -->
-    <dimen name="status_bar_height">48dip</dimen>
-
     <!-- dimensions for the wallpaper picker wallpaper thumbnail width -->
     <dimen name="wallpaper_chooser_grid_width">196dp</dimen>
     <dimen name="wallpaper_chooser_grid_height">140dp</dimen>
diff --git a/res/values-tr/strings.xml b/res/values-tr/strings.xml
index d9ce915..58fd9d0 100644
--- a/res/values-tr/strings.xml
+++ b/res/values-tr/strings.xml
@@ -63,7 +63,7 @@
     <string name="accessibility_delete_button" msgid="3628162007991023603">"Kaldır"</string>
     <string name="delete_zone_label_all_apps_system_app" msgid="3683920959591819044">"Güncelleme kaldırılsın mı?"</string>
     <string name="menu_add" msgid="3065046628354640854">"Ekle"</string>
-    <string name="menu_manage_apps" msgid="2308685199463588895">"Uyglm yönet"</string>
+    <string name="menu_manage_apps" msgid="2308685199463588895">"Uygulamaları yönet"</string>
     <string name="menu_wallpaper" msgid="5837429080911269832">"Duvar Kağıdı"</string>
     <string name="menu_search" msgid="4826514464423239041">"Ara"</string>
     <string name="menu_notifications" msgid="6424587053194766192">"Bildirimler"</string>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index f15d3d8..fb96c0d 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -86,10 +86,6 @@
     <!-- Drag padding to add to the bottom of drop targets -->
     <dimen name="drop_target_drag_padding">14dp</dimen>
 
-    <!-- roughly a status bar (for vertically centering the all apps
-         home icon in landscape) -->
-    <dimen name="status_bar_height">25dip</dimen>
-
 <!-- Dragging -->
     <!-- the area at the edge of the screen that makes the workspace go left
          or right while you're dragging. -->
diff --git a/src/com/android/launcher2/AllAppsView.java b/src/com/android/launcher2/AllAppsView.java
deleted file mode 100644
index e8ca61f..0000000
--- a/src/com/android/launcher2/AllAppsView.java
+++ /dev/null
@@ -1,48 +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 java.util.ArrayList;
-
-public interface AllAppsView {
-    public interface Watcher {
-        public void zoomed(float zoom);
-    }
-
-    public void setup(Launcher launcher, DragController dragController);
-
-    public void zoom(float zoom, boolean animate);
-
-    public boolean isVisible();
-
-    public boolean isAnimating();
-
-    public void setApps(ArrayList<ApplicationInfo> list);
-
-    public void addApps(ArrayList<ApplicationInfo> list);
-
-    public void removeApps(ArrayList<ApplicationInfo> list);
-
-    public void updateApps(ArrayList<ApplicationInfo> list);
-    
-    // Resets the AllApps page to the front
-    public void reset();
-
-    public void dumpState();
-
-    public void surrender();
-}
diff --git a/src/com/android/launcher2/AppWidgetResizeFrame.java b/src/com/android/launcher2/AppWidgetResizeFrame.java
index 8824686..e8b1dc0 100644
--- a/src/com/android/launcher2/AppWidgetResizeFrame.java
+++ b/src/com/android/launcher2/AppWidgetResizeFrame.java
@@ -403,17 +403,17 @@
                     newHeight);
             PropertyValuesHolder x = PropertyValuesHolder.ofInt("x", lp.x, newX);
             PropertyValuesHolder y = PropertyValuesHolder.ofInt("y", lp.y, newY);
-            ObjectAnimator oa = ObjectAnimator.ofPropertyValuesHolder(lp, width, height, x, y);
-            ObjectAnimator leftOa = ObjectAnimator.ofFloat(mLeftHandle, "alpha", 1.0f);
-            ObjectAnimator rightOa = ObjectAnimator.ofFloat(mRightHandle, "alpha", 1.0f);
-            ObjectAnimator topOa = ObjectAnimator.ofFloat(mTopHandle, "alpha", 1.0f);
-            ObjectAnimator bottomOa = ObjectAnimator.ofFloat(mBottomHandle, "alpha", 1.0f);
+            ObjectAnimator oa = LauncherAnimUtils.ofPropertyValuesHolder(lp, width, height, x, y);
+            ObjectAnimator leftOa = LauncherAnimUtils.ofFloat(mLeftHandle, "alpha", 1.0f);
+            ObjectAnimator rightOa = LauncherAnimUtils.ofFloat(mRightHandle, "alpha", 1.0f);
+            ObjectAnimator topOa = LauncherAnimUtils.ofFloat(mTopHandle, "alpha", 1.0f);
+            ObjectAnimator bottomOa = LauncherAnimUtils.ofFloat(mBottomHandle, "alpha", 1.0f);
             oa.addUpdateListener(new AnimatorUpdateListener() {
                 public void onAnimationUpdate(ValueAnimator animation) {
                     requestLayout();
                 }
             });
-            AnimatorSet set = new AnimatorSet();
+            AnimatorSet set = LauncherAnimUtils.createAnimatorSet();
             if (mResizeMode == AppWidgetProviderInfo.RESIZE_VERTICAL) {
                 set.playTogether(oa, topOa, bottomOa);
             } else if (mResizeMode == AppWidgetProviderInfo.RESIZE_HORIZONTAL) {
diff --git a/src/com/android/launcher2/AppsCustomizePagedView.java b/src/com/android/launcher2/AppsCustomizePagedView.java
index a508361..d55260c 100644
--- a/src/com/android/launcher2/AppsCustomizePagedView.java
+++ b/src/com/android/launcher2/AppsCustomizePagedView.java
@@ -17,7 +17,6 @@
 package com.android.launcher2;
 
 import android.animation.AnimatorSet;
-import android.animation.ObjectAnimator;
 import android.animation.ValueAnimator;
 import android.appwidget.AppWidgetHostView;
 import android.appwidget.AppWidgetManager;
@@ -35,15 +34,12 @@
 import android.graphics.Canvas;
 import android.graphics.ColorMatrix;
 import android.graphics.ColorMatrixColorFilter;
-import android.graphics.Insets;
-import android.graphics.MaskFilter;
 import android.graphics.Matrix;
 import android.graphics.Paint;
 import android.graphics.PorterDuff;
 import android.graphics.Rect;
 import android.graphics.RectF;
 import android.graphics.Shader;
-import android.graphics.TableMaskFilter;
 import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Drawable;
 import android.os.AsyncTask;
@@ -60,17 +56,16 @@
 import android.view.animation.DecelerateInterpolator;
 import android.widget.GridLayout;
 import android.widget.ImageView;
-import android.widget.LinearLayout;
 import android.widget.Toast;
 
 import com.android.launcher.R;
 import com.android.launcher2.DropTarget.DragObject;
 
+import java.lang.ref.WeakReference;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Iterator;
 import java.util.List;
-import java.lang.ref.WeakReference;
 
 /**
  * A simple callback interface which also provides the results of the task.
@@ -233,7 +228,7 @@
  * The Apps/Customize page that displays all the applications, widgets, and shortcuts.
  */
 public class AppsCustomizePagedView extends PagedViewWithDraggableItems implements
-        AllAppsView, View.OnClickListener, View.OnKeyListener, DragSource,
+        View.OnClickListener, View.OnKeyListener, DragSource,
         PagedViewIcon.PressedCallback, PagedViewWidget.ShortPressListener,
         LauncherTransitionable {
     static final String TAG = "AppsCustomizePagedView";
@@ -267,7 +262,6 @@
 
     // Caching
     private Canvas mCanvas;
-    private Drawable mDefaultWidgetBackground;
     private IconCache mIconCache;
 
     // Dimens
@@ -336,7 +330,6 @@
 
         // Save the default widget preview background
         Resources resources = context.getResources();
-        mDefaultWidgetBackground = resources.getDrawable(R.drawable.default_widget_preview_holo);
         mAppIconSize = resources.getDimensionPixelSize(R.dimen.app_icon_size);
 
         TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.AppsCustomizePagedView, 0, 0);
@@ -529,20 +522,6 @@
     }
 
     public void onPackagesUpdated() {
-        // TODO: this isn't ideal, but we actually need to delay here. This call is triggered
-        // by a broadcast receiver, and in order for it to work correctly, we need to know that
-        // the AppWidgetService has already received and processed the same broadcast. Since there
-        // is no guarantee about ordering of broadcast receipt, we just delay here. This is a
-        // workaround until we add a callback from AppWidgetService to AppWidgetHost when widget
-        // packages are added, updated or removed.
-        postDelayed(new Runnable() {
-           public void run() {
-               updatePackages();
-           }
-        }, 1500);
-    }
-
-    public void updatePackages() {
         // Get the list of widgets and shortcuts
         mWidgets.clear();
         List<AppWidgetProviderInfo> widgets =
@@ -604,10 +583,10 @@
             // Create a little animation to show that the widget can move
             float offsetY = getResources().getDimensionPixelSize(R.dimen.dragViewOffsetY);
             final ImageView p = (ImageView) v.findViewById(R.id.widget_preview);
-            AnimatorSet bounce = new AnimatorSet();
-            ValueAnimator tyuAnim = ObjectAnimator.ofFloat(p, "translationY", offsetY);
+            AnimatorSet bounce = LauncherAnimUtils.createAnimatorSet();
+            ValueAnimator tyuAnim = LauncherAnimUtils.ofFloat(p, "translationY", offsetY);
             tyuAnim.setDuration(125);
-            ValueAnimator tydAnim = ObjectAnimator.ofFloat(p, "translationY", 0f);
+            ValueAnimator tydAnim = LauncherAnimUtils.ofFloat(p, "translationY", 0f);
             tydAnim.setDuration(100);
             bounce.play(tyuAnim).before(tydAnim);
             bounce.setInterpolator(new AccelerateInterpolator());
@@ -793,24 +772,17 @@
             createItemInfo.spanX = createItemInfo.spanY = 1;
         }
 
-        // We use a custom alpha clip table for the default widget previews
-        Paint alphaClipPaint = null;
-        if (createItemInfo instanceof PendingAddWidgetInfo) {
-            if (((PendingAddWidgetInfo) createItemInfo).previewImage != 0) {
-                MaskFilter alphaClipTable = TableMaskFilter.CreateClipTable(0, 255);
-                alphaClipPaint = new Paint();
-                alphaClipPaint.setMaskFilter(alphaClipTable);
-            }
-        }
+        // Don't clip alpha values for the drag outline if we're using the default widget preview
+        boolean clipAlpha = !(createItemInfo instanceof PendingAddWidgetInfo &&
+                (((PendingAddWidgetInfo) createItemInfo).previewImage == 0));
 
         // Save the preview for the outline generation, then dim the preview
         outline = Bitmap.createScaledBitmap(preview, preview.getWidth(), preview.getHeight(),
                 false);
 
         // Start the drag
-        alphaClipPaint = null;
         mLauncher.lockScreenOrientation();
-        mLauncher.getWorkspace().onDragStartedWithItem(createItemInfo, outline, alphaClipPaint);
+        mLauncher.getWorkspace().onDragStartedWithItem(createItemInfo, outline, clipAlpha);
         mDragController.startDrag(image, preview, this, createItemInfo,
                 DragController.DRAG_ACTION_COPY, null, scale);
         outline.recycle();
@@ -1240,7 +1212,6 @@
                 getResources().getDimensionPixelOffset(R.dimen.shortcut_preview_padding_right);
 
         int scaledIconWidth = (maxWidth - paddingLeft - paddingRight);
-        float scaleSize = scaledIconWidth / (float) mAppIconSize;
 
         renderDrawableToBitmap(
                 icon, tempBitmap, paddingLeft, paddingTop, scaledIconWidth, scaledIconWidth);
@@ -1328,7 +1299,6 @@
                         (int) ((previewDrawableHeight - mAppIconSize * iconScale) / 2);
                 if (iconId > 0)
                     icon = mIconCache.getFullResIcon(packageName, iconId);
-                Resources resources = mLauncher.getResources();
                 if (icon != null) {
                     renderDrawableToBitmap(icon, defaultPreview, hoffset,
                             yoffset, (int) (mAppIconSize * iconScale),
@@ -1688,23 +1658,10 @@
     /*
      * AllAppsView implementation
      */
-    @Override
     public void setup(Launcher launcher, DragController dragController) {
         mLauncher = launcher;
         mDragController = dragController;
     }
-    @Override
-    public void zoom(float zoom, boolean animate) {
-        // TODO-APPS_CUSTOMIZE: Call back to mLauncher.zoomed()
-    }
-    @Override
-    public boolean isVisible() {
-        return (getVisibility() == VISIBLE);
-    }
-    @Override
-    public boolean isAnimating() {
-        return false;
-    }
 
     /**
      * We should call thise method whenever the core data changes (mApps, mWidgets) so that we can
@@ -1723,7 +1680,6 @@
         }
     }
 
-    @Override
     public void setApps(ArrayList<ApplicationInfo> list) {
         mApps = list;
         Collections.sort(mApps, LauncherModel.APP_NAME_COMPARATOR);
@@ -1741,7 +1697,6 @@
             }
         }
     }
-    @Override
     public void addApps(ArrayList<ApplicationInfo> list) {
         addAppsWithoutInvalidate(list);
         updatePageCounts();
@@ -1758,6 +1713,16 @@
         }
         return -1;
     }
+    private int findAppByPackage(List<ApplicationInfo> list, String packageName) {
+        int length = list.size();
+        for (int i = 0; i < length; ++i) {
+            ApplicationInfo info = list.get(i);
+            if (ItemInfo.getPackageName(info.intent).equals(packageName)) {
+                return i;
+            }
+        }
+        return -1;
+    }
     private void removeAppsWithoutInvalidate(ArrayList<ApplicationInfo> list) {
         // loop through all the apps and remove apps that have the same component
         int length = list.size();
@@ -1769,13 +1734,21 @@
             }
         }
     }
-    @Override
-    public void removeApps(ArrayList<ApplicationInfo> list) {
-        removeAppsWithoutInvalidate(list);
+    private void removeAppsWithPackageNameWithoutInvalidate(ArrayList<String> packageNames) {
+        // loop through all the package names and remove apps that have the same package name
+        for (String pn : packageNames) {
+            int removeIndex = findAppByPackage(mApps, pn);
+            while (removeIndex > -1) {
+                mApps.remove(removeIndex);
+                removeIndex = findAppByPackage(mApps, pn);
+            }
+        }
+    }
+    public void removeApps(ArrayList<String> packageNames) {
+        removeAppsWithPackageNameWithoutInvalidate(packageNames);
         updatePageCounts();
         invalidateOnDataChange();
     }
-    @Override
     public void updateApps(ArrayList<ApplicationInfo> list) {
         // We remove and re-add the updated applications list because it's properties may have
         // changed (ie. the title), and this will ensure that the items will be in their proper
@@ -1786,7 +1759,6 @@
         invalidateOnDataChange();
     }
 
-    @Override
     public void reset() {
         // If we have reset, then we should not continue to restore the previous state
         mSaveInstanceStateItemIndex = -1;
@@ -1808,7 +1780,6 @@
         return (AppsCustomizeTabHost) mLauncher.findViewById(R.id.apps_customize_pane);
     }
 
-    @Override
     public void dumpState() {
         // TODO: Dump information related to current list of Applications, Widgets, etc.
         ApplicationInfo.dumpApplicationInfoList(TAG, "mApps", mApps);
@@ -1833,7 +1804,6 @@
         }
     }
 
-    @Override
     public void surrender() {
         // TODO: If we are in the middle of any process (ie. for holographic outlines, etc) we
         // should stop this now.
diff --git a/src/com/android/launcher2/AppsCustomizeTabHost.java b/src/com/android/launcher2/AppsCustomizeTabHost.java
index 9fa2f32..409affe 100644
--- a/src/com/android/launcher2/AppsCustomizeTabHost.java
+++ b/src/com/android/launcher2/AppsCustomizeTabHost.java
@@ -23,7 +23,6 @@
 import android.content.Context;
 import android.content.res.Resources;
 import android.util.AttributeSet;
-import android.util.Log;
 import android.view.LayoutInflater;
 import android.view.MotionEvent;
 import android.view.View;
@@ -58,8 +57,6 @@
     private boolean mResetAfterTransition;
     private Runnable mRelayoutAndMakeVisible;
 
-    private Launcher mLauncher;
-
     public AppsCustomizeTabHost(Context context, AttributeSet attrs) {
         super(context, attrs);
         mLayoutInflater = LayoutInflater.from(context);
@@ -71,10 +68,6 @@
             };
     }
 
-    public void setup(Launcher launcher) {
-        mLauncher = launcher;
-    }
-
     /**
      * Convenience methods to select specific tabs.  We want to set the content type immediately
      * in these cases, but we note that we still call setCurrentTabByTag() so that the tab view
@@ -272,7 +265,7 @@
                 onTabChangedEnd(type);
 
                 // Animate the transition
-                ObjectAnimator outAnim = ObjectAnimator.ofFloat(mAnimationBuffer, "alpha", 0f);
+                ObjectAnimator outAnim = LauncherAnimUtils.ofFloat(mAnimationBuffer, "alpha", 0f);
                 outAnim.addListener(new AnimatorListenerAdapter() {
                     @Override
                     public void onAnimationEnd(Animator animation) {
@@ -285,14 +278,14 @@
                         mAnimationBuffer.removeAllViews();
                     }
                 });
-                ObjectAnimator inAnim = ObjectAnimator.ofFloat(mAppsCustomizePane, "alpha", 1f);
+                ObjectAnimator inAnim = LauncherAnimUtils.ofFloat(mAppsCustomizePane, "alpha", 1f);
                 inAnim.addListener(new AnimatorListenerAdapter() {
                     @Override
                     public void onAnimationEnd(Animator animation) {
                         reloadCurrentPage();
                     }
                 });
-                AnimatorSet animSet = new AnimatorSet();
+                AnimatorSet animSet = LauncherAnimUtils.createAnimatorSet();
                 animSet.playTogether(outAnim, inAnim);
                 animSet.setDuration(duration);
                 animSet.start();
diff --git a/src/com/android/launcher2/CellLayout.java b/src/com/android/launcher2/CellLayout.java
index c028ff1..ccc842e 100644
--- a/src/com/android/launcher2/CellLayout.java
+++ b/src/com/android/launcher2/CellLayout.java
@@ -17,9 +17,8 @@
 package com.android.launcher2;
 
 import android.animation.Animator;
-import android.animation.AnimatorSet;
-import android.animation.ObjectAnimator;
 import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
 import android.animation.TimeInterpolator;
 import android.animation.ValueAnimator;
 import android.animation.ValueAnimator.AnimatorUpdateListener;
@@ -1082,7 +1081,7 @@
                 return true;
             }
 
-            ValueAnimator va = ValueAnimator.ofFloat(0f, 1f);
+            ValueAnimator va = LauncherAnimUtils.ofFloat(0f, 1f);
             va.setDuration(duration);
             mReorderAnimators.put(lp, va);
 
@@ -2064,7 +2063,7 @@
             if (finalDeltaX == 0 && finalDeltaY == 0) {
                 return;
             }
-            ValueAnimator va = ValueAnimator.ofFloat(0f, 1f);
+            ValueAnimator va = LauncherAnimUtils.ofFloat(0f, 1f);
             a = va;
             va.setRepeatMode(ValueAnimator.REVERSE);
             va.setRepeatCount(ValueAnimator.INFINITE);
@@ -2106,13 +2105,13 @@
                 a.cancel();
             }
 
-            AnimatorSet s = new AnimatorSet();
+            AnimatorSet s = LauncherAnimUtils.createAnimatorSet();
             a = s;
             s.playTogether(
-                ObjectAnimator.ofFloat(child, "scaleX", 1f),
-                ObjectAnimator.ofFloat(child, "scaleY", 1f),
-                ObjectAnimator.ofFloat(child, "translationX", 0f),
-                ObjectAnimator.ofFloat(child, "translationY", 0f)
+                LauncherAnimUtils.ofFloat(child, "scaleX", 1f),
+                LauncherAnimUtils.ofFloat(child, "scaleY", 1f),
+                LauncherAnimUtils.ofFloat(child, "translationX", 0f),
+                LauncherAnimUtils.ofFloat(child, "translationY", 0f)
             );
             s.setDuration(REORDER_ANIMATION_DURATION);
             s.setInterpolator(new android.view.animation.DecelerateInterpolator(1.5f));
diff --git a/src/com/android/launcher2/Cling.java b/src/com/android/launcher2/Cling.java
index c83ee2f..33cb26f 100644
--- a/src/com/android/launcher2/Cling.java
+++ b/src/com/android/launcher2/Cling.java
@@ -31,7 +31,6 @@
 import android.view.FocusFinder;
 import android.view.MotionEvent;
 import android.view.View;
-import android.view.accessibility.AccessibilityManager;
 import android.widget.FrameLayout;
 
 import com.android.launcher.R;
@@ -83,6 +82,8 @@
         TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.Cling, defStyle, 0);
         mDrawIdentifier = a.getString(R.styleable.Cling_drawIdentifier);
         a.recycle();
+
+        setClickable(true);
     }
 
     void init(Launcher l, int[] positionData) {
@@ -138,16 +139,8 @@
     }
 
     @Override
-    public View findViewToTakeAccessibilityFocusFromHover(View child, View descendant) {
-        if (descendant.includeForAccessibility()) {
-            return descendant;
-        }
-        return null;
-    }
-
-    @Override
     public View focusSearch(int direction) {
-        return this.focusSearch(null, direction);
+        return this.focusSearch(this, direction);
     }
 
     @Override
diff --git a/src/com/android/launcher2/DeleteDropTarget.java b/src/com/android/launcher2/DeleteDropTarget.java
index 949c035..39a0b09 100644
--- a/src/com/android/launcher2/DeleteDropTarget.java
+++ b/src/com/android/launcher2/DeleteDropTarget.java
@@ -25,7 +25,6 @@
 import android.content.res.Resources;
 import android.graphics.PointF;
 import android.graphics.Rect;
-import android.graphics.drawable.Drawable;
 import android.graphics.drawable.TransitionDrawable;
 import android.util.AttributeSet;
 import android.view.View;
diff --git a/src/com/android/launcher2/DragController.java b/src/com/android/launcher2/DragController.java
index 84f1515..4c42953 100644
--- a/src/com/android/launcher2/DragController.java
+++ b/src/com/android/launcher2/DragController.java
@@ -326,19 +326,17 @@
         }
         endDrag();
     }
-    public void onAppsRemoved(ArrayList<ApplicationInfo> apps, Context context) {
+    public void onAppsRemoved(ArrayList<String> packageNames, Context context) {
         // Cancel the current drag if we are removing an app that we are dragging
         if (mDragObject != null) {
             Object rawDragInfo = mDragObject.dragInfo;
             if (rawDragInfo instanceof ShortcutInfo) {
                 ShortcutInfo dragInfo = (ShortcutInfo) rawDragInfo;
-                for (ApplicationInfo info : apps) {
+                for (String pn : packageNames) {
                     // Added null checks to prevent NPE we've seen in the wild
                     if (dragInfo != null &&
-                        dragInfo.intent != null &&
-                        info.intent != null) {
-                        boolean isSamePackage = dragInfo.getPackageName().equals(
-                                info.getPackageName());
+                        dragInfo.intent != null) {
+                        boolean isSamePackage = dragInfo.getPackageName().equals(pn);
                         if (isSamePackage) {
                             cancelDrag();
                             return;
diff --git a/src/com/android/launcher2/DragLayer.java b/src/com/android/launcher2/DragLayer.java
index 4be1914..0bcd64c 100644
--- a/src/com/android/launcher2/DragLayer.java
+++ b/src/com/android/launcher2/DragLayer.java
@@ -24,8 +24,6 @@
 import android.content.Context;
 import android.content.res.Resources;
 import android.graphics.Canvas;
-import android.graphics.PorterDuff;
-import android.graphics.PorterDuffColorFilter;
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
 import android.util.AttributeSet;
@@ -446,7 +444,6 @@
     public void animateViewIntoPosition(DragView dragView, final View child, int duration,
             final Runnable onFinishAnimationRunnable, View anchorView) {
         ShortcutAndWidgetContainer parentChildren = (ShortcutAndWidgetContainer) child.getParent();
-        CellLayout parent = (CellLayout) (CellLayout) parentChildren.getParent();
         CellLayout.LayoutParams lp =  (CellLayout.LayoutParams) child.getLayoutParams();
         parentChildren.measureChild(child);
 
diff --git a/src/com/android/launcher2/DragView.java b/src/com/android/launcher2/DragView.java
index b6645e1..d7ac97d 100644
--- a/src/com/android/launcher2/DragView.java
+++ b/src/com/android/launcher2/DragView.java
@@ -76,7 +76,7 @@
         final float scale = (width + scaleDps) / width;
 
         // Animate the view into the correct position
-        mAnim = ValueAnimator.ofFloat(0.0f, 1.0f);
+        mAnim = LauncherAnimUtils.ofFloat(0.0f, 1.0f);
         mAnim.setDuration(150);
         mAnim.addUpdateListener(new AnimatorUpdateListener() {
             @Override
@@ -199,7 +199,7 @@
     }
 
     public void crossFade(int duration) {
-        ValueAnimator va = ValueAnimator.ofFloat(0f, 1f);
+        ValueAnimator va = LauncherAnimUtils.ofFloat(0f, 1f);
         va.setDuration(duration);
         va.setInterpolator(new DecelerateInterpolator(1.5f));
         va.addUpdateListener(new AnimatorUpdateListener() {
diff --git a/src/com/android/launcher2/Folder.java b/src/com/android/launcher2/Folder.java
index de2e435..84c815e 100644
--- a/src/com/android/launcher2/Folder.java
+++ b/src/com/android/launcher2/Folder.java
@@ -57,8 +57,6 @@
 public class Folder extends LinearLayout implements DragSource, View.OnClickListener,
         View.OnLongClickListener, DropTarget, FolderListener, TextView.OnEditorActionListener,
         View.OnFocusChangeListener {
-
-    @SuppressWarnings("unused")
     private static final String TAG = "Launcher.Folder";
 
     protected DragController mDragController;
@@ -110,6 +108,8 @@
     private static String sHintText;
     private ObjectAnimator mOpenCloseAnimator;
 
+    private boolean mDestroyed;
+
     /**
      * Used to inflate the Workspace from XML.
      *
@@ -421,7 +421,7 @@
         PropertyValuesHolder scaleX = PropertyValuesHolder.ofFloat("scaleX", 1.0f);
         PropertyValuesHolder scaleY = PropertyValuesHolder.ofFloat("scaleY", 1.0f);
         final ObjectAnimator oa = mOpenCloseAnimator =
-            ObjectAnimator.ofPropertyValuesHolder(this, alpha, scaleX, scaleY);
+            LauncherAnimUtils.ofPropertyValuesHolder(this, alpha, scaleX, scaleY);
 
         oa.addListener(new AnimatorListenerAdapter() {
             @Override
@@ -479,7 +479,7 @@
         PropertyValuesHolder scaleX = PropertyValuesHolder.ofFloat("scaleX", 0.9f);
         PropertyValuesHolder scaleY = PropertyValuesHolder.ofFloat("scaleY", 0.9f);
         final ObjectAnimator oa = mOpenCloseAnimator =
-                ObjectAnimator.ofPropertyValuesHolder(this, alpha, scaleX, scaleY);
+                LauncherAnimUtils.ofPropertyValuesHolder(this, alpha, scaleX, scaleY);
 
         oa.addListener(new AnimatorListenerAdapter() {
             @Override
@@ -945,34 +945,45 @@
     }
 
     private void replaceFolderWithFinalItem() {
-        ItemInfo finalItem = null;
-
-        if (getItemCount() == 1) {
-            finalItem = mInfo.contents.get(0);
-        }
-
-        // Remove the folder completely
-        CellLayout cellLayout = mLauncher.getCellLayout(mInfo.container, mInfo.screen);
-        cellLayout.removeView(mFolderIcon);
-        if (mFolderIcon instanceof DropTarget) {
-            mDragController.removeDropTarget((DropTarget) mFolderIcon);
-        }
-        mLauncher.removeFolder(mInfo);
-
-        if (finalItem != null) {
-            LauncherModel.addOrMoveItemInDatabase(mLauncher, finalItem, mInfo.container,
-                    mInfo.screen, mInfo.cellX, mInfo.cellY);
-        }
-        LauncherModel.deleteItemFromDatabase(mLauncher, mInfo);
-
         // Add the last remaining child to the workspace in place of the folder
-        if (finalItem != null) {
-            View child = mLauncher.createShortcut(R.layout.application, cellLayout,
-                    (ShortcutInfo) finalItem);
+        Runnable onCompleteRunnable = new Runnable() {
+            @Override
+            public void run() {
+                CellLayout cellLayout = mLauncher.getCellLayout(mInfo.container, mInfo.screen);
 
-            mLauncher.getWorkspace().addInScreen(child, mInfo.container, mInfo.screen, mInfo.cellX,
-                    mInfo.cellY, mInfo.spanX, mInfo.spanY);
+                if (getItemCount() <= 1) {
+                    // Remove the folder
+                    LauncherModel.deleteItemFromDatabase(mLauncher, mInfo);
+                    cellLayout.removeView(mFolderIcon);
+                    if (mFolderIcon instanceof DropTarget) {
+                        mDragController.removeDropTarget((DropTarget) mFolderIcon);
+                    }
+                    mLauncher.removeFolder(mInfo);
+                }
+
+                // Move the item from the folder to the workspace, in the position of the folder
+                if (getItemCount() == 1) {
+                    ShortcutInfo finalItem = mInfo.contents.get(0);
+
+                    final View child = mLauncher.createShortcut(R.layout.application, cellLayout,
+                            finalItem);
+                    LauncherModel.addOrMoveItemInDatabase(mLauncher, finalItem, mInfo.container,
+                            mInfo.screen, mInfo.cellX, mInfo.cellY);
+                    mLauncher.getWorkspace().addInScreen(child, mInfo.container, mInfo.screen,
+                            mInfo.cellX, mInfo.cellY, mInfo.spanX, mInfo.spanY);
+                }
+
+            }
+        };
+        View finalChild = getItemAt(0);
+        if (finalChild != null) {
+            mFolderIcon.performDestroyAnimation(finalChild, onCompleteRunnable);
         }
+        mDestroyed = true;
+    }
+
+    boolean isDestroyed() {
+        return mDestroyed;
     }
 
     // This method keeps track of the last item in the folder for the purposes
diff --git a/src/com/android/launcher2/FolderIcon.java b/src/com/android/launcher2/FolderIcon.java
index 4919b57..af3eea9 100644
--- a/src/com/android/launcher2/FolderIcon.java
+++ b/src/com/android/launcher2/FolderIcon.java
@@ -50,8 +50,8 @@
  */
 public class FolderIcon extends LinearLayout implements FolderListener {
     private Launcher mLauncher;
-    Folder mFolder;
-    FolderInfo mInfo;
+    private Folder mFolder;
+    private FolderInfo mInfo;
     private static boolean sStaticValuesDirty = true;
 
     private CheckLongPressHelper mLongPressHelper;
@@ -61,6 +61,7 @@
     private static final int CONSUMPTION_ANIMATION_DURATION = 100;
     private static final int DROP_IN_ANIMATION_DURATION = 400;
     private static final int INITIAL_ITEM_ANIMATION_DURATION = 350;
+    private static final int FINAL_ITEM_ANIMATION_DURATION = 200;
 
     // The degree to which the inner ring grows when accepting drop
     private static final float INNER_RING_GROWTH_FACTOR = 0.15f;
@@ -93,8 +94,10 @@
     private int mPreviewOffsetY;
     private float mMaxPerspectiveShift;
     boolean mAnimating = false;
+
     private PreviewItemDrawingParams mParams = new PreviewItemDrawingParams(0, 0, 0, 0);
     private PreviewItemDrawingParams mAnimParams = new PreviewItemDrawingParams(0, 0, 0, 0);
+    private ArrayList<ShortcutInfo> mHiddenItems = new ArrayList<ShortcutInfo>();
 
     public FolderIcon(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -196,7 +199,7 @@
             if (mNeutralAnimator != null) {
                 mNeutralAnimator.cancel();
             }
-            mAcceptAnimator = ValueAnimator.ofFloat(0f, 1f);
+            mAcceptAnimator = LauncherAnimUtils.ofFloat(0f, 1f);
             mAcceptAnimator.setDuration(CONSUMPTION_ANIMATION_DURATION);
 
             final int previewSize = sPreviewSize;
@@ -225,7 +228,7 @@
             if (mAcceptAnimator != null) {
                 mAcceptAnimator.cancel();
             }
-            mNeutralAnimator = ValueAnimator.ofFloat(0f, 1f);
+            mNeutralAnimator = LauncherAnimUtils.ofFloat(0f, 1f);
             mNeutralAnimator.setDuration(CONSUMPTION_ANIMATION_DURATION);
 
             final int previewSize = sPreviewSize;
@@ -278,6 +281,14 @@
         }
     }
 
+    Folder getFolder() {
+        return mFolder;
+    }
+
+    FolderInfo getFolderInfo() {
+        return mInfo;
+    }
+
     private boolean willAcceptItem(ItemInfo item) {
         final int itemType = item.itemType;
         return ((itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION ||
@@ -287,7 +298,7 @@
 
     public boolean acceptDrop(Object dragInfo) {
         final ItemInfo item = (ItemInfo) dragInfo;
-        return willAcceptItem(item);
+        return !mFolder.isDestroyed() && willAcceptItem(item);
     }
 
     public void addItem(ShortcutInfo item) {
@@ -296,7 +307,7 @@
     }
 
     public void onDragEnter(Object dragInfo) {
-        if (!willAcceptItem((ItemInfo) dragInfo)) return;
+        if (mFolder.isDestroyed() || !willAcceptItem((ItemInfo) dragInfo)) return;
         CellLayout.LayoutParams lp = (CellLayout.LayoutParams) getLayoutParams();
         CellLayout layout = (CellLayout) getParent().getParent();
         mFolderRingAnimator.setCell(lp.cellX, lp.cellY);
@@ -312,16 +323,29 @@
             final ShortcutInfo srcInfo, final DragView srcView, Rect dstRect,
             float scaleRelativeToDragLayer, Runnable postAnimationRunnable) {
 
+        // These correspond two the drawable and view that the icon was dropped _onto_
         Drawable animateDrawable = ((TextView) destView).getCompoundDrawables()[1];
-        computePreviewDrawingParams(animateDrawable.getIntrinsicWidth(), destView.getMeasuredWidth());
-
-        // This will animate the dragView (srcView) into the new folder
-        onDrop(srcInfo, srcView, dstRect, scaleRelativeToDragLayer, 1, postAnimationRunnable, null);
+        computePreviewDrawingParams(animateDrawable.getIntrinsicWidth(),
+                destView.getMeasuredWidth());
 
         // This will animate the first item from it's position as an icon into its
         // position as the first item in the preview
-        animateFirstItem(animateDrawable, INITIAL_ITEM_ANIMATION_DURATION);
+        animateFirstItem(animateDrawable, INITIAL_ITEM_ANIMATION_DURATION, false, null);
         addItem(destInfo);
+
+        // This will animate the dragView (srcView) into the new folder
+        onDrop(srcInfo, srcView, dstRect, scaleRelativeToDragLayer, 1, postAnimationRunnable, null);
+    }
+
+    public void performDestroyAnimation(final View finalView, Runnable onCompleteRunnable) {
+        Drawable animateDrawable = ((TextView) finalView).getCompoundDrawables()[1];
+        computePreviewDrawingParams(animateDrawable.getIntrinsicWidth(), 
+                finalView.getMeasuredWidth());
+
+        // This will animate the first item from it's position as an icon into its
+        // position as the first item in the preview
+        animateFirstItem(animateDrawable, FINAL_ITEM_ANIMATION_DURATION, true,
+                onCompleteRunnable);
     }
 
     public void onDragExit(Object dragInfo) {
@@ -377,9 +401,12 @@
                     1, 1, finalScale, finalScale, DROP_IN_ANIMATION_DURATION,
                     new DecelerateInterpolator(2), new AccelerateInterpolator(2),
                     postAnimationRunnable, DragLayer.ANIMATION_END_DISAPPEAR, null);
+            addItem(item);
+            mHiddenItems.add(item);
             postDelayed(new Runnable() {
                 public void run() {
-                    addItem(item);
+                    mHiddenItems.remove(item);
+                    invalidate();
                 }
             }, DROP_IN_ANIMATION_DURATION);
         } else {
@@ -526,19 +553,20 @@
         if (!mAnimating) {
             for (int i = nItemsInPreview - 1; i >= 0; i--) {
                 v = (TextView) items.get(i);
-                d = v.getCompoundDrawables()[1];
-
-                mParams = computePreviewItemDrawingParams(i, mParams);
-                mParams.drawable = d;
-                drawPreviewItem(canvas, mParams);
+                if (!mHiddenItems.contains(v.getTag())) {
+                    d = v.getCompoundDrawables()[1];
+                    mParams = computePreviewItemDrawingParams(i, mParams);
+                    mParams.drawable = d;
+                    drawPreviewItem(canvas, mParams);
+                }
             }
         } else {
             drawPreviewItem(canvas, mAnimParams);
         }
     }
 
-    private void animateFirstItem(final Drawable d, int duration) {
-        computePreviewDrawingParams(d);
+    private void animateFirstItem(final Drawable d, int duration, final boolean reverse,
+            final Runnable onCompleteRunnable) {
         final PreviewItemDrawingParams finalParams = computePreviewItemDrawingParams(0, null);
 
         final float scale0 = 1.0f;
@@ -546,10 +574,14 @@
         final float transY0 = (mAvailableSpaceInPreview - d.getIntrinsicHeight()) / 2;
         mAnimParams.drawable = d;
 
-        ValueAnimator va = ValueAnimator.ofFloat(0f, 1.0f);
+        ValueAnimator va = LauncherAnimUtils.ofFloat(0f, 1.0f);
         va.addUpdateListener(new AnimatorUpdateListener(){
             public void onAnimationUpdate(ValueAnimator animation) {
                 float progress = (Float) animation.getAnimatedValue();
+                if (reverse) {
+                    progress = 1 - progress;
+                    mPreviewBackground.setAlpha(progress);
+                }
 
                 mAnimParams.transX = transX0 + progress * (finalParams.transX - transX0);
                 mAnimParams.transY = transY0 + progress * (finalParams.transY - transY0);
@@ -565,6 +597,9 @@
             @Override
             public void onAnimationEnd(Animator animation) {
                 mAnimating = false;
+                if (onCompleteRunnable != null) {
+                    onCompleteRunnable.run();
+                }
             }
         });
         va.setDuration(duration);
diff --git a/src/com/android/launcher2/HolographicOutlineHelper.java b/src/com/android/launcher2/HolographicOutlineHelper.java
index 56d194d..1e990dc 100644
--- a/src/com/android/launcher2/HolographicOutlineHelper.java
+++ b/src/com/android/launcher2/HolographicOutlineHelper.java
@@ -19,17 +19,14 @@
 import android.graphics.Bitmap;
 import android.graphics.BlurMaskFilter;
 import android.graphics.Canvas;
-import android.graphics.MaskFilter;
 import android.graphics.Paint;
 import android.graphics.PorterDuff;
 import android.graphics.PorterDuffXfermode;
-import android.graphics.TableMaskFilter;
 
 public class HolographicOutlineHelper {
     private final Paint mHolographicPaint = new Paint();
     private final Paint mBlurPaint = new Paint();
     private final Paint mErasePaint = new Paint();
-    private final Paint mAlphaClipPaint = new Paint();
 
     public static final int MAX_OUTER_BLUR_RADIUS;
     public static final int MIN_OUTER_BLUR_RADIUS;
@@ -61,8 +58,6 @@
         sMediumInnerBlurMaskFilter = new BlurMaskFilter(scale * 2.0f, BlurMaskFilter.Blur.NORMAL);
     }
 
-    private int[] mTempOffset = new int[2];
-
     HolographicOutlineHelper() {
         mHolographicPaint.setFilterBitmap(true);
         mHolographicPaint.setAntiAlias(true);
@@ -71,8 +66,6 @@
         mErasePaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT));
         mErasePaint.setFilterBitmap(true);
         mErasePaint.setAntiAlias(true);
-        MaskFilter alphaClipTable = TableMaskFilter.CreateClipTable(180, 255);
-        mAlphaClipPaint.setMaskFilter(alphaClipTable);
     }
 
     /**
@@ -102,18 +95,28 @@
      */
     void applyExpensiveOutlineWithBlur(Bitmap srcDst, Canvas srcDstCanvas, int color,
             int outlineColor, int thickness) {
-        applyExpensiveOutlineWithBlur(srcDst, srcDstCanvas, color, outlineColor, mAlphaClipPaint,
+        applyExpensiveOutlineWithBlur(srcDst, srcDstCanvas, color, outlineColor, true,
                 thickness);
     }
     void applyExpensiveOutlineWithBlur(Bitmap srcDst, Canvas srcDstCanvas, int color,
-            int outlineColor, Paint alphaClipPaint, int thickness) {
+            int outlineColor, boolean clipAlpha, int thickness) {
 
         // We start by removing most of the alpha channel so as to ignore shadows, and
         // other types of partial transparency when defining the shape of the object
-        if (alphaClipPaint == null) {
-            alphaClipPaint = mAlphaClipPaint;
+        if (clipAlpha) {
+            int[] srcBuffer = new int[srcDst.getWidth() * srcDst.getHeight()];
+            srcDst.getPixels(srcBuffer,
+                    0, srcDst.getWidth(), 0, 0, srcDst.getWidth(), srcDst.getHeight());
+            for (int i = 0; i < srcBuffer.length; i++) {
+                final int alpha = srcBuffer[i] >>> 24;
+                if (alpha < 188) {
+                    srcBuffer[i] = 0;
+                }
+            }
+            srcDst.setPixels(srcBuffer,
+                    0, srcDst.getWidth(), 0, 0, srcDst.getWidth(), srcDst.getHeight());
         }
-        Bitmap glowShape = srcDst.extractAlpha(alphaClipPaint, mTempOffset);
+        Bitmap glowShape = srcDst.extractAlpha();
 
         // calculate the outer blur first
         BlurMaskFilter outerBlurMaskFilter;
@@ -205,8 +208,8 @@
     }
 
     void applyMediumExpensiveOutlineWithBlur(Bitmap srcDst, Canvas srcDstCanvas, int color,
-            int outlineColor, Paint alphaClipPaint) {
-        applyExpensiveOutlineWithBlur(srcDst, srcDstCanvas, color, outlineColor, alphaClipPaint,
+            int outlineColor, boolean clipAlpha) {
+        applyExpensiveOutlineWithBlur(srcDst, srcDstCanvas, color, outlineColor, clipAlpha,
                 MEDIUM);
     }
 
diff --git a/src/com/android/launcher2/InstallShortcutReceiver.java b/src/com/android/launcher2/InstallShortcutReceiver.java
index a525d00..20a1966 100644
--- a/src/com/android/launcher2/InstallShortcutReceiver.java
+++ b/src/com/android/launcher2/InstallShortcutReceiver.java
@@ -22,7 +22,6 @@
 import android.content.SharedPreferences;
 import android.content.pm.ActivityInfo;
 import android.content.pm.PackageManager;
-import android.os.Debug;
 import android.widget.Toast;
 
 import com.android.launcher.R;
diff --git a/src/com/android/launcher2/InterruptibleInOutAnimator.java b/src/com/android/launcher2/InterruptibleInOutAnimator.java
index 135fa39..9831ba3 100644
--- a/src/com/android/launcher2/InterruptibleInOutAnimator.java
+++ b/src/com/android/launcher2/InterruptibleInOutAnimator.java
@@ -45,7 +45,7 @@
     private int mDirection = STOPPED;
 
     public InterruptibleInOutAnimator(long duration, float fromValue, float toValue) {
-        mAnimator = ValueAnimator.ofFloat(fromValue, toValue).setDuration(duration);
+        mAnimator = LauncherAnimUtils.ofFloat(fromValue, toValue).setDuration(duration);
         mOriginalDuration = duration;
         mOriginalFromValue = fromValue;
         mOriginalToValue = toValue;
diff --git a/src/com/android/launcher2/Launcher.java b/src/com/android/launcher2/Launcher.java
index f4180cd..3e8c7aa 100644
--- a/src/com/android/launcher2/Launcher.java
+++ b/src/com/android/launcher2/Launcher.java
@@ -61,11 +61,11 @@
 import android.os.Message;
 import android.os.StrictMode;
 import android.os.SystemClock;
-import android.os.SystemProperties;
 import android.provider.Settings;
 import android.speech.RecognizerIntent;
 import android.text.Selection;
 import android.text.SpannableStringBuilder;
+import android.text.TextUtils;
 import android.text.method.TextKeyListener;
 import android.util.Log;
 import android.view.Display;
@@ -99,6 +99,7 @@
 import java.io.DataInputStream;
 import java.io.DataOutputStream;
 import java.io.FileDescriptor;
+import java.io.FileInputStream;
 import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.io.PrintWriter;
@@ -116,7 +117,7 @@
  */
 public final class Launcher extends Activity
         implements View.OnClickListener, OnLongClickListener, LauncherModel.Callbacks,
-                   AllAppsView.Watcher, View.OnTouchListener {
+                   View.OnTouchListener {
     static final String TAG = "Launcher";
     static final boolean LOGD = false;
 
@@ -145,7 +146,8 @@
     static final int DEFAULT_SCREEN = 2;
 
     private static final String PREFERENCES = "launcher.preferences";
-    static final String FORCE_ENABLE_ROTATION_PROPERTY = "launcher.force_enable_rotation";
+    static final String FORCE_ENABLE_ROTATION_PROPERTY = "debug.force_enable_rotation";
+    static final String DUMP_STATE_PROPERTY = "debug.dumpstate";
 
     // The Intent extra that defines whether to ignore the launch animation
     static final String INTENT_EXTRA_IGNORE_LAUNCH_ANIMATION =
@@ -308,6 +310,20 @@
         int cellY;
     }
 
+
+    private boolean doesFileExist(String filename) {
+        FileInputStream fis = null;
+        try {
+            fis = openFileInput(filename);
+            fis.close();
+            return true;
+        } catch (java.io.FileNotFoundException e) {
+            return false;
+        } catch (java.io.IOException e) {
+            return true;
+        }
+    }
+
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         if (DEBUG_STRICT_MODE) {
@@ -901,7 +917,6 @@
                 findViewById(R.id.apps_customize_pane);
         mAppsCustomizeContent = (AppsCustomizePagedView)
                 mAppsCustomizeTabHost.findViewById(R.id.apps_customize_pane_content);
-        mAppsCustomizeTabHost.setup(this);
         mAppsCustomizeContent.setup(this, dragController);
 
         // Get the all apps button
@@ -1451,7 +1466,7 @@
         mWorkspace = null;
         mDragController = null;
 
-        ValueAnimator.clearAllAnimations();
+        LauncherAnimUtils.onDestroyActivity();
     }
 
     public DragController getDragController() {
@@ -1484,10 +1499,48 @@
         }
         Rect sourceBounds = mSearchDropTargetBar.getSearchBarBounds();
 
+        startGlobalSearch(initialQuery, selectInitialQuery,
+            appSearchData, sourceBounds);
+    }
+
+    /**
+     * Starts the global search activity. This code is a copied from SearchManager
+     */
+    public void startGlobalSearch(String initialQuery,
+            boolean selectInitialQuery, Bundle appSearchData, Rect sourceBounds) {
         final SearchManager searchManager =
-                (SearchManager) getSystemService(Context.SEARCH_SERVICE);
-        searchManager.startSearch(initialQuery, selectInitialQuery, getComponentName(),
-            appSearchData, globalSearch, sourceBounds);
+            (SearchManager) getSystemService(Context.SEARCH_SERVICE);
+        ComponentName globalSearchActivity = searchManager.getGlobalSearchActivity();
+        if (globalSearchActivity == null) {
+            Log.w(TAG, "No global search activity found.");
+            return;
+        }
+        Intent intent = new Intent(SearchManager.INTENT_ACTION_GLOBAL_SEARCH);
+        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        intent.setComponent(globalSearchActivity);
+        // Make sure that we have a Bundle to put source in
+        if (appSearchData == null) {
+            appSearchData = new Bundle();
+        } else {
+            appSearchData = new Bundle(appSearchData);
+        }
+        // Set source to package name of app that starts global search, if not set already.
+        if (!appSearchData.containsKey("source")) {
+            appSearchData.putString("source", getPackageName());
+        }
+        intent.putExtra(SearchManager.APP_DATA, appSearchData);
+        if (!TextUtils.isEmpty(initialQuery)) {
+            intent.putExtra(SearchManager.QUERY, initialQuery);
+        }
+        if (selectInitialQuery) {
+            intent.putExtra(SearchManager.EXTRA_SELECT_QUERY, selectInitialQuery);
+        }
+        intent.setSourceBounds(sourceBounds);
+        try {
+            startActivity(intent);
+        } catch (ActivityNotFoundException ex) {
+            Log.e(TAG, "Global search activity not found: " + globalSearchActivity);
+        }
     }
 
     @Override
@@ -1745,7 +1798,7 @@
                 case KeyEvent.KEYCODE_HOME:
                     return true;
                 case KeyEvent.KEYCODE_VOLUME_DOWN:
-                    if (SystemProperties.getInt("debug.launcher2.dumpstate", 0) != 0) {
+                    if (doesFileExist(DUMP_STATE_PROPERTY)) {
                         dumpState();
                         return true;
                     }
@@ -1988,7 +2041,7 @@
     }
 
     private void handleFolderClick(FolderIcon folderIcon) {
-        final FolderInfo info = folderIcon.mInfo;
+        final FolderInfo info = folderIcon.getFolderInfo();
         Folder openFolder = mWorkspace.getFolderForTag(info);
 
         // If the folder info reports that the associated folder is open, then verify that
@@ -1999,7 +2052,7 @@
             info.opened = false;
         }
 
-        if (!info.opened) {
+        if (!info.opened && !folderIcon.getFolder().isDestroyed()) {
             // Close any open folder
             closeFolder();
             // Open the requested folder
@@ -2056,9 +2109,9 @@
         mFolderIconCanvas.drawColor(0, PorterDuff.Mode.CLEAR);
         fi.draw(mFolderIconCanvas);
         mFolderIconImageView.setImageBitmap(mFolderIconBitmap);
-        if (fi.mFolder != null) {
-            mFolderIconImageView.setPivotX(fi.mFolder.getPivotXForIconAnimation());
-            mFolderIconImageView.setPivotY(fi.mFolder.getPivotYForIconAnimation());
+        if (fi.getFolder() != null) {
+            mFolderIconImageView.setPivotX(fi.getFolder().getPivotXForIconAnimation());
+            mFolderIconImageView.setPivotY(fi.getFolder().getPivotYForIconAnimation());
         }
         // Just in case this image view is still in the drag layer from a previous animation,
         // we remove it and re-add it.
@@ -2066,8 +2119,8 @@
             mDragLayer.removeView(mFolderIconImageView);
         }
         mDragLayer.addView(mFolderIconImageView, lp);
-        if (fi.mFolder != null) {
-            fi.mFolder.bringToFront();
+        if (fi.getFolder() != null) {
+            fi.getFolder().bringToFront();
         }
     }
 
@@ -2088,7 +2141,7 @@
         copyFolderIconToImage(fi);
         fi.setVisibility(View.INVISIBLE);
 
-        ObjectAnimator oa = ObjectAnimator.ofPropertyValuesHolder(mFolderIconImageView, alpha,
+        ObjectAnimator oa = LauncherAnimUtils.ofPropertyValuesHolder(mFolderIconImageView, alpha,
                 scaleX, scaleY);
         oa.setDuration(getResources().getInteger(R.integer.config_folderAnimDuration));
         oa.start();
@@ -2105,7 +2158,7 @@
         // We remove and re-draw the FolderIcon in-case it has changed
         mDragLayer.removeView(mFolderIconImageView);
         copyFolderIconToImage(fi);
-        ObjectAnimator oa = ObjectAnimator.ofPropertyValuesHolder(mFolderIconImageView, alpha,
+        ObjectAnimator oa = LauncherAnimUtils.ofPropertyValuesHolder(mFolderIconImageView, alpha,
                 scaleX, scaleY);
         oa.setDuration(getResources().getInteger(R.integer.config_folderAnimDuration));
         oa.addListener(new AnimatorListenerAdapter() {
@@ -2130,7 +2183,7 @@
      * @param folderInfo The FolderInfo describing the folder to open.
      */
     public void openFolder(FolderIcon folderIcon) {
-        Folder folder = folderIcon.mFolder;
+        Folder folder = folderIcon.getFolder();
         FolderInfo info = folder.mInfo;
 
         info.opened = true;
@@ -2247,13 +2300,6 @@
         return mHotseat.isAllAppsButtonRank(rank);
     }
 
-    // AllAppsView.Watcher
-    public void zoomed(float zoom) {
-        if (zoom == 1.0f) {
-            mWorkspace.setVisibility(View.GONE);
-        }
-    }
-
     /**
      * Helper method for the cameraZoomIn/cameraZoomOut animations
      * @param view The view being animated
@@ -2406,7 +2452,7 @@
 
             // toView should appear right at the end of the workspace shrink
             // animation
-            mStateAnimation = new AnimatorSet();
+            mStateAnimation = LauncherAnimUtils.createAnimatorSet();
             mStateAnimation.play(scaleAnim).after(startDelay);
             mStateAnimation.play(alphaAnim).after(startDelay);
 
@@ -2581,7 +2627,7 @@
                 }
             });
 
-            mStateAnimation = new AnimatorSet();
+            mStateAnimation = LauncherAnimUtils.createAnimatorSet();
 
             dispatchOnLauncherTransitionPrepare(fromView, animated, true);
             dispatchOnLauncherTransitionPrepare(toView, animated, true);
@@ -2765,9 +2811,9 @@
                 mDividerAnimator = null;
             }
             if (animated) {
-                mDividerAnimator = new AnimatorSet();
-                mDividerAnimator.playTogether(ObjectAnimator.ofFloat(mQsbDivider, "alpha", 1f),
-                        ObjectAnimator.ofFloat(mDockDivider, "alpha", 1f));
+                mDividerAnimator = LauncherAnimUtils.createAnimatorSet();
+                mDividerAnimator.playTogether(LauncherAnimUtils.ofFloat(mQsbDivider, "alpha", 1f),
+                        LauncherAnimUtils.ofFloat(mDockDivider, "alpha", 1f));
                 mDividerAnimator.setDuration(mSearchDropTargetBar.getTransitionInDuration());
                 mDividerAnimator.start();
             }
@@ -3345,7 +3391,7 @@
      * @param immediate whether to run the animation or show the results immediately
      */
     private void runNewAppsAnimation(boolean immediate) {
-        AnimatorSet anim = new AnimatorSet();
+        AnimatorSet anim = LauncherAnimUtils.createAnimatorSet();
         Collection<Animator> bounceAnims = new ArrayList<Animator>();
 
         // Order these new views spatially so that they animate in order
@@ -3369,7 +3415,7 @@
         } else {
             for (int i = 0; i < mNewShortcutAnimateViews.size(); ++i) {
                 View v = mNewShortcutAnimateViews.get(i);
-                ValueAnimator bounceAnim = ObjectAnimator.ofPropertyValuesHolder(v,
+                ValueAnimator bounceAnim = LauncherAnimUtils.ofPropertyValuesHolder(v,
                         PropertyValuesHolder.ofFloat("alpha", 1f),
                         PropertyValuesHolder.ofFloat("scaleX", 1f),
                         PropertyValuesHolder.ofFloat("scaleY", 1f));
@@ -3467,17 +3513,17 @@
      *
      * Implementation of the method from LauncherModel.Callbacks.
      */
-    public void bindAppsRemoved(ArrayList<ApplicationInfo> apps, boolean permanent) {
+    public void bindAppsRemoved(ArrayList<String> packageNames, boolean permanent) {
         if (permanent) {
-            mWorkspace.removeItems(apps);
+            mWorkspace.removeItems(packageNames);
         }
 
         if (mAppsCustomizeContent != null) {
-            mAppsCustomizeContent.removeApps(apps);
+            mAppsCustomizeContent.removeApps(packageNames);
         }
 
         // Notify the drag controller
-        mDragController.onAppsRemoved(apps, this);
+        mDragController.onAppsRemoved(packageNames, this);
     }
 
     /**
@@ -3522,8 +3568,7 @@
     }
 
     public boolean isRotationEnabled() {
-        boolean forceEnableRotation = "true".equalsIgnoreCase(SystemProperties.get(
-                FORCE_ENABLE_ROTATION_PROPERTY, "false"));
+        boolean forceEnableRotation = doesFileExist(FORCE_ENABLE_ROTATION_PROPERTY);
         boolean enableRotation = forceEnableRotation ||
                 getResources().getBoolean(R.bool.allow_rotation);
         return enableRotation;
@@ -3561,7 +3606,6 @@
             cling.init(this, positionData);
             cling.setVisibility(View.VISIBLE);
             cling.setLayerType(View.LAYER_TYPE_HARDWARE, null);
-            cling.requestAccessibilityFocus();
             if (animate) {
                 cling.buildLayer();
                 cling.setAlpha(0f);
@@ -3579,7 +3623,7 @@
     }
     private void dismissCling(final Cling cling, final String flag, int duration) {
         if (cling != null) {
-            ObjectAnimator anim = ObjectAnimator.ofFloat(cling, "alpha", 0f);
+            ObjectAnimator anim = LauncherAnimUtils.ofFloat(cling, "alpha", 0f);
             anim.setDuration(duration);
             anim.addListener(new AnimatorListenerAdapter() {
                 public void onAnimationEnd(Animator animation) {
diff --git a/src/com/android/launcher2/LauncherAnimUtils.java b/src/com/android/launcher2/LauncherAnimUtils.java
new file mode 100644
index 0000000..182adf5
--- /dev/null
+++ b/src/com/android/launcher2/LauncherAnimUtils.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2012 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.animation.Animator;
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
+import android.animation.PropertyValuesHolder;
+import android.animation.ValueAnimator;
+
+import java.util.HashSet;
+
+public class LauncherAnimUtils {
+    static HashSet<Animator> sAnimators = new HashSet<Animator>();
+    Animator.AnimatorListener sEndAnimListener = new Animator.AnimatorListener() {
+        public void onAnimationStart(Animator animation) {
+        }
+
+        public void onAnimationRepeat(Animator animation) {
+        }
+
+        public void onAnimationEnd(Animator animation) {
+            sAnimators.remove(animation);
+        }
+
+        public void onAnimationCancel(Animator animation) {
+            sAnimators.remove(animation);
+        }
+    };
+
+    public static void cancelOnDestroyActivity(Animator a) {
+        sAnimators.add(a);
+    }
+
+    public static void onDestroyActivity() {
+        for (Animator a : sAnimators) {
+            if (a.isRunning()) {
+                a.cancel();
+            }
+        }
+    }
+
+    public static AnimatorSet createAnimatorSet() {
+        AnimatorSet anim = new AnimatorSet();
+        cancelOnDestroyActivity(anim);
+        return anim;
+    }
+
+    public static ValueAnimator ofFloat(float... values) {
+        ValueAnimator anim = new ValueAnimator();
+        anim.setFloatValues(values);
+        cancelOnDestroyActivity(anim);
+        return anim;
+    }
+
+    public static ObjectAnimator ofFloat(Object target, String propertyName, float... values) {
+        ObjectAnimator anim = new ObjectAnimator();
+        anim.setTarget(target);
+        anim.setPropertyName(propertyName);
+        anim.setFloatValues(values);
+        cancelOnDestroyActivity(anim);
+        return anim;
+    }
+
+    public static ObjectAnimator ofPropertyValuesHolder(Object target,
+            PropertyValuesHolder... values) {
+        ObjectAnimator anim = new ObjectAnimator();
+        anim.setTarget(target);
+        anim.setValues(values);
+        cancelOnDestroyActivity(anim);
+        return anim;
+    }
+}
diff --git a/src/com/android/launcher2/LauncherAppWidgetHost.java b/src/com/android/launcher2/LauncherAppWidgetHost.java
index 68d4903..45c1d23 100644
--- a/src/com/android/launcher2/LauncherAppWidgetHost.java
+++ b/src/com/android/launcher2/LauncherAppWidgetHost.java
@@ -27,8 +27,12 @@
  * always pick up and move widgets.
  */
 public class LauncherAppWidgetHost extends AppWidgetHost {
-    public LauncherAppWidgetHost(Context context, int hostId) {
-        super(context, hostId);
+
+    Launcher mLauncher;
+
+    public LauncherAppWidgetHost(Launcher launcher, int hostId) {
+        super(launcher, hostId);
+        mLauncher = launcher;
     }
 
     @Override
@@ -42,4 +46,10 @@
         super.stopListening();
         clearViews();
     }
+
+    protected void onProvidersChanged() {
+        // Once we get the message that widget packages are updated, we need to rebind items
+        // in AppsCustomize accordingly.
+        mLauncher.bindPackagesUpdated();
+    }
 }
diff --git a/src/com/android/launcher2/LauncherAppWidgetHostView.java b/src/com/android/launcher2/LauncherAppWidgetHostView.java
index 9970c76..549d334 100644
--- a/src/com/android/launcher2/LauncherAppWidgetHostView.java
+++ b/src/com/android/launcher2/LauncherAppWidgetHostView.java
@@ -18,9 +18,6 @@
 
 import android.appwidget.AppWidgetHostView;
 import android.content.Context;
-import android.content.res.Configuration;
-import android.os.Bundle;
-import android.os.Parcel;
 import android.view.LayoutInflater;
 import android.view.MotionEvent;
 import android.view.View;
diff --git a/src/com/android/launcher2/LauncherModel.java b/src/com/android/launcher2/LauncherModel.java
index fc1a26d..bada5cb 100644
--- a/src/com/android/launcher2/LauncherModel.java
+++ b/src/com/android/launcher2/LauncherModel.java
@@ -135,7 +135,7 @@
         public void bindAllApplications(ArrayList<ApplicationInfo> apps);
         public void bindAppsAdded(ArrayList<ApplicationInfo> apps);
         public void bindAppsUpdated(ArrayList<ApplicationInfo> apps);
-        public void bindAppsRemoved(ArrayList<ApplicationInfo> apps, boolean permanent);
+        public void bindAppsRemoved(ArrayList<String> packageNames, boolean permanent);
         public void bindPackagesUpdated();
         public boolean isAllAppsVisible();
         public boolean isAllAppsButtonRank(int rank);
@@ -1623,25 +1623,25 @@
             }
 
             ArrayList<ApplicationInfo> added = null;
-            ArrayList<ApplicationInfo> removed = null;
             ArrayList<ApplicationInfo> modified = null;
 
             if (mAllAppsList.added.size() > 0) {
                 added = mAllAppsList.added;
                 mAllAppsList.added = new ArrayList<ApplicationInfo>();
             }
-            if (mAllAppsList.removed.size() > 0) {
-                removed = mAllAppsList.removed;
-                mAllAppsList.removed = new ArrayList<ApplicationInfo>();
-                for (ApplicationInfo info: removed) {
-                    mIconCache.remove(info.intent.getComponent());
-                }
-            }
             if (mAllAppsList.modified.size() > 0) {
                 modified = mAllAppsList.modified;
                 mAllAppsList.modified = new ArrayList<ApplicationInfo>();
             }
 
+            // We may be removing packages that have no associated launcher application, so we
+            // pass through the removed package names directly.
+            // NOTE: We flush the icon cache aggressively in removePackage() above.
+            final ArrayList<String> removedPackageNames = new ArrayList<String>();
+            for (int i = 0; i < N; ++i) {
+                removedPackageNames.add(packages[i]);
+            }
+
             final Callbacks callbacks = mCallbacks != null ? mCallbacks.get() : null;
             if (callbacks == null) {
                 Log.w(TAG, "Nobody to tell about the new app.  Launcher is probably loading.");
@@ -1670,14 +1670,13 @@
                     }
                 });
             }
-            if (removed != null) {
+            if (!removedPackageNames.isEmpty()) {
                 final boolean permanent = mOp != OP_UNAVAILABLE;
-                final ArrayList<ApplicationInfo> removedFinal = removed;
                 mHandler.post(new Runnable() {
                     public void run() {
                         Callbacks cb = mCallbacks != null ? mCallbacks.get() : null;
                         if (callbacks == cb && cb != null) {
-                            callbacks.bindAppsRemoved(removedFinal, permanent);
+                            callbacks.bindAppsRemoved(removedPackageNames, permanent);
                         }
                     }
                 });
diff --git a/src/com/android/launcher2/LauncherProvider.java b/src/com/android/launcher2/LauncherProvider.java
index 0720259..ccc126a 100644
--- a/src/com/android/launcher2/LauncherProvider.java
+++ b/src/com/android/launcher2/LauncherProvider.java
@@ -751,12 +751,12 @@
         private static final void beginDocument(XmlPullParser parser, String firstElementName)
                 throws XmlPullParserException, IOException {
             int type;
-            while ((type = parser.next()) != parser.START_TAG
-                    && type != parser.END_DOCUMENT) {
+            while ((type = parser.next()) != XmlPullParser.START_TAG
+                    && type != XmlPullParser.END_DOCUMENT) {
                 ;
             }
 
-            if (type != parser.START_TAG) {
+            if (type != XmlPullParser.START_TAG) {
                 throw new XmlPullParserException("No start tag found");
             }
 
diff --git a/src/com/android/launcher2/LauncherViewPropertyAnimator.java b/src/com/android/launcher2/LauncherViewPropertyAnimator.java
index 88b4cb4..3ffc418 100644
--- a/src/com/android/launcher2/LauncherViewPropertyAnimator.java
+++ b/src/com/android/launcher2/LauncherViewPropertyAnimator.java
@@ -215,6 +215,7 @@
         }
         mViewPropertyAnimator.setListener(this);
         mViewPropertyAnimator.start();
+        LauncherAnimUtils.cancelOnDestroyActivity(this);
     }
 
     public LauncherViewPropertyAnimator translationX(float value) {
diff --git a/src/com/android/launcher2/PagedView.java b/src/com/android/launcher2/PagedView.java
index ad0baf4..4765dae 100644
--- a/src/com/android/launcher2/PagedView.java
+++ b/src/com/android/launcher2/PagedView.java
@@ -18,7 +18,6 @@
 
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
-import android.animation.ObjectAnimator;
 import android.animation.ValueAnimator;
 import android.content.Context;
 import android.content.res.TypedArray;
@@ -791,20 +790,11 @@
                 canvas.clipRect(getScrollX(), getScrollY(), getScrollX() + getRight() - getLeft(),
                         getScrollY() + getBottom() - getTop());
 
-                // On certain graphics drivers, if you draw to a off-screen buffer that's not
-                // used, it can lead to poor performance. We were running into this when
-                // setChildrenLayersEnabled was called on a CellLayout; that triggered a re-draw
-                // of that CellLayout's hardware layer, even if that CellLayout wasn't visible.
-                // As a fix, below we set pages that aren't going to be rendered are to be
-                // View.INVISIBLE, preventing re-drawing of their hardware layer
                 for (int i = getChildCount() - 1; i >= 0; i--) {
                     final View v = getPageAt(i);
                     if (mForceDrawAllChildrenNextFrame ||
                                (leftScreen <= i && i <= rightScreen && shouldDrawChild(v))) {
-                        v.setVisibility(VISIBLE);
                         drawChild(canvas, v, drawingTime);
-                    } else {
-                        v.setVisibility(INVISIBLE);
                     }
                 }
                 mForceDrawAllChildrenNextFrame = false;
@@ -1756,7 +1746,7 @@
             if (immediately) {
                 mScrollIndicator.setAlpha(1f);
             } else {
-                mScrollIndicatorAnimator = ObjectAnimator.ofFloat(mScrollIndicator, "alpha", 1f);
+                mScrollIndicatorAnimator = LauncherAnimUtils.ofFloat(mScrollIndicator, "alpha", 1f);
                 mScrollIndicatorAnimator.setDuration(sScrollIndicatorFadeInDuration);
                 mScrollIndicatorAnimator.start();
             }
@@ -1782,7 +1772,7 @@
                 mScrollIndicator.setVisibility(View.INVISIBLE);
                 mScrollIndicator.setAlpha(0f);
             } else {
-                mScrollIndicatorAnimator = ObjectAnimator.ofFloat(mScrollIndicator, "alpha", 0f);
+                mScrollIndicatorAnimator = LauncherAnimUtils.ofFloat(mScrollIndicator, "alpha", 0f);
                 mScrollIndicatorAnimator.setDuration(sScrollIndicatorFadeOutDuration);
                 mScrollIndicatorAnimator.addListener(new AnimatorListenerAdapter() {
                     private boolean cancelled = false;
diff --git a/src/com/android/launcher2/PagedViewWidgetImageView.java b/src/com/android/launcher2/PagedViewWidgetImageView.java
index 22db0ab..9928177 100644
--- a/src/com/android/launcher2/PagedViewWidgetImageView.java
+++ b/src/com/android/launcher2/PagedViewWidgetImageView.java
@@ -18,12 +18,9 @@
 
 import android.content.Context;
 import android.graphics.Canvas;
-import android.graphics.Insets;
 import android.util.AttributeSet;
 import android.widget.ImageView;
 
-
-
 class PagedViewWidgetImageView extends ImageView {
     public boolean mAllowRequestLayout = true;
 
@@ -39,16 +36,11 @@
 
     @Override
     protected void onDraw(Canvas canvas) {
-
-        Insets insets = Insets.NONE;
-        if (getBackground() != null) {
-            insets = getBackground().getLayoutInsets();
-        }
         canvas.save();
-        canvas.clipRect(getScrollX() + getPaddingLeft() + insets.left,
-                getScrollY() + getPaddingTop() + insets.top,
-                getScrollX() + getRight() - getLeft() - getPaddingRight() - insets.right,
-                getScrollY() + getBottom() - getTop() - getPaddingBottom() - insets.bottom);
+        canvas.clipRect(getScrollX() + getPaddingLeft(),
+                getScrollY() + getPaddingTop(),
+                getScrollX() + getRight() - getLeft() - getPaddingRight(),
+                getScrollY() + getBottom() - getTop() - getPaddingBottom());
 
         super.onDraw(canvas);
         canvas.restore();
diff --git a/src/com/android/launcher2/PreloadReceiver.java b/src/com/android/launcher2/PreloadReceiver.java
index d1bc639..7bec721 100644
--- a/src/com/android/launcher2/PreloadReceiver.java
+++ b/src/com/android/launcher2/PreloadReceiver.java
@@ -19,7 +19,6 @@
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
-import android.util.Log;
 
 public class PreloadReceiver extends BroadcastReceiver {
     @Override
diff --git a/src/com/android/launcher2/RocketLauncher.java b/src/com/android/launcher2/RocketLauncher.java
index 268769d..6eefedd 100644
--- a/src/com/android/launcher2/RocketLauncher.java
+++ b/src/com/android/launcher2/RocketLauncher.java
@@ -21,7 +21,6 @@
 package com.android.launcher2;
 
 import android.animation.AnimatorSet;
-import android.animation.ObjectAnimator;
 import android.animation.TimeAnimator;
 import android.content.ComponentName;
 import android.content.Context;
@@ -150,11 +149,11 @@
                                 }
                             }, LAUNCH_ZOOM_TIME);
                             endscale = 0;
-                            AnimatorSet s = new AnimatorSet();
+                            AnimatorSet s = LauncherAnimUtils.createAnimatorSet();
                             s.playTogether(
-                                ObjectAnimator.ofFloat(this, "scaleX", 15f),
-                                ObjectAnimator.ofFloat(this, "scaleY", 15f),
-                                ObjectAnimator.ofFloat(this, "alpha", 0f)
+                                LauncherAnimUtils.ofFloat(this, "scaleX", 15f),
+                                LauncherAnimUtils.ofFloat(this, "scaleY", 15f),
+                                LauncherAnimUtils.ofFloat(this, "alpha", 0f)
                             );
 
                             // make sure things are still moving until the very last instant the
diff --git a/src/com/android/launcher2/SearchDropTargetBar.java b/src/com/android/launcher2/SearchDropTargetBar.java
index a1d36cd..fada48a 100644
--- a/src/com/android/launcher2/SearchDropTargetBar.java
+++ b/src/com/android/launcher2/SearchDropTargetBar.java
@@ -111,14 +111,14 @@
         // Create the various fade animations
         if (mEnableDropDownDropTargets) {
             mDropTargetBar.setTranslationY(-mBarHeight);
-            mDropTargetBarAnim = ObjectAnimator.ofFloat(mDropTargetBar, "translationY",
+            mDropTargetBarAnim = LauncherAnimUtils.ofFloat(mDropTargetBar, "translationY",
                     -mBarHeight, 0f);
-            mQSBSearchBarAnim = ObjectAnimator.ofFloat(mQSBSearchBar, "translationY", 0,
+            mQSBSearchBarAnim = LauncherAnimUtils.ofFloat(mQSBSearchBar, "translationY", 0,
                     -mBarHeight);
         } else {
             mDropTargetBar.setAlpha(0f);
-            mDropTargetBarAnim = ObjectAnimator.ofFloat(mDropTargetBar, "alpha", 0f, 1f);
-            mQSBSearchBarAnim = ObjectAnimator.ofFloat(mQSBSearchBar, "alpha", 1f, 0f);
+            mDropTargetBarAnim = LauncherAnimUtils.ofFloat(mDropTargetBar, "alpha", 0f, 1f);
+            mQSBSearchBarAnim = LauncherAnimUtils.ofFloat(mQSBSearchBar, "alpha", 1f, 0f);
         }
         setupAnimation(mDropTargetBarAnim, mDropTargetBar);
         setupAnimation(mQSBSearchBarAnim, mQSBSearchBar);
@@ -224,16 +224,14 @@
 
     public Rect getSearchBarBounds() {
         if (mQSBSearchBar != null) {
-            final float appScale = mQSBSearchBar.getContext().getResources()
-                    .getCompatibilityInfo().applicationScale;
             final int[] pos = new int[2];
             mQSBSearchBar.getLocationOnScreen(pos);
 
             final Rect rect = new Rect();
-            rect.left = (int) (pos[0] * appScale + 0.5f);
-            rect.top = (int) (pos[1] * appScale + 0.5f);
-            rect.right = (int) ((pos[0] + mQSBSearchBar.getWidth()) * appScale + 0.5f);
-            rect.bottom = (int) ((pos[1] + mQSBSearchBar.getHeight()) * appScale + 0.5f);
+            rect.left = pos[0];
+            rect.top = pos[1];
+            rect.right = pos[0] + mQSBSearchBar.getWidth();
+            rect.bottom = pos[1] + mQSBSearchBar.getHeight();
             return rect;
         } else {
             return null;
diff --git a/src/com/android/launcher2/Utilities.java b/src/com/android/launcher2/Utilities.java
index b27f7bb..d3e4516 100644
--- a/src/com/android/launcher2/Utilities.java
+++ b/src/com/android/launcher2/Utilities.java
@@ -29,7 +29,6 @@
 import android.graphics.PaintFlagsDrawFilter;
 import android.graphics.PorterDuff;
 import android.graphics.Rect;
-import android.graphics.TableMaskFilter;
 import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.PaintDrawable;
@@ -243,9 +242,7 @@
 
         sBlurPaint.setMaskFilter(new BlurMaskFilter(5 * density, BlurMaskFilter.Blur.NORMAL));
         sGlowColorPressedPaint.setColor(0xffffc300);
-        sGlowColorPressedPaint.setMaskFilter(TableMaskFilter.CreateClipTable(0, 30));
         sGlowColorFocusedPaint.setColor(0xffff8e00);
-        sGlowColorFocusedPaint.setMaskFilter(TableMaskFilter.CreateClipTable(0, 30));
 
         ColorMatrix cm = new ColorMatrix();
         cm.setSaturation(0.2f);
diff --git a/src/com/android/launcher2/Workspace.java b/src/com/android/launcher2/Workspace.java
index 2d2340a..1bd0a35 100644
--- a/src/com/android/launcher2/Workspace.java
+++ b/src/com/android/launcher2/Workspace.java
@@ -24,7 +24,6 @@
 import android.animation.ValueAnimator.AnimatorUpdateListener;
 import android.app.WallpaperManager;
 import android.appwidget.AppWidgetHostView;
-import android.appwidget.AppWidgetManager;
 import android.appwidget.AppWidgetProviderInfo;
 import android.content.ComponentName;
 import android.content.Context;
@@ -33,10 +32,8 @@
 import android.content.res.Resources;
 import android.content.res.TypedArray;
 import android.graphics.Bitmap;
-import android.graphics.Camera;
 import android.graphics.Canvas;
 import android.graphics.Matrix;
-import android.graphics.Paint;
 import android.graphics.Point;
 import android.graphics.PointF;
 import android.graphics.Rect;
@@ -45,7 +42,6 @@
 import android.os.IBinder;
 import android.os.Parcelable;
 import android.util.AttributeSet;
-import android.util.DisplayMetrics;
 import android.util.Log;
 import android.view.Display;
 import android.view.MotionEvent;
@@ -62,7 +58,6 @@
 import java.net.URISyntaxException;
 import java.util.ArrayList;
 import java.util.HashSet;
-import java.util.Iterator;
 import java.util.Set;
 
 /**
@@ -179,11 +174,6 @@
     public static final int DRAG_BITMAP_PADDING = 2;
     private boolean mWorkspaceFadeInAdjacentScreens;
 
-    // Camera and Matrix used to determine the final position of a neighboring CellLayout
-    private final Matrix mMatrix = new Matrix();
-    private final Camera mCamera = new Camera();
-    private final float mTempFloat2[] = new float[2];
-
     enum WallpaperVerticalOffset { TOP, MIDDLE, BOTTOM };
     int mWallpaperWidth;
     int mWallpaperHeight;
@@ -281,6 +271,7 @@
         // With workspace, data is available straight from the get-go
         setDataIsReady();
 
+        mLauncher = (Launcher) context;
         final Resources res = getResources();
         mWorkspaceFadeInAdjacentScreens = res.getBoolean(R.bool.config_workspaceFadeAdjacentScreens);
         mFadeInAdjacentScreens = false;
@@ -299,20 +290,20 @@
             // landscape
             TypedArray actionBarSizeTypedArray =
                 context.obtainStyledAttributes(new int[] { android.R.attr.actionBarSize });
-            DisplayMetrics displayMetrics = res.getDisplayMetrics();
             final float actionBarHeight = actionBarSizeTypedArray.getDimension(0, 0f);
-            final float systemBarHeight = res.getDimension(R.dimen.status_bar_height);
-            final float smallestScreenDim = res.getConfiguration().smallestScreenWidthDp *
-                    displayMetrics.density;
+
+            Point minDims = new Point();
+            Point maxDims = new Point();
+            mLauncher.getWindowManager().getDefaultDisplay().getCurrentSizeRange(minDims, maxDims);
 
             cellCountX = 1;
-            while (CellLayout.widthInPortrait(res, cellCountX + 1) <= smallestScreenDim) {
+            while (CellLayout.widthInPortrait(res, cellCountX + 1) <= minDims.x) {
                 cellCountX++;
             }
 
             cellCountY = 1;
             while (actionBarHeight + CellLayout.heightInLandscape(res, cellCountY + 1)
-                <= smallestScreenDim - systemBarHeight) {
+                <= minDims.y) {
                 cellCountY++;
             }
         }
@@ -334,7 +325,6 @@
         LauncherModel.updateWorkspaceLayoutCells(cellCountX, cellCountY);
         setHapticFeedbackEnabled(false);
 
-        mLauncher = (Launcher) context;
         initWorkspace();
 
         // Disable multitouch across the workspace/all apps/customize tray
@@ -374,19 +364,9 @@
         return r;
     }
 
-    public void buildPageHardwareLayers() {
-        if (getWindowToken() != null) {
-            final int childCount = getChildCount();
-            for (int i = 0; i < childCount; i++) {
-                CellLayout cl = (CellLayout) getChildAt(i);
-                cl.getShortcutsAndWidgets().buildLayer();
-            }
-        }
-    }
-
     public void onDragStart(DragSource source, Object info, int dragAction) {
         mIsDragOccuring = true;
-        updateChildrenLayersEnabled();
+        updateChildrenLayersEnabled(false);
         mLauncher.lockScreenOrientation();
         setChildrenBackgroundAlphaMultipliers(1f);
         // Prevent any Un/InstallShortcutReceivers from updating the db while we are dragging
@@ -396,7 +376,7 @@
 
     public void onDragEnd() {
         mIsDragOccuring = false;
-        updateChildrenLayersEnabled();
+        updateChildrenLayersEnabled(false);
         mLauncher.unlockScreenOrientation(false);
 
         // Re-enable any Un/InstallShortcutReceiver and now process any queued items
@@ -738,7 +718,7 @@
         super.onPageBeginMoving();
 
         if (isHardwareAccelerated()) {
-            updateChildrenLayersEnabled();
+            updateChildrenLayersEnabled(false);
         } else {
             if (mNextPage != INVALID_PAGE) {
                 // we're snapping to a particular screen
@@ -772,7 +752,7 @@
         super.onPageEndMoving();
 
         if (isHardwareAccelerated()) {
-            updateChildrenLayersEnabled();
+            updateChildrenLayersEnabled(false);
         } else {
             clearChildrenCache();
         }
@@ -847,10 +827,12 @@
     }
 
     protected void setWallpaperDimension() {
-        DisplayMetrics displayMetrics = new DisplayMetrics();
-        mLauncher.getWindowManager().getDefaultDisplay().getRealMetrics(displayMetrics);
-        final int maxDim = Math.max(displayMetrics.widthPixels, displayMetrics.heightPixels);
-        final int minDim = Math.min(displayMetrics.widthPixels, displayMetrics.heightPixels);
+        Point minDims = new Point();
+        Point maxDims = new Point();
+        mLauncher.getWindowManager().getDefaultDisplay().getCurrentSizeRange(minDims, maxDims);
+
+        final int maxDim = Math.max(maxDims.x, maxDims.y);
+        final int minDim = Math.min(minDims.x, minDims.y);
 
         // We need to ensure that there is enough extra space in the wallpaper for the intended
         // parallax effects
@@ -1098,7 +1080,7 @@
         if (!isSmall() && !mIsSwitchingState) {
             if (mChildrenOutlineFadeOutAnimation != null) mChildrenOutlineFadeOutAnimation.cancel();
             if (mChildrenOutlineFadeInAnimation != null) mChildrenOutlineFadeInAnimation.cancel();
-            mChildrenOutlineFadeInAnimation = ObjectAnimator.ofFloat(this, "childrenOutlineAlpha", 1.0f);
+            mChildrenOutlineFadeInAnimation = LauncherAnimUtils.ofFloat(this, "childrenOutlineAlpha", 1.0f);
             mChildrenOutlineFadeInAnimation.setDuration(CHILDREN_OUTLINE_FADE_IN_DURATION);
             mChildrenOutlineFadeInAnimation.start();
         }
@@ -1108,7 +1090,7 @@
         if (!isSmall() && !mIsSwitchingState) {
             if (mChildrenOutlineFadeInAnimation != null) mChildrenOutlineFadeInAnimation.cancel();
             if (mChildrenOutlineFadeOutAnimation != null) mChildrenOutlineFadeOutAnimation.cancel();
-            mChildrenOutlineFadeOutAnimation = ObjectAnimator.ofFloat(this, "childrenOutlineAlpha", 0.0f);
+            mChildrenOutlineFadeOutAnimation = LauncherAnimUtils.ofFloat(this, "childrenOutlineAlpha", 0.0f);
             mChildrenOutlineFadeOutAnimation.setDuration(CHILDREN_OUTLINE_FADE_OUT_DURATION);
             mChildrenOutlineFadeOutAnimation.setStartDelay(CHILDREN_OUTLINE_FADE_OUT_DELAY);
             mChildrenOutlineFadeOutAnimation.start();
@@ -1153,7 +1135,7 @@
         float startAlpha = getBackgroundAlpha();
         if (finalAlpha != startAlpha) {
             if (animated) {
-                mBackgroundFadeOutAnimation = ValueAnimator.ofFloat(startAlpha, finalAlpha);
+                mBackgroundFadeOutAnimation = LauncherAnimUtils.ofFloat(startAlpha, finalAlpha);
                 mBackgroundFadeOutAnimation.addUpdateListener(new AnimatorUpdateListener() {
                     public void onAnimationUpdate(ValueAnimator animation) {
                         setBackgroundAlpha(((Float) animation.getAnimatedValue()).floatValue());
@@ -1179,31 +1161,6 @@
         return mBackgroundAlpha;
     }
 
-    /**
-     * Due to 3D transformations, if two CellLayouts are theoretically touching each other,
-     * on the xy plane, when one is rotated along the y-axis, the gap between them is perceived
-     * as being larger. This method computes what offset the rotated view should be translated
-     * in order to minimize this perceived gap.
-     * @param degrees Angle of the view
-     * @param width Width of the view
-     * @param height Height of the view
-     * @return Offset to be used in a View.setTranslationX() call
-     */
-    private float getOffsetXForRotation(float degrees, int width, int height) {
-        mMatrix.reset();
-        mCamera.save();
-        mCamera.rotateY(Math.abs(degrees));
-        mCamera.getMatrix(mMatrix);
-        mCamera.restore();
-
-        mMatrix.preTranslate(-width * 0.5f, -height * 0.5f);
-        mMatrix.postTranslate(width * 0.5f, height * 0.5f);
-        mTempFloat2[0] = width;
-        mTempFloat2[1] = height;
-        mMatrix.mapPoints(mTempFloat2);
-        return (width - mTempFloat2[0]) * (degrees > 0.0f ? 1.0f : -1.0f);
-    }
-
     float backgroundAlphaInterpolator(float r) {
         float pivotA = 0.1f;
         float pivotB = 0.4f;
@@ -1403,18 +1360,34 @@
         }
     }
 
-    private void updateChildrenLayersEnabled() {
+
+    private void updateChildrenLayersEnabled(boolean force) {
         boolean small = mState == State.SMALL || mIsSwitchingState;
-        boolean enableChildrenLayers = small || mAnimatingViewIntoPlace || isPageMoving();
+        boolean enableChildrenLayers = force || small || mAnimatingViewIntoPlace || isPageMoving();
 
         if (enableChildrenLayers != mChildrenLayersEnabled) {
             mChildrenLayersEnabled = enableChildrenLayers;
             for (int i = 0; i < getPageCount(); i++) {
-                ((ViewGroup)getChildAt(i)).setChildrenLayersEnabled(mChildrenLayersEnabled);
+                CellLayout cl = (CellLayout) getChildAt(i);
+                cl.getShortcutsAndWidgets().setLayerType(
+                        mChildrenLayersEnabled ? LAYER_TYPE_HARDWARE : LAYER_TYPE_NONE, null);
             }
         }
     }
 
+    public void buildPageHardwareLayers() {
+        // force layers to be enabled just for the call to buildLayer
+        updateChildrenLayersEnabled(true);
+        if (getWindowToken() != null) {
+            final int childCount = getChildCount();
+            for (int i = 0; i < childCount; i++) {
+                CellLayout cl = (CellLayout) getChildAt(i);
+                cl.getShortcutsAndWidgets().buildLayer();
+            }
+        }
+        updateChildrenLayersEnabled(false);
+    }
+
     protected void onWallpaperTap(MotionEvent ev) {
         final int[] position = mTempCell;
         getLocationOnScreen(position);
@@ -1503,14 +1476,14 @@
         mDragOutline = createDragOutline(v, canvas, DRAG_BITMAP_PADDING);
     }
 
-    public void onDragStartedWithItem(PendingAddItemInfo info, Bitmap b, Paint alphaClipPaint) {
+    public void onDragStartedWithItem(PendingAddItemInfo info, Bitmap b, boolean clipAlpha) {
         final Canvas canvas = new Canvas();
 
         int[] size = estimateItemSize(info.spanX, info.spanY, info, false);
 
         // The outline is used to visualize where the item will land if dropped
         mDragOutline = createDragOutline(b, canvas, DRAG_BITMAP_PADDING, size[0],
-                size[1], alphaClipPaint);
+                size[1], clipAlpha);
     }
 
     public void exitWidgetResizeMode() {
@@ -1548,7 +1521,7 @@
         // Initialize animation arrays for the first time if necessary
         initAnimationArrays();
 
-        AnimatorSet anim = animated ? new AnimatorSet() : null;
+        AnimatorSet anim = animated ? LauncherAnimUtils.createAnimatorSet() : null;
 
         // Stop any scrolling, move to the current page right away
         setCurrentPage(getNextPage());
@@ -1573,7 +1546,7 @@
             if (oldStateIsNormal && stateIsSmall) {
                 zoomIn = false;
                 setLayoutScale(finalScaleFactor);
-                updateChildrenLayersEnabled();
+                updateChildrenLayersEnabled(false);
             } else {
                 finalBackgroundAlpha = 1.0f;
                 setLayoutScale(finalScaleFactor);
@@ -1664,7 +1637,7 @@
                     }
                     if (mOldBackgroundAlphas[i] != 0 ||
                         mNewBackgroundAlphas[i] != 0) {
-                        ValueAnimator bgAnim = ValueAnimator.ofFloat(0f, 1f).setDuration(duration);
+                        ValueAnimator bgAnim = LauncherAnimUtils.ofFloat(0f, 1f).setDuration(duration);
                         bgAnim.setInterpolator(mZoomInInterpolator);
                         bgAnim.addUpdateListener(new LauncherAnimatorUpdateListener() {
                                 public void onAnimationUpdate(float a, float b) {
@@ -1713,7 +1686,7 @@
     public void onLauncherTransitionEnd(Launcher l, boolean animated, boolean toWorkspace) {
         mIsSwitchingState = false;
         mWallpaperOffset.setOverrideHorizontalCatchupConstant(false);
-        updateChildrenLayersEnabled();
+        updateChildrenLayersEnabled(false);
         // The code in getChangeStateAnimation to determine initialAlpha and finalAlpha will ensure
         // ensure that only the current page is visible during (and subsequently, after) the
         // transition animation.  If fade adjacent pages is disabled, then re-enable the page
@@ -1823,7 +1796,7 @@
      * Responsibility for the bitmap is transferred to the caller.
      */
     private Bitmap createDragOutline(Bitmap orig, Canvas canvas, int padding, int w, int h,
-            Paint alphaClipPaint) {
+            boolean clipAlpha) {
         final int outlineColor = getResources().getColor(android.R.color.holo_blue_light);
         final Bitmap b = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
         canvas.setBitmap(b);
@@ -1840,7 +1813,7 @@
 
         canvas.drawBitmap(orig, src, dst, null);
         mOutlineHelper.applyMediumExpensiveOutlineWithBlur(b, canvas, outlineColor, outlineColor,
-                alphaClipPaint);
+                clipAlpha);
         canvas.setBitmap(null);
 
         return b;
@@ -2295,7 +2268,7 @@
                 @Override
                 public void run() {
                     mAnimatingViewIntoPlace = false;
-                    updateChildrenLayersEnabled();
+                    updateChildrenLayersEnabled(false);
                     if (finalResizeRunnable != null) {
                         finalResizeRunnable.run();
                     }
@@ -2418,7 +2391,13 @@
         // Here we store the final page that will be dropped to, if the workspace in fact
         // receives the drop
         if (mInScrollArea) {
-            mDropToLayout = mDragOverlappingLayout;
+            if (isPageMoving()) {
+                // If the user drops while the page is scrolling, we should use that page as the
+                // destination instead of the page that is being hovered over.
+                mDropToLayout = (CellLayout) getPageAt(getNextPage());
+            } else {
+                mDropToLayout = mDragOverlappingLayout;
+            }
         } else {
             mDropToLayout = mDragTargetLayout;
         }
@@ -3318,7 +3297,7 @@
 
         // hardware layers on children are enabled on startup, but should be disabled until
         // needed
-        updateChildrenLayersEnabled();
+        updateChildrenLayersEnabled(false);
         setWallpaperDimension();
     }
 
@@ -3572,14 +3551,9 @@
         }
     }
 
-    void removeItems(final ArrayList<ApplicationInfo> apps) {
-        final AppWidgetManager widgets = AppWidgetManager.getInstance(getContext());
-
+    void removeItems(final ArrayList<String> packages) {
         final HashSet<String> packageNames = new HashSet<String>();
-        final int appCount = apps.size();
-        for (int i = 0; i < appCount; i++) {
-            packageNames.add(apps.get(i).componentName.getPackageName());
-        }
+        packageNames.addAll(packages);
 
         ArrayList<CellLayout> cellLayouts = getWorkspaceAndHotseatCellLayouts();
         for (final CellLayout layoutParent: cellLayouts) {