adding ability to vertically drag an app out of All Apps

Change-Id: I211c9e60026610d9cf9eda0fbc65b15e6850b730
diff --git a/res/values-xlarge/config.xml b/res/values-xlarge/config.xml
index c254eb3..62f1671 100644
--- a/res/values-xlarge/config.xml
+++ b/res/values-xlarge/config.xml
@@ -51,6 +51,7 @@
     <!-- The slope, in percent, of the drag movement needed to drag an item out of the customization
          drawer (y / x * 100%)  -->
     <integer name="config_customizationDrawerDragSlopeThreshold">150</integer>
+    <integer name="config_allAppsDrawerDragSlopeThreshold">150</integer>
 
     <style name="config_orientation">
         <item name="@android:screenOrientation">unspecified</item>
diff --git a/src/com/android/launcher2/AllAppsPagedView.java b/src/com/android/launcher2/AllAppsPagedView.java
index 1ad7e07..c9a3119 100644
--- a/src/com/android/launcher2/AllAppsPagedView.java
+++ b/src/com/android/launcher2/AllAppsPagedView.java
@@ -20,13 +20,13 @@
 
 import android.content.ComponentName;
 import android.content.Context;
+import android.content.res.Resources;
 import android.content.res.TypedArray;
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
 import android.graphics.Color;
 import android.graphics.drawable.Drawable;
 import android.util.AttributeSet;
-import android.util.Log;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.animation.AnimationUtils;
@@ -41,9 +41,8 @@
  * An implementation of PagedView that populates the pages of the workspace
  * with all of the user's applications.
  */
-public class AllAppsPagedView extends PagedView
-        implements AllAppsView, View.OnClickListener, View.OnLongClickListener, DragSource,
-        DropTarget {
+public class AllAppsPagedView extends PagedViewWithDraggableItems implements AllAppsView,
+    View.OnClickListener, DragSource, DropTarget {
 
     private static final String TAG = "AllAppsPagedView";
     private static final boolean DEBUG = false;
@@ -84,6 +83,10 @@
         mInflater = LayoutInflater.from(context);
         a.recycle();
         setSoundEffectsEnabled(false);
+
+        Resources r = context.getResources();
+        setDragSlopeThreshold(
+                r.getInteger(R.integer.config_allAppsDrawerDragSlopeThreshold) / 100.0f);
     }
 
     @Override
@@ -242,10 +245,11 @@
     }
 
     @Override
