Adding tap-to-add behaviour to the customization drawer.

Change-Id: I5a0863a8df2a0b4855112eb29b40b6e7dd550db9
diff --git a/src/com/android/launcher2/CustomizePagedView.java b/src/com/android/launcher2/CustomizePagedView.java
index 79b3e6f..f6cff05 100644
--- a/src/com/android/launcher2/CustomizePagedView.java
+++ b/src/com/android/launcher2/CustomizePagedView.java
@@ -36,10 +36,15 @@
 import android.provider.LiveFolders;
 import android.util.AttributeSet;
 import android.util.Log;
+import android.view.ActionMode;
 import android.view.Gravity;
 import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.MenuItem;
 import android.view.MotionEvent;
 import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Checkable;
 import android.widget.ImageView;
 import android.widget.LinearLayout;
 import android.widget.TextView;
@@ -51,7 +56,7 @@
 
 public class CustomizePagedView extends PagedView
     implements View.OnLongClickListener, View.OnClickListener,
-                DragSource {
+                DragSource, ActionMode.Callback {
 
     public enum CustomizationType {
         WidgetCustomization,
@@ -313,6 +318,9 @@
         mCustomizationType = filterType;
         setCurrentPage(0);
         invalidatePageData();
+
+        // End the current choice mode so that we don't carry selections across tabs
+        endChoiceMode();
     }
 
     @Override
@@ -326,15 +334,43 @@
             return;
         }
 
-        final View animView = v;
+        // On certain pages, we allow single tap to mark items as selected so that they can be
+        // dropped onto the mini workspaces
+        switch (mCustomizationType) {
+        case WidgetCustomization:
+        case ApplicationCustomization:
+        case FolderCustomization:
+        case ShortcutCustomization:
+            if (isChoiceMode(CHOICE_MODE_NONE)) {
+                startChoiceMode(CHOICE_MODE_SINGLE, this);
+            }
+
+            if (v instanceof Checkable) {
+                final Checkable c = (Checkable) v;
+                final boolean wasChecked = c.isChecked();
+                resetCheckedGrandchildren();
+                c.setChecked(!wasChecked);
+
+                // End the current choice mode when we have no items selected
+                if (!c.isChecked()) {
+                    endChoiceMode();
+                }
+            }
+            return;
+        default:
+            break;
+        }
+
+        // Otherwise, we just handle the single click here
         switch (mCustomizationType) {
         case WallpaperCustomization:
             // animate some feedback to the long press
+            final View clickView = v;
             animateClickFeedback(v, new Runnable() {
                 @Override
                 public void run() {
                     // add the shortcut
-                    ResolveInfo info = (ResolveInfo) animView.getTag();
+                    ResolveInfo info = (ResolveInfo) clickView.getTag();
                     Intent createWallpapersIntent = new Intent(Intent.ACTION_SET_WALLPAPER);
                     ComponentName name = new ComponentName(info.activityInfo.packageName,
                             info.activityInfo.name);
@@ -342,6 +378,9 @@
                     mLauncher.processWallpaper(createWallpapersIntent);
                 }
             });
+            break;
+        default:
+            break;
         }
     }
 
@@ -351,46 +390,43 @@
             return false;
         }
 
