blob: e6bf525315def96c15746d81e6463eee01f79268 [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 Cohen59400422014-03-05 18:07:04 -080011import android.content.res.Resources;
Adam Cohen0cf2a7c2011-11-08 15:07:01 -080012import android.graphics.Rect;
Adam Cohend4844c32011-02-18 19:25:06 -080013import android.view.Gravity;
14import android.widget.FrameLayout;
15import android.widget.ImageView;
16
Adam Cohend4844c32011-02-18 19:25:06 -080017public class AppWidgetResizeFrame extends FrameLayout {
Sunny Goyalba776d52015-05-18 20:52:57 -070018 private static final int SNAP_DURATION = 150;
19 private static final float DIMMED_HANDLE_ALPHA = 0f;
20 private static final float RESIZE_THRESHOLD = 0.66f;
21
22 private static Rect sTmpRect = new Rect();
23
24 private final Launcher mLauncher;
25 private final LauncherAppWidgetHostView mWidgetView;
26 private final CellLayout mCellLayout;
27 private final DragLayer mDragLayer;
28
29 private final ImageView mLeftHandle;
30 private final ImageView mRightHandle;
31 private final ImageView mTopHandle;
32 private final ImageView mBottomHandle;
33
34 private final Rect mWidgetPadding;
35
36 private final int mBackgroundPadding;
37 private final int mTouchTargetWidth;
38
39 private final int[] mDirectionVector = new int[2];
40 private final int[] mLastDirectionVector = new int[2];
41 private final int[] mTmpPt = new int[2];
Adam Cohend4844c32011-02-18 19:25:06 -080042
43 private boolean mLeftBorderActive;
44 private boolean mRightBorderActive;
45 private boolean mTopBorderActive;
46 private boolean mBottomBorderActive;
47
48 private int mBaselineWidth;
49 private int mBaselineHeight;
50 private int mBaselineX;
51 private int mBaselineY;
52 private int mResizeMode;
Adam Cohen3cba7222011-03-02 19:03:11 -080053
Adam Cohend4844c32011-02-18 19:25:06 -080054 private int mRunningHInc;
55 private int mRunningVInc;
56 private int mMinHSpan;
57 private int mMinVSpan;
58 private int mDeltaX;
59 private int mDeltaY;
Adam Cohenbebf0422012-04-11 18:06:28 -070060 private int mDeltaXAddOn;
61 private int mDeltaYAddOn;
Adam Cohen1b607ed2011-03-03 17:26:50 -080062
Adam Cohen4459d6b2012-07-13 15:59:15 -070063 private int mTopTouchRegionAdjustment = 0;
64 private int mBottomTouchRegionAdjustment = 0;
65
Michael Jurka3a9fced2012-04-13 14:44:29 -070066 public AppWidgetResizeFrame(Context context,
Adam Cohen67882692011-03-11 15:29:03 -080067 LauncherAppWidgetHostView widgetView, CellLayout cellLayout, DragLayer dragLayer) {
Adam Cohend4844c32011-02-18 19:25:06 -080068
69 super(context);
Adam Cohencbf47e32011-09-16 17:32:37 -070070 mLauncher = (Launcher) context;
Adam Cohend4844c32011-02-18 19:25:06 -080071 mCellLayout = cellLayout;
72 mWidgetView = widgetView;
Adam Cohen59400422014-03-05 18:07:04 -080073 LauncherAppWidgetProviderInfo info = (LauncherAppWidgetProviderInfo)
74 widgetView.getAppWidgetInfo();
75 mResizeMode = info.resizeMode;
Adam Cohen67882692011-03-11 15:29:03 -080076 mDragLayer = dragLayer;
Adam Cohen3cba7222011-03-02 19:03:11 -080077
Adam Cohen59400422014-03-05 18:07:04 -080078 mMinHSpan = info.minSpanX;
79 mMinVSpan = info.minSpanY;
Adam Cohend4844c32011-02-18 19:25:06 -080080
Sunny Goyalba776d52015-05-18 20:52:57 -070081 setBackgroundResource(R.drawable.widget_resize_shadow);
82 setForeground(getResources().getDrawable(R.drawable.widget_resize_frame));
Adam Cohend4844c32011-02-18 19:25:06 -080083 setPadding(0, 0, 0, 0);
84
Sunny Goyalba776d52015-05-18 20:52:57 -070085 final int handleMargin = getResources().getDimensionPixelSize(R.dimen.widget_handle_margin);
Adam Cohend4844c32011-02-18 19:25:06 -080086 LayoutParams lp;
87 mLeftHandle = new ImageView(context);
Sunny Goyalba776d52015-05-18 20:52:57 -070088 mLeftHandle.setImageResource(R.drawable.ic_widget_resize_handle);
89 lp = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT,
Adam Cohen283dcbe2013-09-26 16:35:40 -070090 Gravity.LEFT | Gravity.CENTER_VERTICAL);
Sunny Goyalba776d52015-05-18 20:52:57 -070091 lp.leftMargin = handleMargin;
Adam Cohend4844c32011-02-18 19:25:06 -080092 addView(mLeftHandle, lp);
93
94 mRightHandle = new ImageView(context);
Sunny Goyalba776d52015-05-18 20:52:57 -070095 mRightHandle.setImageResource(R.drawable.ic_widget_resize_handle);
96 lp = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT,
Adam Cohen283dcbe2013-09-26 16:35:40 -070097 Gravity.RIGHT | Gravity.CENTER_VERTICAL);
Sunny Goyalba776d52015-05-18 20:52:57 -070098 lp.rightMargin = handleMargin;
Adam Cohend4844c32011-02-18 19:25:06 -080099 addView(mRightHandle, lp);
100
101 mTopHandle = new ImageView(context);
Sunny Goyalba776d52015-05-18 20:52:57 -0700102 mTopHandle.setImageResource(R.drawable.ic_widget_resize_handle);
103 lp = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT,
Adam Cohend4844c32011-02-18 19:25:06 -0800104 Gravity.CENTER_HORIZONTAL | Gravity.TOP);
Sunny Goyalba776d52015-05-18 20:52:57 -0700105 lp.topMargin = handleMargin;
Adam Cohend4844c32011-02-18 19:25:06 -0800106 addView(mTopHandle, lp);
107
108 mBottomHandle = new ImageView(context);
Sunny Goyalba776d52015-05-18 20:52:57 -0700109 mBottomHandle.setImageResource(R.drawable.ic_widget_resize_handle);
110 lp = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT,
Adam Cohend4844c32011-02-18 19:25:06 -0800111 Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM);
Sunny Goyalba776d52015-05-18 20:52:57 -0700112 lp.bottomMargin = handleMargin;
Adam Cohend4844c32011-02-18 19:25:06 -0800113 addView(mBottomHandle, lp);
114
Adam Cohen59400422014-03-05 18:07:04 -0800115 if (!info.isCustomWidget) {
Sunny Goyalba776d52015-05-18 20:52:57 -0700116 mWidgetPadding = AppWidgetHostView.getDefaultPaddingForWidget(context,
Adam Cohen59400422014-03-05 18:07:04 -0800117 widgetView.getAppWidgetInfo().provider, null);
118 } else {
119 Resources r = context.getResources();
120 int padding = r.getDimensionPixelSize(R.dimen.default_widget_padding);
Sunny Goyalba776d52015-05-18 20:52:57 -0700121 mWidgetPadding = new Rect(padding, padding, padding, padding);
Adam Cohen59400422014-03-05 18:07:04 -0800122 }
123
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
Sunny Goyalba776d52015-05-18 20:52:57 -0700132 mBackgroundPadding = getResources()
133 .getDimensionPixelSize(R.dimen.resize_frame_background_padding);
Adam Cohen3cba7222011-03-02 19:03:11 -0800134 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;
Adam Cohene0489502012-08-27 15:18:53 -0700296 if (hSpanDelta != 0) {
297 mDirectionVector[0] = mLeftBorderActive ? -1 : 1;
298 }
Adam Cohend4844c32011-02-18 19:25:06 -0800299 }
300
301 if (mTopBorderActive || mBottomBorderActive) {
Adam Cohenbebf0422012-04-11 18:06:28 -0700302 spanY += vSpanInc;
303 cellY += cellYInc;
Adam Cohene0489502012-08-27 15:18:53 -0700304 if (vSpanDelta != 0) {
305 mDirectionVector[1] = mTopBorderActive ? -1 : 1;
306 }
Adam Cohend4844c32011-02-18 19:25:06 -0800307 }
308
Adam Cohenbebf0422012-04-11 18:06:28 -0700309 if (!onDismiss && vSpanDelta == 0 && hSpanDelta == 0) return;
Adam Cohend4844c32011-02-18 19:25:06 -0800310
Adam Cohene0489502012-08-27 15:18:53 -0700311 // We always want the final commit to match the feedback, so we make sure to use the
312 // last used direction vector when committing the resize / reorder.
313 if (onDismiss) {
314 mDirectionVector[0] = mLastDirectionVector[0];
315 mDirectionVector[1] = mLastDirectionVector[1];
316 } else {
317 mLastDirectionVector[0] = mDirectionVector[0];
318 mLastDirectionVector[1] = mDirectionVector[1];
319 }
320
Adam Cohenbebf0422012-04-11 18:06:28 -0700321 if (mCellLayout.createAreaForResize(cellX, cellY, spanX, spanY, mWidgetView,
322 mDirectionVector, onDismiss)) {
323 lp.tmpCellX = cellX;
324 lp.tmpCellY = cellY;
325 lp.cellHSpan = spanX;
326 lp.cellVSpan = spanY;
327 mRunningVInc += vSpanDelta;
328 mRunningHInc += hSpanDelta;
Adam Cohena897f392012-04-27 18:12:05 -0700329 if (!onDismiss) {
330 updateWidgetSizeRanges(mWidgetView, mLauncher, spanX, spanY);
331 }
Adam Cohenbebf0422012-04-11 18:06:28 -0700332 }
Adam Cohen67882692011-03-11 15:29:03 -0800333 mWidgetView.requestLayout();
Adam Cohend4844c32011-02-18 19:25:06 -0800334 }
335
Adam Cohena897f392012-04-27 18:12:05 -0700336 static void updateWidgetSizeRanges(AppWidgetHostView widgetView, Launcher launcher,
337 int spanX, int spanY) {
Sunny Goyalba776d52015-05-18 20:52:57 -0700338 getWidgetSizeRanges(launcher, spanX, spanY, sTmpRect);
339 widgetView.updateAppWidgetSize(null, sTmpRect.left, sTmpRect.top,
340 sTmpRect.right, sTmpRect.bottom);
Adam Cohen9e05a5e2012-09-10 15:53:09 -0700341 }
342
Hyunyoung Songb99ff3e2015-04-23 15:17:50 -0700343 public static Rect getWidgetSizeRanges(Launcher launcher, int spanX, int spanY, Rect rect) {
Adam Cohen9e05a5e2012-09-10 15:53:09 -0700344 if (rect == null) {
345 rect = new Rect();
346 }
Adam Cohena897f392012-04-27 18:12:05 -0700347 Rect landMetrics = Workspace.getCellLayoutMetrics(launcher, CellLayout.LANDSCAPE);
348 Rect portMetrics = Workspace.getCellLayoutMetrics(launcher, CellLayout.PORTRAIT);
349 final float density = launcher.getResources().getDisplayMetrics().density;
350
351 // Compute landscape size
352 int cellWidth = landMetrics.left;
353 int cellHeight = landMetrics.top;
354 int widthGap = landMetrics.right;
355 int heightGap = landMetrics.bottom;
356 int landWidth = (int) ((spanX * cellWidth + (spanX - 1) * widthGap) / density);
357 int landHeight = (int) ((spanY * cellHeight + (spanY - 1) * heightGap) / density);
358
359 // Compute portrait size
360 cellWidth = portMetrics.left;
361 cellHeight = portMetrics.top;
362 widthGap = portMetrics.right;
363 heightGap = portMetrics.bottom;
364 int portWidth = (int) ((spanX * cellWidth + (spanX - 1) * widthGap) / density);
365 int portHeight = (int) ((spanY * cellHeight + (spanY - 1) * heightGap) / density);
Adam Cohen9e05a5e2012-09-10 15:53:09 -0700366 rect.set(portWidth, landHeight, landWidth, portHeight);
367 return rect;
Adam Cohena897f392012-04-27 18:12:05 -0700368 }
369
Adam Cohen1b607ed2011-03-03 17:26:50 -0800370 /**
371 * This is the final step of the resize. Here we save the new widget size and position
372 * to LauncherModel and animate the resize frame.
373 */
Adam Cohenbebf0422012-04-11 18:06:28 -0700374 public void commitResize() {
375 resizeWidgetIfNeeded(true);
376 requestLayout();
377 }
Adam Cohend4844c32011-02-18 19:25:06 -0800378
Adam Cohenbebf0422012-04-11 18:06:28 -0700379 public void onTouchUp() {
380 int xThreshold = mCellLayout.getCellWidth() + mCellLayout.getWidthGap();
381 int yThreshold = mCellLayout.getCellHeight() + mCellLayout.getHeightGap();
Adam Cohend4844c32011-02-18 19:25:06 -0800382
Adam Cohenbebf0422012-04-11 18:06:28 -0700383 mDeltaXAddOn = mRunningHInc * xThreshold;
384 mDeltaYAddOn = mRunningVInc * yThreshold;
385 mDeltaX = 0;
386 mDeltaY = 0;
387
Adam Cohend4844c32011-02-18 19:25:06 -0800388 post(new Runnable() {
Adam Cohenbebf0422012-04-11 18:06:28 -0700389 @Override
Adam Cohend4844c32011-02-18 19:25:06 -0800390 public void run() {
391 snapToWidget(true);
392 }
393 });
394 }
395
396 public void snapToWidget(boolean animate) {
Adam Cohen67882692011-03-11 15:29:03 -0800397 final DragLayer.LayoutParams lp = (DragLayer.LayoutParams) getLayoutParams();
Sunny Goyalba776d52015-05-18 20:52:57 -0700398 int newWidth = mWidgetView.getWidth() + 2 * mBackgroundPadding
399 - mWidgetPadding.left - mWidgetPadding.right;
400 int newHeight = mWidgetView.getHeight() + 2 * mBackgroundPadding
401 - mWidgetPadding.top - mWidgetPadding.bottom;
Adam Cohen37b59ff2011-06-13 17:13:42 -0700402
Adam Cohend6e7aa32013-07-09 15:32:37 -0700403 mTmpPt[0] = mWidgetView.getLeft();
404 mTmpPt[1] = mWidgetView.getTop();
405 mDragLayer.getDescendantCoordRelativeToSelf(mCellLayout.getShortcutsAndWidgets(), mTmpPt);
406
Sunny Goyalba776d52015-05-18 20:52:57 -0700407 int newX = mTmpPt[0] - mBackgroundPadding + mWidgetPadding.left;
408 int newY = mTmpPt[1] - mBackgroundPadding + mWidgetPadding.top;
Adam Cohen3cba7222011-03-02 19:03:11 -0800409
Sunny Goyalba776d52015-05-18 20:52:57 -0700410 // We need to make sure the frame's touchable regions lie fully within the bounds of the
Adam Cohen4459d6b2012-07-13 15:59:15 -0700411 // DragLayer. We allow the actual handles to be clipped, but we shift the touch regions
412 // down accordingly to provide a proper touch target.
Adam Cohen3cba7222011-03-02 19:03:11 -0800413 if (newY < 0) {
Adam Cohen4459d6b2012-07-13 15:59:15 -0700414 // In this case we shift the touch region down to start at the top of the DragLayer
415 mTopTouchRegionAdjustment = -newY;
416 } else {
417 mTopTouchRegionAdjustment = 0;
Adam Cohen3cba7222011-03-02 19:03:11 -0800418 }
Adam Cohen67882692011-03-11 15:29:03 -0800419 if (newY + newHeight > mDragLayer.getHeight()) {
Adam Cohen4459d6b2012-07-13 15:59:15 -0700420 // In this case we shift the touch region up to end at the bottom of the DragLayer
421 mBottomTouchRegionAdjustment = -(newY + newHeight - mDragLayer.getHeight());
422 } else {
423 mBottomTouchRegionAdjustment = 0;
Adam Cohen3cba7222011-03-02 19:03:11 -0800424 }
425
Adam Cohend4844c32011-02-18 19:25:06 -0800426 if (!animate) {
427 lp.width = newWidth;
428 lp.height = newHeight;
429 lp.x = newX;
430 lp.y = newY;
431 mLeftHandle.setAlpha(1.0f);
432 mRightHandle.setAlpha(1.0f);
433 mTopHandle.setAlpha(1.0f);
434 mBottomHandle.setAlpha(1.0f);
435 requestLayout();
436 } else {
437 PropertyValuesHolder width = PropertyValuesHolder.ofInt("width", lp.width, newWidth);
Adam Cohen1b607ed2011-03-03 17:26:50 -0800438 PropertyValuesHolder height = PropertyValuesHolder.ofInt("height", lp.height,
439 newHeight);
Adam Cohend4844c32011-02-18 19:25:06 -0800440 PropertyValuesHolder x = PropertyValuesHolder.ofInt("x", lp.x, newX);
441 PropertyValuesHolder y = PropertyValuesHolder.ofInt("y", lp.y, newY);
Michael Jurkaf1ad6082013-03-13 12:55:46 +0100442 ObjectAnimator oa =
443 LauncherAnimUtils.ofPropertyValuesHolder(lp, this, width, height, x, y);
Michael Jurka2ecf9952012-06-18 12:52:28 -0700444 ObjectAnimator leftOa = LauncherAnimUtils.ofFloat(mLeftHandle, "alpha", 1.0f);
445 ObjectAnimator rightOa = LauncherAnimUtils.ofFloat(mRightHandle, "alpha", 1.0f);
446 ObjectAnimator topOa = LauncherAnimUtils.ofFloat(mTopHandle, "alpha", 1.0f);
447 ObjectAnimator bottomOa = LauncherAnimUtils.ofFloat(mBottomHandle, "alpha", 1.0f);
Adam Cohend4844c32011-02-18 19:25:06 -0800448 oa.addUpdateListener(new AnimatorUpdateListener() {
449 public void onAnimationUpdate(ValueAnimator animation) {
450 requestLayout();
451 }
452 });
Michael Jurka2ecf9952012-06-18 12:52:28 -0700453 AnimatorSet set = LauncherAnimUtils.createAnimatorSet();
Adam Cohend4844c32011-02-18 19:25:06 -0800454 if (mResizeMode == AppWidgetProviderInfo.RESIZE_VERTICAL) {
455 set.playTogether(oa, topOa, bottomOa);
456 } else if (mResizeMode == AppWidgetProviderInfo.RESIZE_HORIZONTAL) {
457 set.playTogether(oa, leftOa, rightOa);
458 } else {
459 set.playTogether(oa, leftOa, rightOa, topOa, bottomOa);
460 }
461
462 set.setDuration(SNAP_DURATION);
463 set.start();
464 }
465 }
466}