Launcher2 is now Launcher3.

Changes include
  - moving from com.android.launcher{,2} to
    com.android.launcher3
  - removing wallpapers
  - new temporary icon

Change-Id: I1eabd06059e94a8f3bdf6b620777bd1d2b7c212b
diff --git a/src/com/android/launcher3/AppWidgetResizeFrame.java b/src/com/android/launcher3/AppWidgetResizeFrame.java
new file mode 100644
index 0000000..8e968f8
--- /dev/null
+++ b/src/com/android/launcher3/AppWidgetResizeFrame.java
@@ -0,0 +1,471 @@
+package com.android.launcher3;
+
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
+import android.animation.PropertyValuesHolder;
+import android.animation.ValueAnimator;
+import android.animation.ValueAnimator.AnimatorUpdateListener;
+import android.appwidget.AppWidgetHostView;
+import android.appwidget.AppWidgetProviderInfo;
+import android.content.Context;
+import android.graphics.Rect;
+import android.view.Gravity;
+import android.widget.FrameLayout;
+import android.widget.ImageView;
+
+import com.android.launcher3.R;
+
+public class AppWidgetResizeFrame extends FrameLayout {
+    private LauncherAppWidgetHostView mWidgetView;
+    private CellLayout mCellLayout;
+    private DragLayer mDragLayer;
+    private Workspace mWorkspace;
+    private ImageView mLeftHandle;
+    private ImageView mRightHandle;
+    private ImageView mTopHandle;
+    private ImageView mBottomHandle;
+
+    private boolean mLeftBorderActive;
+    private boolean mRightBorderActive;
+    private boolean mTopBorderActive;
+    private boolean mBottomBorderActive;
+
+    private int mWidgetPaddingLeft;
+    private int mWidgetPaddingRight;
+    private int mWidgetPaddingTop;
+    private int mWidgetPaddingBottom;
+
+    private int mBaselineWidth;
+    private int mBaselineHeight;
+    private int mBaselineX;
+    private int mBaselineY;
+    private int mResizeMode;
+
+    private int mRunningHInc;
+    private int mRunningVInc;
+    private int mMinHSpan;
+    private int mMinVSpan;
+    private int mDeltaX;
+    private int mDeltaY;
+    private int mDeltaXAddOn;
+    private int mDeltaYAddOn;
+
+    private int mBackgroundPadding;
+    private int mTouchTargetWidth;
+
+    private int mTopTouchRegionAdjustment = 0;
+    private int mBottomTouchRegionAdjustment = 0;
+
+    int[] mDirectionVector = new int[2];
+    int[] mLastDirectionVector = new int[2];
+
+    final int SNAP_DURATION = 150;
+    final int BACKGROUND_PADDING = 24;
+    final float DIMMED_HANDLE_ALPHA = 0f;
+    final float RESIZE_THRESHOLD = 0.66f;
+
+    private static Rect mTmpRect = new Rect();
+
+    public static final int LEFT = 0;
+    public static final int TOP = 1;
+    public static final int RIGHT = 2;
+    public static final int BOTTOM = 3;
+
+    private Launcher mLauncher;
+
+    public AppWidgetResizeFrame(Context context,
+            LauncherAppWidgetHostView widgetView, CellLayout cellLayout, DragLayer dragLayer) {
+
+        super(context);
+        mLauncher = (Launcher) context;
+        mCellLayout = cellLayout;
+        mWidgetView = widgetView;
+        mResizeMode = widgetView.getAppWidgetInfo().resizeMode;
+        mDragLayer = dragLayer;
+        mWorkspace = (Workspace) dragLayer.findViewById(R.id.workspace);
+
+        final AppWidgetProviderInfo info = widgetView.getAppWidgetInfo();
+        int[] result = Launcher.getMinSpanForWidget(mLauncher, info);
+        mMinHSpan = result[0];
+        mMinVSpan = result[1];
+
+        setBackgroundResource(R.drawable.widget_resize_frame_holo);
+        setPadding(0, 0, 0, 0);
+
+        LayoutParams lp;
+        mLeftHandle = new ImageView(context);
+        mLeftHandle.setImageResource(R.drawable.widget_resize_handle_left);
+        lp = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT, 
+                Gravity.START | Gravity.CENTER_VERTICAL);
+        addView(mLeftHandle, lp);
+
+        mRightHandle = new ImageView(context);
+        mRightHandle.setImageResource(R.drawable.widget_resize_handle_right);
+        lp = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT, 
+                Gravity.END | Gravity.CENTER_VERTICAL);
+        addView(mRightHandle, lp);
+
+        mTopHandle = new ImageView(context);
+        mTopHandle.setImageResource(R.drawable.widget_resize_handle_top);
+        lp = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT, 
+                Gravity.CENTER_HORIZONTAL | Gravity.TOP);
+        addView(mTopHandle, lp);
+
+        mBottomHandle = new ImageView(context);
+        mBottomHandle.setImageResource(R.drawable.widget_resize_handle_bottom);
+        lp = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT, 
+                Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM);
+        addView(mBottomHandle, lp);
+
+        Rect p = AppWidgetHostView.getDefaultPaddingForWidget(context,
+                widgetView.getAppWidgetInfo().provider, null);
+        mWidgetPaddingLeft = p.left;
+        mWidgetPaddingTop = p.top;
+        mWidgetPaddingRight = p.right;
+        mWidgetPaddingBottom = p.bottom;
+
+        if (mResizeMode == AppWidgetProviderInfo.RESIZE_HORIZONTAL) {
+            mTopHandle.setVisibility(GONE);
+            mBottomHandle.setVisibility(GONE);
+        } else if (mResizeMode == AppWidgetProviderInfo.RESIZE_VERTICAL) {
+            mLeftHandle.setVisibility(GONE);
+            mRightHandle.setVisibility(GONE);
+        }
+
+        final float density = mLauncher.getResources().getDisplayMetrics().density;
+        mBackgroundPadding = (int) Math.ceil(density * BACKGROUND_PADDING);
+        mTouchTargetWidth = 2 * mBackgroundPadding;
+
+        // When we create the resize frame, we first mark all cells as unoccupied. The appropriate
+        // cells (same if not resized, or different) will be marked as occupied when the resize
+        // frame is dismissed.
+        mCellLayout.markCellsAsUnoccupiedForView(mWidgetView);
+    }
+
+    public boolean beginResizeIfPointInRegion(int x, int y) {
+        boolean horizontalActive = (mResizeMode & AppWidgetProviderInfo.RESIZE_HORIZONTAL) != 0;
+        boolean verticalActive = (mResizeMode & AppWidgetProviderInfo.RESIZE_VERTICAL) != 0;
+
+        mLeftBorderActive = (x < mTouchTargetWidth) && horizontalActive;
+        mRightBorderActive = (x > getWidth() - mTouchTargetWidth) && horizontalActive;
+        mTopBorderActive = (y < mTouchTargetWidth + mTopTouchRegionAdjustment) && verticalActive;
+        mBottomBorderActive = (y > getHeight() - mTouchTargetWidth + mBottomTouchRegionAdjustment)
+                && verticalActive;
+
+        boolean anyBordersActive = mLeftBorderActive || mRightBorderActive
+                || mTopBorderActive || mBottomBorderActive;
+
+        mBaselineWidth = getMeasuredWidth();
+        mBaselineHeight = getMeasuredHeight();
+        mBaselineX = getLeft();
+        mBaselineY = getTop();
+
+        if (anyBordersActive) {
+            mLeftHandle.setAlpha(mLeftBorderActive ? 1.0f : DIMMED_HANDLE_ALPHA);
+            mRightHandle.setAlpha(mRightBorderActive ? 1.0f :DIMMED_HANDLE_ALPHA);
+            mTopHandle.setAlpha(mTopBorderActive ? 1.0f : DIMMED_HANDLE_ALPHA);
+            mBottomHandle.setAlpha(mBottomBorderActive ? 1.0f : DIMMED_HANDLE_ALPHA);
+        }
+        return anyBordersActive;
+    }
+
+    /**
+     *  Here we bound the deltas such that the frame cannot be stretched beyond the extents
+     *  of the CellLayout, and such that the frame's borders can't cross.
+     */
+    public void updateDeltas(int deltaX, int deltaY) {
+        if (mLeftBorderActive) {
+            mDeltaX = Math.max(-mBaselineX, deltaX); 
+            mDeltaX = Math.min(mBaselineWidth - 2 * mTouchTargetWidth, mDeltaX);
+        } else if (mRightBorderActive) {
+            mDeltaX = Math.min(mDragLayer.getWidth() - (mBaselineX + mBaselineWidth), deltaX);
+            mDeltaX = Math.max(-mBaselineWidth + 2 * mTouchTargetWidth, mDeltaX);
+        }
+
+        if (mTopBorderActive) {
+            mDeltaY = Math.max(-mBaselineY, deltaY);
+            mDeltaY = Math.min(mBaselineHeight - 2 * mTouchTargetWidth, mDeltaY);
+        } else if (mBottomBorderActive) {
+            mDeltaY = Math.min(mDragLayer.getHeight() - (mBaselineY + mBaselineHeight), deltaY);
+            mDeltaY = Math.max(-mBaselineHeight + 2 * mTouchTargetWidth, mDeltaY);
+        }
+    }
+
+    public void visualizeResizeForDelta(int deltaX, int deltaY) {
+        visualizeResizeForDelta(deltaX, deltaY, false);
+    }
+
+    /**
+     *  Based on the deltas, we resize the frame, and, if needed, we resize the widget.
+     */
+    private void visualizeResizeForDelta(int deltaX, int deltaY, boolean onDismiss) {
+        updateDeltas(deltaX, deltaY);
+        DragLayer.LayoutParams lp = (DragLayer.LayoutParams) getLayoutParams();
+
+        if (mLeftBorderActive) {
+            lp.x = mBaselineX + mDeltaX;
+            lp.width = mBaselineWidth - mDeltaX;
+        } else if (mRightBorderActive) {
+            lp.width = mBaselineWidth + mDeltaX;
+        }
+
+        if (mTopBorderActive) {
+            lp.y = mBaselineY + mDeltaY;
+            lp.height = mBaselineHeight - mDeltaY;
+        } else if (mBottomBorderActive) {
+            lp.height = mBaselineHeight + mDeltaY;
+        }
+
+        resizeWidgetIfNeeded(onDismiss);
+        requestLayout();
+    }
+
+    /**
+     *  Based on the current deltas, we determine if and how to resize the widget.
+     */
+    private void resizeWidgetIfNeeded(boolean onDismiss) {
+        int xThreshold = mCellLayout.getCellWidth() + mCellLayout.getWidthGap();
+        int yThreshold = mCellLayout.getCellHeight() + mCellLayout.getHeightGap();
+
+        int deltaX = mDeltaX + mDeltaXAddOn;
+        int deltaY = mDeltaY + mDeltaYAddOn;
+
+        float hSpanIncF = 1.0f * deltaX / xThreshold - mRunningHInc;
+        float vSpanIncF = 1.0f * deltaY / yThreshold - mRunningVInc;
+
+        int hSpanInc = 0;
+        int vSpanInc = 0;
+        int cellXInc = 0;
+        int cellYInc = 0;
+
+        int countX = mCellLayout.getCountX();
+        int countY = mCellLayout.getCountY();
+
+        if (Math.abs(hSpanIncF) > RESIZE_THRESHOLD) {
+            hSpanInc = Math.round(hSpanIncF);
+        }
+        if (Math.abs(vSpanIncF) > RESIZE_THRESHOLD) {
+            vSpanInc = Math.round(vSpanIncF);
+        }
+
+        if (!onDismiss && (hSpanInc == 0 && vSpanInc == 0)) return;
+
+
+        CellLayout.LayoutParams lp = (CellLayout.LayoutParams) mWidgetView.getLayoutParams();
+
+        int spanX = lp.cellHSpan;
+        int spanY = lp.cellVSpan;
+        int cellX = lp.useTmpCoords ? lp.tmpCellX : lp.cellX;
+        int cellY = lp.useTmpCoords ? lp.tmpCellY : lp.cellY;
+
+        int hSpanDelta = 0;
+        int vSpanDelta = 0;
+
+        // For each border, we bound the resizing based on the minimum width, and the maximum
+        // expandability.
+        if (mLeftBorderActive) {
+            cellXInc = Math.max(-cellX, hSpanInc);
+            cellXInc = Math.min(lp.cellHSpan - mMinHSpan, cellXInc);
+            hSpanInc *= -1;
+            hSpanInc = Math.min(cellX, hSpanInc);
+            hSpanInc = Math.max(-(lp.cellHSpan - mMinHSpan), hSpanInc);
+            hSpanDelta = -hSpanInc;
+
+        } else if (mRightBorderActive) {
+            hSpanInc = Math.min(countX - (cellX + spanX), hSpanInc);
+            hSpanInc = Math.max(-(lp.cellHSpan - mMinHSpan), hSpanInc);
+            hSpanDelta = hSpanInc;
+        }
+
+        if (mTopBorderActive) {
+            cellYInc = Math.max(-cellY, vSpanInc);
+            cellYInc = Math.min(lp.cellVSpan - mMinVSpan, cellYInc);
+            vSpanInc *= -1;
+            vSpanInc = Math.min(cellY, vSpanInc);
+            vSpanInc = Math.max(-(lp.cellVSpan - mMinVSpan), vSpanInc);
+            vSpanDelta = -vSpanInc;
+        } else if (mBottomBorderActive) {
+            vSpanInc = Math.min(countY - (cellY + spanY), vSpanInc);
+            vSpanInc = Math.max(-(lp.cellVSpan - mMinVSpan), vSpanInc);
+            vSpanDelta = vSpanInc;
+        }
+
+        mDirectionVector[0] = 0;
+        mDirectionVector[1] = 0;
+        // Update the widget's dimensions and position according to the deltas computed above
+        if (mLeftBorderActive || mRightBorderActive) {
+            spanX += hSpanInc;
+            cellX += cellXInc;
+            if (hSpanDelta != 0) {
+                mDirectionVector[0] = mLeftBorderActive ? -1 : 1;
+            }
+        }
+
+        if (mTopBorderActive || mBottomBorderActive) {
+            spanY += vSpanInc;
+            cellY += cellYInc;
+            if (vSpanDelta != 0) {
+                mDirectionVector[1] = mTopBorderActive ? -1 : 1;
+            }
+        }
+
+        if (!onDismiss && vSpanDelta == 0 && hSpanDelta == 0) return;
+
+        // We always want the final commit to match the feedback, so we make sure to use the
+        // last used direction vector when committing the resize / reorder.
+        if (onDismiss) {
+            mDirectionVector[0] = mLastDirectionVector[0];
+            mDirectionVector[1] = mLastDirectionVector[1];
+        } else {
+            mLastDirectionVector[0] = mDirectionVector[0];
+            mLastDirectionVector[1] = mDirectionVector[1];
+        }
+
+        if (mCellLayout.createAreaForResize(cellX, cellY, spanX, spanY, mWidgetView,
+                mDirectionVector, onDismiss)) {
+            lp.tmpCellX = cellX;
+            lp.tmpCellY = cellY;
+            lp.cellHSpan = spanX;
+            lp.cellVSpan = spanY;
+            mRunningVInc += vSpanDelta;
+            mRunningHInc += hSpanDelta;
+            if (!onDismiss) {
+                updateWidgetSizeRanges(mWidgetView, mLauncher, spanX, spanY);
+            }
+        }
+        mWidgetView.requestLayout();
+    }
+
+    static void updateWidgetSizeRanges(AppWidgetHostView widgetView, Launcher launcher,
+            int spanX, int spanY) {
+
+        getWidgetSizeRanges(launcher, spanX, spanY, mTmpRect);
+        widgetView.updateAppWidgetSize(null, mTmpRect.left, mTmpRect.top,
+                mTmpRect.right, mTmpRect.bottom);
+    }
+
+    static Rect getWidgetSizeRanges(Launcher launcher, int spanX, int spanY, Rect rect) {
+        if (rect == null) {
+            rect = new Rect();
+        }
+        Rect landMetrics = Workspace.getCellLayoutMetrics(launcher, CellLayout.LANDSCAPE);
+        Rect portMetrics = Workspace.getCellLayoutMetrics(launcher, CellLayout.PORTRAIT);
+        final float density = launcher.getResources().getDisplayMetrics().density;
+
+        // Compute landscape size
+        int cellWidth = landMetrics.left;
+        int cellHeight = landMetrics.top;
+        int widthGap = landMetrics.right;
+        int heightGap = landMetrics.bottom;
+        int landWidth = (int) ((spanX * cellWidth + (spanX - 1) * widthGap) / density);
+        int landHeight = (int) ((spanY * cellHeight + (spanY - 1) * heightGap) / density);
+
+        // Compute portrait size
+        cellWidth = portMetrics.left;
+        cellHeight = portMetrics.top;
+        widthGap = portMetrics.right;
+        heightGap = portMetrics.bottom;
+        int portWidth = (int) ((spanX * cellWidth + (spanX - 1) * widthGap) / density);
+        int portHeight = (int) ((spanY * cellHeight + (spanY - 1) * heightGap) / density);
+        rect.set(portWidth, landHeight, landWidth, portHeight);
+        return rect;
+    }
+
+    /**
+     * This is the final step of the resize. Here we save the new widget size and position
+     * to LauncherModel and animate the resize frame.
+     */
+    public void commitResize() {
+        resizeWidgetIfNeeded(true);
+        requestLayout();
+    }
+
+    public void onTouchUp() {
+        int xThreshold = mCellLayout.getCellWidth() + mCellLayout.getWidthGap();
+        int yThreshold = mCellLayout.getCellHeight() + mCellLayout.getHeightGap();
+
+        mDeltaXAddOn = mRunningHInc * xThreshold; 
+        mDeltaYAddOn = mRunningVInc * yThreshold; 
+        mDeltaX = 0;
+        mDeltaY = 0;
+
+        post(new Runnable() {
+            @Override
+            public void run() {
+                snapToWidget(true);
+            }
+        });
+    }
+
+    public void snapToWidget(boolean animate) {
+        final DragLayer.LayoutParams lp = (DragLayer.LayoutParams) getLayoutParams();
+        int xOffset = mCellLayout.getLeft() + mCellLayout.getPaddingLeft()
+                + mDragLayer.getPaddingLeft() - mWorkspace.getScrollX();
+        int yOffset = mCellLayout.getTop() + mCellLayout.getPaddingTop()
+                + mDragLayer.getPaddingTop() - mWorkspace.getScrollY();
+
+        int newWidth = mWidgetView.getWidth() + 2 * mBackgroundPadding - mWidgetPaddingLeft -
+                mWidgetPaddingRight;
+        int newHeight = mWidgetView.getHeight() + 2 * mBackgroundPadding - mWidgetPaddingTop -
+                mWidgetPaddingBottom;
+
+        int newX = mWidgetView.getLeft() - mBackgroundPadding + xOffset + mWidgetPaddingLeft;
+        int newY = mWidgetView.getTop() - mBackgroundPadding + yOffset + mWidgetPaddingTop;
+
+        // We need to make sure the frame's touchable regions lie fully within the bounds of the 
+        // DragLayer. We allow the actual handles to be clipped, but we shift the touch regions
+        // down accordingly to provide a proper touch target.
+        if (newY < 0) {
+            // In this case we shift the touch region down to start at the top of the DragLayer
+            mTopTouchRegionAdjustment = -newY;
+        } else {
+            mTopTouchRegionAdjustment = 0;
+        }
+        if (newY + newHeight > mDragLayer.getHeight()) {
+            // In this case we shift the touch region up to end at the bottom of the DragLayer
+            mBottomTouchRegionAdjustment = -(newY + newHeight - mDragLayer.getHeight());
+        } else {
+            mBottomTouchRegionAdjustment = 0;
+        }
+
+        if (!animate) {
+            lp.width = newWidth;
+            lp.height = newHeight;
+            lp.x = newX;
+            lp.y = newY;
+            mLeftHandle.setAlpha(1.0f);
+            mRightHandle.setAlpha(1.0f);
+            mTopHandle.setAlpha(1.0f);
+            mBottomHandle.setAlpha(1.0f);
+            requestLayout();
+        } else {
+            PropertyValuesHolder width = PropertyValuesHolder.ofInt("width", lp.width, newWidth);
+            PropertyValuesHolder height = PropertyValuesHolder.ofInt("height", lp.height,
+                    newHeight);
+            PropertyValuesHolder x = PropertyValuesHolder.ofInt("x", lp.x, newX);
+            PropertyValuesHolder y = PropertyValuesHolder.ofInt("y", lp.y, newY);
+            ObjectAnimator oa =
+                    LauncherAnimUtils.ofPropertyValuesHolder(lp, this, width, height, x, y);
+            ObjectAnimator leftOa = LauncherAnimUtils.ofFloat(mLeftHandle, "alpha", 1.0f);
+            ObjectAnimator rightOa = LauncherAnimUtils.ofFloat(mRightHandle, "alpha", 1.0f);
+            ObjectAnimator topOa = LauncherAnimUtils.ofFloat(mTopHandle, "alpha", 1.0f);
+            ObjectAnimator bottomOa = LauncherAnimUtils.ofFloat(mBottomHandle, "alpha", 1.0f);
+            oa.addUpdateListener(new AnimatorUpdateListener() {
+                public void onAnimationUpdate(ValueAnimator animation) {
+                    requestLayout();
+                }
+            });
+            AnimatorSet set = LauncherAnimUtils.createAnimatorSet();
+            if (mResizeMode == AppWidgetProviderInfo.RESIZE_VERTICAL) {
+                set.playTogether(oa, topOa, bottomOa);
+            } else if (mResizeMode == AppWidgetProviderInfo.RESIZE_HORIZONTAL) {
+                set.playTogether(oa, leftOa, rightOa);
+            } else {
+                set.playTogether(oa, leftOa, rightOa, topOa, bottomOa);
+            }
+
+            set.setDuration(SNAP_DURATION);
+            set.start();
+        }
+    }
+}