-        final View animView = v;
-        PendingAddItemInfo createItemInfo = new PendingAddItemInfo();
+        // End the current choice mode before we start dragging anything
+        if (isChoiceMode(CHOICE_MODE_SINGLE)) {
+            endChoiceMode();
+        }
+
+        PendingAddItemInfo createItemInfo;
         switch (mCustomizationType) {
         case WidgetCustomization:
             // Get the icon as the drag representation
-            final LinearLayout l = (LinearLayout) animView;
-            final Drawable icon = ((ImageView) l.findViewById(R.id.icon)).getDrawable();
+            final LinearLayout l = (LinearLayout) v;
+            final Drawable icon = ((ImageView) l.findViewById(R.id.widget_preview)).getDrawable();
             Bitmap b = Bitmap.createBitmap(icon.getIntrinsicWidth(), icon.getIntrinsicHeight(),
                     Bitmap.Config.ARGB_8888);
             Canvas c = new Canvas(b);
             icon.draw(c);
 
-            AppWidgetProviderInfo appWidgetInfo = (AppWidgetProviderInfo) v.getTag();
-            createItemInfo.itemType = LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET;
-            createItemInfo.componentName = appWidgetInfo.provider;
-            mDragController.startDrag(v, b, this, createItemInfo, DragController.DRAG_ACTION_COPY, null);
+            createItemInfo = (PendingAddItemInfo) v.getTag();
+            mDragController.startDrag(v, b, this, createItemInfo, DragController.DRAG_ACTION_COPY,
+                    null);
 
             // Cleanup the icon
             b.recycle();
             return true;
         case FolderCustomization:
-            ResolveInfo resolveInfo = (ResolveInfo) animView.getTag();
-            if (resolveInfo.labelRes == R.string.group_folder) {
-                UserFolderInfo folderInfo = new UserFolderInfo();
-                folderInfo.title = getResources().getText(R.string.folder_name);
+            if (v.getTag() instanceof UserFolderInfo) {
+                // The UserFolderInfo tag is only really used for live folders
+                UserFolderInfo folderInfo = (UserFolderInfo) v.getTag();
                 mDragController.startDrag(
                         v, this, folderInfo, DragController.DRAG_ACTION_COPY, null);
             } else {
-                createItemInfo.itemType = LauncherSettings.Favorites.ITEM_TYPE_LIVE_FOLDER;
-                createItemInfo.componentName = new ComponentName(
-                        resolveInfo.activityInfo.packageName, resolveInfo.activityInfo.name);
+                createItemInfo = (PendingAddItemInfo) v.getTag();
                 mDragController.startDrag(
                         v, this, createItemInfo, DragController.DRAG_ACTION_COPY, null);
             }
             return true;
         case ShortcutCustomization:
-            ResolveInfo info = (ResolveInfo) animView.getTag();
-            createItemInfo.itemType = LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT;
-            createItemInfo.componentName = new ComponentName(
-                    info.activityInfo.packageName, info.activityInfo.name);
+            createItemInfo = (PendingAddItemInfo) v.getTag();
             mDragController.startDrag(
                     v, this, createItemInfo, DragController.DRAG_ACTION_COPY, null);
             return true;
@@ -550,21 +586,26 @@
         layout.removeAllViews();
         for (int i = 0; i < count; ++i) {
             AppWidgetProviderInfo info = (AppWidgetProviderInfo) list.get(i);
+            PendingAddItemInfo createItemInfo = new PendingAddItemInfo();
+            createItemInfo.itemType = LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET;
+            createItemInfo.componentName = info.provider;
+
             LinearLayout l = (LinearLayout) mInflater.inflate(
                     R.layout.customize_paged_view_widget, layout, false);
-            l.setTag(info);
+            l.setTag(createItemInfo);
+            l.setOnClickListener(this);
             l.setOnLongClickListener(this);
 
             final Drawable icon = getWidgetIcon(info);
             final int hSpan = mWorkspaceWidgetLayout.estimateCellHSpan(info.minWidth);
             final int vSpan = mWorkspaceWidgetLayout.estimateCellHSpan(info.minHeight);
 
-            ImageView image = (ImageView) l.findViewById(R.id.icon);
+            ImageView image = (ImageView) l.findViewById(R.id.widget_preview);
             image.setMaxWidth(mMaxWidgetWidth);
             image.setImageDrawable(icon);
-            TextView name = (TextView) l.findViewById(R.id.name);
+            TextView name = (TextView) l.findViewById(R.id.widget_name);
             name.setText(info.label);
-            TextView dims = (TextView) l.findViewById(R.id.dims);
+            TextView dims = (TextView) l.findViewById(R.id.widget_dims);
             dims.setText(mContext.getString(R.string.widget_dims_format, hSpan, vSpan));
 
             layout.addView(l);
@@ -594,13 +635,39 @@
         layout.removeAllViews();
         for (int i = startIndex; i < endIndex; ++i) {
             ResolveInfo info = list.get(i);
+            PendingAddItemInfo createItemInfo = new PendingAddItemInfo();
+
             PagedViewIcon icon = (PagedViewIcon) mInflater.inflate(
                     R.layout.customize_paged_view_item, layout, false);
             icon.applyFromResolveInfo(info, mPackageManager, mPageViewIconCache);
-            if (mCustomizationType == CustomizationType.WallpaperCustomization) {
+            switch (mCustomizationType) {
+            case WallpaperCustomization:
                 icon.setOnClickListener(this);
-            } else {
+                break;
+            case FolderCustomization:
+                if (info.labelRes != R.string.group_folder) {
+                    createItemInfo.itemType = LauncherSettings.Favorites.ITEM_TYPE_LIVE_FOLDER;
+                    createItemInfo.componentName = new ComponentName(info.activityInfo.packageName,
+                            info.activityInfo.name);
+                    icon.setTag(createItemInfo);
+                } else {
+                    UserFolderInfo folderInfo = new UserFolderInfo();
+                    folderInfo.title = getResources().getText(R.string.folder_name);
+                    icon.setTag(folderInfo);
+                }
+                icon.setOnClickListener(this);
                 icon.setOnLongClickListener(this);
+                break;
+            case ShortcutCustomization:
+                createItemInfo.itemType = LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT;
+                createItemInfo.componentName = new ComponentName(info.activityInfo.packageName,
+                        info.activityInfo.name);
+                icon.setTag(createItemInfo);
+                icon.setOnClickListener(this);
+                icon.setOnLongClickListener(this);
+                break;
+            default:
+                break;
             }
 
             final int index = i - startIndex;
@@ -641,6 +708,7 @@
             PagedViewIcon icon = (PagedViewIcon) mInflater.inflate(
                     R.layout.all_apps_paged_view_application, layout, false);
             icon.applyFromApplicationInfo(info, mPageViewIconCache);
+            icon.setOnClickListener(this);
             icon.setOnLongClickListener(this);
 
             final int index = i - startIndex;
@@ -719,10 +787,34 @@
         }
     }
 
+    @Override
     protected int getAssociatedLowerPageBound(int page) {
         return 0;
     }
+    @Override
     protected int getAssociatedUpperPageBound(int page) {
         return getChildCount();
     }
+
+    @Override
+    public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
+        mode.setTitle(R.string.cab_selection_text);
+        return true;
+    }
+
+    @Override
+    public boolean onCreateActionMode(ActionMode mode, Menu menu) {
+        return true;
+    }
+
+    @Override
+    public void onDestroyActionMode(ActionMode mode) {
+        endChoiceMode();
+    }
+
+    @Override
+    public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
+        return false;
+    }
+
 }
