Merge "Support for 600dp & custom clings" into jb-dev
diff --git a/res/drawable-hdpi/search_frame.9.png b/res/drawable-hdpi/search_frame.9.png
index d0c78c4..7fbf24f 100644
--- a/res/drawable-hdpi/search_frame.9.png
+++ b/res/drawable-hdpi/search_frame.9.png
Binary files differ
diff --git a/res/drawable-mdpi/search_frame.9.png b/res/drawable-mdpi/search_frame.9.png
index 7a0e46c..e6e048a 100644
--- a/res/drawable-mdpi/search_frame.9.png
+++ b/res/drawable-mdpi/search_frame.9.png
Binary files differ
diff --git a/res/drawable-xhdpi/search_frame.9.png b/res/drawable-xhdpi/search_frame.9.png
index cb6f294..706b1d8 100644
--- a/res/drawable-xhdpi/search_frame.9.png
+++ b/res/drawable-xhdpi/search_frame.9.png
Binary files differ
diff --git a/res/values-pl/strings.xml b/res/values-pl/strings.xml
index 41af338..64972ba 100644
--- a/res/values-pl/strings.xml
+++ b/res/values-pl/strings.xml
@@ -96,7 +96,7 @@
     <string name="workspace_cling_move_item" msgid="791013895761065070">"Dodaj tu swoje ulubione aplikacje."</string>
     <string name="workspace_cling_open_all_apps" msgid="2459977609848572588">"Aby zobaczyć wszystkie aplikacje, dotknij okręgu."</string>
     <string name="all_apps_cling_title" msgid="2559734712581447107">"Wybierz kilka aplikacji"</string>
-    <string name="all_apps_cling_add_item" msgid="5665035103260318891">"Aby dodać aplikację na ekran główny, dotknij jej i przytrzymaj."</string>
+    <string name="all_apps_cling_add_item" msgid="5665035103260318891">"By dodać aplikację na ekran główny, dotknij i przytrzymaj jej ikonę."</string>
     <string name="folder_cling_title" msgid="4308949882377840953">"Uporządkuj swoje aplikacje za pomocą folderów"</string>
     <string name="folder_cling_move_item" msgid="270598675060435169">"Dotknij i przytrzymaj, aby przenieść aplikację."</string>
     <string name="folder_cling_create_folder" msgid="8352867485656129478">"Aby utworzyć nowy folder na ekranie głównym, ułóż aplikacje jedna na drugiej."</string>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 5806d54..fa85a1b 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -49,6 +49,7 @@
     <dimen name="hotseat_height_gap">-1dp</dimen>
     <dimen name="workspace_overscroll_drawable_padding">0dp</dimen>
     <dimen name="workspace_icon_text_size">12sp</dimen>
+    <dimen name="workspace_spring_loaded_page_spacing">15dp</dimen>
 
     <dimen name="app_icon_drawable_padding">6dp</dimen>
     <dimen name="app_icon_drawable_padding_land">2dp</dimen>
diff --git a/src/com/android/launcher2/AppsCustomizePagedView.java b/src/com/android/launcher2/AppsCustomizePagedView.java
index 2518c6c..5c91d35 100644
--- a/src/com/android/launcher2/AppsCustomizePagedView.java
+++ b/src/com/android/launcher2/AppsCustomizePagedView.java
@@ -49,7 +49,6 @@
 import android.view.LayoutInflater;
 import android.view.MotionEvent;
 import android.view.View;
-import android.view.ViewConfiguration;
 import android.view.ViewGroup;
 import android.view.animation.AccelerateInterpolator;
 import android.view.animation.DecelerateInterpolator;
