blob: 6b7ff886c1aacfb50357dd946f45e8b961a45914 [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;
Tony Wickham71255bb2016-02-10 16:18:15 -080014import android.view.KeyEvent;
15import android.view.View;
Adam Cohend4844c32011-02-18 19:25:06 -080016import android.widget.FrameLayout;
17import android.widget.ImageView;
18
Sunny Goyale78e3d72015-09-24 11:23:31 -070019import com.android.launcher3.accessibility.DragViewStateAnnouncer;
Tony Wickham71255bb2016-02-10 16:18:15 -080020import com.android.launcher3.util.FocusLogic;
Sunny Goyale78e3d72015-09-24 11:23:31 -070021
Tony Wickham71255bb2016-02-10 16:18:15 -080022public class AppWidgetResizeFrame extends FrameLayout implements View.OnKeyListener {
Sunny Goyalba776d52015-05-18 20:52:57 -070023 private static final int SNAP_DURATION = 150;
24 private static final float DIMMED_HANDLE_ALPHA = 0f;
25 private static final float RESIZE_THRESHOLD = 0.66f;
26
27 private static Rect sTmpRect = new Rect();
28
29 private final Launcher mLauncher;
30 private final LauncherAppWidgetHostView mWidgetView;
31 private final CellLayout mCellLayout;
32 private final DragLayer mDragLayer;
33
34 private final ImageView mLeftHandle;
35 private final ImageView mRightHandle;
36 private final ImageView mTopHandle;
37 private final ImageView mBottomHandle;
38
39 private final Rect mWidgetPadding;
40
41 private final int mBackgroundPadding;
42 private final int mTouchTargetWidth;
43
44 private final int[] mDirectionVector = new int[2];
45 private final int[] mLastDirectionVector = new int[2];
46 private final int[] mTmpPt = new int[2];
Adam Cohend4844c32011-02-18 19:25:06 -080047
Sunny Goyale78e3d72015-09-24 11:23:31 -070048 private final DragViewStateAnnouncer mStateAnnouncer;
49
Adam Cohend4844c32011-02-18 19:25:06 -080050 private boolean mLeftBorderActive;
51 private boolean mRightBorderActive;
52 private boolean mTopBorderActive;
53 private boolean mBottomBorderActive;
54
55 private int mBaselineWidth;
56 private int mBaselineHeight;
57 private int mBaselineX;
58 private int mBaselineY;
59 private int mResizeMode;
Adam Cohen3cba7222011-03-02 19:03:11 -080060
Adam Cohend4844c32011-02-18 19:25:06 -080061 private int mRunningHInc;
62 private int mRunningVInc;
63 private int mMinHSpan;
64 private int mMinVSpan;
65 private int mDeltaX;
66 private int mDeltaY;
Adam Cohenbebf0422012-04-11 18:06:28 -070067 private int mDeltaXAddOn;
68 private int mDeltaYAddOn;
Adam Cohen1b607ed2011-03-03 17:26:50 -080069
Adam Cohen4459d6b2012-07-13 15:59:15 -070070 private int mTopTouchRegionAdjustment = 0;
71 private int mBottomTouchRegionAdjustment = 0;
72
Michael Jurka3a9fced2012-04-13 14:44:29 -070073 public AppWidgetResizeFrame(Context context,
Adam Cohen67882692011-03-11 15:29:03 -080074 LauncherAppWidgetHostView widgetView, CellLayout cellLayout, DragLayer dragLayer) {
Adam Cohend4844c32011-02-18 19:25:06 -080075
76 super(context);
Adam Cohencbf47e32011-09-16 17:32:37 -070077 mLauncher = (Launcher) context;
Adam Cohend4844c32011-02-18 19:25:06 -080078 mCellLayout = cellLayout;
79 mWidgetView = widgetView;
Adam Cohen59400422014-03-05 18:07:04 -080080 LauncherAppWidgetProviderInfo info = (LauncherAppWidgetProviderInfo)
81 widgetView.getAppWidgetInfo();
82 mResizeMode = info.resizeMode;
Adam Cohen67882692011-03-11 15:29:03 -080083 mDragLayer = dragLayer;
Adam Cohen3cba7222011-03-02 19:03:11 -080084
Sunny Goyal233ee962015-08-03 13:05:01 -070085 mMinHSpan = info.minSpanX;
86 mMinVSpan = info.minSpanY;
Adam Cohend4844c32011-02-18 19:25:06 -080087
Sunny Goyale78e3d72015-09-24 11:23:31 -070088 mStateAnnouncer = DragViewStateAnnouncer.createFor(this);
89
Sunny Goyalba776d52015-05-18 20:52:57 -070090 setBackgroundResource(R.drawable.widget_resize_shadow);
91 setForeground(getResources().getDrawable(R.drawable.widget_resize_frame));
Adam Cohend4844c32011-02-18 19:25:06 -080092 setPadding(0, 0, 0, 0);
93
Sunny Goyalba776d52015-05-18 20:52:57 -070094 final int handleMargin = getResources().getDimensionPixelSize(R.dimen.widget_handle_margin);
Adam Cohend4844c32011-02-18 19:25:06 -080095 LayoutParams lp;
96 mLeftHandle = new ImageView(context);
Sunny Goyalba776d52015-05-18 20:52:57 -070097 mLeftHandle.setImageResource(R.drawable.ic_widget_resize_handle);
98 lp = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT,
Adam Cohen283dcbe2013-09-26 16:35:40 -070099 Gravity.LEFT | Gravity.CENTER_VERTICAL);
Sunny Goyalba776d52015-05-18 20:52:57 -0700100 lp.leftMargin = handleMargin;
Adam Cohend4844c32011-02-18 19:25:06 -0800101 addView(mLeftHandle, lp);
102
103 mRightHandle = new ImageView(context);
Sunny Goyalba776d52015-05-18 20:52:57 -0700104 mRightHandle.setImageResource(R.drawable.ic_widget_resize_handle);
105 lp = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT,
Adam Cohen283dcbe2013-09-26 16:35:40 -0700106 Gravity.RIGHT | Gravity.CENTER_VERTICAL);
Sunny Goyalba776d52015-05-18 20:52:57 -0700107 lp.rightMargin = handleMargin;
Adam Cohend4844c32011-02-18 19:25:06 -0800108 addView(mRightHandle, lp);
109
110 mTopHandle = new ImageView(context);
Sunny Goyalba776d52015-05-18 20:52:57 -0700111 mTopHandle.setImageResource(R.drawable.ic_widget_resize_handle);
112 lp = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT,
Adam Cohend4844c32011-02-18 19:25:06 -0800113 Gravity.CENTER_HORIZONTAL | Gravity.TOP);
Sunny Goyalba776d52015-05-18 20:52:57 -0700114 lp.topMargin = handleMargin;
Adam Cohend4844c32011-02-18 19:25:06 -0800115 addView(mTopHandle, lp);
116
117 mBottomHandle = new ImageView(context);
Sunny Goyalba776d52015-05-18 20:52:57 -0700118 mBottomHandle.setImageResource(R.drawable.ic_widget_resize_handle);
119 lp = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT,
Adam Cohend4844c32011-02-18 19:25:06 -0800120 Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM);
Sunny Goyalba776d52015-05-18 20:52:57 -0700121 lp.bottomMargin = handleMargin;
Adam Cohend4844c32011-02-18 19:25:06 -0800122 addView(mBottomHandle, lp);
123
Adam Cohen59400422014-03-05 18:07:04 -0800124 if (!info.isCustomWidget) {
Sunny Goyalba776d52015-05-18 20:52:57 -0700125 mWidgetPadding = AppWidgetHostView.getDefaultPaddingForWidget(context,
Adam Cohen59400422014-03-05 18:07:04 -0800126 widgetView.getAppWidgetInfo().provider, null);
127 } else {
128 Resources r = context.getResources();
129 int padding = r.getDimensionPixelSize(R.dimen.default_widget_padding);
Sunny Goyalba776d52015-05-18 20:52:57 -0700130 mWidgetPadding = new Rect(padding, padding, padding, padding);
Adam Cohen59400422014-03-05 18:07:04 -0800131 }
132
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
Sunny Goyalba776d52015-05-18 20:52:57 -0700141 mBackgroundPadding = getResources()
142 .getDimensionPixelSize(R.dimen.resize_frame_background_padding);
Adam Cohen3cba7222011-03-02 19:03:11 -0800143 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);
Tony Wickham71255bb2016-02-10 16:18:15 -0800149
150 setOnKeyListener(this);
Adam Cohend4844c32011-02-18 19:25:06 -0800151 }
152
153 public boolean beginResizeIfPointInRegion(int x, int y) {
154 boolean horizontalActive = (mResizeMode & AppWidgetProviderInfo.RESIZE_HORIZONTAL) != 0;
155 boolean verticalActive = (mResizeMode & AppWidgetProviderInfo.RESIZE_VERTICAL) != 0;
Adam Cohen4459d6b2012-07-13 15:59:15 -0700156
Adam Cohen3cba7222011-03-02 19:03:11 -0800157 mLeftBorderActive = (x < mTouchTargetWidth) && horizontalActive;
158 mRightBorderActive = (x > getWidth() - mTouchTargetWidth) && horizontalActive;
Adam Cohen4459d6b2012-07-13 15:59:15 -0700159 mTopBorderActive = (y < mTouchTargetWidth + mTopTouchRegionAdjustment) && verticalActive;
160 mBottomBorderActive = (y > getHeight() - mTouchTargetWidth + mBottomTouchRegionAdjustment)
161 && verticalActive;
Adam Cohend4844c32011-02-18 19:25:06 -0800162
163 boolean anyBordersActive = mLeftBorderActive || mRightBorderActive
164 || mTopBorderActive || mBottomBorderActive;
165
166 mBaselineWidth = getMeasuredWidth();
167 mBaselineHeight = getMeasuredHeight();
168 mBaselineX = getLeft();
169 mBaselineY = getTop();
Adam Cohend4844c32011-02-18 19:25:06 -0800170
171 if (anyBordersActive) {
Adam Cohen3cba7222011-03-02 19:03:11 -0800172 mLeftHandle.setAlpha(mLeftBorderActive ? 1.0f : DIMMED_HANDLE_ALPHA);
173 mRightHandle.setAlpha(mRightBorderActive ? 1.0f :DIMMED_HANDLE_ALPHA);
174 mTopHandle.setAlpha(mTopBorderActive ? 1.0f : DIMMED_HANDLE_ALPHA);
175 mBottomHandle.setAlpha(mBottomBorderActive ? 1.0f : DIMMED_HANDLE_ALPHA);
Adam Cohend4844c32011-02-18 19:25:06 -0800176 }
Adam Cohend4844c32011-02-18 19:25:06 -0800177 return anyBordersActive;
178 }
179
Adam Cohen1b607ed2011-03-03 17:26:50 -0800180 /**
181 * Here we bound the deltas such that the frame cannot be stretched beyond the extents
182 * of the CellLayout, and such that the frame's borders can't cross.
183 */
Adam Cohend4844c32011-02-18 19:25:06 -0800184 public void updateDeltas(int deltaX, int deltaY) {
185 if (mLeftBorderActive) {
186 mDeltaX = Math.max(-mBaselineX, deltaX);
Adam Cohen3cba7222011-03-02 19:03:11 -0800187 mDeltaX = Math.min(mBaselineWidth - 2 * mTouchTargetWidth, mDeltaX);
Adam Cohend4844c32011-02-18 19:25:06 -0800188 } else if (mRightBorderActive) {
Adam Cohen67882692011-03-11 15:29:03 -0800189 mDeltaX = Math.min(mDragLayer.getWidth() - (mBaselineX + mBaselineWidth), deltaX);
Adam Cohen3cba7222011-03-02 19:03:11 -0800190 mDeltaX = Math.max(-mBaselineWidth + 2 * mTouchTargetWidth, mDeltaX);
Adam Cohend4844c32011-02-18 19:25:06 -0800191 }
192
193 if (mTopBorderActive) {
194 mDeltaY = Math.max(-mBaselineY, deltaY);
Adam Cohen3cba7222011-03-02 19:03:11 -0800195 mDeltaY = Math.min(mBaselineHeight - 2 * mTouchTargetWidth, mDeltaY);
Adam Cohend4844c32011-02-18 19:25:06 -0800196 } else if (mBottomBorderActive) {
Adam Cohen67882692011-03-11 15:29:03 -0800197 mDeltaY = Math.min(mDragLayer.getHeight() - (mBaselineY + mBaselineHeight), deltaY);
Adam Cohen3cba7222011-03-02 19:03:11 -0800198 mDeltaY = Math.max(-mBaselineHeight + 2 * mTouchTargetWidth, mDeltaY);
Adam Cohend4844c32011-02-18 19:25:06 -0800199 }
200 }
201
Adam Cohenbebf0422012-04-11 18:06:28 -0700202 public void visualizeResizeForDelta(int deltaX, int deltaY) {
203 visualizeResizeForDelta(deltaX, deltaY, false);
204 }
205
Adam Cohen1b607ed2011-03-03 17:26:50 -0800206 /**
207 * Based on the deltas, we resize the frame, and, if needed, we resize the widget.
208 */
Adam Cohenbebf0422012-04-11 18:06:28 -0700209 private void visualizeResizeForDelta(int deltaX, int deltaY, boolean onDismiss) {
Adam Cohend4844c32011-02-18 19:25:06 -0800210 updateDeltas(deltaX, deltaY);
Adam Cohen67882692011-03-11 15:29:03 -0800211 DragLayer.LayoutParams lp = (DragLayer.LayoutParams) getLayoutParams();
212
Adam Cohend4844c32011-02-18 19:25:06 -0800213 if (mLeftBorderActive) {
214 lp.x = mBaselineX + mDeltaX;
215 lp.width = mBaselineWidth - mDeltaX;
216 } else if (mRightBorderActive) {
217 lp.width = mBaselineWidth + mDeltaX;
218 }
219
220 if (mTopBorderActive) {
221 lp.y = mBaselineY + mDeltaY;
222 lp.height = mBaselineHeight - mDeltaY;
223 } else if (mBottomBorderActive) {
224 lp.height = mBaselineHeight + mDeltaY;
225 }
226
Adam Cohenbebf0422012-04-11 18:06:28 -0700227 resizeWidgetIfNeeded(onDismiss);
Adam Cohend4844c32011-02-18 19:25:06 -0800228 requestLayout();
229 }
230
Adam Cohen1b607ed2011-03-03 17:26:50 -0800231 /**
232 * Based on the current deltas, we determine if and how to resize the widget.
233 */
Adam Cohenbebf0422012-04-11 18:06:28 -0700234 private void resizeWidgetIfNeeded(boolean onDismiss) {
Adam Cohend4844c32011-02-18 19:25:06 -0800235 int xThreshold = mCellLayout.getCellWidth() + mCellLayout.getWidthGap();
236 int yThreshold = mCellLayout.getCellHeight() + mCellLayout.getHeightGap();
237
Adam Cohenbebf0422012-04-11 18:06:28 -0700238 int deltaX = mDeltaX + mDeltaXAddOn;
239 int deltaY = mDeltaY + mDeltaYAddOn;
240
241 float hSpanIncF = 1.0f * deltaX / xThreshold - mRunningHInc;
242 float vSpanIncF = 1.0f * deltaY / yThreshold - mRunningVInc;
Adam Cohene4b77292011-03-08 18:35:52 -0800243
244 int hSpanInc = 0;
245 int vSpanInc = 0;
Adam Cohend4844c32011-02-18 19:25:06 -0800246 int cellXInc = 0;
247 int cellYInc = 0;
248
Adam Cohenbebf0422012-04-11 18:06:28 -0700249 int countX = mCellLayout.getCountX();
250 int countY = mCellLayout.getCountY();
251
Adam Cohene4b77292011-03-08 18:35:52 -0800252 if (Math.abs(hSpanIncF) > RESIZE_THRESHOLD) {
253 hSpanInc = Math.round(hSpanIncF);
254 }
255 if (Math.abs(vSpanIncF) > RESIZE_THRESHOLD) {
256 vSpanInc = Math.round(vSpanIncF);
257 }
258
Adam Cohenbebf0422012-04-11 18:06:28 -0700259 if (!onDismiss && (hSpanInc == 0 && vSpanInc == 0)) return;
Adam Cohend4844c32011-02-18 19:25:06 -0800260
Adam Cohend4844c32011-02-18 19:25:06 -0800261
262 CellLayout.LayoutParams lp = (CellLayout.LayoutParams) mWidgetView.getLayoutParams();
Adam Cohen1b607ed2011-03-03 17:26:50 -0800263
Adam Cohenbebf0422012-04-11 18:06:28 -0700264 int spanX = lp.cellHSpan;
265 int spanY = lp.cellVSpan;
266 int cellX = lp.useTmpCoords ? lp.tmpCellX : lp.cellX;
267 int cellY = lp.useTmpCoords ? lp.tmpCellY : lp.cellY;
268
269 int hSpanDelta = 0;
270 int vSpanDelta = 0;
271
Adam Cohen1b607ed2011-03-03 17:26:50 -0800272 // For each border, we bound the resizing based on the minimum width, and the maximum
273 // expandability.
Adam Cohend4844c32011-02-18 19:25:06 -0800274 if (mLeftBorderActive) {
Adam Cohenbebf0422012-04-11 18:06:28 -0700275 cellXInc = Math.max(-cellX, hSpanInc);
Adam Cohend4844c32011-02-18 19:25:06 -0800276 cellXInc = Math.min(lp.cellHSpan - mMinHSpan, cellXInc);
277 hSpanInc *= -1;
Adam Cohenbebf0422012-04-11 18:06:28 -0700278 hSpanInc = Math.min(cellX, 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;
281
Adam Cohend4844c32011-02-18 19:25:06 -0800282 } else if (mRightBorderActive) {
Adam Cohenbebf0422012-04-11 18:06:28 -0700283 hSpanInc = Math.min(countX - (cellX + spanX), hSpanInc);
Adam Cohend4844c32011-02-18 19:25:06 -0800284 hSpanInc = Math.max(-(lp.cellHSpan - mMinHSpan), hSpanInc);
Adam Cohenbebf0422012-04-11 18:06:28 -0700285 hSpanDelta = hSpanInc;
Adam Cohend4844c32011-02-18 19:25:06 -0800286 }
287
288 if (mTopBorderActive) {
Adam Cohenbebf0422012-04-11 18:06:28 -0700289 cellYInc = Math.max(-cellY, vSpanInc);
Adam Cohend4844c32011-02-18 19:25:06 -0800290 cellYInc = Math.min(lp.cellVSpan - mMinVSpan, cellYInc);
291 vSpanInc *= -1;
Adam Cohenbebf0422012-04-11 18:06:28 -0700292 vSpanInc = Math.min(cellY, vSpanInc);
Adam Cohend4844c32011-02-18 19:25:06 -0800293 vSpanInc = Math.max(-(lp.cellVSpan - mMinVSpan), vSpanInc);
Adam Cohenbebf0422012-04-11 18:06:28 -0700294 vSpanDelta = -vSpanInc;
Adam Cohend4844c32011-02-18 19:25:06 -0800295 } else if (mBottomBorderActive) {
Adam Cohenbebf0422012-04-11 18:06:28 -0700296 vSpanInc = Math.min(countY - (cellY + spanY), vSpanInc);
Adam Cohend4844c32011-02-18 19:25:06 -0800297 vSpanInc = Math.max(-(lp.cellVSpan - mMinVSpan), vSpanInc);
Adam Cohenbebf0422012-04-11 18:06:28 -0700298 vSpanDelta = vSpanInc;
Adam Cohend4844c32011-02-18 19:25:06 -0800299 }
300
Adam Cohenbebf0422012-04-11 18:06:28 -0700301 mDirectionVector[0] = 0;
302 mDirectionVector[1] = 0;
Adam Cohend4844c32011-02-18 19:25:06 -0800303 // Update the widget's dimensions and position according to the deltas computed above
304 if (mLeftBorderActive || mRightBorderActive) {
Adam Cohenbebf0422012-04-11 18:06:28 -0700305 spanX += hSpanInc;
306 cellX += cellXInc;
Adam Cohene0489502012-08-27 15:18:53 -0700307 if (hSpanDelta != 0) {
308 mDirectionVector[0] = mLeftBorderActive ? -1 : 1;
309 }
Adam Cohend4844c32011-02-18 19:25:06 -0800310 }
311
312 if (mTopBorderActive || mBottomBorderActive) {
Adam Cohenbebf0422012-04-11 18:06:28 -0700313 spanY += vSpanInc;
314 cellY += cellYInc;
Adam Cohene0489502012-08-27 15:18:53 -0700315 if (vSpanDelta != 0) {
316 mDirectionVector[1] = mTopBorderActive ? -1 : 1;
317 }
Adam Cohend4844c32011-02-18 19:25:06 -0800318 }
319
Adam Cohenbebf0422012-04-11 18:06:28 -0700320 if (!onDismiss && vSpanDelta == 0 && hSpanDelta == 0) return;
Adam Cohend4844c32011-02-18 19:25:06 -0800321
Adam Cohene0489502012-08-27 15:18:53 -0700322 // We always want the final commit to match the feedback, so we make sure to use the
323 // last used direction vector when committing the resize / reorder.
324 if (onDismiss) {
325 mDirectionVector[0] = mLastDirectionVector[0];
326 mDirectionVector[1] = mLastDirectionVector[1];
327 } else {
328 mLastDirectionVector[0] = mDirectionVector[0];
329 mLastDirectionVector[1] = mDirectionVector[1];
330 }
331
Adam Cohenbebf0422012-04-11 18:06:28 -0700332 if (mCellLayout.createAreaForResize(cellX, cellY, spanX, spanY, mWidgetView,
333 mDirectionVector, onDismiss)) {
Sunny Goyale78e3d72015-09-24 11:23:31 -0700334 if (mStateAnnouncer != null && (lp.cellHSpan != spanX || lp.cellVSpan != spanY) ) {
335 mStateAnnouncer.announce(
336 mLauncher.getString(R.string.widget_resized, spanX, spanY));
337 }
338
Adam Cohenbebf0422012-04-11 18:06:28 -0700339 lp.tmpCellX = cellX;
340 lp.tmpCellY = cellY;
341 lp.cellHSpan = spanX;
342 lp.cellVSpan = spanY;
343 mRunningVInc += vSpanDelta;
344 mRunningHInc += hSpanDelta;
Sunny Goyale78e3d72015-09-24 11:23:31 -0700345
Adam Cohena897f392012-04-27 18:12:05 -0700346 if (!onDismiss) {
347 updateWidgetSizeRanges(mWidgetView, mLauncher, spanX, spanY);
348 }
Adam Cohenbebf0422012-04-11 18:06:28 -0700349 }
Adam Cohen67882692011-03-11 15:29:03 -0800350 mWidgetView.requestLayout();
Adam Cohend4844c32011-02-18 19:25:06 -0800351 }
352
Adam Cohena897f392012-04-27 18:12:05 -0700353 static void updateWidgetSizeRanges(AppWidgetHostView widgetView, Launcher launcher,
354 int spanX, int spanY) {
Sunny Goyalba776d52015-05-18 20:52:57 -0700355 getWidgetSizeRanges(launcher, spanX, spanY, sTmpRect);
356 widgetView.updateAppWidgetSize(null, sTmpRect.left, sTmpRect.top,
357 sTmpRect.right, sTmpRect.bottom);
Adam Cohen9e05a5e2012-09-10 15:53:09 -0700358 }
359
Hyunyoung Songb99ff3e2015-04-23 15:17:50 -0700360 public static Rect getWidgetSizeRanges(Launcher launcher, int spanX, int spanY, Rect rect) {
Adam Cohen9e05a5e2012-09-10 15:53:09 -0700361 if (rect == null) {
362 rect = new Rect();
363 }
Adam Cohena897f392012-04-27 18:12:05 -0700364 Rect landMetrics = Workspace.getCellLayoutMetrics(launcher, CellLayout.LANDSCAPE);
365 Rect portMetrics = Workspace.getCellLayoutMetrics(launcher, CellLayout.PORTRAIT);
366 final float density = launcher.getResources().getDisplayMetrics().density;
367
368 // Compute landscape size
369 int cellWidth = landMetrics.left;
370 int cellHeight = landMetrics.top;
371 int widthGap = landMetrics.right;
372 int heightGap = landMetrics.bottom;
373 int landWidth = (int) ((spanX * cellWidth + (spanX - 1) * widthGap) / density);
374 int landHeight = (int) ((spanY * cellHeight + (spanY - 1) * heightGap) / density);
375
376 // Compute portrait size
377 cellWidth = portMetrics.left;
378 cellHeight = portMetrics.top;
379 widthGap = portMetrics.right;
380 heightGap = portMetrics.bottom;
381 int portWidth = (int) ((spanX * cellWidth + (spanX - 1) * widthGap) / density);
382 int portHeight = (int) ((spanY * cellHeight + (spanY - 1) * heightGap) / density);
Adam Cohen9e05a5e2012-09-10 15:53:09 -0700383 rect.set(portWidth, landHeight, landWidth, portHeight);
384 return rect;
Adam Cohena897f392012-04-27 18:12:05 -0700385 }
386
Adam Cohen1b607ed2011-03-03 17:26:50 -0800387 /**
388 * This is the final step of the resize. Here we save the new widget size and position
389 * to LauncherModel and animate the resize frame.
390 */
Adam Cohenbebf0422012-04-11 18:06:28 -0700391 public void commitResize() {
392 resizeWidgetIfNeeded(true);
393 requestLayout();
394 }
Adam Cohend4844c32011-02-18 19:25:06 -0800395
Adam Cohenbebf0422012-04-11 18:06:28 -0700396 public void onTouchUp() {
397 int xThreshold = mCellLayout.getCellWidth() + mCellLayout.getWidthGap();
398 int yThreshold = mCellLayout.getCellHeight() + mCellLayout.getHeightGap();
Adam Cohend4844c32011-02-18 19:25:06 -0800399
Adam Cohenbebf0422012-04-11 18:06:28 -0700400 mDeltaXAddOn = mRunningHInc * xThreshold;
401 mDeltaYAddOn = mRunningVInc * yThreshold;
402 mDeltaX = 0;
403 mDeltaY = 0;
404
Adam Cohend4844c32011-02-18 19:25:06 -0800405 post(new Runnable() {
Adam Cohenbebf0422012-04-11 18:06:28 -0700406 @Override
Adam Cohend4844c32011-02-18 19:25:06 -0800407 public void run() {
408 snapToWidget(true);
409 }
410 });
411 }
412
413 public void snapToWidget(boolean animate) {
Adam Cohen67882692011-03-11 15:29:03 -0800414 final DragLayer.LayoutParams lp = (DragLayer.LayoutParams) getLayoutParams();
Sunny Goyalba776d52015-05-18 20:52:57 -0700415 int newWidth = mWidgetView.getWidth() + 2 * mBackgroundPadding
416 - mWidgetPadding.left - mWidgetPadding.right;
417 int newHeight = mWidgetView.getHeight() + 2 * mBackgroundPadding
418 - mWidgetPadding.top - mWidgetPadding.bottom;
Adam Cohen37b59ff2011-06-13 17:13:42 -0700419
Adam Cohend6e7aa32013-07-09 15:32:37 -0700420 mTmpPt[0] = mWidgetView.getLeft();
421 mTmpPt[1] = mWidgetView.getTop();
422 mDragLayer.getDescendantCoordRelativeToSelf(mCellLayout.getShortcutsAndWidgets(), mTmpPt);
423
Sunny Goyalba776d52015-05-18 20:52:57 -0700424 int newX = mTmpPt[0] - mBackgroundPadding + mWidgetPadding.left;
425 int newY = mTmpPt[1] - mBackgroundPadding + mWidgetPadding.top;
Adam Cohen3cba7222011-03-02 19:03:11 -0800426
Sunny Goyalba776d52015-05-18 20:52:57 -0700427 // We need to make sure the frame's touchable regions lie fully within the bounds of the
Adam Cohen4459d6b2012-07-13 15:59:15 -0700428 // DragLayer. We allow the actual handles to be clipped, but we shift the touch regions
429 // down accordingly to provide a proper touch target.
Adam Cohen3cba7222011-03-02 19:03:11 -0800430 if (newY < 0) {
Adam Cohen4459d6b2012-07-13 15:59:15 -0700431 // In this case we shift the touch region down to start at the top of the DragLayer
432 mTopTouchRegionAdjustment = -newY;
433 } else {
434 mTopTouchRegionAdjustment = 0;
Adam Cohen3cba7222011-03-02 19:03:11 -0800435 }
Adam Cohen67882692011-03-11 15:29:03 -0800436 if (newY + newHeight > mDragLayer.getHeight()) {
Adam Cohen4459d6b2012-07-13 15:59:15 -0700437 // In this case we shift the touch region up to end at the bottom of the DragLayer
438 mBottomTouchRegionAdjustment = -(newY + newHeight - mDragLayer.getHeight());
439 } else {
440 mBottomTouchRegionAdjustment = 0;
Adam Cohen3cba7222011-03-02 19:03:11 -0800441 }
442
Adam Cohend4844c32011-02-18 19:25:06 -0800443 if (!animate) {
444 lp.width = newWidth;
445 lp.height = newHeight;
446 lp.x = newX;
447 lp.y = newY;
448 mLeftHandle.setAlpha(1.0f);
449 mRightHandle.setAlpha(1.0f);
450 mTopHandle.setAlpha(1.0f);
451 mBottomHandle.setAlpha(1.0f);
452 requestLayout();
453 } else {
454 PropertyValuesHolder width = PropertyValuesHolder.ofInt("width", lp.width, newWidth);
Adam Cohen1b607ed2011-03-03 17:26:50 -0800455 PropertyValuesHolder height = PropertyValuesHolder.ofInt("height", lp.height,
456 newHeight);
Adam Cohend4844c32011-02-18 19:25:06 -0800457 PropertyValuesHolder x = PropertyValuesHolder.ofInt("x", lp.x, newX);
458 PropertyValuesHolder y = PropertyValuesHolder.ofInt("y", lp.y, newY);
Michael Jurkaf1ad6082013-03-13 12:55:46 +0100459 ObjectAnimator oa =
460 LauncherAnimUtils.ofPropertyValuesHolder(lp, this, width, height, x, y);
Michael Jurka2ecf9952012-06-18 12:52:28 -0700461 ObjectAnimator leftOa = LauncherAnimUtils.ofFloat(mLeftHandle, "alpha", 1.0f);
462 ObjectAnimator rightOa = LauncherAnimUtils.ofFloat(mRightHandle, "alpha", 1.0f);
463 ObjectAnimator topOa = LauncherAnimUtils.ofFloat(mTopHandle, "alpha", 1.0f);
464 ObjectAnimator bottomOa = LauncherAnimUtils.ofFloat(mBottomHandle, "alpha", 1.0f);
Adam Cohend4844c32011-02-18 19:25:06 -0800465 oa.addUpdateListener(new AnimatorUpdateListener() {
466 public void onAnimationUpdate(ValueAnimator animation) {
467 requestLayout();
468 }
469 });
Michael Jurka2ecf9952012-06-18 12:52:28 -0700470 AnimatorSet set = LauncherAnimUtils.createAnimatorSet();
Adam Cohend4844c32011-02-18 19:25:06 -0800471 if (mResizeMode == AppWidgetProviderInfo.RESIZE_VERTICAL) {
472 set.playTogether(oa, topOa, bottomOa);
473 } else if (mResizeMode == AppWidgetProviderInfo.RESIZE_HORIZONTAL) {
474 set.playTogether(oa, leftOa, rightOa);
475 } else {
476 set.playTogether(oa, leftOa, rightOa, topOa, bottomOa);
477 }
478
479 set.setDuration(SNAP_DURATION);
480 set.start();
481 }
Tony Wickham71255bb2016-02-10 16:18:15 -0800482
483 setFocusableInTouchMode(true);
484 requestFocus();
485 }
486
487 @Override
488 public boolean onKey(View v, int keyCode, KeyEvent event) {
489 // Clear the frame and give focus to the widget host view when a directional key is pressed.
490 if (FocusLogic.shouldConsume(keyCode)) {
491 mDragLayer.clearAllResizeFrames();
492 mWidgetView.requestFocus();
493 return true;
494 }
495 return false;
Adam Cohend4844c32011-02-18 19:25:06 -0800496 }
497}