blob: 346c0c39f51089303b4616701f4480dff5af8396 [file] [log] [blame]
Daniel Sandler325dc232013-06-05 22:57:57 -04001package com.android.launcher3;
Adam Cohend4844c32011-02-18 19:25:06 -08002
3import android.animation.AnimatorSet;
4import android.animation.ObjectAnimator;
5import android.animation.PropertyValuesHolder;
6import android.animation.ValueAnimator;
7import android.animation.ValueAnimator.AnimatorUpdateListener;
Adam Cohen0cf2a7c2011-11-08 15:07:01 -08008import android.appwidget.AppWidgetHostView;
Adam Cohend4844c32011-02-18 19:25:06 -08009import android.appwidget.AppWidgetProviderInfo;
10import android.content.Context;
Adam Cohen0cf2a7c2011-11-08 15:07:01 -080011import android.graphics.Rect;
Adam Cohend4844c32011-02-18 19:25:06 -080012import android.view.Gravity;
13import android.widget.FrameLayout;
14import android.widget.ImageView;
15
Daniel Sandler325dc232013-06-05 22:57:57 -040016import com.android.launcher3.R;
Adam Cohend4844c32011-02-18 19:25:06 -080017
18public class AppWidgetResizeFrame extends FrameLayout {
Adam Cohend4844c32011-02-18 19:25:06 -080019 private LauncherAppWidgetHostView mWidgetView;
20 private CellLayout mCellLayout;
Adam Cohen67882692011-03-11 15:29:03 -080021 private DragLayer mDragLayer;
22 private Workspace mWorkspace;
Adam Cohend4844c32011-02-18 19:25:06 -080023 private ImageView mLeftHandle;
24 private ImageView mRightHandle;
Adam Cohen1b607ed2011-03-03 17:26:50 -080025 private ImageView mTopHandle;
Adam Cohend4844c32011-02-18 19:25:06 -080026 private ImageView mBottomHandle;
27
28 private boolean mLeftBorderActive;
29 private boolean mRightBorderActive;
30 private boolean mTopBorderActive;
31 private boolean mBottomBorderActive;
32
Adam Cohen37b59ff2011-06-13 17:13:42 -070033 private int mWidgetPaddingLeft;
34 private int mWidgetPaddingRight;
35 private int mWidgetPaddingTop;
36 private int mWidgetPaddingBottom;
37
Adam Cohend4844c32011-02-18 19:25:06 -080038 private int mBaselineWidth;
39 private int mBaselineHeight;
40 private int mBaselineX;
41 private int mBaselineY;
42 private int mResizeMode;
Adam Cohen3cba7222011-03-02 19:03:11 -080043
Adam Cohend4844c32011-02-18 19:25:06 -080044 private int mRunningHInc;
45 private int mRunningVInc;
46 private int mMinHSpan;
47 private int mMinVSpan;
48 private int mDeltaX;
49 private int mDeltaY;
Adam Cohenbebf0422012-04-11 18:06:28 -070050 private int mDeltaXAddOn;
51 private int mDeltaYAddOn;
Adam Cohen1b607ed2011-03-03 17:26:50 -080052
Adam Cohen3cba7222011-03-02 19:03:11 -080053 private int mBackgroundPadding;
54 private int mTouchTargetWidth;
Adam Cohend4844c32011-02-18 19:25:06 -080055
Adam Cohen4459d6b2012-07-13 15:59:15 -070056 private int mTopTouchRegionAdjustment = 0;
57 private int mBottomTouchRegionAdjustment = 0;
58
Adam Cohenbebf0422012-04-11 18:06:28 -070059 int[] mDirectionVector = new int[2];
Adam Cohene0489502012-08-27 15:18:53 -070060 int[] mLastDirectionVector = new int[2];
Adam Cohend6e7aa32013-07-09 15:32:37 -070061 int[] mTmpPt = new int[2];
Adam Cohend4844c32011-02-18 19:25:06 -080062
Adam Cohend4844c32011-02-18 19:25:06 -080063 final int SNAP_DURATION = 150;
Adam Cohen3cba7222011-03-02 19:03:11 -080064 final int BACKGROUND_PADDING = 24;
Adam Cohene4b77292011-03-08 18:35:52 -080065 final float DIMMED_HANDLE_ALPHA = 0f;
66 final float RESIZE_THRESHOLD = 0.66f;
Adam Cohend4844c32011-02-18 19:25:06 -080067
Adam Cohen9e05a5e2012-09-10 15:53:09 -070068 private static Rect mTmpRect = new Rect();
69
Adam Cohen1b607ed2011-03-03 17:26:50 -080070 public static final int LEFT = 0;
71 public static final int TOP = 1;
72 public static final int RIGHT = 2;
73 public static final int BOTTOM = 3;
74
Adam Cohencbf47e32011-09-16 17:32:37 -070075 private Launcher mLauncher;
76
Michael Jurka3a9fced2012-04-13 14:44:29 -070077 public AppWidgetResizeFrame(Context context,
Adam Cohen67882692011-03-11 15:29:03 -080078 LauncherAppWidgetHostView widgetView, CellLayout cellLayout, DragLayer dragLayer) {
Adam Cohend4844c32011-02-18 19:25:06 -080079
80 super(context);
Adam Cohencbf47e32011-09-16 17:32:37 -070081 mLauncher = (Launcher) context;
Adam Cohend4844c32011-02-18 19:25:06 -080082 mCellLayout = cellLayout;
83 mWidgetView = widgetView;
Adam Cohen27c09b02011-02-28 14:45:11 -080084 mResizeMode = widgetView.getAppWidgetInfo().resizeMode;
Adam Cohen67882692011-03-11 15:29:03 -080085 mDragLayer = dragLayer;
86 mWorkspace = (Workspace) dragLayer.findViewById(R.id.workspace);
Adam Cohen3cba7222011-03-02 19:03:11 -080087
Adam Cohend4844c32011-02-18 19:25:06 -080088 final AppWidgetProviderInfo info = widgetView.getAppWidgetInfo();
Adam Cohen2f093b62012-04-30 18:59:53 -070089 int[] result = Launcher.getMinSpanForWidget(mLauncher, info);
Adam Cohend4844c32011-02-18 19:25:06 -080090 mMinHSpan = result[0];
91 mMinVSpan = result[1];
92
Adam Cohen3cba7222011-03-02 19:03:11 -080093 setBackgroundResource(R.drawable.widget_resize_frame_holo);
Adam Cohend4844c32011-02-18 19:25:06 -080094 setPadding(0, 0, 0, 0);
95
96 LayoutParams lp;
97 mLeftHandle = new ImageView(context);
Adam Cohen3cba7222011-03-02 19:03:11 -080098 mLeftHandle.setImageResource(R.drawable.widget_resize_handle_left);
Adam Cohend4844c32011-02-18 19:25:06 -080099 lp = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT,
Fabrice Di Megliocc11f742012-12-18 16:25:49 -0800100 Gravity.START | Gravity.CENTER_VERTICAL);
Adam Cohend4844c32011-02-18 19:25:06 -0800101 addView(mLeftHandle, lp);
102
103 mRightHandle = new ImageView(context);
Adam Cohen3cba7222011-03-02 19:03:11 -0800104 mRightHandle.setImageResource(R.drawable.widget_resize_handle_right);
Adam Cohend4844c32011-02-18 19:25:06 -0800105 lp = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT,
Fabrice Di Megliocc11f742012-12-18 16:25:49 -0800106 Gravity.END | Gravity.CENTER_VERTICAL);
Adam Cohend4844c32011-02-18 19:25:06 -0800107 addView(mRightHandle, lp);
108
109 mTopHandle = new ImageView(context);
Adam Cohen3cba7222011-03-02 19:03:11 -0800110 mTopHandle.setImageResource(R.drawable.widget_resize_handle_top);
Adam Cohend4844c32011-02-18 19:25:06 -0800111 lp = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT,
112 Gravity.CENTER_HORIZONTAL | Gravity.TOP);
113 addView(mTopHandle, lp);
114
115 mBottomHandle = new ImageView(context);
Adam Cohen3cba7222011-03-02 19:03:11 -0800116 mBottomHandle.setImageResource(R.drawable.widget_resize_handle_bottom);
Adam Cohend4844c32011-02-18 19:25:06 -0800117 lp = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT,
118 Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM);
119 addView(mBottomHandle, lp);
120
Adam Cohen0cf2a7c2011-11-08 15:07:01 -0800121 Rect p = AppWidgetHostView.getDefaultPaddingForWidget(context,
122 widgetView.getAppWidgetInfo().provider, null);
Adam Cohen82ebbd22011-09-30 15:05:40 -0700123 mWidgetPaddingLeft = p.left;
124 mWidgetPaddingTop = p.top;
125 mWidgetPaddingRight = p.right;
126 mWidgetPaddingBottom = p.bottom;
Adam Cohen37b59ff2011-06-13 17:13:42 -0700127
Adam Cohend4844c32011-02-18 19:25:06 -0800128 if (mResizeMode == AppWidgetProviderInfo.RESIZE_HORIZONTAL) {
129 mTopHandle.setVisibility(GONE);
130 mBottomHandle.setVisibility(GONE);
131 } else if (mResizeMode == AppWidgetProviderInfo.RESIZE_VERTICAL) {
132 mLeftHandle.setVisibility(GONE);
133 mRightHandle.setVisibility(GONE);
Adam Cohen3cba7222011-03-02 19:03:11 -0800134 }
135
Adam Cohencbf47e32011-09-16 17:32:37 -0700136 final float density = mLauncher.getResources().getDisplayMetrics().density;
Adam Cohen3cba7222011-03-02 19:03:11 -0800137 mBackgroundPadding = (int) Math.ceil(density * BACKGROUND_PADDING);
138 mTouchTargetWidth = 2 * mBackgroundPadding;
Adam Cohenbebf0422012-04-11 18:06:28 -0700139
140 // When we create the resize frame, we first mark all cells as unoccupied. The appropriate
141 // cells (same if not resized, or different) will be marked as occupied when the resize
142 // frame is dismissed.
143 mCellLayout.markCellsAsUnoccupiedForView(mWidgetView);
Adam Cohend4844c32011-02-18 19:25:06 -0800144 }
145
146 public boolean beginResizeIfPointInRegion(int x, int y) {
147 boolean horizontalActive = (mResizeMode & AppWidgetProviderInfo.RESIZE_HORIZONTAL) != 0;
148 boolean verticalActive = (mResizeMode & AppWidgetProviderInfo.RESIZE_VERTICAL) != 0;
Adam Cohen4459d6b2012-07-13 15:59:15 -0700149
Adam Cohen3cba7222011-03-02 19:03:11 -0800150 mLeftBorderActive = (x < mTouchTargetWidth) && horizontalActive;
151 mRightBorderActive = (x > getWidth() - mTouchTargetWidth) && horizontalActive;
Adam Cohen4459d6b2012-07-13 15:59:15 -0700152 mTopBorderActive = (y < mTouchTargetWidth + mTopTouchRegionAdjustment) && verticalActive;
153 mBottomBorderActive = (y > getHeight() - mTouchTargetWidth + mBottomTouchRegionAdjustment)
154 && verticalActive;
Adam Cohend4844c32011-02-18 19:25:06 -0800155
156 boolean anyBordersActive = mLeftBorderActive || mRightBorderActive
157 || mTopBorderActive || mBottomBorderActive;
158
159 mBaselineWidth = getMeasuredWidth();
160 mBaselineHeight = getMeasuredHeight();
161 mBaselineX = getLeft();
162 mBaselineY = getTop();
Adam Cohend4844c32011-02-18 19:25:06 -0800163
164 if (anyBordersActive) {
Adam Cohen3cba7222011-03-02 19:03:11 -0800165 mLeftHandle.setAlpha(mLeftBorderActive ? 1.0f : DIMMED_HANDLE_ALPHA);
166 mRightHandle.setAlpha(mRightBorderActive ? 1.0f :DIMMED_HANDLE_ALPHA);
167 mTopHandle.setAlpha(mTopBorderActive ? 1.0f : DIMMED_HANDLE_ALPHA);
168 mBottomHandle.setAlpha(mBottomBorderActive ? 1.0f : DIMMED_HANDLE_ALPHA);
Adam Cohend4844c32011-02-18 19:25:06 -0800169 }
Adam Cohend4844c32011-02-18 19:25:06 -0800170 return anyBordersActive;
171 }
172
Adam Cohen1b607ed2011-03-03 17:26:50 -0800173 /**
174 * Here we bound the deltas such that the frame cannot be stretched beyond the extents
175 * of the CellLayout, and such that the frame's borders can't cross.
176 */
Adam Cohend4844c32011-02-18 19:25:06 -0800177 public void updateDeltas(int deltaX, int deltaY) {
178 if (mLeftBorderActive) {
179 mDeltaX = Math.max(-mBaselineX, deltaX);
Adam Cohen3cba7222011-03-02 19:03:11 -0800180 mDeltaX = Math.min(mBaselineWidth - 2 * mTouchTargetWidth, mDeltaX);
Adam Cohend4844c32011-02-18 19:25:06 -0800181 } else if (mRightBorderActive) {
Adam Cohen67882692011-03-11 15:29:03 -0800182 mDeltaX = Math.min(mDragLayer.getWidth() - (mBaselineX + mBaselineWidth), deltaX);
Adam Cohen3cba7222011-03-02 19:03:11 -0800183 mDeltaX = Math.max(-mBaselineWidth + 2 * mTouchTargetWidth, mDeltaX);
Adam Cohend4844c32011-02-18 19:25:06 -0800184 }
185
186 if (mTopBorderActive) {
187 mDeltaY = Math.max(-mBaselineY, deltaY);
Adam Cohen3cba7222011-03-02 19:03:11 -0800188 mDeltaY = Math.min(mBaselineHeight - 2 * mTouchTargetWidth, mDeltaY);
Adam Cohend4844c32011-02-18 19:25:06 -0800189 } else if (mBottomBorderActive) {
Adam Cohen67882692011-03-11 15:29:03 -0800190 mDeltaY = Math.min(mDragLayer.getHeight() - (mBaselineY + mBaselineHeight), deltaY);
Adam Cohen3cba7222011-03-02 19:03:11 -0800191 mDeltaY = Math.max(-mBaselineHeight + 2 * mTouchTargetWidth, mDeltaY);
Adam Cohend4844c32011-02-18 19:25:06 -0800192 }
193 }
194
Adam Cohenbebf0422012-04-11 18:06:28 -0700195 public void visualizeResizeForDelta(int deltaX, int deltaY) {
196 visualizeResizeForDelta(deltaX, deltaY, false);
197 }
198
Adam Cohen1b607ed2011-03-03 17:26:50 -0800199 /**
200 * Based on the deltas, we resize the frame, and, if needed, we resize the widget.
201 */
Adam Cohenbebf0422012-04-11 18:06:28 -0700202 private void visualizeResizeForDelta(int deltaX, int deltaY, boolean onDismiss) {
Adam Cohend4844c32011-02-18 19:25:06 -0800203 updateDeltas(deltaX, deltaY);
Adam Cohen67882692011-03-11 15:29:03 -0800204 DragLayer.LayoutParams lp = (DragLayer.LayoutParams) getLayoutParams();
205
Adam Cohend4844c32011-02-18 19:25:06 -0800206 if (mLeftBorderActive) {
207 lp.x = mBaselineX + mDeltaX;
208 lp.width = mBaselineWidth - mDeltaX;
209 } else if (mRightBorderActive) {
210 lp.width = mBaselineWidth + mDeltaX;
211 }
212
213 if (mTopBorderActive) {
214 lp.y = mBaselineY + mDeltaY;
215 lp.height = mBaselineHeight - mDeltaY;
216 } else if (mBottomBorderActive) {
217 lp.height = mBaselineHeight + mDeltaY;
218 }
219
Adam Cohenbebf0422012-04-11 18:06:28 -0700220 resizeWidgetIfNeeded(onDismiss);
Adam Cohend4844c32011-02-18 19:25:06 -0800221 requestLayout();
222 }
223
Adam Cohen1b607ed2011-03-03 17:26:50 -0800224 /**
225 * Based on the current deltas, we determine if and how to resize the widget.
226 */
Adam Cohenbebf0422012-04-11 18:06:28 -0700227 private void resizeWidgetIfNeeded(boolean onDismiss) {
Adam Cohend4844c32011-02-18 19:25:06 -0800228 int xThreshold = mCellLayout.getCellWidth() + mCellLayout.getWidthGap();
229 int yThreshold = mCellLayout.getCellHeight() + mCellLayout.getHeightGap();
230
Adam Cohenbebf0422012-04-11 18:06:28 -0700231 int deltaX = mDeltaX + mDeltaXAddOn;
232 int deltaY = mDeltaY + mDeltaYAddOn;
233
234 float hSpanIncF = 1.0f * deltaX / xThreshold - mRunningHInc;
235 float vSpanIncF = 1.0f * deltaY / yThreshold - mRunningVInc;
Adam Cohene4b77292011-03-08 18:35:52 -0800236
237 int hSpanInc = 0;
238 int vSpanInc = 0;
Adam Cohend4844c32011-02-18 19:25:06 -0800239 int cellXInc = 0;
240 int cellYInc = 0;
241
Adam Cohenbebf0422012-04-11 18:06:28 -0700242 int countX = mCellLayout.getCountX();
243 int countY = mCellLayout.getCountY();
244
Adam Cohene4b77292011-03-08 18:35:52 -0800245 if (Math.abs(hSpanIncF) > RESIZE_THRESHOLD) {
246 hSpanInc = Math.round(hSpanIncF);
247 }
248 if (Math.abs(vSpanIncF) > RESIZE_THRESHOLD) {
249 vSpanInc = Math.round(vSpanIncF);
250 }
251
Adam Cohenbebf0422012-04-11 18:06:28 -0700252 if (!onDismiss && (hSpanInc == 0 && vSpanInc == 0)) return;
Adam Cohend4844c32011-02-18 19:25:06 -0800253
Adam Cohend4844c32011-02-18 19:25:06 -0800254
255 CellLayout.LayoutParams lp = (CellLayout.LayoutParams) mWidgetView.getLayoutParams();
Adam Cohen1b607ed2011-03-03 17:26:50 -0800256
Adam Cohenbebf0422012-04-11 18:06:28 -0700257 int spanX = lp.cellHSpan;
258 int spanY = lp.cellVSpan;
259 int cellX = lp.useTmpCoords ? lp.tmpCellX : lp.cellX;
260 int cellY = lp.useTmpCoords ? lp.tmpCellY : lp.cellY;
261
262 int hSpanDelta = 0;
263 int vSpanDelta = 0;
264
Adam Cohen1b607ed2011-03-03 17:26:50 -0800265 // For each border, we bound the resizing based on the minimum width, and the maximum
266 // expandability.
Adam Cohend4844c32011-02-18 19:25:06 -0800267 if (mLeftBorderActive) {
Adam Cohenbebf0422012-04-11 18:06:28 -0700268 cellXInc = Math.max(-cellX, hSpanInc);
Adam Cohend4844c32011-02-18 19:25:06 -0800269 cellXInc = Math.min(lp.cellHSpan - mMinHSpan, cellXInc);
270 hSpanInc *= -1;
Adam Cohenbebf0422012-04-11 18:06:28 -0700271 hSpanInc = Math.min(cellX, hSpanInc);
Adam Cohend4844c32011-02-18 19:25:06 -0800272 hSpanInc = Math.max(-(lp.cellHSpan - mMinHSpan), hSpanInc);
Adam Cohenbebf0422012-04-11 18:06:28 -0700273 hSpanDelta = -hSpanInc;
274
Adam Cohend4844c32011-02-18 19:25:06 -0800275 } else if (mRightBorderActive) {
Adam Cohenbebf0422012-04-11 18:06:28 -0700276 hSpanInc = Math.min(countX - (cellX + spanX), hSpanInc);
Adam Cohend4844c32011-02-18 19:25:06 -0800277 hSpanInc = Math.max(-(lp.cellHSpan - mMinHSpan), hSpanInc);
Adam Cohenbebf0422012-04-11 18:06:28 -0700278 hSpanDelta = hSpanInc;
Adam Cohend4844c32011-02-18 19:25:06 -0800279 }
280
281 if (mTopBorderActive) {
Adam Cohenbebf0422012-04-11 18:06:28 -0700282 cellYInc = Math.max(-cellY, vSpanInc);
Adam Cohend4844c32011-02-18 19:25:06 -0800283 cellYInc = Math.min(lp.cellVSpan - mMinVSpan, cellYInc);
284 vSpanInc *= -1;
Adam Cohenbebf0422012-04-11 18:06:28 -0700285 vSpanInc = Math.min(cellY, vSpanInc);
Adam Cohend4844c32011-02-18 19:25:06 -0800286 vSpanInc = Math.max(-(lp.cellVSpan - mMinVSpan), vSpanInc);
Adam Cohenbebf0422012-04-11 18:06:28 -0700287 vSpanDelta = -vSpanInc;
Adam Cohend4844c32011-02-18 19:25:06 -0800288 } else if (mBottomBorderActive) {
Adam Cohenbebf0422012-04-11 18:06:28 -0700289 vSpanInc = Math.min(countY - (cellY + spanY), vSpanInc);
Adam Cohend4844c32011-02-18 19:25:06 -0800290 vSpanInc = Math.max(-(lp.cellVSpan - mMinVSpan), vSpanInc);
Adam Cohenbebf0422012-04-11 18:06:28 -0700291 vSpanDelta = vSpanInc;
Adam Cohend4844c32011-02-18 19:25:06 -0800292 }
293
Adam Cohenbebf0422012-04-11 18:06:28 -0700294 mDirectionVector[0] = 0;
295 mDirectionVector[1] = 0;
Adam Cohend4844c32011-02-18 19:25:06 -0800296 // Update the widget's dimensions and position according to the deltas computed above
297 if (mLeftBorderActive || mRightBorderActive) {
Adam Cohenbebf0422012-04-11 18:06:28 -0700298 spanX += hSpanInc;
299 cellX += cellXInc;
Adam Cohene0489502012-08-27 15:18:53 -0700300 if (hSpanDelta != 0) {
301 mDirectionVector[0] = mLeftBorderActive ? -1 : 1;
302 }
Adam Cohend4844c32011-02-18 19:25:06 -0800303 }
304
305 if (mTopBorderActive || mBottomBorderActive) {
Adam Cohenbebf0422012-04-11 18:06:28 -0700306 spanY += vSpanInc;
307 cellY += cellYInc;
Adam Cohene0489502012-08-27 15:18:53 -0700308 if (vSpanDelta != 0) {
309 mDirectionVector[1] = mTopBorderActive ? -1 : 1;
310 }
Adam Cohend4844c32011-02-18 19:25:06 -0800311 }
312
Adam Cohenbebf0422012-04-11 18:06:28 -0700313 if (!onDismiss && vSpanDelta == 0 && hSpanDelta == 0) return;
Adam Cohend4844c32011-02-18 19:25:06 -0800314
Adam Cohene0489502012-08-27 15:18:53 -0700315 // We always want the final commit to match the feedback, so we make sure to use the
316 // last used direction vector when committing the resize / reorder.
317 if (onDismiss) {
318 mDirectionVector[0] = mLastDirectionVector[0];
319 mDirectionVector[1] = mLastDirectionVector[1];
320 } else {
321 mLastDirectionVector[0] = mDirectionVector[0];
322 mLastDirectionVector[1] = mDirectionVector[1];
323 }
324
Adam Cohenbebf0422012-04-11 18:06:28 -0700325 if (mCellLayout.createAreaForResize(cellX, cellY, spanX, spanY, mWidgetView,
326 mDirectionVector, onDismiss)) {
327 lp.tmpCellX = cellX;
328 lp.tmpCellY = cellY;
329 lp.cellHSpan = spanX;
330 lp.cellVSpan = spanY;
331 mRunningVInc += vSpanDelta;
332 mRunningHInc += hSpanDelta;
Adam Cohena897f392012-04-27 18:12:05 -0700333 if (!onDismiss) {
334 updateWidgetSizeRanges(mWidgetView, mLauncher, spanX, spanY);
335 }
Adam Cohenbebf0422012-04-11 18:06:28 -0700336 }
Adam Cohen67882692011-03-11 15:29:03 -0800337 mWidgetView.requestLayout();
Adam Cohend4844c32011-02-18 19:25:06 -0800338 }
339
Adam Cohena897f392012-04-27 18:12:05 -0700340 static void updateWidgetSizeRanges(AppWidgetHostView widgetView, Launcher launcher,
341 int spanX, int spanY) {
Adam Cohen9e05a5e2012-09-10 15:53:09 -0700342
343 getWidgetSizeRanges(launcher, spanX, spanY, mTmpRect);
344 widgetView.updateAppWidgetSize(null, mTmpRect.left, mTmpRect.top,
345 mTmpRect.right, mTmpRect.bottom);
346 }
347
348 static Rect getWidgetSizeRanges(Launcher launcher, int spanX, int spanY, Rect rect) {
349 if (rect == null) {
350 rect = new Rect();
351 }
Adam Cohena897f392012-04-27 18:12:05 -0700352 Rect landMetrics = Workspace.getCellLayoutMetrics(launcher, CellLayout.LANDSCAPE);
353 Rect portMetrics = Workspace.getCellLayoutMetrics(launcher, CellLayout.PORTRAIT);
354 final float density = launcher.getResources().getDisplayMetrics().density;
355
356 // Compute landscape size
357 int cellWidth = landMetrics.left;
358 int cellHeight = landMetrics.top;
359 int widthGap = landMetrics.right;
360 int heightGap = landMetrics.bottom;
361 int landWidth = (int) ((spanX * cellWidth + (spanX - 1) * widthGap) / density);
362 int landHeight = (int) ((spanY * cellHeight + (spanY - 1) * heightGap) / density);
363
364 // Compute portrait size
365 cellWidth = portMetrics.left;
366 cellHeight = portMetrics.top;
367 widthGap = portMetrics.right;
368 heightGap = portMetrics.bottom;
369 int portWidth = (int) ((spanX * cellWidth + (spanX - 1) * widthGap) / density);
370 int portHeight = (int) ((spanY * cellHeight + (spanY - 1) * heightGap) / density);
Adam Cohen9e05a5e2012-09-10 15:53:09 -0700371 rect.set(portWidth, landHeight, landWidth, portHeight);
372 return rect;
Adam Cohena897f392012-04-27 18:12:05 -0700373 }
374
Adam Cohen1b607ed2011-03-03 17:26:50 -0800375 /**
376 * This is the final step of the resize. Here we save the new widget size and position
377 * to LauncherModel and animate the resize frame.
378 */
Adam Cohenbebf0422012-04-11 18:06:28 -0700379 public void commitResize() {
380 resizeWidgetIfNeeded(true);
381 requestLayout();
382 }
Adam Cohend4844c32011-02-18 19:25:06 -0800383
Adam Cohenbebf0422012-04-11 18:06:28 -0700384 public void onTouchUp() {
385 int xThreshold = mCellLayout.getCellWidth() + mCellLayout.getWidthGap();
386 int yThreshold = mCellLayout.getCellHeight() + mCellLayout.getHeightGap();
Adam Cohend4844c32011-02-18 19:25:06 -0800387
Adam Cohenbebf0422012-04-11 18:06:28 -0700388 mDeltaXAddOn = mRunningHInc * xThreshold;
389 mDeltaYAddOn = mRunningVInc * yThreshold;
390 mDeltaX = 0;
391 mDeltaY = 0;
392
Adam Cohend4844c32011-02-18 19:25:06 -0800393 post(new Runnable() {
Adam Cohenbebf0422012-04-11 18:06:28 -0700394 @Override
Adam Cohend4844c32011-02-18 19:25:06 -0800395 public void run() {
396 snapToWidget(true);
397 }
398 });
399 }
400
401 public void snapToWidget(boolean animate) {
Adam Cohen67882692011-03-11 15:29:03 -0800402 final DragLayer.LayoutParams lp = (DragLayer.LayoutParams) getLayoutParams();
Adam Cohen37b59ff2011-06-13 17:13:42 -0700403 int newWidth = mWidgetView.getWidth() + 2 * mBackgroundPadding - mWidgetPaddingLeft -
404 mWidgetPaddingRight;
405 int newHeight = mWidgetView.getHeight() + 2 * mBackgroundPadding - mWidgetPaddingTop -
406 mWidgetPaddingBottom;
407
Adam Cohend6e7aa32013-07-09 15:32:37 -0700408 mTmpPt[0] = mWidgetView.getLeft();
409 mTmpPt[1] = mWidgetView.getTop();
410 mDragLayer.getDescendantCoordRelativeToSelf(mCellLayout.getShortcutsAndWidgets(), mTmpPt);
411
412 int newX = mTmpPt[0] - mBackgroundPadding + mWidgetPaddingLeft;
413 int newY = mTmpPt[1] - mBackgroundPadding + mWidgetPaddingTop;
Adam Cohen3cba7222011-03-02 19:03:11 -0800414
Adam Cohen4459d6b2012-07-13 15:59:15 -0700415 // We need to make sure the frame's touchable regions lie fully within the bounds of the
416 // DragLayer. We allow the actual handles to be clipped, but we shift the touch regions
417 // down accordingly to provide a proper touch target.
Adam Cohen3cba7222011-03-02 19:03:11 -0800418 if (newY < 0) {
Adam Cohen4459d6b2012-07-13 15:59:15 -0700419 // In this case we shift the touch region down to start at the top of the DragLayer
420 mTopTouchRegionAdjustment = -newY;
421 } else {
422 mTopTouchRegionAdjustment = 0;
Adam Cohen3cba7222011-03-02 19:03:11 -0800423 }
Adam Cohen67882692011-03-11 15:29:03 -0800424 if (newY + newHeight > mDragLayer.getHeight()) {
Adam Cohen4459d6b2012-07-13 15:59:15 -0700425 // In this case we shift the touch region up to end at the bottom of the DragLayer
426 mBottomTouchRegionAdjustment = -(newY + newHeight - mDragLayer.getHeight());
427 } else {
428 mBottomTouchRegionAdjustment = 0;
Adam Cohen3cba7222011-03-02 19:03:11 -0800429 }
430
Adam Cohend4844c32011-02-18 19:25:06 -0800431 if (!animate) {
432 lp.width = newWidth;
433 lp.height = newHeight;
434 lp.x = newX;
435 lp.y = newY;
436 mLeftHandle.setAlpha(1.0f);
437 mRightHandle.setAlpha(1.0f);
438 mTopHandle.setAlpha(1.0f);
439 mBottomHandle.setAlpha(1.0f);
440 requestLayout();
441 } else {
442 PropertyValuesHolder width = PropertyValuesHolder.ofInt("width", lp.width, newWidth);
Adam Cohen1b607ed2011-03-03 17:26:50 -0800443 PropertyValuesHolder height = PropertyValuesHolder.ofInt("height", lp.height,
444 newHeight);
Adam Cohend4844c32011-02-18 19:25:06 -0800445 PropertyValuesHolder x = PropertyValuesHolder.ofInt("x", lp.x, newX);
446 PropertyValuesHolder y = PropertyValuesHolder.ofInt("y", lp.y, newY);
Michael Jurkaf1ad6082013-03-13 12:55:46 +0100447 ObjectAnimator oa =
448 LauncherAnimUtils.ofPropertyValuesHolder(lp, this, width, height, x, y);
Michael Jurka2ecf9952012-06-18 12:52:28 -0700449 ObjectAnimator leftOa = LauncherAnimUtils.ofFloat(mLeftHandle, "alpha", 1.0f);
450 ObjectAnimator rightOa = LauncherAnimUtils.ofFloat(mRightHandle, "alpha", 1.0f);
451 ObjectAnimator topOa = LauncherAnimUtils.ofFloat(mTopHandle, "alpha", 1.0f);
452 ObjectAnimator bottomOa = LauncherAnimUtils.ofFloat(mBottomHandle, "alpha", 1.0f);
Adam Cohend4844c32011-02-18 19:25:06 -0800453 oa.addUpdateListener(new AnimatorUpdateListener() {
454 public void onAnimationUpdate(ValueAnimator animation) {
455 requestLayout();
456 }
457 });
Michael Jurka2ecf9952012-06-18 12:52:28 -0700458 AnimatorSet set = LauncherAnimUtils.createAnimatorSet();
Adam Cohend4844c32011-02-18 19:25:06 -0800459 if (mResizeMode == AppWidgetProviderInfo.RESIZE_VERTICAL) {
460 set.playTogether(oa, topOa, bottomOa);
461 } else if (mResizeMode == AppWidgetProviderInfo.RESIZE_HORIZONTAL) {
462 set.playTogether(oa, leftOa, rightOa);
463 } else {
464 set.playTogether(oa, leftOa, rightOa, topOa, bottomOa);
465 }
466
467 set.setDuration(SNAP_DURATION);
468 set.start();
469 }
470 }
471}