1d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohenpackage com.android.launcher2;
2d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen
3d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohenimport android.animation.AnimatorSet;
4d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohenimport android.animation.ObjectAnimator;
5d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohenimport android.animation.PropertyValuesHolder;
6d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohenimport android.animation.ValueAnimator;
7d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohenimport android.animation.ValueAnimator.AnimatorUpdateListener;
80cf2a7c3eeb75cbd532b011524140a4b963f2c93Adam Cohenimport android.appwidget.AppWidgetHostView;
9d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohenimport android.appwidget.AppWidgetProviderInfo;
10d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohenimport android.content.Context;
110cf2a7c3eeb75cbd532b011524140a4b963f2c93Adam Cohenimport android.graphics.Rect;
12d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohenimport android.view.Gravity;
13d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohenimport android.widget.FrameLayout;
14d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohenimport android.widget.ImageView;
15d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen
16d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohenimport com.android.launcher.R;
17d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen
18d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohenpublic class AppWidgetResizeFrame extends FrameLayout {
19d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen
20d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen    private ItemInfo mItemInfo;
21d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen    private LauncherAppWidgetHostView mWidgetView;
22d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen    private CellLayout mCellLayout;
236788269814a678af976dfc7d6135993e172ce586Adam Cohen    private DragLayer mDragLayer;
246788269814a678af976dfc7d6135993e172ce586Adam Cohen    private Workspace mWorkspace;
25d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen    private ImageView mLeftHandle;
26d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen    private ImageView mRightHandle;
271b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen    private ImageView mTopHandle;
28d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen    private ImageView mBottomHandle;
29d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen
30d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen    private boolean mLeftBorderActive;
31d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen    private boolean mRightBorderActive;
32d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen    private boolean mTopBorderActive;
33d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen    private boolean mBottomBorderActive;
34d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen
3537b59ff9aa601d75392341e45d61bbb5c408439fAdam Cohen    private int mWidgetPaddingLeft;
3637b59ff9aa601d75392341e45d61bbb5c408439fAdam Cohen    private int mWidgetPaddingRight;
3737b59ff9aa601d75392341e45d61bbb5c408439fAdam Cohen    private int mWidgetPaddingTop;
3837b59ff9aa601d75392341e45d61bbb5c408439fAdam Cohen    private int mWidgetPaddingBottom;
3937b59ff9aa601d75392341e45d61bbb5c408439fAdam Cohen
40d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen    private int mBaselineWidth;
41d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen    private int mBaselineHeight;
42d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen    private int mBaselineX;
43d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen    private int mBaselineY;
44d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen    private int mResizeMode;
453cba722d4745b29a47ebc6a472dd921e5c9d7367Adam Cohen
46d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen    private int mRunningHInc;
47d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen    private int mRunningVInc;
48d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen    private int mMinHSpan;
49d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen    private int mMinVSpan;
50d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen    private int mDeltaX;
51d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen    private int mDeltaY;
521b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen
533cba722d4745b29a47ebc6a472dd921e5c9d7367Adam Cohen    private int mBackgroundPadding;
543cba722d4745b29a47ebc6a472dd921e5c9d7367Adam Cohen    private int mTouchTargetWidth;
55d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen
56d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen    private int mExpandability[] = new int[4];
57d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen
58d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen    final int SNAP_DURATION = 150;
593cba722d4745b29a47ebc6a472dd921e5c9d7367Adam Cohen    final int BACKGROUND_PADDING = 24;
60e4b7729b9d6343b4e7e0905e117e5ac469727cbeAdam Cohen    final float DIMMED_HANDLE_ALPHA = 0f;
61e4b7729b9d6343b4e7e0905e117e5ac469727cbeAdam Cohen    final float RESIZE_THRESHOLD = 0.66f;
62d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen
631b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen    public static final int LEFT = 0;
641b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen    public static final int TOP = 1;
651b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen    public static final int RIGHT = 2;
661b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen    public static final int BOTTOM = 3;
671b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen
68cbf47e38e24cc0d63b4bd3f345c050216f06f404Adam Cohen    private Launcher mLauncher;
69cbf47e38e24cc0d63b4bd3f345c050216f06f404Adam Cohen
70d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen    public AppWidgetResizeFrame(Context context, ItemInfo itemInfo,
716788269814a678af976dfc7d6135993e172ce586Adam Cohen            LauncherAppWidgetHostView widgetView, CellLayout cellLayout, DragLayer dragLayer) {
72d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen
73d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen        super(context);
74cbf47e38e24cc0d63b4bd3f345c050216f06f404Adam Cohen        mLauncher = (Launcher) context;
75d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen        mItemInfo = itemInfo;
76d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen        mCellLayout = cellLayout;
77d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen        mWidgetView = widgetView;
7827c09b05d3ed2a4ce9d53140216aba998727a569Adam Cohen        mResizeMode = widgetView.getAppWidgetInfo().resizeMode;
796788269814a678af976dfc7d6135993e172ce586Adam Cohen        mDragLayer = dragLayer;
806788269814a678af976dfc7d6135993e172ce586Adam Cohen        mWorkspace = (Workspace) dragLayer.findViewById(R.id.workspace);
813cba722d4745b29a47ebc6a472dd921e5c9d7367Adam Cohen
82d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen        final AppWidgetProviderInfo info = widgetView.getAppWidgetInfo();
83cbf47e38e24cc0d63b4bd3f345c050216f06f404Adam Cohen        int[] result = mLauncher.getMinResizeSpanForWidget(info, null);
84d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen        mMinHSpan = result[0];
85d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen        mMinVSpan = result[1];
86d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen
873cba722d4745b29a47ebc6a472dd921e5c9d7367Adam Cohen        setBackgroundResource(R.drawable.widget_resize_frame_holo);
88d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen        setPadding(0, 0, 0, 0);
89d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen
90d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen        LayoutParams lp;
91d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen        mLeftHandle = new ImageView(context);
923cba722d4745b29a47ebc6a472dd921e5c9d7367Adam Cohen        mLeftHandle.setImageResource(R.drawable.widget_resize_handle_left);
93d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen        lp = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT,
94d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen                Gravity.LEFT | Gravity.CENTER_VERTICAL);
95d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen        addView(mLeftHandle, lp);
96d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen
97d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen        mRightHandle = new ImageView(context);
983cba722d4745b29a47ebc6a472dd921e5c9d7367Adam Cohen        mRightHandle.setImageResource(R.drawable.widget_resize_handle_right);
99d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen        lp = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT,
100d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen                Gravity.RIGHT | Gravity.CENTER_VERTICAL);
101d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen        addView(mRightHandle, lp);
102d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen
103d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen        mTopHandle = new ImageView(context);
1043cba722d4745b29a47ebc6a472dd921e5c9d7367Adam Cohen        mTopHandle.setImageResource(R.drawable.widget_resize_handle_top);
105d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen        lp = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT,
106d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen                Gravity.CENTER_HORIZONTAL | Gravity.TOP);
107d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen        addView(mTopHandle, lp);
108d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen
109d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen        mBottomHandle = new ImageView(context);
1103cba722d4745b29a47ebc6a472dd921e5c9d7367Adam Cohen        mBottomHandle.setImageResource(R.drawable.widget_resize_handle_bottom);
111d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen        lp = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT,
112d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen                Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM);
113d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen        addView(mBottomHandle, lp);
114d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen
1150cf2a7c3eeb75cbd532b011524140a4b963f2c93Adam Cohen        Rect p = AppWidgetHostView.getDefaultPaddingForWidget(context,
1160cf2a7c3eeb75cbd532b011524140a4b963f2c93Adam Cohen                widgetView.getAppWidgetInfo().provider, null);
11782ebbd2a2f9ae5cb0a9d47f2f3a4293e4d0292d7Adam Cohen        mWidgetPaddingLeft = p.left;
11882ebbd2a2f9ae5cb0a9d47f2f3a4293e4d0292d7Adam Cohen        mWidgetPaddingTop = p.top;
11982ebbd2a2f9ae5cb0a9d47f2f3a4293e4d0292d7Adam Cohen        mWidgetPaddingRight = p.right;
12082ebbd2a2f9ae5cb0a9d47f2f3a4293e4d0292d7Adam Cohen        mWidgetPaddingBottom = p.bottom;
12137b59ff9aa601d75392341e45d61bbb5c408439fAdam Cohen
122d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen        if (mResizeMode == AppWidgetProviderInfo.RESIZE_HORIZONTAL) {
123d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen            mTopHandle.setVisibility(GONE);
124d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen            mBottomHandle.setVisibility(GONE);
125d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen        } else if (mResizeMode == AppWidgetProviderInfo.RESIZE_VERTICAL) {
126d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen            mLeftHandle.setVisibility(GONE);
127d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen            mRightHandle.setVisibility(GONE);
1283cba722d4745b29a47ebc6a472dd921e5c9d7367Adam Cohen        }
1293cba722d4745b29a47ebc6a472dd921e5c9d7367Adam Cohen
130cbf47e38e24cc0d63b4bd3f345c050216f06f404Adam Cohen        final float density = mLauncher.getResources().getDisplayMetrics().density;
1313cba722d4745b29a47ebc6a472dd921e5c9d7367Adam Cohen        mBackgroundPadding = (int) Math.ceil(density * BACKGROUND_PADDING);
1323cba722d4745b29a47ebc6a472dd921e5c9d7367Adam Cohen        mTouchTargetWidth = 2 * mBackgroundPadding;
133d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen    }
134d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen
135d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen    public boolean beginResizeIfPointInRegion(int x, int y) {
136d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen        boolean horizontalActive = (mResizeMode & AppWidgetProviderInfo.RESIZE_HORIZONTAL) != 0;
137d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen        boolean verticalActive = (mResizeMode & AppWidgetProviderInfo.RESIZE_VERTICAL) != 0;
1383cba722d4745b29a47ebc6a472dd921e5c9d7367Adam Cohen        mLeftBorderActive = (x < mTouchTargetWidth) && horizontalActive;
1393cba722d4745b29a47ebc6a472dd921e5c9d7367Adam Cohen        mRightBorderActive = (x > getWidth() - mTouchTargetWidth) && horizontalActive;
1403cba722d4745b29a47ebc6a472dd921e5c9d7367Adam Cohen        mTopBorderActive = (y < mTouchTargetWidth) && verticalActive;
1413cba722d4745b29a47ebc6a472dd921e5c9d7367Adam Cohen        mBottomBorderActive = (y > getHeight() - mTouchTargetWidth) && verticalActive;
142d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen
143d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen        boolean anyBordersActive = mLeftBorderActive || mRightBorderActive
144d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen                || mTopBorderActive || mBottomBorderActive;
145d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen
146d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen        mBaselineWidth = getMeasuredWidth();
147d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen        mBaselineHeight = getMeasuredHeight();
148d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen        mBaselineX = getLeft();
149d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen        mBaselineY = getTop();
150d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen        mRunningHInc = 0;
151d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen        mRunningVInc = 0;
152d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen
153d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen        if (anyBordersActive) {
1543cba722d4745b29a47ebc6a472dd921e5c9d7367Adam Cohen            mLeftHandle.setAlpha(mLeftBorderActive ? 1.0f : DIMMED_HANDLE_ALPHA);
1553cba722d4745b29a47ebc6a472dd921e5c9d7367Adam Cohen            mRightHandle.setAlpha(mRightBorderActive ? 1.0f :DIMMED_HANDLE_ALPHA);
1563cba722d4745b29a47ebc6a472dd921e5c9d7367Adam Cohen            mTopHandle.setAlpha(mTopBorderActive ? 1.0f : DIMMED_HANDLE_ALPHA);
1573cba722d4745b29a47ebc6a472dd921e5c9d7367Adam Cohen            mBottomHandle.setAlpha(mBottomBorderActive ? 1.0f : DIMMED_HANDLE_ALPHA);
158d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen        }
159d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen        mCellLayout.getExpandabilityArrayForView(mWidgetView, mExpandability);
1603cba722d4745b29a47ebc6a472dd921e5c9d7367Adam Cohen
161d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen        return anyBordersActive;
162d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen    }
163d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen
1641b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen    /**
1651b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen     *  Here we bound the deltas such that the frame cannot be stretched beyond the extents
1661b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen     *  of the CellLayout, and such that the frame's borders can't cross.
1671b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen     */
168d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen    public void updateDeltas(int deltaX, int deltaY) {
169d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen        if (mLeftBorderActive) {
170d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen            mDeltaX = Math.max(-mBaselineX, deltaX);
1713cba722d4745b29a47ebc6a472dd921e5c9d7367Adam Cohen            mDeltaX = Math.min(mBaselineWidth - 2 * mTouchTargetWidth, mDeltaX);
172d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen        } else if (mRightBorderActive) {
1736788269814a678af976dfc7d6135993e172ce586Adam Cohen            mDeltaX = Math.min(mDragLayer.getWidth() - (mBaselineX + mBaselineWidth), deltaX);
1743cba722d4745b29a47ebc6a472dd921e5c9d7367Adam Cohen            mDeltaX = Math.max(-mBaselineWidth + 2 * mTouchTargetWidth, mDeltaX);
175d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen        }
176d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen
177d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen        if (mTopBorderActive) {
178d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen            mDeltaY = Math.max(-mBaselineY, deltaY);
1793cba722d4745b29a47ebc6a472dd921e5c9d7367Adam Cohen            mDeltaY = Math.min(mBaselineHeight - 2 * mTouchTargetWidth, mDeltaY);
180d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen        } else if (mBottomBorderActive) {
1816788269814a678af976dfc7d6135993e172ce586Adam Cohen            mDeltaY = Math.min(mDragLayer.getHeight() - (mBaselineY + mBaselineHeight), deltaY);
1823cba722d4745b29a47ebc6a472dd921e5c9d7367Adam Cohen            mDeltaY = Math.max(-mBaselineHeight + 2 * mTouchTargetWidth, mDeltaY);
183d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen        }
184d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen    }
185d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen
1861b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen    /**
1871b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen     *  Based on the deltas, we resize the frame, and, if needed, we resize the widget.
1881b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen     */
189d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen    public void visualizeResizeForDelta(int deltaX, int deltaY) {
190d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen        updateDeltas(deltaX, deltaY);
1916788269814a678af976dfc7d6135993e172ce586Adam Cohen        DragLayer.LayoutParams lp = (DragLayer.LayoutParams) getLayoutParams();
1926788269814a678af976dfc7d6135993e172ce586Adam Cohen
193d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen        if (mLeftBorderActive) {
194d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen            lp.x = mBaselineX + mDeltaX;
195d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen            lp.width = mBaselineWidth - mDeltaX;
196d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen        } else if (mRightBorderActive) {
197d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen            lp.width = mBaselineWidth + mDeltaX;
198d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen        }
199d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen
200d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen        if (mTopBorderActive) {
201d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen            lp.y = mBaselineY + mDeltaY;
202d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen            lp.height = mBaselineHeight - mDeltaY;
203d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen        } else if (mBottomBorderActive) {
204d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen            lp.height = mBaselineHeight + mDeltaY;
205d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen        }
206d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen
207d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen        resizeWidgetIfNeeded();
208d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen        requestLayout();
209d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen    }
210d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen
2111b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen    /**
2121b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen     *  Based on the current deltas, we determine if and how to resize the widget.
2131b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen     */
214d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen    private void resizeWidgetIfNeeded() {
215d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen        int xThreshold = mCellLayout.getCellWidth() + mCellLayout.getWidthGap();
216d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen        int yThreshold = mCellLayout.getCellHeight() + mCellLayout.getHeightGap();
217d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen
218e4b7729b9d6343b4e7e0905e117e5ac469727cbeAdam Cohen        float hSpanIncF = 1.0f * mDeltaX / xThreshold - mRunningHInc;
219e4b7729b9d6343b4e7e0905e117e5ac469727cbeAdam Cohen        float vSpanIncF = 1.0f * mDeltaY / yThreshold - mRunningVInc;
220e4b7729b9d6343b4e7e0905e117e5ac469727cbeAdam Cohen
221e4b7729b9d6343b4e7e0905e117e5ac469727cbeAdam Cohen        int hSpanInc = 0;
222e4b7729b9d6343b4e7e0905e117e5ac469727cbeAdam Cohen        int vSpanInc = 0;
223d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen        int cellXInc = 0;
224d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen        int cellYInc = 0;
225d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen
226e4b7729b9d6343b4e7e0905e117e5ac469727cbeAdam Cohen        if (Math.abs(hSpanIncF) > RESIZE_THRESHOLD) {
227e4b7729b9d6343b4e7e0905e117e5ac469727cbeAdam Cohen            hSpanInc = Math.round(hSpanIncF);
228e4b7729b9d6343b4e7e0905e117e5ac469727cbeAdam Cohen        }
229e4b7729b9d6343b4e7e0905e117e5ac469727cbeAdam Cohen        if (Math.abs(vSpanIncF) > RESIZE_THRESHOLD) {
230e4b7729b9d6343b4e7e0905e117e5ac469727cbeAdam Cohen            vSpanInc = Math.round(vSpanIncF);
231e4b7729b9d6343b4e7e0905e117e5ac469727cbeAdam Cohen        }
232e4b7729b9d6343b4e7e0905e117e5ac469727cbeAdam Cohen
233d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen        if (hSpanInc == 0 && vSpanInc == 0) return;
234d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen
235d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen        // Before we change the widget, we clear the occupied cells associated with it.
236d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen        // The new set of occupied cells is marked below, once the layout params are updated.
237d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen        mCellLayout.markCellsAsUnoccupiedForView(mWidgetView);
238d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen
239d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen        CellLayout.LayoutParams lp = (CellLayout.LayoutParams) mWidgetView.getLayoutParams();
2401b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen
2411b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen        // For each border, we bound the resizing based on the minimum width, and the maximum
2421b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen        // expandability.
243d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen        if (mLeftBorderActive) {
2441b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen            cellXInc = Math.max(-mExpandability[LEFT], hSpanInc);
245d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen            cellXInc = Math.min(lp.cellHSpan - mMinHSpan, cellXInc);
246d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen            hSpanInc *= -1;
2471b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen            hSpanInc = Math.min(mExpandability[LEFT], hSpanInc);
248d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen            hSpanInc = Math.max(-(lp.cellHSpan - mMinHSpan), hSpanInc);
249d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen            mRunningHInc -= hSpanInc;
250d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen        } else if (mRightBorderActive) {
2511b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen            hSpanInc = Math.min(mExpandability[RIGHT], hSpanInc);
252d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen            hSpanInc = Math.max(-(lp.cellHSpan - mMinHSpan), hSpanInc);
253d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen            mRunningHInc += hSpanInc;
254d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen        }
255d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen
256d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen        if (mTopBorderActive) {
2571b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen            cellYInc = Math.max(-mExpandability[TOP], vSpanInc);
258d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen            cellYInc = Math.min(lp.cellVSpan - mMinVSpan, cellYInc);
259d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen            vSpanInc *= -1;
2601b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen            vSpanInc = Math.min(mExpandability[TOP], vSpanInc);
261d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen            vSpanInc = Math.max(-(lp.cellVSpan - mMinVSpan), vSpanInc);
262d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen            mRunningVInc -= vSpanInc;
263d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen        } else if (mBottomBorderActive) {
2641b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen            vSpanInc = Math.min(mExpandability[BOTTOM], vSpanInc);
265d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen            vSpanInc = Math.max(-(lp.cellVSpan - mMinVSpan), vSpanInc);
266d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen            mRunningVInc += vSpanInc;
267d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen        }
268d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen
269d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen        // Update the widget's dimensions and position according to the deltas computed above
270d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen        if (mLeftBorderActive || mRightBorderActive) {
271d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen            lp.cellHSpan += hSpanInc;
272d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen            lp.cellX += cellXInc;
273d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen        }
274d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen
275d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen        if (mTopBorderActive || mBottomBorderActive) {
276d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen            lp.cellVSpan += vSpanInc;
277d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen            lp.cellY += cellYInc;
278d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen        }
279d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen
2801b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen        // Update the expandability array, as we have changed the widget's size.
2813cba722d4745b29a47ebc6a472dd921e5c9d7367Adam Cohen        mCellLayout.getExpandabilityArrayForView(mWidgetView, mExpandability);
282d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen
283d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen        // Update the cells occupied by this widget
284d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen        mCellLayout.markCellsAsOccupiedForView(mWidgetView);
2856788269814a678af976dfc7d6135993e172ce586Adam Cohen        mWidgetView.requestLayout();
286d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen    }
287d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen
2881b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen    /**
2891b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen     * This is the final step of the resize. Here we save the new widget size and position
2901b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen     * to LauncherModel and animate the resize frame.
2911b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen     */
292d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen    public void commitResizeForDelta(int deltaX, int deltaY) {
293d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen        visualizeResizeForDelta(deltaX, deltaY);
294d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen
295d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen        CellLayout.LayoutParams lp = (CellLayout.LayoutParams) mWidgetView.getLayoutParams();
296d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen        LauncherModel.resizeItemInDatabase(getContext(), mItemInfo, lp.cellX, lp.cellY,
297d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen                lp.cellHSpan, lp.cellVSpan);
298d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen        mWidgetView.requestLayout();
299d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen
300d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen        // Once our widget resizes (hence the post), we want to snap the resize frame to it
301d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen        post(new Runnable() {
302d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen            public void run() {
303d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen                snapToWidget(true);
304d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen            }
305d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen        });
306d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen    }
307d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen
308d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen    public void snapToWidget(boolean animate) {
3096788269814a678af976dfc7d6135993e172ce586Adam Cohen        final DragLayer.LayoutParams lp = (DragLayer.LayoutParams) getLayoutParams();
3104b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung        int xOffset = mCellLayout.getLeft() + mCellLayout.getPaddingLeft() - mWorkspace.getScrollX();
3114b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung        int yOffset = mCellLayout.getTop() + mCellLayout.getPaddingTop() - mWorkspace.getScrollY();
312d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen
31337b59ff9aa601d75392341e45d61bbb5c408439fAdam Cohen        int newWidth = mWidgetView.getWidth() + 2 * mBackgroundPadding - mWidgetPaddingLeft -
31437b59ff9aa601d75392341e45d61bbb5c408439fAdam Cohen                mWidgetPaddingRight;
31537b59ff9aa601d75392341e45d61bbb5c408439fAdam Cohen        int newHeight = mWidgetView.getHeight() + 2 * mBackgroundPadding - mWidgetPaddingTop -
31637b59ff9aa601d75392341e45d61bbb5c408439fAdam Cohen                mWidgetPaddingBottom;
31737b59ff9aa601d75392341e45d61bbb5c408439fAdam Cohen
31837b59ff9aa601d75392341e45d61bbb5c408439fAdam Cohen        int newX = mWidgetView.getLeft() - mBackgroundPadding + xOffset + mWidgetPaddingLeft;
31937b59ff9aa601d75392341e45d61bbb5c408439fAdam Cohen        int newY = mWidgetView.getTop() - mBackgroundPadding + yOffset + mWidgetPaddingTop;
3203cba722d4745b29a47ebc6a472dd921e5c9d7367Adam Cohen
3213cba722d4745b29a47ebc6a472dd921e5c9d7367Adam Cohen        // We need to make sure the frame stays within the bounds of the CellLayout
3223cba722d4745b29a47ebc6a472dd921e5c9d7367Adam Cohen        if (newY < 0) {
3233cba722d4745b29a47ebc6a472dd921e5c9d7367Adam Cohen            newHeight -= -newY;
3243cba722d4745b29a47ebc6a472dd921e5c9d7367Adam Cohen            newY = 0;
3253cba722d4745b29a47ebc6a472dd921e5c9d7367Adam Cohen        }
3266788269814a678af976dfc7d6135993e172ce586Adam Cohen        if (newY + newHeight > mDragLayer.getHeight()) {
3276788269814a678af976dfc7d6135993e172ce586Adam Cohen            newHeight -= newY + newHeight - mDragLayer.getHeight();
3283cba722d4745b29a47ebc6a472dd921e5c9d7367Adam Cohen        }
3293cba722d4745b29a47ebc6a472dd921e5c9d7367Adam Cohen
330d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen        if (!animate) {
331d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen            lp.width = newWidth;
332d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen            lp.height = newHeight;
333d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen            lp.x = newX;
334d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen            lp.y = newY;
335d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen            mLeftHandle.setAlpha(1.0f);
336d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen            mRightHandle.setAlpha(1.0f);
337d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen            mTopHandle.setAlpha(1.0f);
338d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen            mBottomHandle.setAlpha(1.0f);
339d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen            requestLayout();
340d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen        } else {
341d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen            PropertyValuesHolder width = PropertyValuesHolder.ofInt("width", lp.width, newWidth);
3421b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen            PropertyValuesHolder height = PropertyValuesHolder.ofInt("height", lp.height,
3431b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen                    newHeight);
344d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen            PropertyValuesHolder x = PropertyValuesHolder.ofInt("x", lp.x, newX);
345d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen            PropertyValuesHolder y = PropertyValuesHolder.ofInt("y", lp.y, newY);
346d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen            ObjectAnimator oa = ObjectAnimator.ofPropertyValuesHolder(lp, width, height, x, y);
347d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen            ObjectAnimator leftOa = ObjectAnimator.ofFloat(mLeftHandle, "alpha", 1.0f);
348d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen            ObjectAnimator rightOa = ObjectAnimator.ofFloat(mRightHandle, "alpha", 1.0f);
349d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen            ObjectAnimator topOa = ObjectAnimator.ofFloat(mTopHandle, "alpha", 1.0f);
350d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen            ObjectAnimator bottomOa = ObjectAnimator.ofFloat(mBottomHandle, "alpha", 1.0f);
351d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen            oa.addUpdateListener(new AnimatorUpdateListener() {
352d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen                public void onAnimationUpdate(ValueAnimator animation) {
353d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen                    requestLayout();
354d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen                }
355d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen            });
356d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen            AnimatorSet set = new AnimatorSet();
357d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen            if (mResizeMode == AppWidgetProviderInfo.RESIZE_VERTICAL) {
358d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen                set.playTogether(oa, topOa, bottomOa);
359d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen            } else if (mResizeMode == AppWidgetProviderInfo.RESIZE_HORIZONTAL) {
360d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen                set.playTogether(oa, leftOa, rightOa);
361d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen            } else {
362d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen                set.playTogether(oa, leftOa, rightOa, topOa, bottomOa);
363d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen            }
364d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen
365d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen            set.setDuration(SNAP_DURATION);
366d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen            set.start();
367d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen        }
368d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen    }
369d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen}
370