blob: eb60054cba938aef699cde7c98f93d11948c50db [file] [log] [blame]
Adam Cohend4844c32011-02-18 19:25:06 -08001package com.android.launcher2;
2
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
16import com.android.launcher.R;
17
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 Cohend4844c32011-02-18 19:25:06 -080061
Adam Cohend4844c32011-02-18 19:25:06 -080062 final int SNAP_DURATION = 150;
Adam Cohen3cba7222011-03-02 19:03:11 -080063 final int BACKGROUND_PADDING = 24;
Adam Cohene4b77292011-03-08 18:35:52 -080064 final float DIMMED_HANDLE_ALPHA = 0f;
65 final float RESIZE_THRESHOLD = 0.66f;
Adam Cohend4844c32011-02-18 19:25:06 -080066
Adam Cohen1b607ed2011-03-03 17:26:50 -080067 public static final int LEFT = 0;
68 public static final int TOP = 1;
69 public static final int RIGHT = 2;
70 public static final int BOTTOM = 3;
71
Adam Cohencbf47e32011-09-16 17:32:37 -070072 private Launcher mLauncher;
73
Michael Jurka3a9fced2012-04-13 14:44:29 -070074 public AppWidgetResizeFrame(Context context,
Adam Cohen67882692011-03-11 15:29:03 -080075 LauncherAppWidgetHostView widgetView, CellLayout cellLayout, DragLayer dragLayer) {
Adam Cohend4844c32011-02-18 19:25:06 -080076
77 super(context);
Adam Cohencbf47e32011-09-16 17:32:37 -070078 mLauncher = (Launcher) context;
Adam Cohend4844c32011-02-18 19:25:06 -080079 mCellLayout = cellLayout;
80 mWidgetView = widgetView;
Adam Cohen27c09b02011-02-28 14:45:11 -080081 mResizeMode = widgetView.getAppWidgetInfo().resizeMode;
Adam Cohen67882692011-03-11 15:29:03 -080082 mDragLayer = dragLayer;
83 mWorkspace = (Workspace) dragLayer.findViewById(R.id.workspace);
Adam Cohen3cba7222011-03-02 19:03:11 -080084
Adam Cohend4844c32011-02-18 19:25:06 -080085 final AppWidgetProviderInfo info = widgetView.getAppWidgetInfo();
Adam Cohen2f093b62012-04-30 18:59:53 -070086 int[] result = Launcher.getMinSpanForWidget(mLauncher, info);
Adam Cohend4844c32011-02-18 19:25:06 -080087 mMinHSpan = result[0];
88 mMinVSpan = result[1];
89
Adam Cohen3cba7222011-03-02 19:03:11 -080090 setBackgroundResource(R.drawable.widget_resize_frame_holo);
Adam Cohend4844c32011-02-18 19:25:06 -080091 setPadding(0, 0, 0, 0);
92
93 LayoutParams lp;
94 mLeftHandle = new ImageView(context);
Adam Cohen3cba7222011-03-02 19:03:11 -080095 mLeftHandle.setImageResource(R.drawable.widget_resize_handle_left);
Adam Cohend4844c32011-02-18 19:25:06 -080096 lp = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT,
97 Gravity.LEFT | Gravity.CENTER_VERTICAL);
98 addView(mLeftHandle, lp);
99
100 mRightHandle = new ImageView(context);
Adam Cohen3cba7222011-03-02 19:03:11 -0800101 mRightHandle.setImageResource(R.drawable.widget_resize_handle_right);
Adam Cohend4844c32011-02-18 19:25:06 -0800102 lp = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT,
103 Gravity.RIGHT | Gravity.CENTER_VERTICAL);
104 addView(mRightHandle, lp);
105
106 mTopHandle = new ImageView(context);
Adam Cohen3cba7222011-03-02 19:03:11 -0800107 mTopHandle.setImageResource(R.drawable.widget_resize_handle_top);
Adam Cohend4844c32011-02-18 19:25:06 -0800108 lp = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT,
109 Gravity.CENTER_HORIZONTAL | Gravity.TOP);
110 addView(mTopHandle, lp);
111
112 mBottomHandle = new ImageView(context);
Adam Cohen3cba7222011-03-02 19:03:11 -0800113 mBottomHandle.setImageResource(R.drawable.widget_resize_handle_bottom);
Adam Cohend4844c32011-02-18 19:25:06 -0800114 lp = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT,
115 Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM);
116 addView(mBottomHandle, lp);
117
Adam Cohen0cf2a7c2011-11-08 15:07:01 -0800118 Rect p = AppWidgetHostView.getDefaultPaddingForWidget(context,
119 widgetView.getAppWidgetInfo().provider, null);
Adam Cohen82ebbd22011-09-30 15:05:40 -0700120 mWidgetPaddingLeft = p.left;
121 mWidgetPaddingTop = p.top;
122 mWidgetPaddingRight = p.right;
123 mWidgetPaddingBottom = p.bottom;
Adam Cohen37b59ff2011-06-13 17:13:42 -0700124
Adam Cohend4844c32011-02-18 19:25:06 -0800125 if (mResizeMode == AppWidgetProviderInfo.RESIZE_HORIZONTAL) {
126 mTopHandle.setVisibility(GONE);
127 mBottomHandle.setVisibility(GONE);
128 } else if (mResizeMode == AppWidgetProviderInfo.RESIZE_VERTICAL) {
129 mLeftHandle.setVisibility(GONE);
130 mRightHandle.setVisibility(GONE);
Adam Cohen3cba7222011-03-02 19:03:11 -0800131 }
132
Adam Cohencbf47e32011-09-16 17:32:37 -0700133 final float density = mLauncher.getResources().getDisplayMetrics().density;
Adam Cohen3cba7222011-03-02 19:03:11 -0800134 mBackgroundPadding = (int) Math.ceil(density * BACKGROUND_PADDING);
135 mTouchTargetWidth = 2 * mBackgroundPadding;
Adam Cohenbebf0422012-04-11 18:06:28 -0700136
137 // When we create the resize frame, we first mark all cells as unoccupied. The appropriate
138 // cells (same if not resized, or different) will be marked as occupied when the resize
139 // frame is dismissed.
140 mCellLayout.markCellsAsUnoccupiedForView(mWidgetView);
Adam Cohend4844c32011-02-18 19:25:06 -0800141 }
142
143 public boolean beginResizeIfPointInRegion(int x, int y) {
144 boolean horizontalActive = (mResizeMode & AppWidgetProviderInfo.RESIZE_HORIZONTAL) != 0;
145 boolean verticalActive = (mResizeMode & AppWidgetProviderInfo.RESIZE_VERTICAL) != 0;
Adam Cohen4459d6b2012-07-13 15:59:15 -0700146
Adam Cohen3cba7222011-03-02 19:03:11 -0800147 mLeftBorderActive = (x < mTouchTargetWidth) && horizontalActive;
148 mRightBorderActive = (x > getWidth() - mTouchTargetWidth) && horizontalActive;
Adam Cohen4459d6b2012-07-13 15:59:15 -0700149 mTopBorderActive = (y < mTouchTargetWidth + mTopTouchRegionAdjustment) && verticalActive;
150 mBottomBorderActive = (y > getHeight() - mTouchTargetWidth + mBottomTouchRegionAdjustment)
151 && verticalActive;
Adam Cohend4844c32011-02-18 19:25:06 -0800152
153 boolean anyBordersActive = mLeftBorderActive || mRightBorderActive
154 || mTopBorderActive || mBottomBorderActive;
155
156 mBaselineWidth = getMeasuredWidth();
157 mBaselineHeight = getMeasuredHeight();
158 mBaselineX = getLeft();
159 mBaselineY = getTop();
Adam Cohend4844c32011-02-18 19:25:06 -0800160
161 if (anyBordersActive) {
Adam Cohen3cba7222011-03-02 19:03:11 -0800162 mLeftHandle.setAlpha(mLeftBorderActive ? 1.0f : DIMMED_HANDLE_ALPHA);
163 mRightHandle.setAlpha(mRightBorderActive ? 1.0f :DIMMED_HANDLE_ALPHA);
164 mTopHandle.setAlpha(mTopBorderActive ? 1.0f : DIMMED_HANDLE_ALPHA);
165 mBottomHandle.setAlpha(mBottomBorderActive ? 1.0f : DIMMED_HANDLE_ALPHA);
Adam Cohend4844c32011-02-18 19:25:06 -0800166 }
Adam Cohend4844c32011-02-18 19:25:06 -0800167 return anyBordersActive;
168 }
169
Adam Cohen1b607ed2011-03-03 17:26:50 -0800170 /**
171 * Here we bound the deltas such that the frame cannot be stretched beyond the extents
172 * of the CellLayout, and such that the frame's borders can't cross.
173 */
Adam Cohend4844c32011-02-18 19:25:06 -0800174 public void updateDeltas(int deltaX, int deltaY) {
175 if (mLeftBorderActive) {
176 mDeltaX = Math.max(-mBaselineX, deltaX);
Adam Cohen3cba7222011-03-02 19:03:11 -0800177 mDeltaX = Math.min(mBaselineWidth - 2 * mTouchTargetWidth, mDeltaX);
Adam Cohend4844c32011-02-18 19:25:06 -0800178 } else if (mRightBorderActive) {
Adam Cohen67882692011-03-11 15:29:03 -0800179 mDeltaX = Math.min(mDragLayer.getWidth() - (mBaselineX + mBaselineWidth), deltaX);
Adam Cohen3cba7222011-03-02 19:03:11 -0800180 mDeltaX = Math.max(-mBaselineWidth + 2 * mTouchTargetWidth, mDeltaX);
Adam Cohend4844c32011-02-18 19:25:06 -0800181 }
182
183 if (mTopBorderActive) {
184 mDeltaY = Math.max(-mBaselineY, deltaY);
Adam Cohen3cba7222011-03-02 19:03:11 -0800185 mDeltaY = Math.min(mBaselineHeight - 2 * mTouchTargetWidth, mDeltaY);
Adam Cohend4844c32011-02-18 19:25:06 -0800186 } else if (mBottomBorderActive) {
Adam Cohen67882692011-03-11 15:29:03 -0800187 mDeltaY = Math.min(mDragLayer.getHeight() - (mBaselineY + mBaselineHeight), deltaY);
Adam Cohen3cba7222011-03-02 19:03:11 -0800188 mDeltaY = Math.max(-mBaselineHeight + 2 * mTouchTargetWidth, mDeltaY);
Adam Cohend4844c32011-02-18 19:25:06 -0800189 }
190 }
191
Adam Cohenbebf0422012-04-11 18:06:28 -0700192 public void visualizeResizeForDelta(int deltaX, int deltaY) {
193 visualizeResizeForDelta(deltaX, deltaY, false);
194 }
195
Adam Cohen1b607ed2011-03-03 17:26:50 -0800196 /**
197 * Based on the deltas, we resize the frame, and, if needed, we resize the widget.
198 */
Adam Cohenbebf0422012-04-11 18:06:28 -0700199 private void visualizeResizeForDelta(int deltaX, int deltaY, boolean onDismiss) {
Adam Cohend4844c32011-02-18 19:25:06 -0800200 updateDeltas(deltaX, deltaY);
Adam Cohen67882692011-03-11 15:29:03 -0800201 DragLayer.LayoutParams lp = (DragLayer.LayoutParams) getLayoutParams();
202
Adam Cohend4844c32011-02-18 19:25:06 -0800203 if (mLeftBorderActive) {
204 lp.x = mBaselineX + mDeltaX;
205 lp.width = mBaselineWidth - mDeltaX;
206 } else if (mRightBorderActive) {
207 lp.width = mBaselineWidth + mDeltaX;
208 }
209
210 if (mTopBorderActive) {
211 lp.y = mBaselineY + mDeltaY;
212 lp.height = mBaselineHeight - mDeltaY;
213 } else if (mBottomBorderActive) {
214 lp.height = mBaselineHeight + mDeltaY;
215 }
216
Adam Cohenbebf0422012-04-11 18:06:28 -0700217 resizeWidgetIfNeeded(onDismiss);
Adam Cohend4844c32011-02-18 19:25:06 -0800218 requestLayout();
219 }
220
Adam Cohen1b607ed2011-03-03 17:26:50 -0800221 /**
222 * Based on the current deltas, we determine if and how to resize the widget.
223 */
Adam Cohenbebf0422012-04-11 18:06:28 -0700224 private void resizeWidgetIfNeeded(boolean onDismiss) {
Adam Cohend4844c32011-02-18 19:25:06 -0800225 int xThreshold = mCellLayout.getCellWidth() + mCellLayout.getWidthGap();
226 int yThreshold = mCellLayout.getCellHeight() + mCellLayout.getHeightGap();
227
Adam Cohenbebf0422012-04-11 18:06:28 -0700228 int deltaX = mDeltaX + mDeltaXAddOn;
229 int deltaY = mDeltaY + mDeltaYAddOn;
230
231 float hSpanIncF = 1.0f * deltaX / xThreshold - mRunningHInc;
232 float vSpanIncF = 1.0f * deltaY / yThreshold - mRunningVInc;
Adam Cohene4b77292011-03-08 18:35:52 -0800233
234 int hSpanInc = 0;
235 int vSpanInc = 0;
Adam Cohend4844c32011-02-18 19:25:06 -0800236 int cellXInc = 0;
237 int cellYInc = 0;
238
Adam Cohenbebf0422012-04-11 18:06:28 -0700239 int countX = mCellLayout.getCountX();
240 int countY = mCellLayout.getCountY();
241
Adam Cohene4b77292011-03-08 18:35:52 -0800242 if (Math.abs(hSpanIncF) > RESIZE_THRESHOLD) {
243 hSpanInc = Math.round(hSpanIncF);
244 }
245 if (Math.abs(vSpanIncF) > RESIZE_THRESHOLD) {
246 vSpanInc = Math.round(vSpanIncF);
247 }
248
Adam Cohenbebf0422012-04-11 18:06:28 -0700249 if (!onDismiss && (hSpanInc == 0 && vSpanInc == 0)) return;
Adam Cohend4844c32011-02-18 19:25:06 -0800250
Adam Cohend4844c32011-02-18 19:25:06 -0800251
252 CellLayout.LayoutParams lp = (CellLayout.LayoutParams) mWidgetView.getLayoutParams();
Adam Cohen1b607ed2011-03-03 17:26:50 -0800253
Adam Cohenbebf0422012-04-11 18:06:28 -0700254 int spanX = lp.cellHSpan;
255 int spanY = lp.cellVSpan;
256 int cellX = lp.useTmpCoords ? lp.tmpCellX : lp.cellX;
257 int cellY = lp.useTmpCoords ? lp.tmpCellY : lp.cellY;
258
259 int hSpanDelta = 0;
260 int vSpanDelta = 0;
261
Adam Cohen1b607ed2011-03-03 17:26:50 -0800262 // For each border, we bound the resizing based on the minimum width, and the maximum
263 // expandability.
Adam Cohend4844c32011-02-18 19:25:06 -0800264 if (mLeftBorderActive) {
Adam Cohenbebf0422012-04-11 18:06:28 -0700265 cellXInc = Math.max(-cellX, hSpanInc);
Adam Cohend4844c32011-02-18 19:25:06 -0800266 cellXInc = Math.min(lp.cellHSpan - mMinHSpan, cellXInc);
267 hSpanInc *= -1;
Adam Cohenbebf0422012-04-11 18:06:28 -0700268 hSpanInc = Math.min(cellX, hSpanInc);
Adam Cohend4844c32011-02-18 19:25:06 -0800269 hSpanInc = Math.max(-(lp.cellHSpan - mMinHSpan), hSpanInc);
Adam Cohenbebf0422012-04-11 18:06:28 -0700270 hSpanDelta = -hSpanInc;
271
Adam Cohend4844c32011-02-18 19:25:06 -0800272 } else if (mRightBorderActive) {
Adam Cohenbebf0422012-04-11 18:06:28 -0700273 hSpanInc = Math.min(countX - (cellX + spanX), hSpanInc);
Adam Cohend4844c32011-02-18 19:25:06 -0800274 hSpanInc = Math.max(-(lp.cellHSpan - mMinHSpan), hSpanInc);
Adam Cohenbebf0422012-04-11 18:06:28 -0700275 hSpanDelta = hSpanInc;
Adam Cohend4844c32011-02-18 19:25:06 -0800276 }
277
278 if (mTopBorderActive) {
Adam Cohenbebf0422012-04-11 18:06:28 -0700279 cellYInc = Math.max(-cellY, vSpanInc);
Adam Cohend4844c32011-02-18 19:25:06 -0800280 cellYInc = Math.min(lp.cellVSpan - mMinVSpan, cellYInc);
281 vSpanInc *= -1;
Adam Cohenbebf0422012-04-11 18:06:28 -0700282 vSpanInc = Math.min(cellY, vSpanInc);
Adam Cohend4844c32011-02-18 19:25:06 -0800283 vSpanInc = Math.max(-(lp.cellVSpan - mMinVSpan), vSpanInc);
Adam Cohenbebf0422012-04-11 18:06:28 -0700284 vSpanDelta = -vSpanInc;
Adam Cohend4844c32011-02-18 19:25:06 -0800285 } else if (mBottomBorderActive) {
Adam Cohenbebf0422012-04-11 18:06:28 -0700286 vSpanInc = Math.min(countY - (cellY + spanY), vSpanInc);
Adam Cohend4844c32011-02-18 19:25:06 -0800287 vSpanInc = Math.max(-(lp.cellVSpan - mMinVSpan), vSpanInc);
Adam Cohenbebf0422012-04-11 18:06:28 -0700288 vSpanDelta = vSpanInc;
Adam Cohend4844c32011-02-18 19:25:06 -0800289 }
290
Adam Cohenbebf0422012-04-11 18:06:28 -0700291 mDirectionVector[0] = 0;
292 mDirectionVector[1] = 0;
Adam Cohend4844c32011-02-18 19:25:06 -0800293 // Update the widget's dimensions and position according to the deltas computed above
294 if (mLeftBorderActive || mRightBorderActive) {
Adam Cohenbebf0422012-04-11 18:06:28 -0700295 spanX += hSpanInc;
296 cellX += cellXInc;
Adam Cohene0489502012-08-27 15:18:53 -0700297 if (hSpanDelta != 0) {
298 mDirectionVector[0] = mLeftBorderActive ? -1 : 1;
299 }
Adam Cohend4844c32011-02-18 19:25:06 -0800300 }
301
302 if (mTopBorderActive || mBottomBorderActive) {
Adam Cohenbebf0422012-04-11 18:06:28 -0700303 spanY += vSpanInc;
304 cellY += cellYInc;
Adam Cohene0489502012-08-27 15:18:53 -0700305 if (vSpanDelta != 0) {
306 mDirectionVector[1] = mTopBorderActive ? -1 : 1;
307 }
Adam Cohend4844c32011-02-18 19:25:06 -0800308 }
309
Adam Cohenbebf0422012-04-11 18:06:28 -0700310 if (!onDismiss && vSpanDelta == 0 && hSpanDelta == 0) return;
Adam Cohend4844c32011-02-18 19:25:06 -0800311
Adam Cohene0489502012-08-27 15:18:53 -0700312 // We always want the final commit to match the feedback, so we make sure to use the
313 // last used direction vector when committing the resize / reorder.
314 if (onDismiss) {
315 mDirectionVector[0] = mLastDirectionVector[0];
316 mDirectionVector[1] = mLastDirectionVector[1];
317 } else {
318 mLastDirectionVector[0] = mDirectionVector[0];
319 mLastDirectionVector[1] = mDirectionVector[1];
320 }
321
Adam Cohenbebf0422012-04-11 18:06:28 -0700322 if (mCellLayout.createAreaForResize(cellX, cellY, spanX, spanY, mWidgetView,
323 mDirectionVector, onDismiss)) {
324 lp.tmpCellX = cellX;
325 lp.tmpCellY = cellY;
326 lp.cellHSpan = spanX;
327 lp.cellVSpan = spanY;
328 mRunningVInc += vSpanDelta;
329 mRunningHInc += hSpanDelta;
Adam Cohena897f392012-04-27 18:12:05 -0700330 if (!onDismiss) {
331 updateWidgetSizeRanges(mWidgetView, mLauncher, spanX, spanY);
332 }
Adam Cohenbebf0422012-04-11 18:06:28 -0700333 }
Adam Cohen67882692011-03-11 15:29:03 -0800334 mWidgetView.requestLayout();
Adam Cohend4844c32011-02-18 19:25:06 -0800335 }
336
Adam Cohena897f392012-04-27 18:12:05 -0700337 static void updateWidgetSizeRanges(AppWidgetHostView widgetView, Launcher launcher,
338 int spanX, int spanY) {
339 Rect landMetrics = Workspace.getCellLayoutMetrics(launcher, CellLayout.LANDSCAPE);
340 Rect portMetrics = Workspace.getCellLayoutMetrics(launcher, CellLayout.PORTRAIT);
341 final float density = launcher.getResources().getDisplayMetrics().density;
342
343 // Compute landscape size
344 int cellWidth = landMetrics.left;
345 int cellHeight = landMetrics.top;
346 int widthGap = landMetrics.right;
347 int heightGap = landMetrics.bottom;
348 int landWidth = (int) ((spanX * cellWidth + (spanX - 1) * widthGap) / density);
349 int landHeight = (int) ((spanY * cellHeight + (spanY - 1) * heightGap) / density);
350
351 // Compute portrait size
352 cellWidth = portMetrics.left;
353 cellHeight = portMetrics.top;
354 widthGap = portMetrics.right;
355 heightGap = portMetrics.bottom;
356 int portWidth = (int) ((spanX * cellWidth + (spanX - 1) * widthGap) / density);
357 int portHeight = (int) ((spanY * cellHeight + (spanY - 1) * heightGap) / density);
358
359 widgetView.updateAppWidgetSize(null, portWidth, landHeight, landWidth, portHeight);
360 }
361
Adam Cohen1b607ed2011-03-03 17:26:50 -0800362 /**
363 * This is the final step of the resize. Here we save the new widget size and position
364 * to LauncherModel and animate the resize frame.
365 */
Adam Cohenbebf0422012-04-11 18:06:28 -0700366 public void commitResize() {
367 resizeWidgetIfNeeded(true);
368 requestLayout();
369 }
Adam Cohend4844c32011-02-18 19:25:06 -0800370
Adam Cohenbebf0422012-04-11 18:06:28 -0700371 public void onTouchUp() {
372 int xThreshold = mCellLayout.getCellWidth() + mCellLayout.getWidthGap();
373 int yThreshold = mCellLayout.getCellHeight() + mCellLayout.getHeightGap();
Adam Cohend4844c32011-02-18 19:25:06 -0800374
Adam Cohenbebf0422012-04-11 18:06:28 -0700375 mDeltaXAddOn = mRunningHInc * xThreshold;
376 mDeltaYAddOn = mRunningVInc * yThreshold;
377 mDeltaX = 0;
378 mDeltaY = 0;
379
Adam Cohend4844c32011-02-18 19:25:06 -0800380 post(new Runnable() {
Adam Cohenbebf0422012-04-11 18:06:28 -0700381 @Override
Adam Cohend4844c32011-02-18 19:25:06 -0800382 public void run() {
383 snapToWidget(true);
384 }
385 });
386 }
387
388 public void snapToWidget(boolean animate) {
Adam Cohen67882692011-03-11 15:29:03 -0800389 final DragLayer.LayoutParams lp = (DragLayer.LayoutParams) getLayoutParams();
Winson Chung4b825dcd2011-06-19 12:41:22 -0700390 int xOffset = mCellLayout.getLeft() + mCellLayout.getPaddingLeft() - mWorkspace.getScrollX();
391 int yOffset = mCellLayout.getTop() + mCellLayout.getPaddingTop() - mWorkspace.getScrollY();
Adam Cohend4844c32011-02-18 19:25:06 -0800392
Adam Cohen37b59ff2011-06-13 17:13:42 -0700393 int newWidth = mWidgetView.getWidth() + 2 * mBackgroundPadding - mWidgetPaddingLeft -
394 mWidgetPaddingRight;
395 int newHeight = mWidgetView.getHeight() + 2 * mBackgroundPadding - mWidgetPaddingTop -
396 mWidgetPaddingBottom;
397
398 int newX = mWidgetView.getLeft() - mBackgroundPadding + xOffset + mWidgetPaddingLeft;
399 int newY = mWidgetView.getTop() - mBackgroundPadding + yOffset + mWidgetPaddingTop;
Adam Cohen3cba7222011-03-02 19:03:11 -0800400
Adam Cohen4459d6b2012-07-13 15:59:15 -0700401 // We need to make sure the frame's touchable regions lie fully within the bounds of the
402 // DragLayer. We allow the actual handles to be clipped, but we shift the touch regions
403 // down accordingly to provide a proper touch target.
Adam Cohen3cba7222011-03-02 19:03:11 -0800404 if (newY < 0) {
Adam Cohen4459d6b2012-07-13 15:59:15 -0700405 // In this case we shift the touch region down to start at the top of the DragLayer
406 mTopTouchRegionAdjustment = -newY;
407 } else {
408 mTopTouchRegionAdjustment = 0;
Adam Cohen3cba7222011-03-02 19:03:11 -0800409 }
Adam Cohen67882692011-03-11 15:29:03 -0800410 if (newY + newHeight > mDragLayer.getHeight()) {
Adam Cohen4459d6b2012-07-13 15:59:15 -0700411 // In this case we shift the touch region up to end at the bottom of the DragLayer
412 mBottomTouchRegionAdjustment = -(newY + newHeight - mDragLayer.getHeight());
413 } else {
414 mBottomTouchRegionAdjustment = 0;
Adam Cohen3cba7222011-03-02 19:03:11 -0800415 }
416
Adam Cohend4844c32011-02-18 19:25:06 -0800417 if (!animate) {
418 lp.width = newWidth;
419 lp.height = newHeight;
420 lp.x = newX;
421 lp.y = newY;
422 mLeftHandle.setAlpha(1.0f);
423 mRightHandle.setAlpha(1.0f);
424 mTopHandle.setAlpha(1.0f);
425 mBottomHandle.setAlpha(1.0f);
426 requestLayout();
427 } else {
428 PropertyValuesHolder width = PropertyValuesHolder.ofInt("width", lp.width, newWidth);
Adam Cohen1b607ed2011-03-03 17:26:50 -0800429 PropertyValuesHolder height = PropertyValuesHolder.ofInt("height", lp.height,
430 newHeight);
Adam Cohend4844c32011-02-18 19:25:06 -0800431 PropertyValuesHolder x = PropertyValuesHolder.ofInt("x", lp.x, newX);
432 PropertyValuesHolder y = PropertyValuesHolder.ofInt("y", lp.y, newY);
Michael Jurka2ecf9952012-06-18 12:52:28 -0700433 ObjectAnimator oa = LauncherAnimUtils.ofPropertyValuesHolder(lp, width, height, x, y);
434 ObjectAnimator leftOa = LauncherAnimUtils.ofFloat(mLeftHandle, "alpha", 1.0f);
435 ObjectAnimator rightOa = LauncherAnimUtils.ofFloat(mRightHandle, "alpha", 1.0f);
436 ObjectAnimator topOa = LauncherAnimUtils.ofFloat(mTopHandle, "alpha", 1.0f);
437 ObjectAnimator bottomOa = LauncherAnimUtils.ofFloat(mBottomHandle, "alpha", 1.0f);
Adam Cohend4844c32011-02-18 19:25:06 -0800438 oa.addUpdateListener(new AnimatorUpdateListener() {
439 public void onAnimationUpdate(ValueAnimator animation) {
440 requestLayout();
441 }
442 });
Michael Jurka2ecf9952012-06-18 12:52:28 -0700443 AnimatorSet set = LauncherAnimUtils.createAnimatorSet();
Adam Cohend4844c32011-02-18 19:25:06 -0800444 if (mResizeMode == AppWidgetProviderInfo.RESIZE_VERTICAL) {
445 set.playTogether(oa, topOa, bottomOa);
446 } else if (mResizeMode == AppWidgetProviderInfo.RESIZE_HORIZONTAL) {
447 set.playTogether(oa, leftOa, rightOa);
448 } else {
449 set.playTogether(oa, leftOa, rightOa, topOa, bottomOa);
450 }
451
452 set.setDuration(SNAP_DURATION);
453 set.start();
454 }
455 }
456}