Merge branch 'master' into honeycomb-release
diff --git a/res/drawable-hdpi/hotseat_bg_center.9.png b/res/drawable-hdpi/hotseat_bg_center.9.png
index 50a9521..e162970 100644
--- a/res/drawable-hdpi/hotseat_bg_center.9.png
+++ b/res/drawable-hdpi/hotseat_bg_center.9.png
Binary files differ
diff --git a/res/drawable-hdpi/hotseat_bg_left.9.png b/res/drawable-hdpi/hotseat_bg_left.9.png
index 78cbaf9..39e079d 100644
--- a/res/drawable-hdpi/hotseat_bg_left.9.png
+++ b/res/drawable-hdpi/hotseat_bg_left.9.png
Binary files differ
diff --git a/res/drawable-hdpi/hotseat_bg_right.9.png b/res/drawable-hdpi/hotseat_bg_right.9.png
index 6cf8ead..921216b 100644
--- a/res/drawable-hdpi/hotseat_bg_right.9.png
+++ b/res/drawable-hdpi/hotseat_bg_right.9.png
Binary files differ
diff --git a/res/drawable-hdpi/hotseat_browser_focused.png b/res/drawable-hdpi/hotseat_browser_focused.png
index 4020a89..4ab51dd 100644
--- a/res/drawable-hdpi/hotseat_browser_focused.png
+++ b/res/drawable-hdpi/hotseat_browser_focused.png
Binary files differ
diff --git a/res/drawable-hdpi/hotseat_browser_normal.png b/res/drawable-hdpi/hotseat_browser_normal.png
index c7f902a..77ae927 100644
--- a/res/drawable-hdpi/hotseat_browser_normal.png
+++ b/res/drawable-hdpi/hotseat_browser_normal.png
Binary files differ
diff --git a/res/drawable-hdpi/hotseat_browser_pressed.png b/res/drawable-hdpi/hotseat_browser_pressed.png
index bfa23b3..cfe963b 100644
--- a/res/drawable-hdpi/hotseat_browser_pressed.png
+++ b/res/drawable-hdpi/hotseat_browser_pressed.png
Binary files differ
diff --git a/res/drawable-hdpi/trashcan.png b/res/drawable-hdpi/trashcan.png
index 482fbd8..89b23ee 100644
--- a/res/drawable-hdpi/trashcan.png
+++ b/res/drawable-hdpi/trashcan.png
Binary files differ
diff --git a/res/drawable-hdpi/trashcan_hover.png b/res/drawable-hdpi/trashcan_hover.png
index 484acef..d156d46 100644
--- a/res/drawable-hdpi/trashcan_hover.png
+++ b/res/drawable-hdpi/trashcan_hover.png
Binary files differ
diff --git a/res/drawable-mdpi/hotseat_bg_center.9.png b/res/drawable-mdpi/hotseat_bg_center.9.png
index 28c3402..a9a05ba 100644
--- a/res/drawable-mdpi/hotseat_bg_center.9.png
+++ b/res/drawable-mdpi/hotseat_bg_center.9.png
Binary files differ
diff --git a/res/drawable-mdpi/hotseat_bg_left.9.png b/res/drawable-mdpi/hotseat_bg_left.9.png
index 605eb1e..35dfead 100644
--- a/res/drawable-mdpi/hotseat_bg_left.9.png
+++ b/res/drawable-mdpi/hotseat_bg_left.9.png
Binary files differ
diff --git a/res/drawable-mdpi/hotseat_bg_right.9.png b/res/drawable-mdpi/hotseat_bg_right.9.png
index 5df3f00..9adfa31 100644
--- a/res/drawable-mdpi/hotseat_bg_right.9.png
+++ b/res/drawable-mdpi/hotseat_bg_right.9.png
Binary files differ
diff --git a/res/drawable-xlarge/ic_no_applications.png b/res/drawable-xlarge/ic_no_applications.png
new file mode 100644
index 0000000..a4f695a
--- /dev/null
+++ b/res/drawable-xlarge/ic_no_applications.png
Binary files differ
diff --git a/res/layout-xlarge/customize_paged_view_wallpaper_placeholder.xml b/res/layout-xlarge/all_apps_no_items_placeholder.xml
similarity index 87%
rename from res/layout-xlarge/customize_paged_view_wallpaper_placeholder.xml
rename to res/layout-xlarge/all_apps_no_items_placeholder.xml
index 6112532..f5ecdec 100644
--- a/res/layout-xlarge/customize_paged_view_wallpaper_placeholder.xml
+++ b/res/layout-xlarge/all_apps_no_items_placeholder.xml
@@ -17,20 +17,20 @@
 <TextView
     xmlns:android="http://schemas.android.com/apk/res/android"
 
-    android:id="@+id/wallpaper_icon"
+    android:id="@+id/no_items_icon"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:gravity="center_vertical"
     android:paddingTop="2dip"
 
     android:textColor="#FFFFFFFF"
-    android:textSize="14sp"
+    android:textSize="15sp"
     android:shadowColor="#FF000000"
     android:shadowDx="0.0"
     android:shadowDy="1.0"
     android:shadowRadius="1.0"
-    android:drawableLeft="@drawable/ic_launcher_wallpaper"
-    android:drawablePadding="10dip"
+    android:drawableLeft="@drawable/ic_no_applications"
+    android:drawablePadding="0dip"
 
     android:maxLines="2"
     android:fadingEdge="horizontal" />
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 4f74b59..8999282 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -67,6 +67,12 @@
     <!--  Tile of the tab for applications that were downloaded from market [CHAR_LIMIT=12] -->
     <string name="all_apps_tab_downloaded">Downloaded</string>
 
+    <!-- All Apps pane -->
+    <!-- Message to show when there are no games [CHAR_LIMIT=25] -->
+    <string name="all_apps_no_games">No games found.</string>
+    <!-- Message to show when there are no downloaded apps [CHAR_LIMIT=25] -->
+    <string name="all_apps_no_downloads">No downloaded apps found.</string>
+
     <!-- Customization Drawer -->
     <!-- The format string for the dimensions of a widget in the drawer -->
     <string name="widget_dims_format" translatable="false">%1$d x %2$d</string>