diff --git a/src/com/android/launcher2/HolographicOutlineHelper.java b/src/com/android/launcher2/HolographicOutlineHelper.java
index 597a725..9e61b79 100644
--- a/src/com/android/launcher2/HolographicOutlineHelper.java
+++ b/src/com/android/launcher2/HolographicOutlineHelper.java
@@ -35,8 +35,6 @@
     private static final BlurMaskFilter mThickInnerBlurMaskFilter = new BlurMaskFilter(4.0f,
             BlurMaskFilter.Blur.NORMAL);
 
-    public static float DEFAULT_STROKE_WIDTH = 6.0f;
-
     HolographicOutlineHelper() {
         mHolographicPaint.setFilterBitmap(true);
         mHolographicPaint.setAntiAlias(true);
diff --git a/src/com/android/launcher2/PagedView.java b/src/com/android/launcher2/PagedView.java
index 9dbe61d..17d18f8 100644
--- a/src/com/android/launcher2/PagedView.java
+++ b/src/com/android/launcher2/PagedView.java
@@ -1097,7 +1097,7 @@
         ArrayList<Checkable> checked = new ArrayList<Checkable>();
         final int childCount = getChildCount();
         for (int i = 0; i < childCount; ++i) {
-            final PagedViewCellLayout layout = (PagedViewCellLayout) getChildAt(i);
+            final ViewGroup layout = (ViewGroup) getChildAt(i);
             final int grandChildCount = layout.getChildCount();
             for (int j = 0; j < grandChildCount; ++j) {
                 final View v = layout.getChildAt(j);
@@ -1117,7 +1117,7 @@
         if (mChoiceMode == CHOICE_MODE_SINGLE) {
             final int childCount = getChildCount();
             for (int i = 0; i < childCount; ++i) {
-                final PagedViewCellLayout layout = (PagedViewCellLayout) getChildAt(i);
+                final ViewGroup layout = (ViewGroup) getChildAt(i);
                 final int grandChildCount = layout.getChildCount();
                 for (int j = 0; j < grandChildCount; ++j) {
                     final View v = layout.getChildAt(j);
diff --git a/src/com/android/launcher2/PagedViewWidgetIcon.java b/src/com/android/launcher2/PagedViewWidgetIcon.java
new file mode 100644
index 0000000..f285dab
--- /dev/null
+++ b/src/com/android/launcher2/PagedViewWidgetIcon.java
@@ -0,0 +1,156 @@
+/*
+ * 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.content.res.TypedArray;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffXfermode;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.Checkable;
+import android.widget.LinearLayout;
+
+import com.android.launcher.R;
+
+/**
+ * An widget icon for use specifically in the CustomizePagedView.  In class form so that
+ * we can add logic for how it will look when checked/unchecked.
+ */
+public class PagedViewWidgetIcon extends LinearLayout implements Checkable {
+    private static final String TAG = "PagedViewIcon";
+
+    // Holographic outline
+    private final Paint mPaint = new Paint();
+    private static HolographicOutlineHelper sHolographicOutlineHelper;
+    private final Paint mErasePaint = new Paint();
+    private Bitmap mCheckedOutline;
+    private Canvas mHolographicOutlineCanvas;
+    private boolean mIsHolographicUpdatePass;
+
+    private int mAlpha;
+
+    private boolean mIsChecked;
+
+    // Highlight colours
+    private int mCheckedBlurColor;
+    private int mCheckedOutlineColor;
+
+
+    public PagedViewWidgetIcon(Context context) {
+        this(context, null);
+    }
+
+    public PagedViewWidgetIcon(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public PagedViewWidgetIcon(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.PagedViewWidgetIcon,
+                defStyle, 0);
+        mCheckedBlurColor = a.getColor(R.styleable.PagedViewWidgetIcon_checkedBlurColor, 0);
+        mCheckedOutlineColor = a.getColor(R.styleable.PagedViewWidgetIcon_checkedOutlineColor, 0);
+        mErasePaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT));
+        mErasePaint.setFilterBitmap(true);
+        a.recycle();
+
+        if (sHolographicOutlineHelper == null) {
+            sHolographicOutlineHelper = new HolographicOutlineHelper();
+        }
+
+        setWillNotDraw(false);
+    }
+
+    public void invalidateCheckedImage() {
+        if (mCheckedOutline != null) {
+            mCheckedOutline.recycle();
+            mCheckedOutline = null;
+        }
+    }
+
+    @Override
+    protected void onDraw(Canvas canvas) {
+        // Draw the view itself
+        if (mIsHolographicUpdatePass) {
+            canvas.save();
+            final float alpha = getAlpha();
+            super.setAlpha(1.0f);
+            super.onDraw(canvas);
+            super.setAlpha(alpha);
+            canvas.restore();
+        } else {
+            if (mAlpha > 0) {
+                super.onDraw(canvas);
+            }
+        }
+
+        // Draw the holographic checked overlay if necessary
+        if (!mIsHolographicUpdatePass) {
+            if (mCheckedOutline != null) {
+                mPaint.setAlpha(255);
+                canvas.drawBitmap(mCheckedOutline, 0, 0, mPaint);
+            }
+        }
+    }
+
+    @Override
+    public boolean isChecked() {
+        return mIsChecked;
+    }
+
+    @Override
+    public void setChecked(boolean checked) {
+        if (mIsChecked != checked) {
+            mIsChecked = checked;
+
+            if (mIsChecked) {
+                // set a flag to indicate that we are going to draw the view at full alpha
+                mIsHolographicUpdatePass = true;
+                final int width = getMeasuredWidth();
+                final int height = getMeasuredHeight();
+                mCheckedOutline = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
+                mHolographicOutlineCanvas = new Canvas(mCheckedOutline);
+                mHolographicOutlineCanvas.concat(getMatrix());
+                draw(mHolographicOutlineCanvas);
+                sHolographicOutlineHelper.applyExpensiveOutlineWithBlur(mCheckedOutline,
+                        mHolographicOutlineCanvas, mCheckedBlurColor, mCheckedOutlineColor);
+
+                // Unlike PagedViewIcon, we can't seem to properly set the clip rect for all the
+                // children to respect when drawing... so for now, we erase over those parts in the
+                // checked highlight image
+                mHolographicOutlineCanvas.drawRect(0, findViewById(R.id.divider).getTop(),
+                        width, height, mErasePaint);
+
+                mIsHolographicUpdatePass = false;
+                mHolographicOutlineCanvas = null;
+            } else {
+                invalidateCheckedImage();
+            }
+
+            invalidate();
+        }
+    }
+
+    @Override
+    public void toggle() {
+        setChecked(!mIsChecked);
+    }
+}