-    public boolean onLongClick(View v) {
+    protected boolean beginDragging(View v) {
         if (!v.isInTouchMode()) {
             return false;
         }
+        super.beginDragging(v);
 
         // Start drag mode after the item is selected
         setupDragMode();
@@ -475,6 +479,7 @@
                         R.layout.all_apps_paged_view_application, layout, false);
                 text.setOnClickListener(this);
                 text.setOnLongClickListener(this);
+                text.setOnTouchListener(this);
 
                 layout.addViewToCellLayout(text, -1, i,
                     new PagedViewCellLayout.LayoutParams(0, 0, 1, 1));
diff --git a/src/com/android/launcher2/CustomizePagedView.java b/src/com/android/launcher2/CustomizePagedView.java
index 694d4d0..429c7fd 100644
--- a/src/com/android/launcher2/CustomizePagedView.java
+++ b/src/com/android/launcher2/CustomizePagedView.java
@@ -16,10 +16,7 @@
 
 package com.android.launcher2;
 
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.List;
+import com.android.launcher.R;
 
 import org.xmlpull.v1.XmlPullParser;
 
@@ -55,7 +52,6 @@
 import android.view.LayoutInflater;
 import android.view.Menu;
 import android.view.MenuItem;
-import android.view.MotionEvent;
 import android.view.View;
 import android.view.animation.DecelerateInterpolator;
 import android.view.animation.Interpolator;
@@ -63,12 +59,14 @@
 import android.widget.LinearLayout;
 import android.widget.TextView;
 
-import com.android.launcher.R;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
 
 
-public class CustomizePagedView extends PagedView
-    implements View.OnLongClickListener, View.OnClickListener, View.OnTouchListener,
-                DragSource, ActionMode.Callback {
+public class CustomizePagedView extends PagedViewWithDraggableItems
+    implements View.OnClickListener, DragSource, ActionMode.Callback {
 
     public enum CustomizationType {
         WidgetCustomization,
@@ -80,12 +78,9 @@
     private static final String TAG = "CustomizeWorkspace";
     private static final boolean DEBUG = false;
 
-    private View mLastTouchedItem;
     private Launcher mLauncher;
     private DragController mDragController;
     private PackageManager mPackageManager;
-    private boolean mIsDragging;
-    private float mDragSlopeThreshold;
 
     private CustomizationType mCustomizationType;
 
@@ -158,8 +153,8 @@
         mInflater = LayoutInflater.from(context);
 
         final Resources r = context.getResources();
-        mDragSlopeThreshold =
-            r.getInteger(R.integer.config_customizationDrawerDragSlopeThreshold) / 100.0f;
+        setDragSlopeThreshold(
+                r.getInteger(R.integer.config_customizationDrawerDragSlopeThreshold) / 100.0f);
 
         setVisibility(View.GONE);
         setSoundEffectsEnabled(false);
@@ -324,8 +319,6 @@
 
         // End the current choice mode so that we don't carry selections across tabs
         endChoiceMode();
-        // Reset the touch item (if we are mid-dragging)
-        mLastTouchedItem = null;
     }
 
     @Override
@@ -480,98 +473,6 @@
         }
     }
 
-    @Override
-    public boolean onLongClick(View v) {
-        // Return early if this is not initiated from a touch
-        if (!v.isInTouchMode()) return false;
-        // Return early if we are still animating the pages
-        if (mNextPage != INVALID_PAGE) return false;
-        return beginDragging(v);
-    }
-
-    @Override
-    public boolean onTouch(View v, MotionEvent event) {
-        mLastTouchedItem = v;
-        return false;
-    }
-
-    /*
-     * Determines if we should change the touch state to start scrolling after the
-     * user moves their touch point too far.
-     */
-    protected void determineScrollingStart(MotionEvent ev) {
-        if (!mIsDragging) super.determineScrollingStart(ev);
-    }
-
-    /*
-     * Determines if we should change the touch state to start dragging after the
-     * user moves their touch point far enough.
-     */
-    protected void determineDraggingStart(MotionEvent ev) {
-        /*
-         * Locally do absolute value. mLastMotionX is set to the y value
-         * of the down event.
-         */
-        final int pointerIndex = ev.findPointerIndex(mActivePointerId);
-        final float x = ev.getX(pointerIndex);
-        final float y = ev.getY(pointerIndex);
-        final int xDiff = (int) Math.abs(x - mLastMotionX);
-        final int yDiff = (int) Math.abs(y - mLastMotionY);
-
-        final int touchSlop = mTouchSlop;
-        boolean yMoved = yDiff > touchSlop;
-        boolean isUpwardMotion = (yDiff / (float) xDiff) > mDragSlopeThreshold;
-
-        if (isUpwardMotion && yMoved && mLastTouchedItem != null) {
-            // Drag if the user moved far enough along the Y axis
-            beginDragging(mLastTouchedItem);
-
-            // Cancel any pending longpress
-            if (mAllowLongPress) {
-                mAllowLongPress = false;
-                // Try canceling the long press. It could also have been scheduled
-                // by a distant descendant, so use the mAllowLongPress flag to block
-                // everything
-                final View currentPage = getPageAt(mCurrentPage);
-                if (currentPage != null) {
-                    currentPage.cancelLongPress();
-                }
-            }
-        }
-    }
-
-    @Override
-    public boolean onInterceptTouchEvent(MotionEvent ev) {
-        final int action = ev.getAction();
-        switch (action & MotionEvent.ACTION_MASK) {
-            case MotionEvent.ACTION_DOWN:
-                mIsDragging = false;
-                break;
-            case MotionEvent.ACTION_MOVE:
-                if (mTouchState != TOUCH_STATE_SCROLLING && !mIsDragging) {
-                    determineDraggingStart(ev);
-                }
-                break;
-        }
-        return super.onInterceptTouchEvent(ev);
-    }
-
-    @Override
-    public boolean onTouchEvent(MotionEvent ev) {
-        final int action = ev.getAction();
-        switch (action & MotionEvent.ACTION_MASK) {
-            case MotionEvent.ACTION_DOWN:
-                mIsDragging = false;
-                break;
-            case MotionEvent.ACTION_MOVE:
-                if (mTouchState != TOUCH_STATE_SCROLLING && !mIsDragging) {
-                    determineDraggingStart(ev);
-                }
-                break;
-        }
-        return super.onTouchEvent(ev);
-    }
-
     Bitmap drawableToBitmap(Drawable d, View v) {
         Bitmap b = Bitmap.createBitmap(v.getWidth(), v.getHeight(), Bitmap.Config.ARGB_8888);
         Canvas c = new Canvas(b);
@@ -585,12 +486,12 @@
                 v.findViewById(R.id.widget_preview) : v;
     }
 
-    private boolean beginDragging(View v) {
+    protected boolean beginDragging(View v) {
         // End the current choice mode before we start dragging anything
         if (isChoiceMode(CHOICE_MODE_SINGLE)) {
             endChoiceMode();
         }
-        mIsDragging = true;
+        super.beginDragging(v);
 
         switch (mCustomizationType) {
         case WidgetCustomization: {
diff --git a/src/com/android/launcher2/PagedViewWithDraggableItems.java b/src/com/android/launcher2/PagedViewWithDraggableItems.java
new file mode 100644
index 0000000..283cced
--- /dev/null
+++ b/src/com/android/launcher2/PagedViewWithDraggableItems.java
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher2;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+import android.view.View;
+
+
+/* Class that does most of the work of enabling dragging items out of a PagedView by performing a
+ * vertical drag. Used by both CustomizePagedView and AllAppsPagedView.
+ * Subclasses must do the following:
+ *   * call setDragSlopeThreshold after making an instance of the PagedViewWithDraggableItems
+ *   * call child.setOnLongClickListener(this) and child.setOnTouchListener(this) on all children
+ *       (good place to do it is in syncPageItems)
+ *   * override beginDragging(View) (but be careful to call super.beginDragging(View)
+ *
+ */
+public abstract class PagedViewWithDraggableItems extends PagedView
+    implements View.OnLongClickListener, View.OnTouchListener {
+    private View mLastTouchedItem;
+    private boolean mIsDragging;
+    private float mDragSlopeThreshold;
+
+    public PagedViewWithDraggableItems(Context context) {
+        super(context, null);
+    }
+
+    public PagedViewWithDraggableItems(Context context, AttributeSet attrs) {
+        super(context, attrs, 0);
+    }
+
+    public PagedViewWithDraggableItems(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+    }
+
+    protected boolean beginDragging(View v) {
+        mIsDragging = true;
+        return false;
+    }
+
+    @Override
+    public boolean onInterceptTouchEvent(MotionEvent ev) {
+        final int action = ev.getAction();
+        switch (action & MotionEvent.ACTION_MASK) {
+            case MotionEvent.ACTION_DOWN:
+                mIsDragging = false;
+                mLastTouchedItem = null;
+                break;
+            case MotionEvent.ACTION_MOVE:
+                if (mTouchState != TOUCH_STATE_SCROLLING && !mIsDragging) {
+                    determineDraggingStart(ev);
+                }
+                break;
+        }
+        return super.onInterceptTouchEvent(ev);
+    }
+
+    @Override
+    public boolean onTouch(View v, MotionEvent event) {
+        mLastTouchedItem = v;
+        return false;
+    }
+
+    @Override
+    public boolean onTouchEvent(MotionEvent ev) {
+        final int action = ev.getAction();
+        switch (action & MotionEvent.ACTION_MASK) {
+            case MotionEvent.ACTION_DOWN:
+                mIsDragging = false;
+                mLastTouchedItem = null;
+                break;
+            case MotionEvent.ACTION_MOVE:
+                if (mTouchState != TOUCH_STATE_SCROLLING && !mIsDragging) {
+                    determineDraggingStart(ev);
+                }
+                break;
+        }
+        return super.onTouchEvent(ev);
+    }
+
+    @Override
+    public boolean onLongClick(View v) {
+        // Return early if this is not initiated from a touch
+        if (!v.isInTouchMode()) return false;
+        // Return early if we are still animating the pages
+        if (mNextPage != INVALID_PAGE) return false;
+        return beginDragging(v);
+    }
+
+
+    /*
+     * Determines if we should change the touch state to start scrolling after the
+     * user moves their touch point too far.
+     */
+    protected void determineScrollingStart(MotionEvent ev) {
+        if (!mIsDragging) super.determineScrollingStart(ev);
+    }
+
+    /*
+     * Determines if we should change the touch state to start dragging after the
+     * user moves their touch point far enough.
+     */
+    protected void determineDraggingStart(MotionEvent ev) {
+        /*
+         * Locally do absolute value. mLastMotionX is set to the y value
+         * of the down event.
+         */
+        final int pointerIndex = ev.findPointerIndex(mActivePointerId);
+        final float x = ev.getX(pointerIndex);
+        final float y = ev.getY(pointerIndex);
+        final int xDiff = (int) Math.abs(x - mLastMotionX);
+        final int yDiff = (int) Math.abs(y - mLastMotionY);
+
+        final int touchSlop = mTouchSlop;
+        boolean yMoved = yDiff > touchSlop;
+        boolean isUpwardMotion = (yDiff / (float) xDiff) > mDragSlopeThreshold;
+
+        if (isUpwardMotion && yMoved && mLastTouchedItem != null) {
+            // Drag if the user moved far enough along the Y axis
+            beginDragging(mLastTouchedItem);
+
+            // Cancel any pending long press
+            if (mAllowLongPress) {
+                mAllowLongPress = false;
+                // Try canceling the long press. It could also have been scheduled
+                // by a distant descendant, so use the mAllowLongPress flag to block
+                // everything
+                final View currentPage = getPageAt(mCurrentPage);
+                if (currentPage != null) {
+                    currentPage.cancelLongPress();
+                }
+            }
+        }
+    }
+
+    public void setDragSlopeThreshold(float dragSlopeThreshold) {
+        mDragSlopeThreshold = dragSlopeThreshold;
+    }
+}