@@ -171,7 +170,7 @@
         AllAppsView, View.OnClickListener, View.OnKeyListener, DragSource,
         PagedViewIcon.PressedCallback, PagedViewWidget.ShortPressListener,
         LauncherTransitionable {
-    static final String LOG_TAG = "AppsCustomizePagedView";
+    static final String TAG = "AppsCustomizePagedView";
 
     /**
      * The different content types that this paged view can show.
@@ -490,7 +489,7 @@
                     mWidgets.add(widget);
                 }
             } else {
-                Log.e(LOG_TAG, "Widget " + widget.provider + " has invalid dimensions (" +
+                Log.e(TAG, "Widget " + widget.provider + " has invalid dimensions (" +
                         widget.minWidth + ", " + widget.minHeight + ")");
             }
         }
@@ -612,32 +611,43 @@
     public void onShortPress(View v) {
         // We are anticipating a long press, and we use this time to load bind and instantiate
         // the widget. This will need to be cleaned up if it turns out no long press occurs.
+        if (mCreateWidgetInfo != null) {
+            // Just in case the cleanup process wasn't properly executed. This shouldn't happen.
+            cleanupWidgetPreloading(false);
+        }
         mCreateWidgetInfo = new PendingAddWidgetInfo((PendingAddWidgetInfo) v.getTag());
         preloadWidget(mCreateWidgetInfo);
     }
 
-    private void cleanupWidgetPreloading() {
-        PendingAddWidgetInfo info = mCreateWidgetInfo;
-        mCreateWidgetInfo = null;
-        if (mWidgetCleanupState >= 0 && mWidgetLoadingId != -1) {
-            mLauncher.getAppWidgetHost().deleteAppWidgetId(mWidgetLoadingId);
-        }
-        if (mWidgetCleanupState == WIDGET_BOUND) {
-            removeCallbacks(mInflateWidgetRunnable);
-        } else if (mWidgetCleanupState == WIDGET_INFLATED) {
-            AppWidgetHostView widget = info.boundWidget;
-            int widgetId = widget.getAppWidgetId();
-            mLauncher.getAppWidgetHost().deleteAppWidgetId(widgetId);
-            mLauncher.getDragLayer().removeView(widget);
+    private void cleanupWidgetPreloading(boolean widgetWasAdded) {
+        if (!widgetWasAdded) {
+            // If the widget was not added, we may need to do further cleanup.
+            PendingAddWidgetInfo info = mCreateWidgetInfo;
+            mCreateWidgetInfo = null;
+            // First step was to allocate a widget id, revert that.
+            if ((mWidgetCleanupState == WIDGET_BOUND || mWidgetCleanupState == WIDGET_INFLATED) &&
+                    mWidgetLoadingId != -1) {
+                mLauncher.getAppWidgetHost().deleteAppWidgetId(mWidgetLoadingId);
+            }
+            if (mWidgetCleanupState == WIDGET_BOUND) {
+                // We never actually inflated the widget, so remove the callback to do so.
+                removeCallbacks(mInflateWidgetRunnable);
+            } else if (mWidgetCleanupState == WIDGET_INFLATED) {
+                // The widget was inflated and added to the DragLayer -- remove it.
+                AppWidgetHostView widget = info.boundWidget;
+                mLauncher.getDragLayer().removeView(widget);
+            }
         }
         mWidgetCleanupState = WIDGET_NO_CLEANUP_REQUIRED;
         mWidgetLoadingId = -1;
+        mCreateWidgetInfo = null;
+        PagedViewWidget.resetShortPressTarget();
     }
 
     @Override
     public void cleanUpShortPress(View v) {
         if (!mDraggingWidget) {
-            cleanupWidgetPreloading();
+            cleanupWidgetPreloading(false);
         }
     }
 
@@ -692,6 +702,8 @@
                     mWidgetPreviewIconPaddedDimension, Bitmap.Config.ARGB_8888);
             Drawable d = image.getDrawable();
             mCanvas.setBitmap(preview);
+            mCanvas.translate((mWidgetPreviewIconPaddedDimension - d.getIntrinsicWidth()) / 2,
+                    (mWidgetPreviewIconPaddedDimension - d.getIntrinsicHeight()) / 2);
             d.draw(mCanvas);
             mCanvas.setBitmap(null);
             createItemInfo.spanX = createItemInfo.spanY = 1;
@@ -829,8 +841,8 @@
             }
 
             d.deferDragViewCleanupPostAnimation = false;
-            cleanupWidgetPreloading();
         }
+        cleanupWidgetPreloading(success);
         mDraggingWidget = false;
     }
 
@@ -838,7 +850,7 @@
     public void onFlingToDeleteCompleted() {
         // We just dismiss the drag when we fling, so cleanup here
         endDragging(null, true, true);
-        cleanupWidgetPreloading();
+        cleanupWidgetPreloading(false);
         mDraggingWidget = false;
     }
 
@@ -1130,7 +1142,7 @@
         if (previewImage != 0) {
             drawable = mPackageManager.getDrawable(packageName, previewImage, null);
             if (drawable == null) {
-                Log.w(LOG_TAG, "Can't load widget preview drawable 0x" +
+                Log.w(TAG, "Can't load widget preview drawable 0x" +
                         Integer.toHexString(previewImage) + " for provider: " + provider);
             }
         }
@@ -1620,8 +1632,8 @@
     @Override
     public void dumpState() {
         // TODO: Dump information related to current list of Applications, Widgets, etc.
-        ApplicationInfo.dumpApplicationInfoList(LOG_TAG, "mApps", mApps);
-        dumpAppWidgetProviderInfoList(LOG_TAG, "mWidgets", mWidgets);
+        ApplicationInfo.dumpApplicationInfoList(TAG, "mApps", mApps);
+        dumpAppWidgetProviderInfoList(TAG, "mWidgets", mWidgets);
     }
 
     private void dumpAppWidgetProviderInfoList(String tag, String label,
diff --git a/src/com/android/launcher2/LauncherModel.java b/src/com/android/launcher2/LauncherModel.java
index bc88a98..fc1a26d 100644
--- a/src/com/android/launcher2/LauncherModel.java
+++ b/src/com/android/launcher2/LauncherModel.java
@@ -1089,7 +1089,9 @@
 
                                 // App shortcuts that used to be automatically added to Launcher
                                 // didn't always have the correct intent flags set, so do that here
-                                if (intent.getAction().equals(Intent.ACTION_MAIN) &&
+                                if (intent.getAction() != null &&
+                                        intent.getCategories() != null &&
+                                        intent.getAction().equals(Intent.ACTION_MAIN) &&
                                         intent.getCategories().contains(Intent.CATEGORY_LAUNCHER)) {
                                     intent.addFlags(
                                         Intent.FLAG_ACTIVITY_NEW_TASK |
diff --git a/src/com/android/launcher2/PagedView.java b/src/com/android/launcher2/PagedView.java
index a3080a8..5d9cf81 100644
--- a/src/com/android/launcher2/PagedView.java
+++ b/src/com/android/launcher2/PagedView.java
@@ -75,6 +75,8 @@
     private static final int MIN_SNAP_VELOCITY = 1500;
     private static final int MIN_FLING_VELOCITY = 250;
 
+    static final int AUTOMATIC_PAGE_SPACING = -1;
+
     protected int mFlingThresholdVelocity;
     protected int mMinFlingVelocity;
     protected int mMinSnapVelocity;
@@ -450,17 +452,23 @@
 
         final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
         final int widthSize = MeasureSpec.getSize(widthMeasureSpec);
+        final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
+        int heightSize = MeasureSpec.getSize(heightMeasureSpec);
         if (widthMode != MeasureSpec.EXACTLY) {
             throw new IllegalStateException("Workspace can only be used in EXACTLY mode.");
         }
 
+        // Return early if we aren't given a proper dimension
+        if (widthSize <= 0 || heightSize <= 0) {
+            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+            return;
+        }
+
         /* Allow the height to be set as WRAP_CONTENT. This allows the particular case
          * of the All apps view on XLarge displays to not take up more space then it needs. Width
          * is still not allowed to be set as WRAP_CONTENT since many parts of the code expect
          * each page to have the same width.
          */
-        final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
-        int heightSize = MeasureSpec.getSize(heightMeasureSpec);
         int maxChildHeight = 0;
 
         final int verticalPadding = getPaddingTop() + getPaddingBottom();
@@ -507,12 +515,17 @@
 
         setMeasuredDimension(widthSize, heightSize);
 
+        // We can't call getChildOffset/getRelativeChildOffset until we set the measured dimensions.
+        // We also wait until we set the measured dimensions before flushing the cache as well, to
+        // ensure that the cache is filled with good values.
+        invalidateCachedOffsets();
+
         if (childCount > 0) {
             if (DEBUG) Log.d(TAG, "getRelativeChildOffset(): " + getMeasuredWidth() + ", "
                     + getChildWidth(0));
 
             // Calculate the variable page spacing if necessary
-            if (mPageSpacing < 0) {
+            if (mPageSpacing == AUTOMATIC_PAGE_SPACING) {
                 // The gap between pages in the PagedView should be equal to the gap from the page
                 // to the edge of the screen (so it is not visible in the current screen).  To
                 // account for unequal padding on each side of the paged view, we take the maximum
@@ -524,10 +537,6 @@
             }
         }
 
-        // We can't call getChildOffset/getRelativeChildOffset until we set the measured dimensions.
-        // We also wait until we set the measured dimensions before flushing the cache as well, to
-        // ensure that the cache is filled with good values.
-        invalidateCachedOffsets();
         updateScrollingIndicatorPosition();
 
         if (childCount > 0) {
@@ -747,6 +756,10 @@
         }
     }
 
+    protected boolean shouldDrawChild(View child) {
+        return child.getAlpha() > 0;
+    }
+
     @Override
     protected void dispatchDraw(Canvas canvas) {
         int halfScreenSize = getMeasuredWidth() / 2;
@@ -783,7 +796,7 @@
                 // View.INVISIBLE, preventing re-drawing of their hardware layer
                 for (int i = getChildCount() - 1; i >= 0; i--) {
                     final View v = getPageAt(i);
-                    if (leftScreen <= i && i <= rightScreen && v.getAlpha() > 0) {
+                    if (leftScreen <= i && i <= rightScreen && shouldDrawChild(v)) {
                         v.setVisibility(VISIBLE);
                         drawChild(canvas, v, drawingTime);
                     } else {
diff --git a/src/com/android/launcher2/PagedViewWidget.java b/src/com/android/launcher2/PagedViewWidget.java
index 774bf1f..f78aa4c 100644
--- a/src/com/android/launcher2/PagedViewWidget.java
+++ b/src/com/android/launcher2/PagedViewWidget.java
@@ -42,6 +42,7 @@
     CheckForShortPress mPendingCheckForShortPress = null;
     ShortPressListener mShortPressListener = null;
     boolean mShortPressTriggered = false;
+    static PagedViewWidget sShortpressTarget = null;
 
     public PagedViewWidget(Context context) {
         this(context, null);
@@ -141,13 +142,16 @@
     class CheckForShortPress implements Runnable {
         public void run() {
             if (mShortPressListener != null) {
+                if (sShortpressTarget != null) return;
                 mShortPressListener.onShortPress(PagedViewWidget.this);
             }
+            sShortpressTarget = PagedViewWidget.this;
             mShortPressTriggered = true;
         }
     }
 
     private void checkForShortPress() {
+        if (sShortpressTarget != null) return;
         if (mPendingCheckForShortPress == null) {
             mPendingCheckForShortPress = new CheckForShortPress();
         }
@@ -173,6 +177,10 @@
         }
     }
 
+    static void resetShortPressTarget() {
+        sShortpressTarget = null;
+    }
+
     @Override
     public boolean onTouchEvent(MotionEvent event) {
         super.onTouchEvent(event);
@@ -190,6 +198,7 @@
             case MotionEvent.ACTION_MOVE:
                 break;
         }
+
         // We eat up the touch events here, since the PagedView (which uses the same swiping
         // touch code as Workspace previously) uses onInterceptTouchEvent() to determine when
         // the user is scrolling between pages.  This means that if the pages themselves don't
diff --git a/src/com/android/launcher2/SearchDropTargetBar.java b/src/com/android/launcher2/SearchDropTargetBar.java
index 5a1ba69..03512b2 100644
--- a/src/com/android/launcher2/SearchDropTargetBar.java
+++ b/src/com/android/launcher2/SearchDropTargetBar.java
@@ -54,6 +54,7 @@
     private boolean mDeferOnDragEnd = false;
 
     private Drawable mPreviousBackground;
+    private boolean mEnableDropDownDropTargets;
 
     public SearchDropTargetBar(Context context, AttributeSet attrs) {
         this(context, attrs, 0);
@@ -108,11 +109,11 @@
         mInfoDropTarget.setSearchDropTargetBar(this);
         mDeleteDropTarget.setSearchDropTargetBar(this);
 
-        boolean enableDropDownDropTargets =
+        mEnableDropDownDropTargets =
             getResources().getBoolean(R.bool.config_useDropTargetDownTransition);
 
         // Create the various fade animations
-        if (enableDropDownDropTargets) {
+        if (mEnableDropDownDropTargets) {
             mDropTargetBar.setTranslationY(-mBarHeight);
             mDropTargetBarFadeInAnim = ObjectAnimator.ofFloat(mDropTargetBar, "translationY", 0f);
             mDropTargetBarFadeOutAnim = ObjectAnimator.ofFloat(mDropTargetBar, "translationY",
@@ -154,7 +155,11 @@
             mQSBSearchBarFadeInAnim.start();
         } else {
             mQSBSearchBar.setVisibility(View.VISIBLE);
-            mQSBSearchBar.setAlpha(1f);
+            if (mEnableDropDownDropTargets) {
+                mQSBSearchBar.setTranslationY(0);
+            } else {
+                mQSBSearchBar.setAlpha(1f);
+            }
         }
         mIsSearchBarHidden = false;
     }
@@ -164,7 +169,11 @@
             mQSBSearchBarFadeOutAnim.start();
         } else {
             mQSBSearchBar.setVisibility(View.INVISIBLE);
-            mQSBSearchBar.setAlpha(0f);
+            if (mEnableDropDownDropTargets) {
+                mQSBSearchBar.setTranslationY(0);
+            } else {
+                mQSBSearchBar.setAlpha(0f);
+            }
         }
         mIsSearchBarHidden = true;
     }
diff --git a/src/com/android/launcher2/Workspace.java b/src/com/android/launcher2/Workspace.java
index 3910c45..d15d318 100644
--- a/src/com/android/launcher2/Workspace.java
+++ b/src/com/android/launcher2/Workspace.java
@@ -199,6 +199,7 @@
     private Point mDisplaySize = new Point();
     private boolean mIsStaticWallpaper;
     private int mWallpaperTravelWidth;
+    private int mSpringLoadedPageSpacing;
 
     // Variables relating to the creation of user folders by hovering shortcuts over shortcuts
     private static final int FOLDER_CREATION_TIMEOUT = 0;
@@ -322,6 +323,8 @@
 
         mSpringLoadedShrinkFactor =
             res.getInteger(R.integer.config_workspaceSpringLoadShrinkPercentage) / 100.0f;
+        mSpringLoadedPageSpacing =
+                res.getDimensionPixelSize(R.dimen.workspace_spring_loaded_page_spacing);
 
         // if the value is manually specified, use that instead
         cellCountX = a.getInt(R.styleable.Workspace_cellCountX, cellCountX);
@@ -450,6 +453,13 @@
     public void onChildViewRemoved(View parent, View child) {
     }
 
+    protected boolean shouldDrawChild(View child) {
+        final CellLayout cl = (CellLayout) child;
+        return super.shouldDrawChild(child) &&
+            (cl.getShortcutsAndWidgets().getAlpha() > 0 ||
+             cl.getBackgroundAlpha() > 0);
+    }
+
     /**
      * @return The open folder on the current screen, or null if there is none
      */
@@ -1536,6 +1546,7 @@
 
         if (state != State.NORMAL) {
             finalScaleFactor = mSpringLoadedShrinkFactor - (stateIsSmall ? 0.1f : 0);
+            setPageSpacing(mSpringLoadedPageSpacing);
             if (oldStateIsNormal && stateIsSmall) {
                 zoomIn = false;
                 setLayoutScale(finalScaleFactor);
@@ -1545,6 +1556,7 @@
                 setLayoutScale(finalScaleFactor);
             }
         } else {
+            setPageSpacing(PagedView.AUTOMATIC_PAGE_SPACING);
             setLayoutScale(1.0f);
         }