diff --git a/src/com/android/launcher2/AllAppsPagedView.java b/src/com/android/launcher2/AllAppsPagedView.java
index cbb46e2..42101eb 100644
--- a/src/com/android/launcher2/AllAppsPagedView.java
+++ b/src/com/android/launcher2/AllAppsPagedView.java
@@ -16,13 +16,16 @@
 
 package com.android.launcher2;
 
-import com.android.launcher.R;
+import java.util.ArrayList;
+import java.util.Collections;
 
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.res.TypedArray;
+import android.graphics.drawable.Drawable;
 import android.util.AttributeSet;
 import android.view.ActionMode;
+import android.view.Gravity;
 import android.view.LayoutInflater;
 import android.view.Menu;
 import android.view.MenuItem;
@@ -32,8 +35,7 @@
 import android.widget.Checkable;
 import android.widget.TextView;
 
-import java.util.ArrayList;
-import java.util.Collections;
+import com.android.launcher.R;
 
 /**
  * An implementation of PagedView that populates the pages of the workspace
@@ -341,8 +343,9 @@
 
     @Override
     public void syncPages() {
-        // ensure that we have the right number of pages
-        int numPages = (int) Math.ceil((float) mFilteredApps.size() / (mCellCountX * mCellCountY));
+        // ensure that we have the right number of pages (min of 1, since we have placeholders)
+        int numPages = Math.max(1,
+                (int) Math.ceil((float) mFilteredApps.size() / (mCellCountX * mCellCountY)));
         int curNumPages = getChildCount();
         // remove any extra pages after the "last" page
         int extraPageDiff = curNumPages - numPages;
@@ -364,41 +367,82 @@
 
     @Override
     public void syncPageItems(int page) {
-        // ensure that we have the right number of items on the pages
+        // Ensure that we have the right number of items on the pages
         final int cellsPerPage = mCellCountX * mCellCountY;
         final int startIndex = page * cellsPerPage;
         final int endIndex = Math.min(startIndex + cellsPerPage, mFilteredApps.size());
         PagedViewCellLayout layout = (PagedViewCellLayout) getChildAt(page);
 
-        final int curNumPageItems = layout.getChildCount();
-        final int numPageItems = endIndex - startIndex;
+        if (!mFilteredApps.isEmpty()) {
+            int curNumPageItems = layout.getChildCount();
+            int numPageItems = endIndex - startIndex;
 
-        // remove any extra items
-        int extraPageItemsDiff = curNumPageItems - numPageItems;
-        for (int i = 0; i < extraPageItemsDiff; ++i) {
-            layout.removeViewAt(numPageItems);
-        }
-        // add any necessary items
-        for (int i = curNumPageItems; i < numPageItems; ++i) {
-            TextView text = (TextView) mInflater.inflate(R.layout.all_apps_paged_view_application, layout, false);
-            text.setOnClickListener(this);
-            text.setOnLongClickListener(this);
+            // If we were previously an empty page, then restart anew
+            boolean wasEmptyPage = false;
+            if (curNumPageItems == 1) {
+                View icon = layout.getChildAt(0);
+                if (icon.getTag() == null) {
+                    wasEmptyPage = true;
+                }
+            }
 
-            layout.addViewToCellLayout(text, -1, i,
-                new PagedViewCellLayout.LayoutParams(0, 0, 1, 1));
-        }
+            if (wasEmptyPage) {
+                // Remove all the previous items
+                curNumPageItems = 0;
+                layout.removeAllViews();
+            } else {
+                // Remove any extra items
+                int extraPageItemsDiff = curNumPageItems - numPageItems;
+                for (int i = 0; i < extraPageItemsDiff; ++i) {
+                    layout.removeViewAt(numPageItems);
+                }
+            }
 
-        // actually reapply to the existing text views
-        for (int i = startIndex; i < endIndex; ++i) {
-            final int index = i - startIndex;
-            final ApplicationInfo info = mFilteredApps.get(i);
-            PagedViewIcon icon = (PagedViewIcon) layout.getChildAt(index);
-            icon.applyFromApplicationInfo(info, mPageViewIconCache);
+            // Add any necessary items
+            for (int i = curNumPageItems; i < numPageItems; ++i) {
+                TextView text = (TextView) mInflater.inflate(
+                        R.layout.all_apps_paged_view_application, layout, false);
+                text.setOnClickListener(this);
+                text.setOnLongClickListener(this);
 
-            PagedViewCellLayout.LayoutParams params = 
-                (PagedViewCellLayout.LayoutParams) icon.getLayoutParams();
-            params.cellX = index % mCellCountX;
-            params.cellY = index / mCellCountX;
+                layout.addViewToCellLayout(text, -1, i,
+                    new PagedViewCellLayout.LayoutParams(0, 0, 1, 1));
+            }
+
+            // Actually reapply to the existing text views
+            for (int i = startIndex; i < endIndex; ++i) {
+                final int index = i - startIndex;
+                final ApplicationInfo info = mFilteredApps.get(i);
+                PagedViewIcon icon = (PagedViewIcon) layout.getChildAt(index);
+                icon.applyFromApplicationInfo(info, mPageViewIconCache);
+
+                PagedViewCellLayout.LayoutParams params =
+                    (PagedViewCellLayout.LayoutParams) icon.getLayoutParams();
+                params.cellX = index % mCellCountX;
+                params.cellY = index / mCellCountX;
+            }
+
+            // Default to left-aligned icons
+            layout.enableCenteredContent(false);
+        } else {
+            // There are no items, so show the user a small message
+            TextView icon = (TextView) mInflater.inflate(
+                    R.layout.all_apps_no_items_placeholder, layout, false);
+            switch (mAppFilter) {
+            case ApplicationInfo.GAME_FLAG:
+                icon.setText(mContext.getString(R.string.all_apps_no_games));
+                break;
+            case ApplicationInfo.DOWNLOADED_FLAG:
+                icon.setText(mContext.getString(R.string.all_apps_no_downloads));
+                break;
+            default: break;
+            }
+
+            // Center-align the message
+            layout.enableCenteredContent(true);
+            layout.removeAllViews();
+            layout.addViewToCellLayout(icon, -1, 0,
+                    new PagedViewCellLayout.LayoutParams(0, 0, 2, 1));
         }
     }
 
diff --git a/src/com/android/launcher2/AllAppsTabbed.java b/src/com/android/launcher2/AllAppsTabbed.java
index aff8ddd..cc6a149 100644
--- a/src/com/android/launcher2/AllAppsTabbed.java
+++ b/src/com/android/launcher2/AllAppsTabbed.java
@@ -103,7 +103,8 @@
                 // animate the changing of the tab content by fading pages in and out
                 final int duration = 150;
                 final float alpha = mAllApps.getAlpha();
-                ValueAnimator alphaAnim = new ObjectAnimator(duration, mAllApps, "alpha", alpha, 0.0f);
+                ValueAnimator alphaAnim = ObjectAnimator.ofFloat(mAllApps, "alpha", alpha, 0.0f).
+                        setDuration(duration);
                 alphaAnim.addListener(new AnimatorListenerAdapter() {
                     public void onAnimationEnd(Animator animation) {
                         String tag = getCurrentTabTag();
@@ -118,9 +119,8 @@
                         }
 
                         final float alpha = mAllApps.getAlpha();
-                        ValueAnimator alphaAnim =
-                            new ObjectAnimator(duration, mAllApps, "alpha", alpha, 1.0f);
-                        alphaAnim.start();
+                        ObjectAnimator.ofFloat(mAllApps, "alpha", alpha, 1.0f).
+                                setDuration(duration).start();
                     }
                 });
                 alphaAnim.start();
diff --git a/src/com/android/launcher2/CellLayout.java b/src/com/android/launcher2/CellLayout.java
index 3c6a8aa..57953c0 100644
--- a/src/com/android/launcher2/CellLayout.java
+++ b/src/com/android/launcher2/CellLayout.java
@@ -94,7 +94,7 @@
     // These arrays are used to implement the drag visualization on x-large screens.
     // They are used as circular arrays, indexed by mDragOutlineCurrent.
     private Point[] mDragOutlines = new Point[8];
-    private int[] mDragOutlineAlphas = new int[mDragOutlines.length];
+    private float[] mDragOutlineAlphas = new float[mDragOutlines.length];
     private InterruptibleInOutAnimator[] mDragOutlineAnims =
             new InterruptibleInOutAnimator[mDragOutlines.length];
 
@@ -175,13 +175,13 @@
         // Set up the animation for fading the crosshairs in and out
         int animDuration = res.getInteger(R.integer.config_crosshairsFadeInTime);
         mCrosshairsAnimator = new InterruptibleInOutAnimator(animDuration, 0.0f, 1.0f);
-        mCrosshairsAnimator.addUpdateListener(new AnimatorUpdateListener() {
+        mCrosshairsAnimator.getAnimator().addUpdateListener(new AnimatorUpdateListener() {
             public void onAnimationUpdate(ValueAnimator animation) {
                 mCrosshairsVisibility = ((Float) animation.getAnimatedValue()).floatValue();
                 CellLayout.this.invalidate();
             }
         });
-        mCrosshairsAnimator.setInterpolator(interp);
+        mCrosshairsAnimator.getAnimator().setInterpolator(interp);
 
         for (int i = 0; i < mDragOutlines.length; i++) {
             mDragOutlines[i] = new Point(-1, -1);
@@ -192,8 +192,8 @@
         // behind the drag path.
         // Set up all the animations that are used to implement this fading.
         final int duration = res.getInteger(R.integer.config_dragOutlineFadeTime);
-        final int fromAlphaValue = 0;
-        final int toAlphaValue = res.getInteger(R.integer.config_dragOutlineMaxAlpha);
+        final float fromAlphaValue = 0;
+        final float toAlphaValue = (float)res.getInteger(R.integer.config_dragOutlineMaxAlpha);
 
         for (int i = 0; i < mDragOutlineAlphas.length; i++) {
             mDragOutlineAlphas[i] = fromAlphaValue;
@@ -202,10 +202,9 @@
         for (int i = 0; i < mDragOutlineAnims.length; i++) {
             final InterruptibleInOutAnimator anim =
                 new InterruptibleInOutAnimator(duration, fromAlphaValue, toAlphaValue);
-            anim.setInterpolator(interp);
-
+            anim.getAnimator().setInterpolator(interp);
             final int thisIndex = i;
-            anim.addUpdateListener(new AnimatorUpdateListener() {
+            anim.getAnimator().addUpdateListener(new AnimatorUpdateListener() {
                 public void onAnimationUpdate(ValueAnimator animation) {
                     final Bitmap outline = (Bitmap)anim.getTag();
 
@@ -221,7 +220,7 @@
                         // Try to prevent it from continuing to run
                         animation.cancel();
                     } else {
-                        mDragOutlineAlphas[thisIndex] = (Integer) animation.getAnimatedValue();
+                        mDragOutlineAlphas[thisIndex] = (Float) animation.getAnimatedValue();
                         final int left = mDragOutlines[thisIndex].x;
                         final int top = mDragOutlines[thisIndex].y;
                         CellLayout.this.invalidate(left, top,
@@ -231,9 +230,9 @@
             });
             // The animation holds a reference to the drag outline bitmap as long is it's
             // running. This way the bitmap can be GCed when the animations are complete.
-            anim.addListener(new AnimatorListenerAdapter() {
+            anim.getAnimator().addListener(new AnimatorListenerAdapter() {
                 public void onAnimationEnd(Animator animation) {
-                    if ((Integer) anim.getAnimatedValue() == 0) {
+                    if ((Float) ((ValueAnimator) animation).getAnimatedValue() == 0f) {
                         anim.setTag(null);
                     }
                 }
@@ -311,11 +310,11 @@
 
         final Paint paint = new Paint();
         for (int i = 0; i < mDragOutlines.length; i++) {
-            final int alpha = mDragOutlineAlphas[i];
+            final float alpha = mDragOutlineAlphas[i];
             if (alpha > 0) {
                 final Point p = mDragOutlines[i];
                 final Bitmap b = (Bitmap) mDragOutlineAnims[i].getTag();
-                paint.setAlpha(alpha);
+                paint.setAlpha((int)(alpha + .5f));
                 canvas.drawBitmap(b, p.x, p.y, paint);
             }
         }
@@ -1089,8 +1088,6 @@
             mDragCell[0] = -1;
             mDragCell[1] = -1;
 
-            setHover(false);
-
             // Fade out the drag indicators
             if (mCrosshairsAnimator != null) {
                 mCrosshairsAnimator.animateOut();
diff --git a/src/com/android/launcher2/InterruptibleInOutAnimator.java b/src/com/android/launcher2/InterruptibleInOutAnimator.java
index 0b2f345..bed7e6b 100644
--- a/src/com/android/launcher2/InterruptibleInOutAnimator.java
+++ b/src/com/android/launcher2/InterruptibleInOutAnimator.java
@@ -18,6 +18,7 @@
 
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
+import android.animation.ObjectAnimator;
 import android.animation.ValueAnimator;
 import android.util.Log;
 
@@ -28,10 +29,11 @@
  * be exactly reversed. Using this class, both the 'in' and the 'out' animation use the
  * interpolator in the same direction.
  */
