blob: 2070eb638038bd44c7dc3ea4a1f98ba2ae9b9074 [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 Cohend4844c32011-02-18 19:25:06 -080060
Adam Cohend4844c32011-02-18 19:25:06 -080061 final int SNAP_DURATION = 150;
Adam Cohen3cba7222011-03-02 19:03:11 -080062 final int BACKGROUND_PADDING = 24;
Adam Cohene4b77292011-03-08 18:35:52 -080063 final float DIMMED_HANDLE_ALPHA = 0f;
64 final float RESIZE_THRESHOLD = 0.66f;
Adam Cohend4844c32011-02-18 19:25:06 -080065
Adam Cohen1b607ed2011-03-03 17:26:50 -080066 public static final int LEFT = 0;
67 public static final int TOP = 1;
68 public static final int RIGHT = 2;
69 public static final int BOTTOM = 3;
70
Adam Cohencbf47e32011-09-16 17:32:37 -070071 private Launcher mLauncher;
72
Michael Jurka3a9fced2012-04-13 14:44:29 -070073 public AppWidgetResizeFrame(Context context,
Adam Cohen67882692011-03-11 15:29:03 -080074 LauncherAppWidgetHostView widgetView, CellLayout cellLayout, DragLayer dragLayer) {
Adam Cohend4844c32011-02-18 19:25:06 -080075
76 super(context);
Adam Cohencbf47e32011-09-16 17:32:37 -070077 mLauncher = (Launcher) context;
Adam Cohend4844c32011-02-18 19:25:06 -080078 mCellLayout = cellLayout;
79 mWidgetView = widgetView;
Adam Cohen27c09b02011-02-28 14:45:11 -080080 mResizeMode = widgetView.getAppWidgetInfo().resizeMode;
Adam Cohen67882692011-03-11 15:29:03 -080081 mDragLayer = dragLayer;
82 mWorkspace = (Workspace) dragLayer.findViewById(R.id.workspace);
Adam Cohen3cba7222011-03-02 19:03:11 -080083
Adam Cohend4844c32011-02-18 19:25:06 -080084 final AppWidgetProviderInfo info = widgetView.getAppWidgetInfo();
Adam Cohen2f093b62012-04-30 18:59:53 -070085 int[] result = Launcher.getMinSpanForWidget(mLauncher, info);
Adam Cohend4844c32011-02-18 19:25:06 -080086 mMinHSpan = result[0];
87 mMinVSpan = result[1];
88
Adam Cohen3cba7222011-03-02 19:03:11 -080089 setBackgroundResource(R.drawable.widget_resize_frame_holo);
Adam Cohend4844c32011-02-18 19:25:06 -080090 setPadding(0, 0, 0, 0);
91
92 LayoutParams lp;
93 mLeftHandle = new ImageView(context);
Adam Cohen3cba7222011-03-02 19:03:11 -080094 mLeftHandle.setImageResource(R.drawable.widget_resize_handle_left);
Adam Cohend4844c32011-02-18 19:25:06 -080095 lp = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT,
96 Gravity.LEFT | Gravity.CENTER_VERTICAL);
97 addView(mLeftHandle, lp);
98
99 mRightHandle = new ImageView(context);
Adam Cohen3cba7222011-03-02 19:03:11 -0800100 mRightHandle.setImageResource(R.drawable.widget_resize_handle_right);
Adam Cohend4844c32011-02-18 19:25:06 -0800101 lp = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT,
102 Gravity.RIGHT | Gravity.CENTER_VERTICAL);
103 addView(mRightHandle, lp);
104
105 mTopHandle = new ImageView(context);
Adam Cohen3cba7222011-03-02 19:03:11 -0800106 mTopHandle.setImageResource(R.drawable.widget_resize_handle_top);
Adam Cohend4844c32011-02-18 19:25:06 -0800107 lp = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT,
108 Gravity.CENTER_HORIZONTAL | Gravity.TOP);
109 addView(mTopHandle, lp);
110
111 mBottomHandle = new ImageView(context);
Adam Cohen3cba7222011-03-02 19:03:11 -0800112 mBottomHandle.setImageResource(R.drawable.widget_resize_handle_bottom);
Adam Cohend4844c32011-02-18 19:25:06 -0800113 lp = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT,
114 Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM);
115 addView(mBottomHandle, lp);
116
Adam Cohen0cf2a7c2011-11-08 15:07:01 -0800117 Rect p = AppWidgetHostView.getDefaultPaddingForWidget(context,
118 widgetView.getAppWidgetInfo().provider, null);
Adam Cohen82ebbd22011-09-30 15:05:40 -0700119 mWidgetPaddingLeft = p.left;
120 mWidgetPaddingTop = p.top;
121 mWidgetPaddingRight = p.right;
122 mWidgetPaddingBottom = p.bottom;
Adam Cohen37b59ff2011-06-13 17:13:42 -0700123
Adam Cohend4844c32011-02-18 19:25:06 -0800124 if (mResizeMode == AppWidgetProviderInfo.RESIZE_HORIZONTAL) {
125 mTopHandle.setVisibility(GONE);
126 mBottomHandle.setVisibility(GONE);
127 } else if (mResizeMode == AppWidgetProviderInfo.RESIZE_VERTICAL) {
128 mLeftHandle.setVisibility(GONE);
129 mRightHandle.setVisibility(GONE);
Adam Cohen3cba7222011-03-02 19:03:11 -0800130 }
131
Adam Cohencbf47e32011-09-16 17:32:37 -0700132 final float density = mLauncher.getResources().getDisplayMetrics().density;
Adam Cohen3cba7222011-03-02 19:03:11 -0800133 mBackgroundPadding = (int) Math.ceil(density * BACKGROUND_PADDING);
134 mTouchTargetWidth = 2 * mBackgroundPadding;
Adam Cohenbebf0422012-04-11 18:06:28 -0700135
136 // When we create the resize frame, we first mark all cells as unoccupied. The appropriate
137 // cells (same if not resized, or different) will be marked as occupied when the resize
138 // frame is dismissed.
139 mCellLayout.markCellsAsUnoccupiedForView(mWidgetView);
Adam Cohend4844c32011-02-18 19:25:06 -0800140 }
141
142 public boolean beginResizeIfPointInRegion(int x, int y) {
143 boolean horizontalActive = (mResizeMode & AppWidgetProviderInfo.RESIZE_HORIZONTAL) != 0;
144 boolean verticalActive = (mResizeMode & AppWidgetProviderInfo.RESIZE_VERTICAL) != 0;
Adam Cohen4459d6b2012-07-13 15:59:15 -0700145
Adam Cohen3cba7222011-03-02 19:03:11 -0800146 mLeftBorderActive = (x < mTouchTargetWidth) && horizontalActive;
147 mRightBorderActive = (x > getWidth() - mTouchTargetWidth) && horizontalActive;
Adam Cohen4459d6b2012-07-13 15:59:15 -0700148 mTopBorderActive = (y < mTouchTargetWidth + mTopTouchRegionAdjustment) && verticalActive;
149 mBottomBorderActive = (y > getHeight() - mTouchTargetWidth + mBottomTouchRegionAdjustment)
150 && verticalActive;
Adam Cohend4844c32011-02-18 19:25:06 -0800151
152 boolean anyBordersActive = mLeftBorderActive || mRightBorderActive
153 || mTopBorderActive || mBottomBorderActive;
154
155 mBaselineWidth = getMeasuredWidth();
156 mBaselineHeight = getMeasuredHeight();
157 mBaselineX = getLeft();
158 mBaselineY = getTop();
Adam Cohend4844c32011-02-18 19:25:06 -0800159
160 if (anyBordersActive) {
Adam Cohen3cba7222011-03-02 19:03:11 -0800161 mLeftHandle.setAlpha(mLeftBorderActive ? 1.0f : DIMMED_HANDLE_ALPHA);
162 mRightHandle.setAlpha(mRightBorderActive ? 1.0f :DIMMED_HANDLE_ALPHA);
163 mTopHandle.setAlpha(mTopBorderActive ? 1.0f : DIMMED_HANDLE_ALPHA);
164 mBottomHandle.setAlpha(mBottomBorderActive ? 1.0f : DIMMED_HANDLE_ALPHA);
Adam Cohend4844c32011-02-18 19:25:06 -0800165 }
Adam Cohend4844c32011-02-18 19:25:06 -0800166 return anyBordersActive;
167 }
168
Adam Cohen1b607ed2011-03-03 17:26:50 -0800169 /**
170 * Here we bound the deltas such that the frame cannot be stretched beyond the extents
171 * of the CellLayout, and such that the frame's borders can't cross.
172 */
Adam Cohend4844c32011-02-18 19:25:06 -0800173 public void updateDeltas(int deltaX, int deltaY) {
174 if (mLeftBorderActive) {
175 mDeltaX = Math.max(-mBaselineX, deltaX);
Adam Cohen3cba7222011-03-02 19:03:11 -0800176 mDeltaX = Math.min(mBaselineWidth - 2 * mTouchTargetWidth, mDeltaX);
Adam Cohend4844c32011-02-18 19:25:06 -0800177 } else if (mRightBorderActive) {
Adam Cohen67882692011-03-11 15:29:03 -0800178 mDeltaX = Math.min(mDragLayer.getWidth() - (mBaselineX + mBaselineWidth), deltaX);
Adam Cohen3cba7222011-03-02 19:03:11 -0800179 mDeltaX = Math.max(-mBaselineWidth + 2 * mTouchTargetWidth, mDeltaX);
Adam Cohend4844c32011-02-18 19:25:06 -0800180 }
181
182 if (mTopBorderActive) {
183 mDeltaY = Math.max(-mBaselineY, deltaY);
Adam Cohen3cba7222011-03-02 19:03:11 -0800184 mDeltaY = Math.min(mBaselineHeight - 2 * mTouchTargetWidth, mDeltaY);
Adam Cohend4844c32011-02-18 19:25:06 -0800185 } else if (mBottomBorderActive) {
Adam Cohen67882692011-03-11 15:29:03 -0800186 mDeltaY = Math.min(mDragLayer.getHeight() - (mBaselineY + mBaselineHeight), deltaY);
Adam Cohen3cba7222011-03-02 19:03:11 -0800187 mDeltaY = Math.max(-mBaselineHeight + 2 * mTouchTargetWidth, mDeltaY);
Adam Cohend4844c32011-02-18 19:25:06 -0800188 }
189 }
190
Adam Cohenbebf0422012-04-11 18:06:28 -0700191 public void visualizeResizeForDelta(int deltaX, int deltaY) {
192 visualizeResizeForDelta(deltaX, deltaY, false);
193 }
194
Adam Cohen1b607ed2011-03-03 17:26:50 -0800195 /**
196 * Based on the deltas, we resize the frame, and, if needed, we resize the widget.
197 */
Adam Cohenbebf0422012-04-11 18:06:28 -0700198 private void visualizeResizeForDelta(int deltaX, int deltaY, boolean onDismiss) {
Adam Cohend4844c32011-02-18 19:25:06 -0800199 updateDeltas(deltaX, deltaY);
Adam Cohen67882692011-03-11 15:29:03 -0800200 DragLayer.LayoutParams lp = (DragLayer.LayoutParams) getLayoutParams();
201
Adam Cohend4844c32011-02-18 19:25:06 -0800202 if (mLeftBorderActive) {
203 lp.x = mBaselineX + mDeltaX;
204 lp.width = mBaselineWidth - mDeltaX;
205 } else if (mRightBorderActive) {
206 lp.width = mBaselineWidth + mDeltaX;
207 }
208
209 if (mTopBorderActive) {
210 lp.y = mBaselineY + mDeltaY;
211 lp.height = mBaselineHeight - mDeltaY;
212 } else if (mBottomBorderActive) {
213 lp.height = mBaselineHeight + mDeltaY;
214 }
215
Adam Cohenbebf0422012-04-11 18:06:28 -0700216 resizeWidgetIfNeeded(onDismiss);
Adam Cohend4844c32011-02-18 19:25:06 -0800217 requestLayout();
218 }
219
Adam Cohen1b607ed2011-03-03 17:26:50 -0800220 /**
221 * Based on the current deltas, we determine if and how to resize the widget.
222 */
Adam Cohenbebf0422012-04-11 18:06:28 -0700223 private void resizeWidgetIfNeeded(boolean onDismiss) {
Adam Cohend4844c32011-02-18 19:25:06 -0800224 int xThreshold = mCellLayout.getCellWidth() + mCellLayout.getWidthGap();
225 int yThreshold = mCellLayout.getCellHeight() + mCellLayout.getHeightGap();
226
Adam Cohenbebf0422012-04-11 18:06:28 -0700227 int deltaX = mDeltaX + mDeltaXAddOn;
228 int deltaY = mDeltaY + mDeltaYAddOn;
229
230 float hSpanIncF = 1.0f * deltaX / xThreshold - mRunningHInc;
231 float vSpanIncF = 1.0f * deltaY / yThreshold - mRunningVInc;
Adam Cohene4b77292011-03-08 18:35:52 -0800232
233 int hSpanInc = 0;
234 int vSpanInc = 0;
Adam Cohend4844c32011-02-18 19:25:06 -0800235 int cellXInc = 0;
236 int cellYInc = 0;
237
Adam Cohenbebf0422012-04-11 18:06:28 -0700238 int countX = mCellLayout.getCountX();
239 int countY = mCellLayout.getCountY();
240
Adam Cohene4b77292011-03-08 18:35:52 -0800241 if (Math.abs(hSpanIncF) > RESIZE_THRESHOLD) {
242 hSpanInc = Math.round(hSpanIncF);
243 }
244 if (Math.abs(vSpanIncF) > RESIZE_THRESHOLD) {
245 vSpanInc = Math.round(vSpanIncF);
246 }
247
Adam Cohenbebf0422012-04-11 18:06:28 -0700248 if (!onDismiss && (hSpanInc == 0 && vSpanInc == 0)) return;
Adam Cohend4844c32011-02-18 19:25:06 -0800249
Adam Cohend4844c32011-02-18 19:25:06 -0800250
251 CellLayout.LayoutParams lp = (CellLayout.LayoutParams) mWidgetView.getLayoutParams();
Adam Cohen1b607ed2011-03-03 17:26:50 -0800252
Adam Cohenbebf0422012-04-11 18:06:28 -0700253 int spanX = lp.cellHSpan;
254 int spanY = lp.cellVSpan;
255 int cellX = lp.useTmpCoords ? lp.tmpCellX : lp.cellX;
256 int cellY = lp.useTmpCoords ? lp.tmpCellY : lp.cellY;
257
258 int hSpanDelta = 0;
259 int vSpanDelta = 0;
260
Adam Cohen1b607ed2011-03-03 17:26:50 -0800261 // For each border, we bound the resizing based on the minimum width, and the maximum
262 // expandability.
Adam Cohend4844c32011-02-18 19:25:06 -0800263 if (mLeftBorderActive) {
Adam Cohenbebf0422012-04-11 18:06:28 -0700264 cellXInc = Math.max(-cellX, hSpanInc);
Adam Cohend4844c32011-02-18 19:25:06 -0800265 cellXInc = Math.min(lp.cellHSpan - mMinHSpan, cellXInc);
266 hSpanInc *= -1;
Adam Cohenbebf0422012-04-11 18:06:28 -0700267 hSpanInc = Math.min(cellX, hSpanInc);
Adam Cohend4844c32011-02-18 19:25:06 -0800268 hSpanInc = Math.max(-(lp.cellHSpan - mMinHSpan), hSpanInc);
Adam Cohenbebf0422012-04-11 18:06:28 -0700269 hSpanDelta = -hSpanInc;
270
Adam Cohend4844c32011-02-18 19:25:06 -0800271 } else if (mRightBorderActive) {
Adam Cohenbebf0422012-04-11 18:06:28 -0700272 hSpanInc = Math.min(countX - (cellX + spanX), hSpanInc);
Adam Cohend4844c32011-02-18 19:25:06 -0800273 hSpanInc = Math.max(-(lp.cellHSpan - mMinHSpan), hSpanInc);
Adam Cohenbebf0422012-04-11 18:06:28 -0700274 hSpanDelta = hSpanInc;
Adam Cohend4844c32011-02-18 19:25:06 -0800275 }
276
277 if (mTopBorderActive) {
Adam Cohenbebf0422012-04-11 18:06:28 -0700278 cellYInc = Math.max(-cellY, vSpanInc);
Adam Cohend4844c32011-02-18 19:25:06 -0800279 cellYInc = Math.min(lp.cellVSpan - mMinVSpan, cellYInc);
280 vSpanInc *= -1;
Adam Cohenbebf0422012-04-11 18:06:28 -0700281 vSpanInc = Math.min(cellY, vSpanInc);
Adam Cohend4844c32011-02-18 19:25:06 -0800282 vSpanInc = Math.max(-(lp.cellVSpan - mMinVSpan), vSpanInc);
Adam Cohenbebf0422012-04-11 18:06:28 -0700283 vSpanDelta = -vSpanInc;
Adam Cohend4844c32011-02-18 19:25:06 -0800284 } else if (mBottomBorderActive) {
Adam Cohenbebf0422012-04-11 18:06:28 -0700285 vSpanInc = Math.min(countY - (cellY + spanY), 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 }
289
Adam Cohenbebf0422012-04-11 18:06:28 -0700290 mDirectionVector[0] = 0;
291 mDirectionVector[1] = 0;
Adam Cohend4844c32011-02-18 19:25:06 -0800292 // Update the widget's dimensions and position according to the deltas computed above
293 if (mLeftBorderActive || mRightBorderActive) {
Adam Cohenbebf0422012-04-11 18:06:28 -0700294 spanX += hSpanInc;
295 cellX += cellXInc;
296 mDirectionVector[0] = mLeftBorderActive ? -1 : 1;
Adam Cohend4844c32011-02-18 19:25:06 -0800297 }
298
299 if (mTopBorderActive || mBottomBorderActive) {
Adam Cohenbebf0422012-04-11 18:06:28 -0700300 spanY += vSpanInc;
301 cellY += cellYInc;
302 mDirectionVector[1] = mTopBorderActive ? -1 : 1;
Adam Cohend4844c32011-02-18 19:25:06 -0800303 }
304
Adam Cohenbebf0422012-04-11 18:06:28 -0700305 if (!onDismiss && vSpanDelta == 0 && hSpanDelta == 0) return;
Adam Cohend4844c32011-02-18 19:25:06 -0800306
Adam Cohenbebf0422012-04-11 18:06:28 -0700307 if (mCellLayout.createAreaForResize(cellX, cellY, spanX, spanY, mWidgetView,
308 mDirectionVector, onDismiss)) {
309 lp.tmpCellX = cellX;
310 lp.tmpCellY = cellY;
311 lp.cellHSpan = spanX;
312 lp.cellVSpan = spanY;
313 mRunningVInc += vSpanDelta;
314 mRunningHInc += hSpanDelta;
Adam Cohena897f392012-04-27 18:12:05 -0700315 if (!onDismiss) {
316 updateWidgetSizeRanges(mWidgetView, mLauncher, spanX, spanY);
317 }
Adam Cohenbebf0422012-04-11 18:06:28 -0700318 }
Adam Cohen67882692011-03-11 15:29:03 -0800319 mWidgetView.requestLayout();
Adam Cohend4844c32011-02-18 19:25:06 -0800320 }
321
Adam Cohena897f392012-04-27 18:12:05 -0700322 static void updateWidgetSizeRanges(AppWidgetHostView widgetView, Launcher launcher,
323 int spanX, int spanY) {
324 Rect landMetrics = Workspace.getCellLayoutMetrics(launcher, CellLayout.LANDSCAPE);
325 Rect portMetrics = Workspace.getCellLayoutMetrics(launcher, CellLayout.PORTRAIT);
326 final float density = launcher.getResources().getDisplayMetrics().density;
327
328 // Compute landscape size
329 int cellWidth = landMetrics.left;
330 int cellHeight = landMetrics.top;
331 int widthGap = landMetrics.right;
332 int heightGap = landMetrics.bottom;
333 int landWidth = (int) ((spanX * cellWidth + (spanX - 1) * widthGap) / density);
334 int landHeight = (int) ((spanY * cellHeight + (spanY - 1) * heightGap) / density);
335
336 // Compute portrait size
337 cellWidth = portMetrics.left;
338 cellHeight = portMetrics.top;
339 widthGap = portMetrics.right;
340 heightGap = portMetrics.bottom;
341 int portWidth = (int) ((spanX * cellWidth + (spanX - 1) * widthGap) / density);
342 int portHeight = (int) ((spanY * cellHeight + (spanY - 1) * heightGap) / density);
343
344 widgetView.updateAppWidgetSize(null, portWidth, landHeight, landWidth, portHeight);
345 }
346
Adam Cohen1b607ed2011-03-03 17:26:50 -0800347 /**
348 * This is the final step of the resize. Here we save the new widget size and position
349 * to LauncherModel and animate the resize frame.
350 */
Adam Cohenbebf0422012-04-11 18:06:28 -0700351 public void commitResize() {
352 resizeWidgetIfNeeded(true);
353 requestLayout();
354 }
Adam Cohend4844c32011-02-18 19:25:06 -0800355
Adam Cohenbebf0422012-04-11 18:06:28 -0700356 public void onTouchUp() {
357 int xThreshold = mCellLayout.getCellWidth() + mCellLayout.getWidthGap();
358 int yThreshold = mCellLayout.getCellHeight() + mCellLayout.getHeightGap();
Adam Cohend4844c32011-02-18 19:25:06 -0800359
Adam Cohenbebf0422012-04-11 18:06:28 -0700360 mDeltaXAddOn = mRunningHInc * xThreshold;
361 mDeltaYAddOn = mRunningVInc * yThreshold;
362 mDeltaX = 0;
363 mDeltaY = 0;
364
Adam Cohend4844c32011-02-18 19:25:06 -0800365 post(new Runnable() {
Adam Cohenbebf0422012-04-11 18:06:28 -0700366 @Override
Adam Cohend4844c32011-02-18 19:25:06 -0800367 public void run() {
368 snapToWidget(true);
369 }
370 });
371 }
372
373 public void snapToWidget(boolean animate) {
Adam Cohen67882692011-03-11 15:29:03 -0800374 final DragLayer.LayoutParams lp = (DragLayer.LayoutParams) getLayoutParams();
Winson Chung4b825dcd2011-06-19 12:41:22 -0700375 int xOffset = mCellLayout.getLeft() + mCellLayout.getPaddingLeft() - mWorkspace.getScrollX();
376 int yOffset = mCellLayout.getTop() + mCellLayout.getPaddingTop() - mWorkspace.getScrollY();
Adam Cohend4844c32011-02-18 19:25:06 -0800377
Adam Cohen37b59ff2011-06-13 17:13:42 -0700378 int newWidth = mWidgetView.getWidth() + 2 * mBackgroundPadding - mWidgetPaddingLeft -
379 mWidgetPaddingRight;
380 int newHeight = mWidgetView.getHeight() + 2 * mBackgroundPadding - mWidgetPaddingTop -
381 mWidgetPaddingBottom;
382
383 int newX = mWidgetView.getLeft() - mBackgroundPadding + xOffset + mWidgetPaddingLeft;
384 int newY = mWidgetView.getTop() - mBackgroundPadding + yOffset + mWidgetPaddingTop;
Adam Cohen3cba7222011-03-02 19:03:11 -0800385
Adam Cohen4459d6b2012-07-13 15:59:15 -0700386 // We need to make sure the frame's touchable regions lie fully within the bounds of the
387 // DragLayer. We allow the actual handles to be clipped, but we shift the touch regions
388 // down accordingly to provide a proper touch target.
Adam Cohen3cba7222011-03-02 19:03:11 -0800389 if (newY < 0) {
Adam Cohen4459d6b2012-07-13 15:59:15 -0700390 // In this case we shift the touch region down to start at the top of the DragLayer
391 mTopTouchRegionAdjustment = -newY;
392 } else {
393 mTopTouchRegionAdjustment = 0;
Adam Cohen3cba7222011-03-02 19:03:11 -0800394 }
Adam Cohen67882692011-03-11 15:29:03 -0800395 if (newY + newHeight > mDragLayer.getHeight()) {
Adam Cohen4459d6b2012-07-13 15:59:15 -0700396 // In this case we shift the touch region up to end at the bottom of the DragLayer
397 mBottomTouchRegionAdjustment = -(newY + newHeight - mDragLayer.getHeight());
398 } else {
399 mBottomTouchRegionAdjustment = 0;
Adam Cohen3cba7222011-03-02 19:03:11 -0800400 }
401
Adam Cohend4844c32011-02-18 19:25:06 -0800402 if (!animate) {
403 lp.width = newWidth;
404 lp.height = newHeight;
405 lp.x = newX;
406 lp.y = newY;
407 mLeftHandle.setAlpha(1.0f);
408 mRightHandle.setAlpha(1.0f);
409 mTopHandle.setAlpha(1.0f);
410 mBottomHandle.setAlpha(1.0f);
411 requestLayout();
412 } else {
413 PropertyValuesHolder width = PropertyValuesHolder.ofInt("width", lp.width, newWidth);
Adam Cohen1b607ed2011-03-03 17:26:50 -0800414 PropertyValuesHolder height = PropertyValuesHolder.ofInt("height", lp.height,
415 newHeight);
Adam Cohend4844c32011-02-18 19:25:06 -0800416 PropertyValuesHolder x = PropertyValuesHolder.ofInt("x", lp.x, newX);
417 PropertyValuesHolder y = PropertyValuesHolder.ofInt("y", lp.y, newY);
Michael Jurka2ecf9952012-06-18 12:52:28 -0700418 ObjectAnimator oa = LauncherAnimUtils.ofPropertyValuesHolder(lp, width, height, x, y);
419 ObjectAnimator leftOa = LauncherAnimUtils.ofFloat(mLeftHandle, "alpha", 1.0f);
420 ObjectAnimator rightOa = LauncherAnimUtils.ofFloat(mRightHandle, "alpha", 1.0f);
421 ObjectAnimator topOa = LauncherAnimUtils.ofFloat(mTopHandle, "alpha", 1.0f);
422 ObjectAnimator bottomOa = LauncherAnimUtils.ofFloat(mBottomHandle, "alpha", 1.0f);
Adam Cohend4844c32011-02-18 19:25:06 -0800423 oa.addUpdateListener(new AnimatorUpdateListener() {
424 public void onAnimationUpdate(ValueAnimator animation) {
425 requestLayout();
426 }
427 });
Michael Jurka2ecf9952012-06-18 12:52:28 -0700428 AnimatorSet set = LauncherAnimUtils.createAnimatorSet();
Adam Cohend4844c32011-02-18 19:25:06 -0800429 if (mResizeMode == AppWidgetProviderInfo.RESIZE_VERTICAL) {
430 set.playTogether(oa, topOa, bottomOa);
431 } else if (mResizeMode == AppWidgetProviderInfo.RESIZE_HORIZONTAL) {
432 set.playTogether(oa, leftOa, rightOa);
433 } else {
434 set.playTogether(oa, leftOa, rightOa, topOa, bottomOa);
435 }
436
437 set.setDuration(SNAP_DURATION);
438 set.start();
439 }
440 }
441}