blob: 3c698c01488665aae359106e8126d04c0c4cd339 [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 {
Adam Cohend4844c32011-02-18 19:25:06 -080018 private LauncherAppWidgetHostView mWidgetView;
19 private CellLayout mCellLayout;
Adam Cohen67882692011-03-11 15:29:03 -080020 private DragLayer mDragLayer;
Adam Cohend4844c32011-02-18 19:25:06 -080021 private ImageView mLeftHandle;
22 private ImageView mRightHandle;
Adam Cohen1b607ed2011-03-03 17:26:50 -080023 private ImageView mTopHandle;
Adam Cohend4844c32011-02-18 19:25:06 -080024 private ImageView mBottomHandle;
25
26 private boolean mLeftBorderActive;
27 private boolean mRightBorderActive;
28 private boolean mTopBorderActive;
29 private boolean mBottomBorderActive;
30
Adam Cohen37b59ff2011-06-13 17:13:42 -070031 private int mWidgetPaddingLeft;
32 private int mWidgetPaddingRight;
33 private int mWidgetPaddingTop;
34 private int mWidgetPaddingBottom;
35
Adam Cohend4844c32011-02-18 19:25:06 -080036 private int mBaselineWidth;
37 private int mBaselineHeight;
38 private int mBaselineX;
39 private int mBaselineY;
40 private int mResizeMode;
Adam Cohen3cba7222011-03-02 19:03:11 -080041
Adam Cohend4844c32011-02-18 19:25:06 -080042 private int mRunningHInc;
43 private int mRunningVInc;
44 private int mMinHSpan;
45 private int mMinVSpan;
46 private int mDeltaX;
47 private int mDeltaY;
Adam Cohenbebf0422012-04-11 18:06:28 -070048 private int mDeltaXAddOn;
49 private int mDeltaYAddOn;
Adam Cohen1b607ed2011-03-03 17:26:50 -080050
Adam Cohen3cba7222011-03-02 19:03:11 -080051 private int mBackgroundPadding;
52 private int mTouchTargetWidth;
Adam Cohend4844c32011-02-18 19:25:06 -080053
Adam Cohen4459d6b2012-07-13 15:59:15 -070054 private int mTopTouchRegionAdjustment = 0;
55 private int mBottomTouchRegionAdjustment = 0;
56
Adam Cohenbebf0422012-04-11 18:06:28 -070057 int[] mDirectionVector = new int[2];
Adam Cohene0489502012-08-27 15:18:53 -070058 int[] mLastDirectionVector = new int[2];
Adam Cohend6e7aa32013-07-09 15:32:37 -070059 int[] mTmpPt = 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 Cohen9e05a5e2012-09-10 15:53:09 -070066 private static Rect mTmpRect = new Rect();
67
Adam Cohen1b607ed2011-03-03 17:26:50 -080068 public static final int LEFT = 0;
69 public static final int TOP = 1;
70 public static final int RIGHT = 2;
71 public static final int BOTTOM = 3;
72
Adam Cohencbf47e32011-09-16 17:32:37 -070073 private Launcher mLauncher;
74
Michael Jurka3a9fced2012-04-13 14:44:29 -070075 public AppWidgetResizeFrame(Context context,
Adam Cohen67882692011-03-11 15:29:03 -080076 LauncherAppWidgetHostView widgetView, CellLayout cellLayout, DragLayer dragLayer) {
Adam Cohend4844c32011-02-18 19:25:06 -080077
78 super(context);
Adam Cohencbf47e32011-09-16 17:32:37 -070079 mLauncher = (Launcher) context;
Adam Cohend4844c32011-02-18 19:25:06 -080080 mCellLayout = cellLayout;
81 mWidgetView = widgetView;
Adam Cohen59400422014-03-05 18:07:04 -080082 LauncherAppWidgetProviderInfo info = (LauncherAppWidgetProviderInfo)
83 widgetView.getAppWidgetInfo();
84 mResizeMode = info.resizeMode;
Adam Cohen67882692011-03-11 15:29:03 -080085 mDragLayer = dragLayer;
Adam Cohen3cba7222011-03-02 19:03:11 -080086
Adam Cohen59400422014-03-05 18:07:04 -080087 mMinHSpan = info.minSpanX;
88 mMinVSpan = info.minSpanY;
Adam Cohend4844c32011-02-18 19:25:06 -080089
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,
Adam Cohen283dcbe2013-09-26 16:35:40 -070097 Gravity.LEFT | Gravity.CENTER_VERTICAL);
Adam Cohend4844c32011-02-18 19:25:06 -080098 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,
Adam Cohen283dcbe2013-09-26 16:35:40 -0700103 Gravity.RIGHT | Gravity.CENTER_VERTICAL);
Adam Cohend4844c32011-02-18 19:25:06 -0800104 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 Cohen59400422014-03-05 18:07:04 -0800118 Rect p = new Rect(0, 0, 0, 0);
119 if (!info.isCustomWidget) {
120 p = AppWidgetHostView.getDefaultPaddingForWidget(context,
121 widgetView.getAppWidgetInfo().provider, null);
122 } else {
123 Resources r = context.getResources();
124 int padding = r.getDimensionPixelSize(R.dimen.default_widget_padding);
125 p.set(padding, padding, padding, padding);
126 }
127
Adam Cohen82ebbd22011-09-30 15:05:40 -0700128 mWidgetPaddingLeft = p.left;
129 mWidgetPaddingTop = p.top;
130 mWidgetPaddingRight = p.right;
131 mWidgetPaddingBottom = p.bottom;
Adam Cohen37b59ff2011-06-13 17:13:42 -0700132
Adam Cohend4844c32011-02-18 19:25:06 -0800133 if (mResizeMode == AppWidgetProviderInfo.RESIZE_HORIZONTAL) {
134 mTopHandle.setVisibility(GONE);
135 mBottomHandle.setVisibility(GONE);
136 } else if (mResizeMode == AppWidgetProviderInfo.RESIZE_VERTICAL) {
137 mLeftHandle.setVisibility(GONE);
138 mRightHandle.setVisibility(GONE);
Adam Cohen3cba7222011-03-02 19:03:11 -0800139 }
140
Adam Cohencbf47e32011-09-16 17:32:37 -0700141 final float density = mLauncher.getResources().getDisplayMetrics().density;
Adam Cohen3cba7222011-03-02 19:03:11 -0800142 mBackgroundPadding = (int) Math.ceil(density * BACKGROUND_PADDING);
143 mTouchTargetWidth = 2 * mBackgroundPadding;
Adam Cohenbebf0422012-04-11 18:06:28 -0700144
145 // When we create the resize frame, we first mark all cells as unoccupied. The appropriate
146 // cells (same if not resized, or different) will be marked as occupied when the resize
147 // frame is dismissed.
148 mCellLayout.markCellsAsUnoccupiedForView(mWidgetView);
Adam Cohend4844c32011-02-18 19:25:06 -0800149 }
150
151 public boolean beginResizeIfPointInRegion(int x, int y) {
152 boolean horizontalActive = (mResizeMode & AppWidgetProviderInfo.RESIZE_HORIZONTAL) != 0;
153 boolean verticalActive = (mResizeMode & AppWidgetProviderInfo.RESIZE_VERTICAL) != 0;
Adam Cohen4459d6b2012-07-13 15:59:15 -0700154
Adam Cohen3cba7222011-03-02 19:03:11 -0800155 mLeftBorderActive = (x < mTouchTargetWidth) && horizontalActive;
156 mRightBorderActive = (x > getWidth() - mTouchTargetWidth) && horizontalActive;
Adam Cohen4459d6b2012-07-13 15:59:15 -0700157 mTopBorderActive = (y < mTouchTargetWidth + mTopTouchRegionAdjustment) && verticalActive;
158 mBottomBorderActive = (y > getHeight() - mTouchTargetWidth + mBottomTouchRegionAdjustment)
159 && verticalActive;
Adam Cohend4844c32011-02-18 19:25:06 -0800160
161 boolean anyBordersActive = mLeftBorderActive || mRightBorderActive
162 || mTopBorderActive || mBottomBorderActive;
163
164 mBaselineWidth = getMeasuredWidth();
165 mBaselineHeight = getMeasuredHeight();
166 mBaselineX = getLeft();
167 mBaselineY = getTop();
Adam Cohend4844c32011-02-18 19:25:06 -0800168
169 if (anyBordersActive) {
Adam Cohen3cba7222011-03-02 19:03:11 -0800170 mLeftHandle.setAlpha(mLeftBorderActive ? 1.0f : DIMMED_HANDLE_ALPHA);
171 mRightHandle.setAlpha(mRightBorderActive ? 1.0f :DIMMED_HANDLE_ALPHA);
172 mTopHandle.setAlpha(mTopBorderActive ? 1.0f : DIMMED_HANDLE_ALPHA);
173 mBottomHandle.setAlpha(mBottomBorderActive ? 1.0f : DIMMED_HANDLE_ALPHA);
Adam Cohend4844c32011-02-18 19:25:06 -0800174 }
Adam Cohend4844c32011-02-18 19:25:06 -0800175 return anyBordersActive;
176 }
177
Adam Cohen1b607ed2011-03-03 17:26:50 -0800178 /**
179 * Here we bound the deltas such that the frame cannot be stretched beyond the extents
180 * of the CellLayout, and such that the frame's borders can't cross.
181 */
Adam Cohend4844c32011-02-18 19:25:06 -0800182 public void updateDeltas(int deltaX, int deltaY) {
183 if (mLeftBorderActive) {
184 mDeltaX = Math.max(-mBaselineX, deltaX);
Adam Cohen3cba7222011-03-02 19:03:11 -0800185 mDeltaX = Math.min(mBaselineWidth - 2 * mTouchTargetWidth, mDeltaX);
Adam Cohend4844c32011-02-18 19:25:06 -0800186 } else if (mRightBorderActive) {
Adam Cohen67882692011-03-11 15:29:03 -0800187 mDeltaX = Math.min(mDragLayer.getWidth() - (mBaselineX + mBaselineWidth), deltaX);
Adam Cohen3cba7222011-03-02 19:03:11 -0800188 mDeltaX = Math.max(-mBaselineWidth + 2 * mTouchTargetWidth, mDeltaX);
Adam Cohend4844c32011-02-18 19:25:06 -0800189 }
190
191 if (mTopBorderActive) {
192 mDeltaY = Math.max(-mBaselineY, deltaY);
Adam Cohen3cba7222011-03-02 19:03:11 -0800193 mDeltaY = Math.min(mBaselineHeight - 2 * mTouchTargetWidth, mDeltaY);
Adam Cohend4844c32011-02-18 19:25:06 -0800194 } else if (mBottomBorderActive) {
Adam Cohen67882692011-03-11 15:29:03 -0800195 mDeltaY = Math.min(mDragLayer.getHeight() - (mBaselineY + mBaselineHeight), deltaY);
Adam Cohen3cba7222011-03-02 19:03:11 -0800196 mDeltaY = Math.max(-mBaselineHeight + 2 * mTouchTargetWidth, mDeltaY);
Adam Cohend4844c32011-02-18 19:25:06 -0800197 }
198 }
199
Adam Cohenbebf0422012-04-11 18:06:28 -0700200 public void visualizeResizeForDelta(int deltaX, int deltaY) {
201 visualizeResizeForDelta(deltaX, deltaY, false);
202 }
203
Adam Cohen1b607ed2011-03-03 17:26:50 -0800204 /**
205 * Based on the deltas, we resize the frame, and, if needed, we resize the widget.
206 */
Adam Cohenbebf0422012-04-11 18:06:28 -0700207 private void visualizeResizeForDelta(int deltaX, int deltaY, boolean onDismiss) {
Adam Cohend4844c32011-02-18 19:25:06 -0800208 updateDeltas(deltaX, deltaY);
Adam Cohen67882692011-03-11 15:29:03 -0800209 DragLayer.LayoutParams lp = (DragLayer.LayoutParams) getLayoutParams();
210
Adam Cohend4844c32011-02-18 19:25:06 -0800211 if (mLeftBorderActive) {
212 lp.x = mBaselineX + mDeltaX;
213 lp.width = mBaselineWidth - mDeltaX;
214 } else if (mRightBorderActive) {
215 lp.width = mBaselineWidth + mDeltaX;
216 }
217
218 if (mTopBorderActive) {
219 lp.y = mBaselineY + mDeltaY;
220 lp.height = mBaselineHeight - mDeltaY;
221 } else if (mBottomBorderActive) {
222 lp.height = mBaselineHeight + mDeltaY;
223 }
224
Adam Cohenbebf0422012-04-11 18:06:28 -0700225 resizeWidgetIfNeeded(onDismiss);
Adam Cohend4844c32011-02-18 19:25:06 -0800226 requestLayout();
227 }
228
Adam Cohen1b607ed2011-03-03 17:26:50 -0800229 /**
230 * Based on the current deltas, we determine if and how to resize the widget.
231 */
Adam Cohenbebf0422012-04-11 18:06:28 -0700232 private void resizeWidgetIfNeeded(boolean onDismiss) {
Adam Cohend4844c32011-02-18 19:25:06 -0800233 int xThreshold = mCellLayout.getCellWidth() + mCellLayout.getWidthGap();
234 int yThreshold = mCellLayout.getCellHeight() + mCellLayout.getHeightGap();
235
Adam Cohenbebf0422012-04-11 18:06:28 -0700236 int deltaX = mDeltaX + mDeltaXAddOn;
237 int deltaY = mDeltaY + mDeltaYAddOn;
238
239 float hSpanIncF = 1.0f * deltaX / xThreshold - mRunningHInc;
240 float vSpanIncF = 1.0f * deltaY / yThreshold - mRunningVInc;
Adam Cohene4b77292011-03-08 18:35:52 -0800241
242 int hSpanInc = 0;
243 int vSpanInc = 0;
Adam Cohend4844c32011-02-18 19:25:06 -0800244 int cellXInc = 0;
245 int cellYInc = 0;
246
Adam Cohenbebf0422012-04-11 18:06:28 -0700247 int countX = mCellLayout.getCountX();
248 int countY = mCellLayout.getCountY();
249
Adam Cohene4b77292011-03-08 18:35:52 -0800250 if (Math.abs(hSpanIncF) > RESIZE_THRESHOLD) {
251 hSpanInc = Math.round(hSpanIncF);
252 }
253 if (Math.abs(vSpanIncF) > RESIZE_THRESHOLD) {
254 vSpanInc = Math.round(vSpanIncF);
255 }
256
Adam Cohenbebf0422012-04-11 18:06:28 -0700257 if (!onDismiss && (hSpanInc == 0 && vSpanInc == 0)) return;
Adam Cohend4844c32011-02-18 19:25:06 -0800258
Adam Cohend4844c32011-02-18 19:25:06 -0800259
260 CellLayout.LayoutParams lp = (CellLayout.LayoutParams) mWidgetView.getLayoutParams();
Adam Cohen1b607ed2011-03-03 17:26:50 -0800261
Adam Cohenbebf0422012-04-11 18:06:28 -0700262 int spanX = lp.cellHSpan;
263 int spanY = lp.cellVSpan;
264 int cellX = lp.useTmpCoords ? lp.tmpCellX : lp.cellX;
265 int cellY = lp.useTmpCoords ? lp.tmpCellY : lp.cellY;
266
267 int hSpanDelta = 0;
268 int vSpanDelta = 0;
269
Adam Cohen1b607ed2011-03-03 17:26:50 -0800270 // For each border, we bound the resizing based on the minimum width, and the maximum
271 // expandability.
Adam Cohend4844c32011-02-18 19:25:06 -0800272 if (mLeftBorderActive) {
Adam Cohenbebf0422012-04-11 18:06:28 -0700273 cellXInc = Math.max(-cellX, hSpanInc);
Adam Cohend4844c32011-02-18 19:25:06 -0800274 cellXInc = Math.min(lp.cellHSpan - mMinHSpan, cellXInc);
275 hSpanInc *= -1;
Adam Cohenbebf0422012-04-11 18:06:28 -0700276 hSpanInc = Math.min(cellX, hSpanInc);
Adam Cohend4844c32011-02-18 19:25:06 -0800277 hSpanInc = Math.max(-(lp.cellHSpan - mMinHSpan), hSpanInc);
Adam Cohenbebf0422012-04-11 18:06:28 -0700278 hSpanDelta = -hSpanInc;
279
Adam Cohend4844c32011-02-18 19:25:06 -0800280 } else if (mRightBorderActive) {
Adam Cohenbebf0422012-04-11 18:06:28 -0700281 hSpanInc = Math.min(countX - (cellX + spanX), hSpanInc);
Adam Cohend4844c32011-02-18 19:25:06 -0800282 hSpanInc = Math.max(-(lp.cellHSpan - mMinHSpan), hSpanInc);
Adam Cohenbebf0422012-04-11 18:06:28 -0700283 hSpanDelta = hSpanInc;
Adam Cohend4844c32011-02-18 19:25:06 -0800284 }
285
286 if (mTopBorderActive) {
Adam Cohenbebf0422012-04-11 18:06:28 -0700287 cellYInc = Math.max(-cellY, vSpanInc);
Adam Cohend4844c32011-02-18 19:25:06 -0800288 cellYInc = Math.min(lp.cellVSpan - mMinVSpan, cellYInc);
289 vSpanInc *= -1;
Adam Cohenbebf0422012-04-11 18:06:28 -0700290 vSpanInc = Math.min(cellY, vSpanInc);
Adam Cohend4844c32011-02-18 19:25:06 -0800291 vSpanInc = Math.max(-(lp.cellVSpan - mMinVSpan), vSpanInc);
Adam Cohenbebf0422012-04-11 18:06:28 -0700292 vSpanDelta = -vSpanInc;
Adam Cohend4844c32011-02-18 19:25:06 -0800293 } else if (mBottomBorderActive) {
Adam Cohenbebf0422012-04-11 18:06:28 -0700294 vSpanInc = Math.min(countY - (cellY + spanY), vSpanInc);
Adam Cohend4844c32011-02-18 19:25:06 -0800295 vSpanInc = Math.max(-(lp.cellVSpan - mMinVSpan), vSpanInc);
Adam Cohenbebf0422012-04-11 18:06:28 -0700296 vSpanDelta = vSpanInc;
Adam Cohend4844c32011-02-18 19:25:06 -0800297 }
298
Adam Cohenbebf0422012-04-11 18:06:28 -0700299 mDirectionVector[0] = 0;
300 mDirectionVector[1] = 0;
Adam Cohend4844c32011-02-18 19:25:06 -0800301 // Update the widget's dimensions and position according to the deltas computed above
302 if (mLeftBorderActive || mRightBorderActive) {
Adam Cohenbebf0422012-04-11 18:06:28 -0700303 spanX += hSpanInc;
304 cellX += cellXInc;
Adam Cohene0489502012-08-27 15:18:53 -0700305 if (hSpanDelta != 0) {
306 mDirectionVector[0] = mLeftBorderActive ? -1 : 1;
307 }
Adam Cohend4844c32011-02-18 19:25:06 -0800308 }
309
310 if (mTopBorderActive || mBottomBorderActive) {
Adam Cohenbebf0422012-04-11 18:06:28 -0700311 spanY += vSpanInc;
312 cellY += cellYInc;
Adam Cohene0489502012-08-27 15:18:53 -0700313 if (vSpanDelta != 0) {
314 mDirectionVector[1] = mTopBorderActive ? -1 : 1;
315 }
Adam Cohend4844c32011-02-18 19:25:06 -0800316 }
317
Adam Cohenbebf0422012-04-11 18:06:28 -0700318 if (!onDismiss && vSpanDelta == 0 && hSpanDelta == 0) return;
Adam Cohend4844c32011-02-18 19:25:06 -0800319
Adam Cohene0489502012-08-27 15:18:53 -0700320 // We always want the final commit to match the feedback, so we make sure to use the
321 // last used direction vector when committing the resize / reorder.
322 if (onDismiss) {
323 mDirectionVector[0] = mLastDirectionVector[0];
324 mDirectionVector[1] = mLastDirectionVector[1];
325 } else {
326 mLastDirectionVector[0] = mDirectionVector[0];
327 mLastDirectionVector[1] = mDirectionVector[1];
328 }
329
Adam Cohenbebf0422012-04-11 18:06:28 -0700330 if (mCellLayout.createAreaForResize(cellX, cellY, spanX, spanY, mWidgetView,
331 mDirectionVector, onDismiss)) {
332 lp.tmpCellX = cellX;
333 lp.tmpCellY = cellY;
334 lp.cellHSpan = spanX;
335 lp.cellVSpan = spanY;
336 mRunningVInc += vSpanDelta;
337 mRunningHInc += hSpanDelta;
Adam Cohena897f392012-04-27 18:12:05 -0700338 if (!onDismiss) {
339 updateWidgetSizeRanges(mWidgetView, mLauncher, spanX, spanY);
340 }
Adam Cohenbebf0422012-04-11 18:06:28 -0700341 }
Adam Cohen67882692011-03-11 15:29:03 -0800342 mWidgetView.requestLayout();
Adam Cohend4844c32011-02-18 19:25:06 -0800343 }
344
Adam Cohena897f392012-04-27 18:12:05 -0700345 static void updateWidgetSizeRanges(AppWidgetHostView widgetView, Launcher launcher,
346 int spanX, int spanY) {
Adam Cohen9e05a5e2012-09-10 15:53:09 -0700347 getWidgetSizeRanges(launcher, spanX, spanY, mTmpRect);
348 widgetView.updateAppWidgetSize(null, mTmpRect.left, mTmpRect.top,
349 mTmpRect.right, mTmpRect.bottom);
350 }
351
Hyunyoung Songb99ff3e2015-04-23 15:17:50 -0700352 public static Rect getWidgetSizeRanges(Launcher launcher, int spanX, int spanY, Rect rect) {
Adam Cohen9e05a5e2012-09-10 15:53:09 -0700353 if (rect == null) {
354 rect = new Rect();
355 }
Adam Cohena897f392012-04-27 18:12:05 -0700356 Rect landMetrics = Workspace.getCellLayoutMetrics(launcher, CellLayout.LANDSCAPE);
357 Rect portMetrics = Workspace.getCellLayoutMetrics(launcher, CellLayout.PORTRAIT);
358 final float density = launcher.getResources().getDisplayMetrics().density;
359
360 // Compute landscape size
361 int cellWidth = landMetrics.left;
362 int cellHeight = landMetrics.top;
363 int widthGap = landMetrics.right;
364 int heightGap = landMetrics.bottom;
365 int landWidth = (int) ((spanX * cellWidth + (spanX - 1) * widthGap) / density);
366 int landHeight = (int) ((spanY * cellHeight + (spanY - 1) * heightGap) / density);
367
368 // Compute portrait size
369 cellWidth = portMetrics.left;
370 cellHeight = portMetrics.top;
371 widthGap = portMetrics.right;
372 heightGap = portMetrics.bottom;
373 int portWidth = (int) ((spanX * cellWidth + (spanX - 1) * widthGap) / density);
374 int portHeight = (int) ((spanY * cellHeight + (spanY - 1) * heightGap) / density);
Adam Cohen9e05a5e2012-09-10 15:53:09 -0700375 rect.set(portWidth, landHeight, landWidth, portHeight);
376 return rect;
Adam Cohena897f392012-04-27 18:12:05 -0700377 }
378
Adam Cohen1b607ed2011-03-03 17:26:50 -0800379 /**
380 * This is the final step of the resize. Here we save the new widget size and position
381 * to LauncherModel and animate the resize frame.
382 */
Adam Cohenbebf0422012-04-11 18:06:28 -0700383 public void commitResize() {
384 resizeWidgetIfNeeded(true);
385 requestLayout();
386 }
Adam Cohend4844c32011-02-18 19:25:06 -0800387
Adam Cohenbebf0422012-04-11 18:06:28 -0700388 public void onTouchUp() {
389 int xThreshold = mCellLayout.getCellWidth() + mCellLayout.getWidthGap();
390 int yThreshold = mCellLayout.getCellHeight() + mCellLayout.getHeightGap();
Adam Cohend4844c32011-02-18 19:25:06 -0800391
Adam Cohenbebf0422012-04-11 18:06:28 -0700392 mDeltaXAddOn = mRunningHInc * xThreshold;
393 mDeltaYAddOn = mRunningVInc * yThreshold;
394 mDeltaX = 0;
395 mDeltaY = 0;
396
Adam Cohend4844c32011-02-18 19:25:06 -0800397 post(new Runnable() {
Adam Cohenbebf0422012-04-11 18:06:28 -0700398 @Override
Adam Cohend4844c32011-02-18 19:25:06 -0800399 public void run() {
400 snapToWidget(true);
401 }
402 });
403 }
404
405 public void snapToWidget(boolean animate) {
Adam Cohen67882692011-03-11 15:29:03 -0800406 final DragLayer.LayoutParams lp = (DragLayer.LayoutParams) getLayoutParams();
Adam Cohen37b59ff2011-06-13 17:13:42 -0700407 int newWidth = mWidgetView.getWidth() + 2 * mBackgroundPadding - mWidgetPaddingLeft -
408 mWidgetPaddingRight;
409 int newHeight = mWidgetView.getHeight() + 2 * mBackgroundPadding - mWidgetPaddingTop -
410 mWidgetPaddingBottom;
411
Adam Cohend6e7aa32013-07-09 15:32:37 -0700412 mTmpPt[0] = mWidgetView.getLeft();
413 mTmpPt[1] = mWidgetView.getTop();
414 mDragLayer.getDescendantCoordRelativeToSelf(mCellLayout.getShortcutsAndWidgets(), mTmpPt);
415
416 int newX = mTmpPt[0] - mBackgroundPadding + mWidgetPaddingLeft;
417 int newY = mTmpPt[1] - mBackgroundPadding + mWidgetPaddingTop;
Adam Cohen3cba7222011-03-02 19:03:11 -0800418
Adam Cohen4459d6b2012-07-13 15:59:15 -0700419 // We need to make sure the frame's touchable regions lie fully within the bounds of the
420 // DragLayer. We allow the actual handles to be clipped, but we shift the touch regions
421 // down accordingly to provide a proper touch target.
Adam Cohen3cba7222011-03-02 19:03:11 -0800422 if (newY < 0) {
Adam Cohen4459d6b2012-07-13 15:59:15 -0700423 // In this case we shift the touch region down to start at the top of the DragLayer
424 mTopTouchRegionAdjustment = -newY;
425 } else {
426 mTopTouchRegionAdjustment = 0;
Adam Cohen3cba7222011-03-02 19:03:11 -0800427 }
Adam Cohen67882692011-03-11 15:29:03 -0800428 if (newY + newHeight > mDragLayer.getHeight()) {
Adam Cohen4459d6b2012-07-13 15:59:15 -0700429 // In this case we shift the touch region up to end at the bottom of the DragLayer
430 mBottomTouchRegionAdjustment = -(newY + newHeight - mDragLayer.getHeight());
431 } else {
432 mBottomTouchRegionAdjustment = 0;
Adam Cohen3cba7222011-03-02 19:03:11 -0800433 }
434
Adam Cohend4844c32011-02-18 19:25:06 -0800435 if (!animate) {
436 lp.width = newWidth;
437 lp.height = newHeight;
438 lp.x = newX;
439 lp.y = newY;
440 mLeftHandle.setAlpha(1.0f);
441 mRightHandle.setAlpha(1.0f);
442 mTopHandle.setAlpha(1.0f);
443 mBottomHandle.setAlpha(1.0f);
444 requestLayout();
445 } else {
446 PropertyValuesHolder width = PropertyValuesHolder.ofInt("width", lp.width, newWidth);
Adam Cohen1b607ed2011-03-03 17:26:50 -0800447 PropertyValuesHolder height = PropertyValuesHolder.ofInt("height", lp.height,
448 newHeight);
Adam Cohend4844c32011-02-18 19:25:06 -0800449 PropertyValuesHolder x = PropertyValuesHolder.ofInt("x", lp.x, newX);
450 PropertyValuesHolder y = PropertyValuesHolder.ofInt("y", lp.y, newY);
Michael Jurkaf1ad6082013-03-13 12:55:46 +0100451 ObjectAnimator oa =
452 LauncherAnimUtils.ofPropertyValuesHolder(lp, this, width, height, x, y);
Michael Jurka2ecf9952012-06-18 12:52:28 -0700453 ObjectAnimator leftOa = LauncherAnimUtils.ofFloat(mLeftHandle, "alpha", 1.0f);
454 ObjectAnimator rightOa = LauncherAnimUtils.ofFloat(mRightHandle, "alpha", 1.0f);
455 ObjectAnimator topOa = LauncherAnimUtils.ofFloat(mTopHandle, "alpha", 1.0f);
456 ObjectAnimator bottomOa = LauncherAnimUtils.ofFloat(mBottomHandle, "alpha", 1.0f);
Adam Cohend4844c32011-02-18 19:25:06 -0800457 oa.addUpdateListener(new AnimatorUpdateListener() {
458 public void onAnimationUpdate(ValueAnimator animation) {
459 requestLayout();
460 }
461 });
Michael Jurka2ecf9952012-06-18 12:52:28 -0700462 AnimatorSet set = LauncherAnimUtils.createAnimatorSet();
Adam Cohend4844c32011-02-18 19:25:06 -0800463 if (mResizeMode == AppWidgetProviderInfo.RESIZE_VERTICAL) {
464 set.playTogether(oa, topOa, bottomOa);
465 } else if (mResizeMode == AppWidgetProviderInfo.RESIZE_HORIZONTAL) {
466 set.playTogether(oa, leftOa, rightOa);
467 } else {
468 set.playTogether(oa, leftOa, rightOa, topOa, bottomOa);
469 }
470
471 set.setDuration(SNAP_DURATION);
472 set.start();
473 }
474 }
475}