-public class InterruptibleInOutAnimator extends ValueAnimator {
+public class InterruptibleInOutAnimator {
     private long mOriginalDuration;
-    private Object mOriginalFromValue;
-    private Object mOriginalToValue;
+    private float mOriginalFromValue;
+    private float mOriginalToValue;
+    private ValueAnimator mAnimator;
 
     private boolean mFirstRun = true;
 
@@ -41,41 +43,41 @@
     private static final int IN = 1;
     private static final int OUT = 2;
 
+
     private int mDirection = STOPPED;
 
-    public InterruptibleInOutAnimator(long duration, Object fromValue, Object toValue) {
-        super(duration, fromValue, toValue);
+    public InterruptibleInOutAnimator(long duration, float fromValue, float toValue) {
+        mAnimator = ValueAnimator.ofFloat(fromValue, toValue).setDuration(duration);
         mOriginalDuration = duration;
         mOriginalFromValue = fromValue;
         mOriginalToValue = toValue;
     }
 
     private void animate(int direction) {
-        final long currentPlayTime = getCurrentPlayTime();
-        final Object toValue = (direction == IN) ? mOriginalToValue : mOriginalFromValue;
-        final Object startValue = mFirstRun ? mOriginalFromValue : getAnimatedValue();
+        final long currentPlayTime = mAnimator.getCurrentPlayTime();
+        final float toValue = (direction == IN) ? mOriginalToValue : mOriginalFromValue;
+        final float startValue = mFirstRun ? mOriginalFromValue :
+                ((Float) mAnimator.getAnimatedValue()).floatValue();
 
         // Make sure it's stopped before we modify any values
         cancel();
 
         if (startValue != toValue) {
             mDirection = direction;
-            setDuration(mOriginalDuration - currentPlayTime);
-            setValues(startValue, toValue);
-            start();
+            mAnimator.setDuration(mOriginalDuration - currentPlayTime);
+            mAnimator.setFloatValues(startValue, toValue);
+            mAnimator.start();
             mFirstRun = false;
         }
     }
 
-    @Override
     public void cancel() {
-        super.cancel();
+        mAnimator.cancel();
         mDirection = STOPPED;
     }
 
-    @Override
     public void end() {
-        super.end();
+        mAnimator.end();
         mDirection = STOPPED;
     }
 
@@ -112,4 +114,8 @@
     public Object getTag() {
         return mTag;
     }
+
+    public ValueAnimator getAnimator() {
+        return mAnimator;
+    }
 }
diff --git a/src/com/android/launcher2/Launcher.java b/src/com/android/launcher2/Launcher.java
index d7c2f5b..6fcf432 100644
--- a/src/com/android/launcher2/Launcher.java
+++ b/src/com/android/launcher2/Launcher.java
@@ -318,8 +318,9 @@
                     // animate the changing of the tab content by fading pages in and out
                     final int duration = 150;
                     final float alpha = mCustomizePagedView.getAlpha();
-                    ValueAnimator alphaAnim = new ObjectAnimator(duration, mCustomizePagedView,
+                    ValueAnimator alphaAnim = ObjectAnimator.ofFloat(mCustomizePagedView,
                             "alpha", alpha, 0.0f);
+                    alphaAnim.setDuration(duration);
                     alphaAnim.addListener(new AnimatorListenerAdapter() {
                         public void onAnimationEnd(Animator animation) {
                             String tag = mHomeCustomizationDrawer.getCurrentTabTag();
@@ -341,8 +342,9 @@
                             }
 
                             final float alpha = mCustomizePagedView.getAlpha();
-                            ValueAnimator alphaAnim = new ObjectAnimator(duration,
+                            ValueAnimator alphaAnim = ObjectAnimator.ofFloat(
                                     mCustomizePagedView, "alpha", alpha, 1.0f);
+                            alphaAnim.setDuration(duration);
                             alphaAnim.start();
                         }
                     });
@@ -2284,7 +2286,8 @@
                 getResources().getInteger(R.integer.config_toolbarButtonFadeOutTime);
 
         if (seq != null) {
-            Animator anim = new ObjectAnimator<Float>(duration, view, "alpha", show ? 1.0f : 0.0f);
+            Animator anim = ObjectAnimator.ofFloat(view, "alpha", show ? 1.0f : 0.0f);
+            anim.setDuration(duration);
             anim.addListener(new AnimatorListenerAdapter() {
                 public void onAnimationStart(Animator animation) {
                     if (showing) showToolbarButton(view);
@@ -2383,9 +2386,10 @@
         }
 
         if (animated) {
-            ValueAnimator scaleAnim = new ObjectAnimator(duration, toView,
-                    new PropertyValuesHolder<Float>("scaleX", scale, 1.0f),
-                    new PropertyValuesHolder<Float>("scaleY", scale, 1.0f));
+            ValueAnimator scaleAnim = ObjectAnimator.ofPropertyValuesHolder(toView,
+                    PropertyValuesHolder.ofFloat("scaleX", scale, 1.0f),
+                    PropertyValuesHolder.ofFloat("scaleY", scale, 1.0f));
+            scaleAnim.setDuration(duration);
             scaleAnim.setInterpolator(new DecelerateInterpolator());
             scaleAnim.addListener(new AnimatorListenerAdapter() {
                 public void onAnimationStart(Animator animation) {
@@ -2445,9 +2449,10 @@
         if (animated) {
             if (mStateAnimation != null) mStateAnimation.cancel();
             mStateAnimation = new AnimatorSet();
-            ValueAnimator scaleAnim = new ObjectAnimator(duration, fromView,
-                    new PropertyValuesHolder<Float>("scaleX", scaleFactor),
-                    new PropertyValuesHolder<Float>("scaleY", scaleFactor));
+            ValueAnimator scaleAnim = ObjectAnimator.ofPropertyValuesHolder(fromView,
+                    PropertyValuesHolder.ofFloat("scaleX", scaleFactor),
+                    PropertyValuesHolder.ofFloat("scaleY", scaleFactor));
+            scaleAnim.setDuration(duration);
             scaleAnim.setInterpolator(new AccelerateInterpolator());
             mStateAnimation.addListener(new AnimatorListenerAdapter() {
                 public void onAnimationEnd(Animator animation) {
@@ -2522,10 +2527,13 @@
             AnimatorSet toolbarShowAnim = new AnimatorSet();
             hideAndShowToolbarButtons(toState, toolbarShowAnim, toolbarHideAnim);
 
-            mStateAnimation.playTogether(
-                    toolbarHideAnim,
-                    new ObjectAnimator(duration, fromView, "y", fromViewStartY, fromViewEndY),
-                    new ObjectAnimator(duration, toView, "y", toViewStartY, toViewEndY));
+            ObjectAnimator fromAnim = ObjectAnimator.ofFloat(fromView, "y",
+                    fromViewStartY, fromViewEndY);
+            fromAnim.setDuration(duration);
+            ObjectAnimator toAnim = ObjectAnimator.ofFloat(toView, "y",
+                    toViewStartY, toViewEndY);
+            fromAnim.setDuration(duration);
+            mStateAnimation.playTogether(toolbarHideAnim, fromAnim, toAnim);
 
             // Show the new toolbar buttons just as the main animation is ending
             final int fadeInTime = res.getInteger(R.integer.config_toolbarButtonFadeInTime);
diff --git a/src/com/android/launcher2/PagedView.java b/src/com/android/launcher2/PagedView.java
index 52f4a5e..11261a5 100644
--- a/src/com/android/launcher2/PagedView.java
+++ b/src/com/android/launcher2/PagedView.java
@@ -80,7 +80,7 @@
     protected final static int TOUCH_STATE_SCROLLING = 1;
     protected final static int TOUCH_STATE_PREV_PAGE = 2;
     protected final static int TOUCH_STATE_NEXT_PAGE = 3;
-    protected final static float ALPHA_QUANTIZE_LEVEL = 0.01f;
+    protected final static float ALPHA_QUANTIZE_LEVEL = 0.0001f;
 
     protected int mTouchState = TOUCH_STATE_REST;
 
diff --git a/src/com/android/launcher2/PagedViewIcon.java b/src/com/android/launcher2/PagedViewIcon.java
index ff5ea49..0f7898b 100644
--- a/src/com/android/launcher2/PagedViewIcon.java
+++ b/src/com/android/launcher2/PagedViewIcon.java
@@ -137,7 +137,7 @@
     protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
         super.onLayout(changed, left, top, right, bottom);
 
-        if (mHolographicOutline == null) {
+        if (mIconCache != null && mHolographicOutline == null) {
             // update the clipping rect to be used in the holographic pass below
             getDrawingRect(mDrawableClipRect);
             mDrawableClipRect.bottom = getPaddingTop() + getCompoundPaddingTop();
diff --git a/src/com/android/launcher2/Workspace.java b/src/com/android/launcher2/Workspace.java
index 75e39e0..1b6b139 100644
--- a/src/com/android/launcher2/Workspace.java
+++ b/src/com/android/launcher2/Workspace.java
@@ -16,6 +16,7 @@
 
 package com.android.launcher2;
 
+import android.animation.AnimatorListenerAdapter;
 import com.android.launcher.R;
 
 import android.animation.Animator;
@@ -80,8 +81,8 @@
     private static final int BACKGROUND_FADE_IN_DURATION = 100;
 
     // These animators are used to fade the background
-    private ObjectAnimator<Float> mBackgroundFadeInAnimation;
-    private ObjectAnimator<Float> mBackgroundFadeOutAnimation;
+    private ObjectAnimator mBackgroundFadeInAnimation;
+    private ObjectAnimator mBackgroundFadeOutAnimation;
     private float mBackgroundAlpha = 0;
 
     private final WallpaperManager mWallpaperManager;
@@ -194,15 +195,13 @@
         LauncherApplication app = (LauncherApplication)context.getApplicationContext();
         mIconCache = app.getIconCache();
 
-        mUnshrinkAnimationListener = new AnimatorListener() {
+        mUnshrinkAnimationListener = new AnimatorListenerAdapter() {
             public void onAnimationStart(Animator animation) {
                 mIsInUnshrinkAnimation = true;
             }
             public void onAnimationEnd(Animator animation) {
                 mIsInUnshrinkAnimation = false;
             }
-            public void onAnimationCancel(Animator animation) {}
-            public void onAnimationRepeat(Animator animation) {}
         };
 
         mSnapVelocity = 600;
@@ -477,8 +476,8 @@
         if (!mIsSmall && !mIsInUnshrinkAnimation) {
             if (mBackgroundFadeOutAnimation != null) mBackgroundFadeOutAnimation.cancel();
             if (mBackgroundFadeInAnimation != null) mBackgroundFadeInAnimation.cancel();
-            mBackgroundFadeInAnimation = new ObjectAnimator<Float>(BACKGROUND_FADE_IN_DURATION,
-                    this, new PropertyValuesHolder<Float>("backgroundAlpha", 1.0f));
+            mBackgroundFadeInAnimation = ObjectAnimator.ofFloat(this, "backgroundAlpha", 1.0f);
+            mBackgroundFadeInAnimation.setDuration(BACKGROUND_FADE_IN_DURATION);
             mBackgroundFadeInAnimation.start();
         }
     }
@@ -487,8 +486,8 @@
         if (!mIsSmall && !mIsInUnshrinkAnimation) {
             if (mBackgroundFadeInAnimation != null) mBackgroundFadeInAnimation.cancel();
             if (mBackgroundFadeOutAnimation != null) mBackgroundFadeOutAnimation.cancel();
-            mBackgroundFadeOutAnimation = new ObjectAnimator<Float>(BACKGROUND_FADE_OUT_DURATION,
-                    this, new PropertyValuesHolder<Float>("backgroundAlpha", 0.0f));
+            mBackgroundFadeOutAnimation = ObjectAnimator.ofFloat(this, "backgroundAlpha", 0.0f);
+            mBackgroundFadeOutAnimation.setDuration(BACKGROUND_FADE_OUT_DURATION);
             mBackgroundFadeOutAnimation.setStartDelay(BACKGROUND_FADE_OUT_DELAY);
             mBackgroundFadeOutAnimation.start();
         }
@@ -750,16 +749,18 @@
 
             if (animated) {
                 final int duration = res.getInteger(R.integer.config_workspaceShrinkTime);
-                new ObjectAnimator<Float>(duration, cl,
-                        new PropertyValuesHolder<Float>("x", newX),
-                        new PropertyValuesHolder<Float>("y", newY),
-                        new PropertyValuesHolder<Float>("scaleX",
+                ObjectAnimator anim = ObjectAnimator.ofPropertyValuesHolder(cl,
+                        PropertyValuesHolder.ofFloat("x", newX),
+                        PropertyValuesHolder.ofFloat("y", newY),
+                        PropertyValuesHolder.ofFloat("scaleX",
                                 SHRINK_FACTOR * rotationScaleX * extraShrinkFactor),
-                        new PropertyValuesHolder<Float>("scaleY",
+                        PropertyValuesHolder.ofFloat("scaleY",
                                 SHRINK_FACTOR * rotationScaleY * extraShrinkFactor),
-                        new PropertyValuesHolder<Float>("backgroundAlpha", finalAlpha),
-                        new PropertyValuesHolder<Float>("alpha", finalAlpha),
-                        new PropertyValuesHolder<Float>("rotationY", rotation)).start();
+                        PropertyValuesHolder.ofFloat("backgroundAlpha", finalAlpha),
+                        PropertyValuesHolder.ofFloat("alpha", finalAlpha),
+                        PropertyValuesHolder.ofFloat("rotationY", rotation));
+                anim.setDuration(duration);
+                anim.start();
             } else {
                 cl.setX((int)newX);
                 cl.setY((int)newY);
@@ -902,14 +903,15 @@
                 }
 
                 if (animated) {
+
                     s.playTogether(
-                            new ObjectAnimator<Float>(duration, cl, "translationX", 0.0f),
-                            new ObjectAnimator<Float>(duration, cl, "translationY", 0.0f),
-                            new ObjectAnimator<Float>(duration, cl, "scaleX", 1.0f),
-                            new ObjectAnimator<Float>(duration, cl, "scaleY", 1.0f),
-                            new ObjectAnimator<Float>(duration, cl, "backgroundAlpha", 0.0f),
-                            new ObjectAnimator<Float>(duration, cl, "alpha", finalAlphaValue),
-                            new ObjectAnimator<Float>(duration, cl, "rotationY", rotation));
+                            ObjectAnimator.ofFloat(cl, "translationX", 0.0f).setDuration(duration),
+                            ObjectAnimator.ofFloat(cl, "translationY", 0.0f).setDuration(duration),
+                            ObjectAnimator.ofFloat(cl, "scaleX", 1.0f).setDuration(duration),
+                            ObjectAnimator.ofFloat(cl, "scaleY", 1.0f).setDuration(duration),
+                            ObjectAnimator.ofFloat(cl, "backgroundAlpha", 0.0f).setDuration(duration),
+                            ObjectAnimator.ofFloat(cl, "alpha", finalAlphaValue).setDuration(duration),
+                            ObjectAnimator.ofFloat(cl, "rotationY", rotation).setDuration(duration));
                 } else {
                     cl.setTranslationX(0.0f);
                     cl.setTranslationY(0.0f);
@@ -1046,50 +1048,46 @@
 
     public void onDrop(DragSource source, int x, int y, int xOffset, int yOffset,
             DragView dragView, Object dragInfo) {
-        CellLayout cellLayout;
+        if (mDragTargetLayout == null) {
+            // cancel the drag if we're not over a screen at time of drop
+            // TODO: maybe add a nice fade here?
+            return;
+        }
         int originX = x - xOffset;
         int originY = y - yOffset;
         if (mIsSmall || mIsInUnshrinkAnimation) {
-            cellLayout = findMatchingPageForDragOver(dragView, originX, originY, xOffset, yOffset);
-            if (cellLayout == null) {
-                // cancel the drag if we're not over a mini-screen at time of drop
-                // TODO: maybe add a nice fade here?
-                return;
-            }
             // get originX and originY in the local coordinate system of the screen
             mTempOriginXY[0] = originX;
             mTempOriginXY[1] = originY;
-            mapPointFromSelfToChild(cellLayout, mTempOriginXY);
+            mapPointFromSelfToChild(mDragTargetLayout, mTempOriginXY);
             originX = (int)mTempOriginXY[0];
             originY = (int)mTempOriginXY[1];
-        } else {
-            cellLayout = getCurrentDropLayout();
         }
 
         if (source != this) {
-            onDropExternal(originX, originY, dragInfo, cellLayout);
+            onDropExternal(originX, originY, dragInfo, mDragTargetLayout);
         } else {
             // Move internally
             if (mDragInfo != null) {
                 final View cell = mDragInfo.cell;
 
                 mTargetCell = findNearestVacantArea(originX, originY,
-                        mDragInfo.spanX, mDragInfo.spanY, cell, cellLayout,
+                        mDragInfo.spanX, mDragInfo.spanY, cell, mDragTargetLayout,
                         mTargetCell);
 
-                int screen = indexOfChild(cellLayout);
+                int screen = indexOfChild(mDragTargetLayout);
                 if (screen != mDragInfo.screen) {
                     final CellLayout originalCellLayout = (CellLayout) getChildAt(mDragInfo.screen);
                     originalCellLayout.removeView(cell);
                     addInScreen(cell, screen, mTargetCell[0], mTargetCell[1],
                             mDragInfo.spanX, mDragInfo.spanY);
                 }
-                cellLayout.onDropChild(cell);
+                mDragTargetLayout.onDropChild(cell);
 
                 // update the item's position after drop
                 final ItemInfo info = (ItemInfo) cell.getTag();
                 CellLayout.LayoutParams lp = (CellLayout.LayoutParams) cell.getLayoutParams();
-                cellLayout.onMove(cell, mTargetCell[0], mTargetCell[1]);
+                mDragTargetLayout.onMove(cell, mTargetCell[0], mTargetCell[1]);
                 lp.cellX = mTargetCell[0];
                 lp.cellY = mTargetCell[1];
                 cell.setId(LauncherModel.getCellLayoutChildId(-1, mDragInfo.screen,
@@ -1104,15 +1102,17 @@
 
     public void onDragEnter(DragSource source, int x, int y, int xOffset,
             int yOffset, DragView dragView, Object dragInfo) {
-        getCurrentDropLayout().onDragEnter(dragView);
-        showOutlines();
+        if (!mIsSmall) {
+            getCurrentDropLayout().onDragEnter(dragView);
+            showOutlines();
+        }
     }
 
     public DropTarget getDropTargetDelegate(DragSource source, int x, int y, int xOffset, int yOffset,
             DragView dragView, Object dragInfo) {
 
         if (mIsSmall || mIsInUnshrinkAnimation) {
-            // If we're shrunken, don't let anyone drag on folders/etc  that are on the mini-screens
+            // If we're shrunken, don't let anyone drag on folders/etc that are on the mini-screens
             return null;
         }
         // We may need to delegate the drag to a child view. If a 1x1 item
@@ -1165,7 +1165,7 @@
     * coordinate space. The argument xy is modified with the return result.
     *
     * if cachedInverseMatrix is not null, this method will just use that matrix instead of
-    * computing it itself; we use this to avoid redudant matrix inversions in
+    * computing it itself; we use this to avoid redundant matrix inversions in
     * findMatchingPageForDragOver
     *
     */
@@ -1290,87 +1290,79 @@
                 }
             }
         }
-
-        if (bestMatchingScreen != mDragTargetLayout) {
-            if (mDragTargetLayout != null) {
-                mDragTargetLayout.onDragExit();
-            }
-            mDragTargetLayout = bestMatchingScreen;
-            // TODO: Should we be calling mDragTargetLayout.onDragEnter() here?
-        }
         return bestMatchingScreen;
     }
 
     public void onDragOver(DragSource source, int x, int y, int xOffset, int yOffset,
             DragView dragView, Object dragInfo) {
-        CellLayout currentLayout;
-        int originX = x - xOffset;
-        int originY = y - yOffset;
-        if (mIsSmall || mIsInUnshrinkAnimation) {
-            currentLayout = findMatchingPageForDragOver(
-                    dragView, originX, originY, xOffset, yOffset);
-
-            if (currentLayout == null) {
-                return;
-            }
-
-            currentLayout.setHover(true);
-            // get originX and originY in the local coordinate system of the screen
-            mTempOriginXY[0] = originX;
-            mTempOriginXY[1] = originY;
-            mapPointFromSelfToChild(currentLayout, mTempOriginXY);
-            originX = (int)mTempOriginXY[0];
-            originY = (int)mTempOriginXY[1];
-        } else {
-            currentLayout = getCurrentDropLayout();
-        }
-
-        final ItemInfo item = (ItemInfo)dragInfo;
-
-        if (dragInfo instanceof LauncherAppWidgetInfo) {
-            LauncherAppWidgetInfo widgetInfo = (LauncherAppWidgetInfo)dragInfo;
-
-            if (widgetInfo.spanX == -1) {
-                // Calculate the grid spans needed to fit this widget
-                int[] spans = currentLayout.rectToCell(widgetInfo.minWidth, widgetInfo.minHeight, null);
-                item.spanX = spans[0];
-                item.spanY = spans[1];
-            }
-        }
-
-        if (source instanceof AllAppsPagedView) {
-            // This is a hack to fix the point used to determine which cell an icon from the all
-            // apps screen is over
-            if (item != null && item.spanX == 1 && currentLayout != null) {
-                int dragRegionLeft = (dragView.getWidth() - currentLayout.getCellWidth()) / 2;
-
-                originX += dragRegionLeft - dragView.getDragRegionLeft();
-                if (dragView.getDragRegionWidth() != currentLayout.getCellWidth()) {
-                    dragView.setDragRegion(dragView.getDragRegionLeft(), dragView.getDragRegionTop(),
-                            currentLayout.getCellWidth(), dragView.getDragRegionHeight());
-                }
-            }
-        }
-
         // When touch is inside the scroll area, skip dragOver actions for the current screen
         if (!mInScrollArea) {
-            if (currentLayout != mDragTargetLayout) {
-                if (mDragTargetLayout != null) {
-                    mDragTargetLayout.onDragExit();
-                }
-                currentLayout.onDragEnter(dragView);
-                mDragTargetLayout = currentLayout;
-            }
+            CellLayout layout;
+            int originX = x - xOffset;
+            int originY = y - yOffset;
+            if (mIsSmall || mIsInUnshrinkAnimation) {
+                layout = findMatchingPageForDragOver(
+                        dragView, originX, originY, xOffset, yOffset);
 
-            // only visualize the drop locations for moving icons within the home screen on tablet
-            // on phone, we also visualize icons dragged in from All Apps
-            if ((!LauncherApplication.isScreenXLarge() || source == this)
-                    && mDragTargetLayout != null) {
-                final View child = (mDragInfo == null) ? null : mDragInfo.cell;
-                int localOriginX = originX - (mDragTargetLayout.getLeft() - mScrollX);
-                int localOriginY = originY - (mDragTargetLayout.getTop() - mScrollY);
-                mDragTargetLayout.visualizeDropLocation(
-                        child, mDragOutline, localOriginX, localOriginY, item.spanX, item.spanY);
+                if (layout != mDragTargetLayout) {
+                    if (mDragTargetLayout != null) {
+                        mDragTargetLayout.setHover(false);
+                    }
+                    mDragTargetLayout = layout;
+                    if (mDragTargetLayout != null) {
+                        mDragTargetLayout.setHover(true);
+                    }
+                }
+            } else {
+                layout = getCurrentDropLayout();
+
+                final ItemInfo item = (ItemInfo)dragInfo;
+                if (dragInfo instanceof LauncherAppWidgetInfo) {
+                    LauncherAppWidgetInfo widgetInfo = (LauncherAppWidgetInfo)dragInfo;
+
+                    if (widgetInfo.spanX == -1) {
+                        // Calculate the grid spans needed to fit this widget
+                        int[] spans = layout.rectToCell(
+                                widgetInfo.minWidth, widgetInfo.minHeight, null);
+                        item.spanX = spans[0];
+                        item.spanY = spans[1];
+                    }
+                }
+
+                if (source instanceof AllAppsPagedView) {
+                    // This is a hack to fix the point used to determine which cell an icon from
+                    // the all apps screen is over
+                    if (item != null && item.spanX == 1 && layout != null) {
+                        int dragRegionLeft = (dragView.getWidth() - layout.getCellWidth()) / 2;
+
+                        originX += dragRegionLeft - dragView.getDragRegionLeft();
+                        if (dragView.getDragRegionWidth() != layout.getCellWidth()) {
+                            dragView.setDragRegion(dragView.getDragRegionLeft(),
+                                    dragView.getDragRegionTop(),
+                                    layout.getCellWidth(),
+                                    dragView.getDragRegionHeight());
+                        }
+                    }
+                }
+
+                if (layout != mDragTargetLayout) {
+                    if (mDragTargetLayout != null) {
+                        mDragTargetLayout.onDragExit();
+                    }
+                    layout.onDragEnter(dragView);
+                    mDragTargetLayout = layout;
+                }
+
+                // only visualize the drop locations for moving icons within the home screen on
+                // tablet on phone, we also visualize icons dragged in from All Apps
+                if ((!LauncherApplication.isScreenXLarge() || source == this)
+                        && mDragTargetLayout != null) {
+                    final View child = (mDragInfo == null) ? null : mDragInfo.cell;
+                    int localOriginX = originX - (mDragTargetLayout.getLeft() - mScrollX);
+                    int localOriginY = originY - (mDragTargetLayout.getTop() - mScrollY);
+                    mDragTargetLayout.visualizeDropLocation(child, mDragOutline,
+                            localOriginX, localOriginY, item.spanX, item.spanY);
+                }
             }
         }
     }
@@ -1483,6 +1475,8 @@
      * screen while a scroll is in progress.
      */
     private CellLayout getCurrentDropLayout() {
+        // if we're currently small, use findMatchingPageForDragOver instead
+        if (mIsSmall) return null;
         int index = mScroller.isFinished() ? mCurrentPage : mNextPage;
         return (CellLayout) getChildAt(index);
     }
@@ -1502,24 +1496,21 @@
      */
     public boolean acceptDrop(DragSource source, int x, int y,
             int xOffset, int yOffset, DragView dragView, Object dragInfo) {
-        CellLayout layout;
-        if (mIsSmall || mIsInUnshrinkAnimation) {
-            layout = findMatchingPageForDragOver(
-                    dragView, x - xOffset, y - yOffset, xOffset, yOffset);
-            if (layout == null) {
-                // cancel the drag if we're not over a mini-screen at time of drop
-                return false;
-            }
-        } else {
-            layout = getCurrentDropLayout();
+        // call onDragOver one more time, in case the current layout has changed
+        onDragOver(source, x, y, xOffset, yOffset, dragView, dragInfo);
+
+        if (mDragTargetLayout == null) {
+            // cancel the drag if we're not over a screen at time of drop
+            return false;
         }
+
         final CellLayout.CellInfo dragCellInfo = mDragInfo;
         final int spanX = dragCellInfo == null ? 1 : dragCellInfo.spanX;
         final int spanY = dragCellInfo == null ? 1 : dragCellInfo.spanY;
 
         final View ignoreView = dragCellInfo == null ? null : dragCellInfo.cell;
 
-        if (layout.findCellForSpanIgnoring(null, spanX, spanY, ignoreView)) {
+        if (mDragTargetLayout.findCellForSpanIgnoring(null, spanX, spanY, ignoreView)) {
             return true;
         } else {
             mLauncher.showOutOfSpaceMessage();
@@ -1606,24 +1597,28 @@
 
     @Override
     public void onEnterScrollArea(int direction) {
-        mInScrollArea = true;
-        final int screen = getCurrentPage() + ((direction == DragController.SCROLL_LEFT) ? -1 : 1);
-        if (0 <= screen && screen < getChildCount()) {
-            ((CellLayout) getChildAt(screen)).setHover(true);
-        }
+        if (!mIsSmall && !mIsInUnshrinkAnimation) {
+            mInScrollArea = true;
+            final int screen = getCurrentPage() + ((direction == DragController.SCROLL_LEFT) ? -1 : 1);
+            if (0 <= screen && screen < getChildCount()) {
+                ((CellLayout) getChildAt(screen)).setHover(true);
+            }
 
-        if (mDragTargetLayout != null) {
-            mDragTargetLayout.onDragExit();
-            mDragTargetLayout = null;
+            if (mDragTargetLayout != null) {
+                mDragTargetLayout.onDragExit();
+                mDragTargetLayout = null;
+            }
         }
     }
 
     @Override
     public void onExitScrollArea() {
-        mInScrollArea = false;
-        final int childCount = getChildCount();
-        for (int i = 0; i < childCount; i++) {
-            ((CellLayout) getChildAt(i)).setHover(false);
+        if (mInScrollArea) {
+            mInScrollArea = false;
+            final int childCount = getChildCount();
+            for (int i = 0; i < childCount; i++) {
+                ((CellLayout) getChildAt(i)).setHover(false);
+            }
         }
     }