blob: d8685360808b79ea7c7a41c8002934d8e1d59693 [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
Sunny Goyale78e3d72015-09-24 11:23:31 -070017import com.android.launcher3.accessibility.DragViewStateAnnouncer;
18
Adam Cohend4844c32011-02-18 19:25:06 -080019public class AppWidgetResizeFrame extends FrameLayout {
Sunny Goyalba776d52015-05-18 20:52:57 -070020 private static final int SNAP_DURATION = 150;
21 private static final float DIMMED_HANDLE_ALPHA = 0f;
22 private static final float RESIZE_THRESHOLD = 0.66f;
23
24 private static Rect sTmpRect = new Rect();
25
26 private final Launcher mLauncher;
27 private final LauncherAppWidgetHostView mWidgetView;
28 private final CellLayout mCellLayout;
29 private final DragLayer mDragLayer;
30
31 private final ImageView mLeftHandle;
32 private final ImageView mRightHandle;
33 private final ImageView mTopHandle;
34 private final ImageView mBottomHandle;
35
36 private final Rect mWidgetPadding;
37
38 private final int mBackgroundPadding;
39 private final int mTouchTargetWidth;
40
41 private final int[] mDirectionVector = new int[2];
42 private final int[] mLastDirectionVector = new int[2];
43 private final int[] mTmpPt = new int[2];
Adam Cohend4844c32011-02-18 19:25:06 -080044
Sunny Goyale78e3d72015-09-24 11:23:31 -070045 private final DragViewStateAnnouncer mStateAnnouncer;
46
Adam Cohend4844c32011-02-18 19:25:06 -080047 private boolean mLeftBorderActive;
48 private boolean mRightBorderActive;
49 private boolean mTopBorderActive;
50 private boolean mBottomBorderActive;
51
52 private int mBaselineWidth;
53 private int mBaselineHeight;
54 private int mBaselineX;
55 private int mBaselineY;
56 private int mResizeMode;
Adam Cohen3cba7222011-03-02 19:03:11 -080057
Adam Cohend4844c32011-02-18 19:25:06 -080058 private int mRunningHInc;
59 private int mRunningVInc;
60 private int mMinHSpan;
61 private int mMinVSpan;
62 private int mDeltaX;
63 private int mDeltaY;
Adam Cohenbebf0422012-04-11 18:06:28 -070064 private int mDeltaXAddOn;
65 private int mDeltaYAddOn;
Adam Cohen1b607ed2011-03-03 17:26:50 -080066
Adam Cohen4459d6b2012-07-13 15:59:15 -070067 private int mTopTouchRegionAdjustment = 0;
68 private int mBottomTouchRegionAdjustment = 0;
69
Michael Jurka3a9fced2012-04-13 14:44:29 -070070 public AppWidgetResizeFrame(Context context,
Adam Cohen67882692011-03-11 15:29:03 -080071 LauncherAppWidgetHostView widgetView, CellLayout cellLayout, DragLayer dragLayer) {
Adam Cohend4844c32011-02-18 19:25:06 -080072
73 super(context);
Adam Cohencbf47e32011-09-16 17:32:37 -070074 mLauncher = (Launcher) context;
Adam Cohend4844c32011-02-18 19:25:06 -080075 mCellLayout = cellLayout;
76 mWidgetView = widgetView;
Adam Cohen59400422014-03-05 18:07:04 -080077 LauncherAppWidgetProviderInfo info = (LauncherAppWidgetProviderInfo)
78 widgetView.getAppWidgetInfo();
79 mResizeMode = info.resizeMode;
Adam Cohen67882692011-03-11 15:29:03 -080080 mDragLayer = dragLayer;
Adam Cohen3cba7222011-03-02 19:03:11 -080081
Sunny Goyal233ee962015-08-03 13:05:01 -070082 mMinHSpan = info.minSpanX;
83 mMinVSpan = info.minSpanY;
Adam Cohend4844c32011-02-18 19:25:06 -080084
Sunny Goyale78e3d72015-09-24 11:23:31 -070085 mStateAnnouncer = DragViewStateAnnouncer.createFor(this);
86
Sunny Goyalba776d52015-05-18 20:52:57 -070087 setBackgroundResource(R.drawable.widget_resize_shadow);
88 setForeground(getResources().getDrawable(R.drawable.widget_resize_frame));
Adam Cohend4844c32011-02-18 19:25:06 -080089 setPadding(0, 0, 0, 0);
90
Sunny Goyalba776d52015-05-18 20:52:57 -070091 final int handleMargin = getResources().getDimensionPixelSize(R.dimen.widget_handle_margin);
Adam Cohend4844c32011-02-18 19:25:06 -080092 LayoutParams lp;
93 mLeftHandle = new ImageView(context);
Sunny Goyalba776d52015-05-18 20:52:57 -070094 mLeftHandle.setImageResource(R.drawable.ic_widget_resize_handle);
95 lp = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT,
Adam Cohen283dcbe2013-09-26 16:35:40 -070096 Gravity.LEFT | Gravity.CENTER_VERTICAL);
Sunny Goyalba776d52015-05-18 20:52:57 -070097 lp.leftMargin = handleMargin;
Adam Cohend4844c32011-02-18 19:25:06 -080098 addView(mLeftHandle, lp);
99
100 mRightHandle = new ImageView(context);
Sunny Goyalba776d52015-05-18 20:52:57 -0700101 mRightHandle.setImageResource(R.drawable.ic_widget_resize_handle);
102 lp = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT,
Adam Cohen283dcbe2013-09-26 16:35:40 -0700103 Gravity.RIGHT | Gravity.CENTER_VERTICAL);
Sunny Goyalba776d52015-05-18 20:52:57 -0700104 lp.rightMargin = handleMargin;
Adam Cohend4844c32011-02-18 19:25:06 -0800105 addView(mRightHandle, lp);
106
107 mTopHandle = new ImageView(context);
Sunny Goyalba776d52015-05-18 20:52:57 -0700108 mTopHandle.setImageResource(R.drawable.ic_widget_resize_handle);
109 lp = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT,
Adam Cohend4844c32011-02-18 19:25:06 -0800110 Gravity.CENTER_HORIZONTAL | Gravity.TOP);
Sunny Goyalba776d52015-05-18 20:52:57 -0700111 lp.topMargin = handleMargin;
Adam Cohend4844c32011-02-18 19:25:06 -0800112 addView(mTopHandle, lp);
113
114 mBottomHandle = new ImageView(context);
Sunny Goyalba776d52015-05-18 20:52:57 -0700115 mBottomHandle.setImageResource(R.drawable.ic_widget_resize_handle);
116 lp = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT,
Adam Cohend4844c32011-02-18 19:25:06 -0800117 Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM);
Sunny Goyalba776d52015-05-18 20:52:57 -0700118 lp.bottomMargin = handleMargin;
Adam Cohend4844c32011-02-18 19:25:06 -0800119 addView(mBottomHandle, lp);
120
Adam Cohen59400422014-03-05 18:07:04 -0800121 if (!info.isCustomWidget) {
Sunny Goyalba776d52015-05-18 20:52:57 -0700122 mWidgetPadding = AppWidgetHostView.getDefaultPaddingForWidget(context,
Adam Cohen59400422014-03-05 18:07:04 -0800123 widgetView.getAppWidgetInfo().provider, null);
124 } else {
125 Resources r = context.getResources();
126 int padding = r.getDimensionPixelSize(R.dimen.default_widget_padding);
Sunny Goyalba776d52015-05-18 20:52:57 -0700127 mWidgetPadding = new Rect(padding, padding, padding, padding);
Adam Cohen59400422014-03-05 18:07:04 -0800128 }
129
Adam Cohend4844c32011-02-18 19:25:06 -0800130 if (mResizeMode == AppWidgetProviderInfo.RESIZE_HORIZONTAL) {
131 mTopHandle.setVisibility(GONE);
132 mBottomHandle.setVisibility(GONE);
133 } else if (mResizeMode == AppWidgetProviderInfo.RESIZE_VERTICAL) {
134 mLeftHandle.setVisibility(GONE);
135 mRightHandle.setVisibility(GONE);
Adam Cohen3cba7222011-03-02 19:03:11 -0800136 }
137
Sunny Goyalba776d52015-05-18 20:52:57 -0700138 mBackgroundPadding = getResources()
139 .getDimensionPixelSize(R.dimen.resize_frame_background_padding);
Adam Cohen3cba7222011-03-02 19:03:11 -0800140 mTouchTargetWidth = 2 * mBackgroundPadding;
Adam Cohenbebf0422012-04-11 18:06:28 -0700141
142 // When we create the resize frame, we first mark all cells as unoccupied. The appropriate
143 // cells (same if not resized, or different) will be marked as occupied when the resize
144 // frame is dismissed.
145 mCellLayout.markCellsAsUnoccupiedForView(mWidgetView);
Adam Cohend4844c32011-02-18 19:25:06 -0800146 }
147
148 public boolean beginResizeIfPointInRegion(int x, int y) {
149 boolean horizontalActive = (mResizeMode & AppWidgetProviderInfo.RESIZE_HORIZONTAL) != 0;
150 boolean verticalActive = (mResizeMode & AppWidgetProviderInfo.RESIZE_VERTICAL) != 0;
Adam Cohen4459d6b2012-07-13 15:59:15 -0700151
Adam Cohen3cba7222011-03-02 19:03:11 -0800152 mLeftBorderActive = (x < mTouchTargetWidth) && horizontalActive;
153 mRightBorderActive = (x > getWidth() - mTouchTargetWidth) && horizontalActive;
Adam Cohen4459d6b2012-07-13 15:59:15 -0700154 mTopBorderActive = (y < mTouchTargetWidth + mTopTouchRegionAdjustment) && verticalActive;
155 mBottomBorderActive = (y > getHeight() - mTouchTargetWidth + mBottomTouchRegionAdjustment)
156 && verticalActive;
Adam Cohend4844c32011-02-18 19:25:06 -0800157
158 boolean anyBordersActive = mLeftBorderActive || mRightBorderActive
159 || mTopBorderActive || mBottomBorderActive;
160
161 mBaselineWidth = getMeasuredWidth();
162 mBaselineHeight = getMeasuredHeight();
163 mBaselineX = getLeft();
164 mBaselineY = getTop();
Adam Cohend4844c32011-02-18 19:25:06 -0800165
166 if (anyBordersActive) {
Adam Cohen3cba7222011-03-02 19:03:11 -0800167 mLeftHandle.setAlpha(mLeftBorderActive ? 1.0f : DIMMED_HANDLE_ALPHA);
168 mRightHandle.setAlpha(mRightBorderActive ? 1.0f :DIMMED_HANDLE_ALPHA);
169 mTopHandle.setAlpha(mTopBorderActive ? 1.0f : DIMMED_HANDLE_ALPHA);
170 mBottomHandle.setAlpha(mBottomBorderActive ? 1.0f : DIMMED_HANDLE_ALPHA);
Adam Cohend4844c32011-02-18 19:25:06 -0800171 }
Adam Cohend4844c32011-02-18 19:25:06 -0800172 return anyBordersActive;
173 }
174
Adam Cohen1b607ed2011-03-03 17:26:50 -0800175 /**
176 * Here we bound the deltas such that the frame cannot be stretched beyond the extents
177 * of the CellLayout, and such that the frame's borders can't cross.
178 */
Adam Cohend4844c32011-02-18 19:25:06 -0800179 public void updateDeltas(int deltaX, int deltaY) {
180 if (mLeftBorderActive) {
181 mDeltaX = Math.max(-mBaselineX, deltaX);
Adam Cohen3cba7222011-03-02 19:03:11 -0800182 mDeltaX = Math.min(mBaselineWidth - 2 * mTouchTargetWidth, mDeltaX);
Adam Cohend4844c32011-02-18 19:25:06 -0800183 } else if (mRightBorderActive) {
Adam Cohen67882692011-03-11 15:29:03 -0800184 mDeltaX = Math.min(mDragLayer.getWidth() - (mBaselineX + mBaselineWidth), deltaX);
Adam Cohen3cba7222011-03-02 19:03:11 -0800185 mDeltaX = Math.max(-mBaselineWidth + 2 * mTouchTargetWidth, mDeltaX);
Adam Cohend4844c32011-02-18 19:25:06 -0800186 }
187
188 if (mTopBorderActive) {
189 mDeltaY = Math.max(-mBaselineY, deltaY);
Adam Cohen3cba7222011-03-02 19:03:11 -0800190 mDeltaY = Math.min(mBaselineHeight - 2 * mTouchTargetWidth, mDeltaY);
Adam Cohend4844c32011-02-18 19:25:06 -0800191 } else if (mBottomBorderActive) {
Adam Cohen67882692011-03-11 15:29:03 -0800192 mDeltaY = Math.min(mDragLayer.getHeight() - (mBaselineY + mBaselineHeight), deltaY);
Adam Cohen3cba7222011-03-02 19:03:11 -0800193 mDeltaY = Math.max(-mBaselineHeight + 2 * mTouchTargetWidth, mDeltaY);
Adam Cohend4844c32011-02-18 19:25:06 -0800194 }
195 }
196
Adam Cohenbebf0422012-04-11 18:06:28 -0700197 public void visualizeResizeForDelta(int deltaX, int deltaY) {
198 visualizeResizeForDelta(deltaX, deltaY, false);
199 }
200
Adam Cohen1b607ed2011-03-03 17:26:50 -0800201 /**
202 * Based on the deltas, we resize the frame, and, if needed, we resize the widget.
203 */
Adam Cohenbebf0422012-04-11 18:06:28 -0700204 private void visualizeResizeForDelta(int deltaX, int deltaY, boolean onDismiss) {
Adam Cohend4844c32011-02-18 19:25:06 -0800205 updateDeltas(deltaX, deltaY);
Adam Cohen67882692011-03-11 15:29:03 -0800206 DragLayer.LayoutParams lp = (DragLayer.LayoutParams) getLayoutParams();
207
Adam Cohend4844c32011-02-18 19:25:06 -0800208 if (mLeftBorderActive) {
209 lp.x = mBaselineX + mDeltaX;
210 lp.width = mBaselineWidth - mDeltaX;
211 } else if (mRightBorderActive) {
212 lp.width = mBaselineWidth + mDeltaX;
213 }
214
215 if (mTopBorderActive) {
216 lp.y = mBaselineY + mDeltaY;
217 lp.height = mBaselineHeight - mDeltaY;
218 } else if (mBottomBorderActive) {
219 lp.height = mBaselineHeight + mDeltaY;
220 }
221
Adam Cohenbebf0422012-04-11 18:06:28 -0700222 resizeWidgetIfNeeded(onDismiss);
Adam Cohend4844c32011-02-18 19:25:06 -0800223 requestLayout();
224 }
225
Adam Cohen1b607ed2011-03-03 17:26:50 -0800226 /**
227 * Based on the current deltas, we determine if and how to resize the widget.
228 */
Adam Cohenbebf0422012-04-11 18:06:28 -0700229 private void resizeWidgetIfNeeded(boolean onDismiss) {
Adam Cohend4844c32011-02-18 19:25:06 -0800230 int xThreshold = mCellLayout.getCellWidth() + mCellLayout.getWidthGap();
231 int yThreshold = mCellLayout.getCellHeight() + mCellLayout.getHeightGap();
232
Adam Cohenbebf0422012-04-11 18:06:28 -0700233 int deltaX = mDeltaX + mDeltaXAddOn;
234 int deltaY = mDeltaY + mDeltaYAddOn;
235
236 float hSpanIncF = 1.0f * deltaX / xThreshold - mRunningHInc;
237 float vSpanIncF = 1.0f * deltaY / yThreshold - mRunningVInc;
Adam Cohene4b77292011-03-08 18:35:52 -0800238
239 int hSpanInc = 0;
240 int vSpanInc = 0;
Adam Cohend4844c32011-02-18 19:25:06 -0800241 int cellXInc = 0;
242 int cellYInc = 0;
243
Adam Cohenbebf0422012-04-11 18:06:28 -0700244 int countX = mCellLayout.getCountX();
245 int countY = mCellLayout.getCountY();
246
Adam Cohene4b77292011-03-08 18:35:52 -0800247 if (Math.abs(hSpanIncF) > RESIZE_THRESHOLD) {
248 hSpanInc = Math.round(hSpanIncF);
249 }
250 if (Math.abs(vSpanIncF) > RESIZE_THRESHOLD) {
251 vSpanInc = Math.round(vSpanIncF);
252 }
253
Adam Cohenbebf0422012-04-11 18:06:28 -0700254 if (!onDismiss && (hSpanInc == 0 && vSpanInc == 0)) return;
Adam Cohend4844c32011-02-18 19:25:06 -0800255
Adam Cohend4844c32011-02-18 19:25:06 -0800256
257 CellLayout.LayoutParams lp = (CellLayout.LayoutParams) mWidgetView.getLayoutParams();
Adam Cohen1b607ed2011-03-03 17:26:50 -0800258
Adam Cohenbebf0422012-04-11 18:06:28 -0700259 int spanX = lp.cellHSpan;
260 int spanY = lp.cellVSpan;
261 int cellX = lp.useTmpCoords ? lp.tmpCellX : lp.cellX;
262 int cellY = lp.useTmpCoords ? lp.tmpCellY : lp.cellY;
263
264 int hSpanDelta = 0;
265 int vSpanDelta = 0;
266
Adam Cohen1b607ed2011-03-03 17:26:50 -0800267 // For each border, we bound the resizing based on the minimum width, and the maximum
268 // expandability.
Adam Cohend4844c32011-02-18 19:25:06 -0800269 if (mLeftBorderActive) {
Adam Cohenbebf0422012-04-11 18:06:28 -0700270 cellXInc = Math.max(-cellX, hSpanInc);
Adam Cohend4844c32011-02-18 19:25:06 -0800271 cellXInc = Math.min(lp.cellHSpan - mMinHSpan, cellXInc);
272 hSpanInc *= -1;
Adam Cohenbebf0422012-04-11 18:06:28 -0700273 hSpanInc = Math.min(cellX, hSpanInc);
Adam Cohend4844c32011-02-18 19:25:06 -0800274 hSpanInc = Math.max(-(lp.cellHSpan - mMinHSpan), hSpanInc);
Adam Cohenbebf0422012-04-11 18:06:28 -0700275 hSpanDelta = -hSpanInc;
276
Adam Cohend4844c32011-02-18 19:25:06 -0800277 } else if (mRightBorderActive) {
Adam Cohenbebf0422012-04-11 18:06:28 -0700278 hSpanInc = Math.min(countX - (cellX + spanX), hSpanInc);
Adam Cohend4844c32011-02-18 19:25:06 -0800279 hSpanInc = Math.max(-(lp.cellHSpan - mMinHSpan), hSpanInc);
Adam Cohenbebf0422012-04-11 18:06:28 -0700280 hSpanDelta = hSpanInc;
Adam Cohend4844c32011-02-18 19:25:06 -0800281 }
282
283 if (mTopBorderActive) {
Adam Cohenbebf0422012-04-11 18:06:28 -0700284 cellYInc = Math.max(-cellY, vSpanInc);
Adam Cohend4844c32011-02-18 19:25:06 -0800285 cellYInc = Math.min(lp.cellVSpan - mMinVSpan, cellYInc);
286 vSpanInc *= -1;
Adam Cohenbebf0422012-04-11 18:06:28 -0700287 vSpanInc = Math.min(cellY, vSpanInc);
Adam Cohend4844c32011-02-18 19:25:06 -0800288 vSpanInc = Math.max(-(lp.cellVSpan - mMinVSpan), vSpanInc);
Adam Cohenbebf0422012-04-11 18:06:28 -0700289 vSpanDelta = -vSpanInc;
Adam Cohend4844c32011-02-18 19:25:06 -0800290 } else if (mBottomBorderActive) {
Adam Cohenbebf0422012-04-11 18:06:28 -0700291 vSpanInc = Math.min(countY - (cellY + spanY), vSpanInc);
Adam Cohend4844c32011-02-18 19:25:06 -0800292 vSpanInc = Math.max(-(lp.cellVSpan - mMinVSpan), vSpanInc);
Adam Cohenbebf0422012-04-11 18:06:28 -0700293 vSpanDelta = vSpanInc;
Adam Cohend4844c32011-02-18 19:25:06 -0800294 }
295
Adam Cohenbebf0422012-04-11 18:06:28 -0700296 mDirectionVector[0] = 0;
297 mDirectionVector[1] = 0;
Adam Cohend4844c32011-02-18 19:25:06 -0800298 // Update the widget's dimensions and position according to the deltas computed above
299 if (mLeftBorderActive || mRightBorderActive) {
Adam Cohenbebf0422012-04-11 18:06:28 -0700300 spanX += hSpanInc;
301 cellX += cellXInc;
Adam Cohene0489502012-08-27 15:18:53 -0700302 if (hSpanDelta != 0) {
303 mDirectionVector[0] = mLeftBorderActive ? -1 : 1;
304 }
Adam Cohend4844c32011-02-18 19:25:06 -0800305 }
306
307 if (mTopBorderActive || mBottomBorderActive) {
Adam Cohenbebf0422012-04-11 18:06:28 -0700308 spanY += vSpanInc;
309 cellY += cellYInc;
Adam Cohene0489502012-08-27 15:18:53 -0700310 if (vSpanDelta != 0) {
311 mDirectionVector[1] = mTopBorderActive ? -1 : 1;
312 }
Adam Cohend4844c32011-02-18 19:25:06 -0800313 }
314
Adam Cohenbebf0422012-04-11 18:06:28 -0700315 if (!onDismiss && vSpanDelta == 0 && hSpanDelta == 0) return;
Adam Cohend4844c32011-02-18 19:25:06 -0800316
Adam Cohene0489502012-08-27 15:18:53 -0700317 // We always want the final commit to match the feedback, so we make sure to use the
318 // last used direction vector when committing the resize / reorder.
319 if (onDismiss) {
320 mDirectionVector[0] = mLastDirectionVector[0];
321 mDirectionVector[1] = mLastDirectionVector[1];
322 } else {
323 mLastDirectionVector[0] = mDirectionVector[0];
324 mLastDirectionVector[1] = mDirectionVector[1];
325 }
326
Adam Cohenbebf0422012-04-11 18:06:28 -0700327 if (mCellLayout.createAreaForResize(cellX, cellY, spanX, spanY, mWidgetView,
328 mDirectionVector, onDismiss)) {
Sunny Goyale78e3d72015-09-24 11:23:31 -0700329 if (mStateAnnouncer != null && (lp.cellHSpan != spanX || lp.cellVSpan != spanY) ) {
330 mStateAnnouncer.announce(
331 mLauncher.getString(R.string.widget_resized, spanX, spanY));
332 }
333
Adam Cohenbebf0422012-04-11 18:06:28 -0700334 lp.tmpCellX = cellX;
335 lp.tmpCellY = cellY;
336 lp.cellHSpan = spanX;
337 lp.cellVSpan = spanY;
338 mRunningVInc += vSpanDelta;
339 mRunningHInc += hSpanDelta;
Sunny Goyale78e3d72015-09-24 11:23:31 -0700340
Adam Cohena897f392012-04-27 18:12:05 -0700341 if (!onDismiss) {
342 updateWidgetSizeRanges(mWidgetView, mLauncher, spanX, spanY);
343 }
Adam Cohenbebf0422012-04-11 18:06:28 -0700344 }
Adam Cohen67882692011-03-11 15:29:03 -0800345 mWidgetView.requestLayout();
Adam Cohend4844c32011-02-18 19:25:06 -0800346 }
347
Adam Cohena897f392012-04-27 18:12:05 -0700348 static void updateWidgetSizeRanges(AppWidgetHostView widgetView, Launcher launcher,
349 int spanX, int spanY) {
Sunny Goyalba776d52015-05-18 20:52:57 -0700350 getWidgetSizeRanges(launcher, spanX, spanY, sTmpRect);
351 widgetView.updateAppWidgetSize(null, sTmpRect.left, sTmpRect.top,
352 sTmpRect.right, sTmpRect.bottom);
Adam Cohen9e05a5e2012-09-10 15:53:09 -0700353 }
354
Hyunyoung Songb99ff3e2015-04-23 15:17:50 -0700355 public static Rect getWidgetSizeRanges(Launcher launcher, int spanX, int spanY, Rect rect) {
Adam Cohen9e05a5e2012-09-10 15:53:09 -0700356 if (rect == null) {
357 rect = new Rect();
358 }
Adam Cohena897f392012-04-27 18:12:05 -0700359 Rect landMetrics = Workspace.getCellLayoutMetrics(launcher, CellLayout.LANDSCAPE);
360 Rect portMetrics = Workspace.getCellLayoutMetrics(launcher, CellLayout.PORTRAIT);
361 final float density = launcher.getResources().getDisplayMetrics().density;
362
363 // Compute landscape size
364 int cellWidth = landMetrics.left;
365 int cellHeight = landMetrics.top;
366 int widthGap = landMetrics.right;
367 int heightGap = landMetrics.bottom;
368 int landWidth = (int) ((spanX * cellWidth + (spanX - 1) * widthGap) / density);
369 int landHeight = (int) ((spanY * cellHeight + (spanY - 1) * heightGap) / density);
370
371 // Compute portrait size
372 cellWidth = portMetrics.left;
373 cellHeight = portMetrics.top;
374 widthGap = portMetrics.right;
375 heightGap = portMetrics.bottom;
376 int portWidth = (int) ((spanX * cellWidth + (spanX - 1) * widthGap) / density);
377 int portHeight = (int) ((spanY * cellHeight + (spanY - 1) * heightGap) / density);
Adam Cohen9e05a5e2012-09-10 15:53:09 -0700378 rect.set(portWidth, landHeight, landWidth, portHeight);
379 return rect;
Adam Cohena897f392012-04-27 18:12:05 -0700380 }
381
Adam Cohen1b607ed2011-03-03 17:26:50 -0800382 /**
383 * This is the final step of the resize. Here we save the new widget size and position
384 * to LauncherModel and animate the resize frame.
385 */
Adam Cohenbebf0422012-04-11 18:06:28 -0700386 public void commitResize() {
387 resizeWidgetIfNeeded(true);
388 requestLayout();
389 }
Adam Cohend4844c32011-02-18 19:25:06 -0800390
Adam Cohenbebf0422012-04-11 18:06:28 -0700391 public void onTouchUp() {
392 int xThreshold = mCellLayout.getCellWidth() + mCellLayout.getWidthGap();
393 int yThreshold = mCellLayout.getCellHeight() + mCellLayout.getHeightGap();
Adam Cohend4844c32011-02-18 19:25:06 -0800394
Adam Cohenbebf0422012-04-11 18:06:28 -0700395 mDeltaXAddOn = mRunningHInc * xThreshold;
396 mDeltaYAddOn = mRunningVInc * yThreshold;
397 mDeltaX = 0;
398 mDeltaY = 0;
399
Adam Cohend4844c32011-02-18 19:25:06 -0800400 post(new Runnable() {
Adam Cohenbebf0422012-04-11 18:06:28 -0700401 @Override
Adam Cohend4844c32011-02-18 19:25:06 -0800402 public void run() {
403 snapToWidget(true);
404 }
405 });
406 }
407
408 public void snapToWidget(boolean animate) {
Adam Cohen67882692011-03-11 15:29:03 -0800409 final DragLayer.LayoutParams lp = (DragLayer.LayoutParams) getLayoutParams();
Sunny Goyalba776d52015-05-18 20:52:57 -0700410 int newWidth = mWidgetView.getWidth() + 2 * mBackgroundPadding
411 - mWidgetPadding.left - mWidgetPadding.right;
412 int newHeight = mWidgetView.getHeight() + 2 * mBackgroundPadding
413 - mWidgetPadding.top - mWidgetPadding.bottom;
Adam Cohen37b59ff2011-06-13 17:13:42 -0700414
Adam Cohend6e7aa32013-07-09 15:32:37 -0700415 mTmpPt[0] = mWidgetView.getLeft();
416 mTmpPt[1] = mWidgetView.getTop();
417 mDragLayer.getDescendantCoordRelativeToSelf(mCellLayout.getShortcutsAndWidgets(), mTmpPt);
418
Sunny Goyalba776d52015-05-18 20:52:57 -0700419 int newX = mTmpPt[0] - mBackgroundPadding + mWidgetPadding.left;
420 int newY = mTmpPt[1] - mBackgroundPadding + mWidgetPadding.top;
Adam Cohen3cba7222011-03-02 19:03:11 -0800421
Sunny Goyalba776d52015-05-18 20:52:57 -0700422 // We need to make sure the frame's touchable regions lie fully within the bounds of the
Adam Cohen4459d6b2012-07-13 15:59:15 -0700423 // DragLayer. We allow the actual handles to be clipped, but we shift the touch regions
424 // down accordingly to provide a proper touch target.
Adam Cohen3cba7222011-03-02 19:03:11 -0800425 if (newY < 0) {
Adam Cohen4459d6b2012-07-13 15:59:15 -0700426 // In this case we shift the touch region down to start at the top of the DragLayer
427 mTopTouchRegionAdjustment = -newY;
428 } else {
429 mTopTouchRegionAdjustment = 0;
Adam Cohen3cba7222011-03-02 19:03:11 -0800430 }
Adam Cohen67882692011-03-11 15:29:03 -0800431 if (newY + newHeight > mDragLayer.getHeight()) {
Adam Cohen4459d6b2012-07-13 15:59:15 -0700432 // In this case we shift the touch region up to end at the bottom of the DragLayer
433 mBottomTouchRegionAdjustment = -(newY + newHeight - mDragLayer.getHeight());
434 } else {
435 mBottomTouchRegionAdjustment = 0;
Adam Cohen3cba7222011-03-02 19:03:11 -0800436 }
437
Adam Cohend4844c32011-02-18 19:25:06 -0800438 if (!animate) {
439 lp.width = newWidth;
440 lp.height = newHeight;
441 lp.x = newX;
442 lp.y = newY;
443 mLeftHandle.setAlpha(1.0f);
444 mRightHandle.setAlpha(1.0f);
445 mTopHandle.setAlpha(1.0f);
446 mBottomHandle.setAlpha(1.0f);
447 requestLayout();
448 } else {
449 PropertyValuesHolder width = PropertyValuesHolder.ofInt("width", lp.width, newWidth);
Adam Cohen1b607ed2011-03-03 17:26:50 -0800450 PropertyValuesHolder height = PropertyValuesHolder.ofInt("height", lp.height,
451 newHeight);
Adam Cohend4844c32011-02-18 19:25:06 -0800452 PropertyValuesHolder x = PropertyValuesHolder.ofInt("x", lp.x, newX);
453 PropertyValuesHolder y = PropertyValuesHolder.ofInt("y", lp.y, newY);
Michael Jurkaf1ad6082013-03-13 12:55:46 +0100454 ObjectAnimator oa =
455 LauncherAnimUtils.ofPropertyValuesHolder(lp, this, width, height, x, y);
Michael Jurka2ecf9952012-06-18 12:52:28 -0700456 ObjectAnimator leftOa = LauncherAnimUtils.ofFloat(mLeftHandle, "alpha", 1.0f);
457 ObjectAnimator rightOa = LauncherAnimUtils.ofFloat(mRightHandle, "alpha", 1.0f);
458 ObjectAnimator topOa = LauncherAnimUtils.ofFloat(mTopHandle, "alpha", 1.0f);
459 ObjectAnimator bottomOa = LauncherAnimUtils.ofFloat(mBottomHandle, "alpha", 1.0f);
Adam Cohend4844c32011-02-18 19:25:06 -0800460 oa.addUpdateListener(new AnimatorUpdateListener() {
461 public void onAnimationUpdate(ValueAnimator animation) {
462 requestLayout();
463 }
464 });
Michael Jurka2ecf9952012-06-18 12:52:28 -0700465 AnimatorSet set = LauncherAnimUtils.createAnimatorSet();
Adam Cohend4844c32011-02-18 19:25:06 -0800466 if (mResizeMode == AppWidgetProviderInfo.RESIZE_VERTICAL) {
467 set.playTogether(oa, topOa, bottomOa);
468 } else if (mResizeMode == AppWidgetProviderInfo.RESIZE_HORIZONTAL) {
469 set.playTogether(oa, leftOa, rightOa);
470 } else {
471 set.playTogether(oa, leftOa, rightOa, topOa, bottomOa);
472 }
473
474 set.setDuration(SNAP_DURATION);
475 set.start();
476 }
477 }
478}