blob: 7762ece5f09ea7655e40b19f7aa4482481023c4e [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 Cohen9e05a5e2012-09-10 15:53:09 -070067 private static Rect mTmpRect = new Rect();
68
Adam Cohen1b607ed2011-03-03 17:26:50 -080069 public static final int LEFT = 0;
70 public static final int TOP = 1;
71 public static final int RIGHT = 2;
72 public static final int BOTTOM = 3;
73
Adam Cohencbf47e32011-09-16 17:32:37 -070074 private Launcher mLauncher;
75
Michael Jurka3a9fced2012-04-13 14:44:29 -070076 public AppWidgetResizeFrame(Context context,
Adam Cohen67882692011-03-11 15:29:03 -080077 LauncherAppWidgetHostView widgetView, CellLayout cellLayout, DragLayer dragLayer) {
Adam Cohend4844c32011-02-18 19:25:06 -080078
79 super(context);
Adam Cohencbf47e32011-09-16 17:32:37 -070080 mLauncher = (Launcher) context;
Adam Cohend4844c32011-02-18 19:25:06 -080081 mCellLayout = cellLayout;
82 mWidgetView = widgetView;
Adam Cohen27c09b02011-02-28 14:45:11 -080083 mResizeMode = widgetView.getAppWidgetInfo().resizeMode;
Adam Cohen67882692011-03-11 15:29:03 -080084 mDragLayer = dragLayer;
85 mWorkspace = (Workspace) dragLayer.findViewById(R.id.workspace);
Adam Cohen3cba7222011-03-02 19:03:11 -080086
Adam Cohend4844c32011-02-18 19:25:06 -080087 final AppWidgetProviderInfo info = widgetView.getAppWidgetInfo();
Adam Cohen2f093b62012-04-30 18:59:53 -070088 int[] result = Launcher.getMinSpanForWidget(mLauncher, info);
Adam Cohend4844c32011-02-18 19:25:06 -080089 mMinHSpan = result[0];
90 mMinVSpan = result[1];
91
Adam Cohen3cba7222011-03-02 19:03:11 -080092 setBackgroundResource(R.drawable.widget_resize_frame_holo);
Adam Cohend4844c32011-02-18 19:25:06 -080093 setPadding(0, 0, 0, 0);
94
95 LayoutParams lp;
96 mLeftHandle = new ImageView(context);
Adam Cohen3cba7222011-03-02 19:03:11 -080097 mLeftHandle.setImageResource(R.drawable.widget_resize_handle_left);
Adam Cohend4844c32011-02-18 19:25:06 -080098 lp = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT,
99 Gravity.LEFT | Gravity.CENTER_VERTICAL);
100 addView(mLeftHandle, lp);
101
102 mRightHandle = new ImageView(context);
Adam Cohen3cba7222011-03-02 19:03:11 -0800103 mRightHandle.setImageResource(R.drawable.widget_resize_handle_right);
Adam Cohend4844c32011-02-18 19:25:06 -0800104 lp = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT,
105 Gravity.RIGHT | Gravity.CENTER_VERTICAL);
106 addView(mRightHandle, lp);
107
108 mTopHandle = new ImageView(context);
Adam Cohen3cba7222011-03-02 19:03:11 -0800109 mTopHandle.setImageResource(R.drawable.widget_resize_handle_top);
Adam Cohend4844c32011-02-18 19:25:06 -0800110 lp = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT,
111 Gravity.CENTER_HORIZONTAL | Gravity.TOP);
112 addView(mTopHandle, lp);
113
114 mBottomHandle = new ImageView(context);
Adam Cohen3cba7222011-03-02 19:03:11 -0800115 mBottomHandle.setImageResource(R.drawable.widget_resize_handle_bottom);
Adam Cohend4844c32011-02-18 19:25:06 -0800116 lp = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT,
117 Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM);
118 addView(mBottomHandle, lp);
119
Adam Cohen0cf2a7c2011-11-08 15:07:01 -0800120 Rect p = AppWidgetHostView.getDefaultPaddingForWidget(context,
121 widgetView.getAppWidgetInfo().provider, null);
Adam Cohen82ebbd22011-09-30 15:05:40 -0700122 mWidgetPaddingLeft = p.left;
123 mWidgetPaddingTop = p.top;
124 mWidgetPaddingRight = p.right;
125 mWidgetPaddingBottom = p.bottom;
Adam Cohen37b59ff2011-06-13 17:13:42 -0700126
Adam Cohend4844c32011-02-18 19:25:06 -0800127 if (mResizeMode == AppWidgetProviderInfo.RESIZE_HORIZONTAL) {
128 mTopHandle.setVisibility(GONE);
129 mBottomHandle.setVisibility(GONE);
130 } else if (mResizeMode == AppWidgetProviderInfo.RESIZE_VERTICAL) {
131 mLeftHandle.setVisibility(GONE);
132 mRightHandle.setVisibility(GONE);
Adam Cohen3cba7222011-03-02 19:03:11 -0800133 }
134
Adam Cohencbf47e32011-09-16 17:32:37 -0700135 final float density = mLauncher.getResources().getDisplayMetrics().density;
Adam Cohen3cba7222011-03-02 19:03:11 -0800136 mBackgroundPadding = (int) Math.ceil(density * BACKGROUND_PADDING);
137 mTouchTargetWidth = 2 * mBackgroundPadding;
Adam Cohenbebf0422012-04-11 18:06:28 -0700138
139 // When we create the resize frame, we first mark all cells as unoccupied. The appropriate
140 // cells (same if not resized, or different) will be marked as occupied when the resize
141 // frame is dismissed.
142 mCellLayout.markCellsAsUnoccupiedForView(mWidgetView);
Adam Cohend4844c32011-02-18 19:25:06 -0800143 }
144
145 public boolean beginResizeIfPointInRegion(int x, int y) {
146 boolean horizontalActive = (mResizeMode & AppWidgetProviderInfo.RESIZE_HORIZONTAL) != 0;
147 boolean verticalActive = (mResizeMode & AppWidgetProviderInfo.RESIZE_VERTICAL) != 0;
Adam Cohen4459d6b2012-07-13 15:59:15 -0700148
Adam Cohen3cba7222011-03-02 19:03:11 -0800149 mLeftBorderActive = (x < mTouchTargetWidth) && horizontalActive;
150 mRightBorderActive = (x > getWidth() - mTouchTargetWidth) && horizontalActive;
Adam Cohen4459d6b2012-07-13 15:59:15 -0700151 mTopBorderActive = (y < mTouchTargetWidth + mTopTouchRegionAdjustment) && verticalActive;
152 mBottomBorderActive = (y > getHeight() - mTouchTargetWidth + mBottomTouchRegionAdjustment)
153 && verticalActive;
Adam Cohend4844c32011-02-18 19:25:06 -0800154
155 boolean anyBordersActive = mLeftBorderActive || mRightBorderActive
156 || mTopBorderActive || mBottomBorderActive;
157
158 mBaselineWidth = getMeasuredWidth();
159 mBaselineHeight = getMeasuredHeight();
160 mBaselineX = getLeft();
161 mBaselineY = getTop();
Adam Cohend4844c32011-02-18 19:25:06 -0800162
163 if (anyBordersActive) {
Adam Cohen3cba7222011-03-02 19:03:11 -0800164 mLeftHandle.setAlpha(mLeftBorderActive ? 1.0f : DIMMED_HANDLE_ALPHA);
165 mRightHandle.setAlpha(mRightBorderActive ? 1.0f :DIMMED_HANDLE_ALPHA);
166 mTopHandle.setAlpha(mTopBorderActive ? 1.0f : DIMMED_HANDLE_ALPHA);
167 mBottomHandle.setAlpha(mBottomBorderActive ? 1.0f : DIMMED_HANDLE_ALPHA);
Adam Cohend4844c32011-02-18 19:25:06 -0800168 }
Adam Cohend4844c32011-02-18 19:25:06 -0800169 return anyBordersActive;
170 }
171
Adam Cohen1b607ed2011-03-03 17:26:50 -0800172 /**
173 * Here we bound the deltas such that the frame cannot be stretched beyond the extents
174 * of the CellLayout, and such that the frame's borders can't cross.
175 */
Adam Cohend4844c32011-02-18 19:25:06 -0800176 public void updateDeltas(int deltaX, int deltaY) {
177 if (mLeftBorderActive) {
178 mDeltaX = Math.max(-mBaselineX, deltaX);
Adam Cohen3cba7222011-03-02 19:03:11 -0800179 mDeltaX = Math.min(mBaselineWidth - 2 * mTouchTargetWidth, mDeltaX);
Adam Cohend4844c32011-02-18 19:25:06 -0800180 } else if (mRightBorderActive) {
Adam Cohen67882692011-03-11 15:29:03 -0800181 mDeltaX = Math.min(mDragLayer.getWidth() - (mBaselineX + mBaselineWidth), deltaX);
Adam Cohen3cba7222011-03-02 19:03:11 -0800182 mDeltaX = Math.max(-mBaselineWidth + 2 * mTouchTargetWidth, mDeltaX);
Adam Cohend4844c32011-02-18 19:25:06 -0800183 }
184
185 if (mTopBorderActive) {
186 mDeltaY = Math.max(-mBaselineY, deltaY);
Adam Cohen3cba7222011-03-02 19:03:11 -0800187 mDeltaY = Math.min(mBaselineHeight - 2 * mTouchTargetWidth, mDeltaY);
Adam Cohend4844c32011-02-18 19:25:06 -0800188 } else if (mBottomBorderActive) {
Adam Cohen67882692011-03-11 15:29:03 -0800189 mDeltaY = Math.min(mDragLayer.getHeight() - (mBaselineY + mBaselineHeight), deltaY);
Adam Cohen3cba7222011-03-02 19:03:11 -0800190 mDeltaY = Math.max(-mBaselineHeight + 2 * mTouchTargetWidth, mDeltaY);
Adam Cohend4844c32011-02-18 19:25:06 -0800191 }
192 }
193
Adam Cohenbebf0422012-04-11 18:06:28 -0700194 public void visualizeResizeForDelta(int deltaX, int deltaY) {
195 visualizeResizeForDelta(deltaX, deltaY, false);
196 }
197
Adam Cohen1b607ed2011-03-03 17:26:50 -0800198 /**
199 * Based on the deltas, we resize the frame, and, if needed, we resize the widget.
200 */
Adam Cohenbebf0422012-04-11 18:06:28 -0700201 private void visualizeResizeForDelta(int deltaX, int deltaY, boolean onDismiss) {
Adam Cohend4844c32011-02-18 19:25:06 -0800202 updateDeltas(deltaX, deltaY);
Adam Cohen67882692011-03-11 15:29:03 -0800203 DragLayer.LayoutParams lp = (DragLayer.LayoutParams) getLayoutParams();
204
Adam Cohend4844c32011-02-18 19:25:06 -0800205 if (mLeftBorderActive) {
206 lp.x = mBaselineX + mDeltaX;
207 lp.width = mBaselineWidth - mDeltaX;
208 } else if (mRightBorderActive) {
209 lp.width = mBaselineWidth + mDeltaX;
210 }
211
212 if (mTopBorderActive) {
213 lp.y = mBaselineY + mDeltaY;
214 lp.height = mBaselineHeight - mDeltaY;
215 } else if (mBottomBorderActive) {
216 lp.height = mBaselineHeight + mDeltaY;
217 }
218
Adam Cohenbebf0422012-04-11 18:06:28 -0700219 resizeWidgetIfNeeded(onDismiss);
Adam Cohend4844c32011-02-18 19:25:06 -0800220 requestLayout();
221 }
222
Adam Cohen1b607ed2011-03-03 17:26:50 -0800223 /**
224 * Based on the current deltas, we determine if and how to resize the widget.
225 */
Adam Cohenbebf0422012-04-11 18:06:28 -0700226 private void resizeWidgetIfNeeded(boolean onDismiss) {
Adam Cohend4844c32011-02-18 19:25:06 -0800227 int xThreshold = mCellLayout.getCellWidth() + mCellLayout.getWidthGap();
228 int yThreshold = mCellLayout.getCellHeight() + mCellLayout.getHeightGap();
229
Adam Cohenbebf0422012-04-11 18:06:28 -0700230 int deltaX = mDeltaX + mDeltaXAddOn;
231 int deltaY = mDeltaY + mDeltaYAddOn;
232
233 float hSpanIncF = 1.0f * deltaX / xThreshold - mRunningHInc;
234 float vSpanIncF = 1.0f * deltaY / yThreshold - mRunningVInc;
Adam Cohene4b77292011-03-08 18:35:52 -0800235
236 int hSpanInc = 0;
237 int vSpanInc = 0;
Adam Cohend4844c32011-02-18 19:25:06 -0800238 int cellXInc = 0;
239 int cellYInc = 0;
240
Adam Cohenbebf0422012-04-11 18:06:28 -0700241 int countX = mCellLayout.getCountX();
242 int countY = mCellLayout.getCountY();
243
Adam Cohene4b77292011-03-08 18:35:52 -0800244 if (Math.abs(hSpanIncF) > RESIZE_THRESHOLD) {
245 hSpanInc = Math.round(hSpanIncF);
246 }
247 if (Math.abs(vSpanIncF) > RESIZE_THRESHOLD) {
248 vSpanInc = Math.round(vSpanIncF);
249 }
250
Adam Cohenbebf0422012-04-11 18:06:28 -0700251 if (!onDismiss && (hSpanInc == 0 && vSpanInc == 0)) return;
Adam Cohend4844c32011-02-18 19:25:06 -0800252
Adam Cohend4844c32011-02-18 19:25:06 -0800253
254 CellLayout.LayoutParams lp = (CellLayout.LayoutParams) mWidgetView.getLayoutParams();
Adam Cohen1b607ed2011-03-03 17:26:50 -0800255
Adam Cohenbebf0422012-04-11 18:06:28 -0700256 int spanX = lp.cellHSpan;
257 int spanY = lp.cellVSpan;
258 int cellX = lp.useTmpCoords ? lp.tmpCellX : lp.cellX;
259 int cellY = lp.useTmpCoords ? lp.tmpCellY : lp.cellY;
260
261 int hSpanDelta = 0;
262 int vSpanDelta = 0;
263
Adam Cohen1b607ed2011-03-03 17:26:50 -0800264 // For each border, we bound the resizing based on the minimum width, and the maximum
265 // expandability.
Adam Cohend4844c32011-02-18 19:25:06 -0800266 if (mLeftBorderActive) {
Adam Cohenbebf0422012-04-11 18:06:28 -0700267 cellXInc = Math.max(-cellX, hSpanInc);
Adam Cohend4844c32011-02-18 19:25:06 -0800268 cellXInc = Math.min(lp.cellHSpan - mMinHSpan, cellXInc);
269 hSpanInc *= -1;
Adam Cohenbebf0422012-04-11 18:06:28 -0700270 hSpanInc = Math.min(cellX, hSpanInc);
Adam Cohend4844c32011-02-18 19:25:06 -0800271 hSpanInc = Math.max(-(lp.cellHSpan - mMinHSpan), hSpanInc);
Adam Cohenbebf0422012-04-11 18:06:28 -0700272 hSpanDelta = -hSpanInc;
273
Adam Cohend4844c32011-02-18 19:25:06 -0800274 } else if (mRightBorderActive) {
Adam Cohenbebf0422012-04-11 18:06:28 -0700275 hSpanInc = Math.min(countX - (cellX + spanX), hSpanInc);
Adam Cohend4844c32011-02-18 19:25:06 -0800276 hSpanInc = Math.max(-(lp.cellHSpan - mMinHSpan), hSpanInc);
Adam Cohenbebf0422012-04-11 18:06:28 -0700277 hSpanDelta = hSpanInc;
Adam Cohend4844c32011-02-18 19:25:06 -0800278 }
279
280 if (mTopBorderActive) {
Adam Cohenbebf0422012-04-11 18:06:28 -0700281 cellYInc = Math.max(-cellY, vSpanInc);
Adam Cohend4844c32011-02-18 19:25:06 -0800282 cellYInc = Math.min(lp.cellVSpan - mMinVSpan, cellYInc);
283 vSpanInc *= -1;
Adam Cohenbebf0422012-04-11 18:06:28 -0700284 vSpanInc = Math.min(cellY, vSpanInc);
Adam Cohend4844c32011-02-18 19:25:06 -0800285 vSpanInc = Math.max(-(lp.cellVSpan - mMinVSpan), vSpanInc);
Adam Cohenbebf0422012-04-11 18:06:28 -0700286 vSpanDelta = -vSpanInc;
Adam Cohend4844c32011-02-18 19:25:06 -0800287 } else if (mBottomBorderActive) {
Adam Cohenbebf0422012-04-11 18:06:28 -0700288 vSpanInc = Math.min(countY - (cellY + spanY), vSpanInc);
Adam Cohend4844c32011-02-18 19:25:06 -0800289 vSpanInc = Math.max(-(lp.cellVSpan - mMinVSpan), vSpanInc);
Adam Cohenbebf0422012-04-11 18:06:28 -0700290 vSpanDelta = vSpanInc;
Adam Cohend4844c32011-02-18 19:25:06 -0800291 }
292
Adam Cohenbebf0422012-04-11 18:06:28 -0700293 mDirectionVector[0] = 0;
294 mDirectionVector[1] = 0;
Adam Cohend4844c32011-02-18 19:25:06 -0800295 // Update the widget's dimensions and position according to the deltas computed above
296 if (mLeftBorderActive || mRightBorderActive) {
Adam Cohenbebf0422012-04-11 18:06:28 -0700297 spanX += hSpanInc;
298 cellX += cellXInc;
Adam Cohene0489502012-08-27 15:18:53 -0700299 if (hSpanDelta != 0) {
300 mDirectionVector[0] = mLeftBorderActive ? -1 : 1;
301 }
Adam Cohend4844c32011-02-18 19:25:06 -0800302 }
303
304 if (mTopBorderActive || mBottomBorderActive) {
Adam Cohenbebf0422012-04-11 18:06:28 -0700305 spanY += vSpanInc;
306 cellY += cellYInc;
Adam Cohene0489502012-08-27 15:18:53 -0700307 if (vSpanDelta != 0) {
308 mDirectionVector[1] = mTopBorderActive ? -1 : 1;
309 }
Adam Cohend4844c32011-02-18 19:25:06 -0800310 }
311
Adam Cohenbebf0422012-04-11 18:06:28 -0700312 if (!onDismiss && vSpanDelta == 0 && hSpanDelta == 0) return;
Adam Cohend4844c32011-02-18 19:25:06 -0800313
Adam Cohene0489502012-08-27 15:18:53 -0700314 // We always want the final commit to match the feedback, so we make sure to use the
315 // last used direction vector when committing the resize / reorder.
316 if (onDismiss) {
317 mDirectionVector[0] = mLastDirectionVector[0];
318 mDirectionVector[1] = mLastDirectionVector[1];
319 } else {
320 mLastDirectionVector[0] = mDirectionVector[0];
321 mLastDirectionVector[1] = mDirectionVector[1];
322 }
323
Adam Cohenbebf0422012-04-11 18:06:28 -0700324 if (mCellLayout.createAreaForResize(cellX, cellY, spanX, spanY, mWidgetView,
325 mDirectionVector, onDismiss)) {
326 lp.tmpCellX = cellX;
327 lp.tmpCellY = cellY;
328 lp.cellHSpan = spanX;
329 lp.cellVSpan = spanY;
330 mRunningVInc += vSpanDelta;
331 mRunningHInc += hSpanDelta;
Adam Cohena897f392012-04-27 18:12:05 -0700332 if (!onDismiss) {
333 updateWidgetSizeRanges(mWidgetView, mLauncher, spanX, spanY);
334 }
Adam Cohenbebf0422012-04-11 18:06:28 -0700335 }
Adam Cohen67882692011-03-11 15:29:03 -0800336 mWidgetView.requestLayout();
Adam Cohend4844c32011-02-18 19:25:06 -0800337 }
338
Adam Cohena897f392012-04-27 18:12:05 -0700339 static void updateWidgetSizeRanges(AppWidgetHostView widgetView, Launcher launcher,
340 int spanX, int spanY) {
Adam Cohen9e05a5e2012-09-10 15:53:09 -0700341
342 getWidgetSizeRanges(launcher, spanX, spanY, mTmpRect);
343 widgetView.updateAppWidgetSize(null, mTmpRect.left, mTmpRect.top,
344 mTmpRect.right, mTmpRect.bottom);
345 }
346
347 static Rect getWidgetSizeRanges(Launcher launcher, int spanX, int spanY, Rect rect) {
348 if (rect == null) {
349 rect = new Rect();
350 }
Adam Cohena897f392012-04-27 18:12:05 -0700351 Rect landMetrics = Workspace.getCellLayoutMetrics(launcher, CellLayout.LANDSCAPE);
352 Rect portMetrics = Workspace.getCellLayoutMetrics(launcher, CellLayout.PORTRAIT);
353 final float density = launcher.getResources().getDisplayMetrics().density;
354
355 // Compute landscape size
356 int cellWidth = landMetrics.left;
357 int cellHeight = landMetrics.top;
358 int widthGap = landMetrics.right;
359 int heightGap = landMetrics.bottom;
360 int landWidth = (int) ((spanX * cellWidth + (spanX - 1) * widthGap) / density);
361 int landHeight = (int) ((spanY * cellHeight + (spanY - 1) * heightGap) / density);
362
363 // Compute portrait size
364 cellWidth = portMetrics.left;
365 cellHeight = portMetrics.top;
366 widthGap = portMetrics.right;
367 heightGap = portMetrics.bottom;
368 int portWidth = (int) ((spanX * cellWidth + (spanX - 1) * widthGap) / density);
369 int portHeight = (int) ((spanY * cellHeight + (spanY - 1) * heightGap) / density);
Adam Cohen9e05a5e2012-09-10 15:53:09 -0700370 rect.set(portWidth, landHeight, landWidth, portHeight);
371 return rect;
Adam Cohena897f392012-04-27 18:12:05 -0700372 }
373
Adam Cohen1b607ed2011-03-03 17:26:50 -0800374 /**
375 * This is the final step of the resize. Here we save the new widget size and position
376 * to LauncherModel and animate the resize frame.
377 */
Adam Cohenbebf0422012-04-11 18:06:28 -0700378 public void commitResize() {
379 resizeWidgetIfNeeded(true);
380 requestLayout();
381 }
Adam Cohend4844c32011-02-18 19:25:06 -0800382
Adam Cohenbebf0422012-04-11 18:06:28 -0700383 public void onTouchUp() {
384 int xThreshold = mCellLayout.getCellWidth() + mCellLayout.getWidthGap();
385 int yThreshold = mCellLayout.getCellHeight() + mCellLayout.getHeightGap();
Adam Cohend4844c32011-02-18 19:25:06 -0800386
Adam Cohenbebf0422012-04-11 18:06:28 -0700387 mDeltaXAddOn = mRunningHInc * xThreshold;
388 mDeltaYAddOn = mRunningVInc * yThreshold;
389 mDeltaX = 0;
390 mDeltaY = 0;
391
Adam Cohend4844c32011-02-18 19:25:06 -0800392 post(new Runnable() {
Adam Cohenbebf0422012-04-11 18:06:28 -0700393 @Override
Adam Cohend4844c32011-02-18 19:25:06 -0800394 public void run() {
395 snapToWidget(true);
396 }
397 });
398 }
399
400 public void snapToWidget(boolean animate) {
Adam Cohen67882692011-03-11 15:29:03 -0800401 final DragLayer.LayoutParams lp = (DragLayer.LayoutParams) getLayoutParams();
Winson Chung4b825dcd2011-06-19 12:41:22 -0700402 int xOffset = mCellLayout.getLeft() + mCellLayout.getPaddingLeft() - mWorkspace.getScrollX();
403 int yOffset = mCellLayout.getTop() + mCellLayout.getPaddingTop() - mWorkspace.getScrollY();
Adam Cohend4844c32011-02-18 19:25:06 -0800404
Adam Cohen37b59ff2011-06-13 17:13:42 -0700405 int newWidth = mWidgetView.getWidth() + 2 * mBackgroundPadding - mWidgetPaddingLeft -
406 mWidgetPaddingRight;
407 int newHeight = mWidgetView.getHeight() + 2 * mBackgroundPadding - mWidgetPaddingTop -
408 mWidgetPaddingBottom;
409
410 int newX = mWidgetView.getLeft() - mBackgroundPadding + xOffset + mWidgetPaddingLeft;
411 int newY = mWidgetView.getTop() - mBackgroundPadding + yOffset + mWidgetPaddingTop;
Adam Cohen3cba7222011-03-02 19:03:11 -0800412
Adam Cohen4459d6b2012-07-13 15:59:15 -0700413 // We need to make sure the frame's touchable regions lie fully within the bounds of the
414 // DragLayer. We allow the actual handles to be clipped, but we shift the touch regions
415 // down accordingly to provide a proper touch target.
Adam Cohen3cba7222011-03-02 19:03:11 -0800416 if (newY < 0) {
Adam Cohen4459d6b2012-07-13 15:59:15 -0700417 // In this case we shift the touch region down to start at the top of the DragLayer
418 mTopTouchRegionAdjustment = -newY;
419 } else {
420 mTopTouchRegionAdjustment = 0;
Adam Cohen3cba7222011-03-02 19:03:11 -0800421 }
Adam Cohen67882692011-03-11 15:29:03 -0800422 if (newY + newHeight > mDragLayer.getHeight()) {
Adam Cohen4459d6b2012-07-13 15:59:15 -0700423 // In this case we shift the touch region up to end at the bottom of the DragLayer
424 mBottomTouchRegionAdjustment = -(newY + newHeight - mDragLayer.getHeight());
425 } else {
426 mBottomTouchRegionAdjustment = 0;
Adam Cohen3cba7222011-03-02 19:03:11 -0800427 }
428
Adam Cohend4844c32011-02-18 19:25:06 -0800429 if (!animate) {
430 lp.width = newWidth;
431 lp.height = newHeight;
432 lp.x = newX;
433 lp.y = newY;
434 mLeftHandle.setAlpha(1.0f);
435 mRightHandle.setAlpha(1.0f);
436 mTopHandle.setAlpha(1.0f);
437 mBottomHandle.setAlpha(1.0f);
438 requestLayout();
439 } else {
440 PropertyValuesHolder width = PropertyValuesHolder.ofInt("width", lp.width, newWidth);
Adam Cohen1b607ed2011-03-03 17:26:50 -0800441 PropertyValuesHolder height = PropertyValuesHolder.ofInt("height", lp.height,
442 newHeight);
Adam Cohend4844c32011-02-18 19:25:06 -0800443 PropertyValuesHolder x = PropertyValuesHolder.ofInt("x", lp.x, newX);
444 PropertyValuesHolder y = PropertyValuesHolder.ofInt("y", lp.y, newY);
Michael Jurka2ecf9952012-06-18 12:52:28 -0700445 ObjectAnimator oa = LauncherAnimUtils.ofPropertyValuesHolder(lp, width, height, x, y);
446 ObjectAnimator leftOa = LauncherAnimUtils.ofFloat(mLeftHandle, "alpha", 1.0f);
447 ObjectAnimator rightOa = LauncherAnimUtils.ofFloat(mRightHandle, "alpha", 1.0f);
448 ObjectAnimator topOa = LauncherAnimUtils.ofFloat(mTopHandle, "alpha", 1.0f);
449 ObjectAnimator bottomOa = LauncherAnimUtils.ofFloat(mBottomHandle, "alpha", 1.0f);
Adam Cohend4844c32011-02-18 19:25:06 -0800450 oa.addUpdateListener(new AnimatorUpdateListener() {
451 public void onAnimationUpdate(ValueAnimator animation) {
452 requestLayout();
453 }
454 });
Michael Jurka2ecf9952012-06-18 12:52:28 -0700455 AnimatorSet set = LauncherAnimUtils.createAnimatorSet();
Adam Cohend4844c32011-02-18 19:25:06 -0800456 if (mResizeMode == AppWidgetProviderInfo.RESIZE_VERTICAL) {
457 set.playTogether(oa, topOa, bottomOa);
458 } else if (mResizeMode == AppWidgetProviderInfo.RESIZE_HORIZONTAL) {
459 set.playTogether(oa, leftOa, rightOa);
460 } else {
461 set.playTogether(oa, leftOa, rightOa, topOa, bottomOa);
462 }
463
464 set.setDuration(SNAP_DURATION);
465 set.start();
466 }
467 }
468}