blob: daeca3bef0749e9d1412da930a90351d60d68932 [file] [log] [blame]
Daniel Sandler325dc232013-06-05 22:57:57 -04001package com.android.launcher3;
Adam Cohend4844c32011-02-18 19:25:06 -08002
Vadim Tryshevfedca432015-08-19 17:55:02 -07003import com.android.launcher3.dragndrop.DragLayer;
4
Adam Cohend4844c32011-02-18 19:25:06 -08005import android.animation.AnimatorSet;
6import android.animation.ObjectAnimator;
7import android.animation.PropertyValuesHolder;
8import android.animation.ValueAnimator;
9import android.animation.ValueAnimator.AnimatorUpdateListener;
Adam Cohen0cf2a7c2011-11-08 15:07:01 -080010import android.appwidget.AppWidgetHostView;
Adam Cohend4844c32011-02-18 19:25:06 -080011import android.appwidget.AppWidgetProviderInfo;
12import android.content.Context;
Adam Cohen59400422014-03-05 18:07:04 -080013import android.content.res.Resources;
Sunny Goyal756cd262015-08-20 12:33:21 -070014import android.graphics.Point;
Adam Cohen0cf2a7c2011-11-08 15:07:01 -080015import android.graphics.Rect;
Adam Cohend4844c32011-02-18 19:25:06 -080016import android.view.Gravity;
Tony Wickham71255bb2016-02-10 16:18:15 -080017import android.view.KeyEvent;
18import android.view.View;
Adam Cohend4844c32011-02-18 19:25:06 -080019import android.widget.FrameLayout;
20import android.widget.ImageView;
21
Sunny Goyale78e3d72015-09-24 11:23:31 -070022import com.android.launcher3.accessibility.DragViewStateAnnouncer;
Tony Wickham71255bb2016-02-10 16:18:15 -080023import com.android.launcher3.util.FocusLogic;
Sunny Goyale78e3d72015-09-24 11:23:31 -070024
Tony Wickham71255bb2016-02-10 16:18:15 -080025public class AppWidgetResizeFrame extends FrameLayout implements View.OnKeyListener {
Sunny Goyalba776d52015-05-18 20:52:57 -070026 private static final int SNAP_DURATION = 150;
27 private static final float DIMMED_HANDLE_ALPHA = 0f;
28 private static final float RESIZE_THRESHOLD = 0.66f;
29
Sunny Goyal756cd262015-08-20 12:33:21 -070030 private static final Rect sTmpRect = new Rect();
31
32 // Represents the cell size on the grid in the two orientations.
33 private static Point[] sCellSize;
Sunny Goyalba776d52015-05-18 20:52:57 -070034
35 private final Launcher mLauncher;
36 private final LauncherAppWidgetHostView mWidgetView;
37 private final CellLayout mCellLayout;
38 private final DragLayer mDragLayer;
39
40 private final ImageView mLeftHandle;
41 private final ImageView mRightHandle;
42 private final ImageView mTopHandle;
43 private final ImageView mBottomHandle;
44
45 private final Rect mWidgetPadding;
46
47 private final int mBackgroundPadding;
48 private final int mTouchTargetWidth;
49
50 private final int[] mDirectionVector = new int[2];
51 private final int[] mLastDirectionVector = new int[2];
52 private final int[] mTmpPt = new int[2];
Adam Cohend4844c32011-02-18 19:25:06 -080053
Sunny Goyale78e3d72015-09-24 11:23:31 -070054 private final DragViewStateAnnouncer mStateAnnouncer;
55
Adam Cohend4844c32011-02-18 19:25:06 -080056 private boolean mLeftBorderActive;
57 private boolean mRightBorderActive;
58 private boolean mTopBorderActive;
59 private boolean mBottomBorderActive;
60
61 private int mBaselineWidth;
62 private int mBaselineHeight;
63 private int mBaselineX;
64 private int mBaselineY;
65 private int mResizeMode;
Adam Cohen3cba7222011-03-02 19:03:11 -080066
Adam Cohend4844c32011-02-18 19:25:06 -080067 private int mRunningHInc;
68 private int mRunningVInc;
69 private int mMinHSpan;
70 private int mMinVSpan;
71 private int mDeltaX;
72 private int mDeltaY;
Adam Cohenbebf0422012-04-11 18:06:28 -070073 private int mDeltaXAddOn;
74 private int mDeltaYAddOn;
Adam Cohen1b607ed2011-03-03 17:26:50 -080075
Adam Cohen4459d6b2012-07-13 15:59:15 -070076 private int mTopTouchRegionAdjustment = 0;
77 private int mBottomTouchRegionAdjustment = 0;
78
Michael Jurka3a9fced2012-04-13 14:44:29 -070079 public AppWidgetResizeFrame(Context context,
Adam Cohen67882692011-03-11 15:29:03 -080080 LauncherAppWidgetHostView widgetView, CellLayout cellLayout, DragLayer dragLayer) {
Adam Cohend4844c32011-02-18 19:25:06 -080081
82 super(context);
Adam Cohencbf47e32011-09-16 17:32:37 -070083 mLauncher = (Launcher) context;
Adam Cohend4844c32011-02-18 19:25:06 -080084 mCellLayout = cellLayout;
85 mWidgetView = widgetView;
Adam Cohen59400422014-03-05 18:07:04 -080086 LauncherAppWidgetProviderInfo info = (LauncherAppWidgetProviderInfo)
87 widgetView.getAppWidgetInfo();
88 mResizeMode = info.resizeMode;
Adam Cohen67882692011-03-11 15:29:03 -080089 mDragLayer = dragLayer;
Adam Cohen3cba7222011-03-02 19:03:11 -080090
Sunny Goyal233ee962015-08-03 13:05:01 -070091 mMinHSpan = info.minSpanX;
92 mMinVSpan = info.minSpanY;
Adam Cohend4844c32011-02-18 19:25:06 -080093
Sunny Goyale78e3d72015-09-24 11:23:31 -070094 mStateAnnouncer = DragViewStateAnnouncer.createFor(this);
95
Sunny Goyalba776d52015-05-18 20:52:57 -070096 setBackgroundResource(R.drawable.widget_resize_shadow);
97 setForeground(getResources().getDrawable(R.drawable.widget_resize_frame));
Adam Cohend4844c32011-02-18 19:25:06 -080098 setPadding(0, 0, 0, 0);
99
Sunny Goyalba776d52015-05-18 20:52:57 -0700100 final int handleMargin = getResources().getDimensionPixelSize(R.dimen.widget_handle_margin);
Adam Cohend4844c32011-02-18 19:25:06 -0800101 LayoutParams lp;
102 mLeftHandle = new ImageView(context);
Sunny Goyalba776d52015-05-18 20:52:57 -0700103 mLeftHandle.setImageResource(R.drawable.ic_widget_resize_handle);
104 lp = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT,
Adam Cohen283dcbe2013-09-26 16:35:40 -0700105 Gravity.LEFT | Gravity.CENTER_VERTICAL);
Sunny Goyalba776d52015-05-18 20:52:57 -0700106 lp.leftMargin = handleMargin;
Adam Cohend4844c32011-02-18 19:25:06 -0800107 addView(mLeftHandle, lp);
108
109 mRightHandle = new ImageView(context);
Sunny Goyalba776d52015-05-18 20:52:57 -0700110 mRightHandle.setImageResource(R.drawable.ic_widget_resize_handle);
111 lp = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT,
Adam Cohen283dcbe2013-09-26 16:35:40 -0700112 Gravity.RIGHT | Gravity.CENTER_VERTICAL);
Sunny Goyalba776d52015-05-18 20:52:57 -0700113 lp.rightMargin = handleMargin;
Adam Cohend4844c32011-02-18 19:25:06 -0800114 addView(mRightHandle, lp);
115
116 mTopHandle = new ImageView(context);
Sunny Goyalba776d52015-05-18 20:52:57 -0700117 mTopHandle.setImageResource(R.drawable.ic_widget_resize_handle);
118 lp = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT,
Adam Cohend4844c32011-02-18 19:25:06 -0800119 Gravity.CENTER_HORIZONTAL | Gravity.TOP);
Sunny Goyalba776d52015-05-18 20:52:57 -0700120 lp.topMargin = handleMargin;
Adam Cohend4844c32011-02-18 19:25:06 -0800121 addView(mTopHandle, lp);
122
123 mBottomHandle = new ImageView(context);
Sunny Goyalba776d52015-05-18 20:52:57 -0700124 mBottomHandle.setImageResource(R.drawable.ic_widget_resize_handle);
125 lp = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT,
Adam Cohend4844c32011-02-18 19:25:06 -0800126 Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM);
Sunny Goyalba776d52015-05-18 20:52:57 -0700127 lp.bottomMargin = handleMargin;
Adam Cohend4844c32011-02-18 19:25:06 -0800128 addView(mBottomHandle, lp);
129
Adam Cohen59400422014-03-05 18:07:04 -0800130 if (!info.isCustomWidget) {
Sunny Goyalba776d52015-05-18 20:52:57 -0700131 mWidgetPadding = AppWidgetHostView.getDefaultPaddingForWidget(context,
Adam Cohen59400422014-03-05 18:07:04 -0800132 widgetView.getAppWidgetInfo().provider, null);
133 } else {
134 Resources r = context.getResources();
135 int padding = r.getDimensionPixelSize(R.dimen.default_widget_padding);
Sunny Goyalba776d52015-05-18 20:52:57 -0700136 mWidgetPadding = new Rect(padding, padding, padding, padding);
Adam Cohen59400422014-03-05 18:07:04 -0800137 }
138
Adam Cohend4844c32011-02-18 19:25:06 -0800139 if (mResizeMode == AppWidgetProviderInfo.RESIZE_HORIZONTAL) {
140 mTopHandle.setVisibility(GONE);
141 mBottomHandle.setVisibility(GONE);
142 } else if (mResizeMode == AppWidgetProviderInfo.RESIZE_VERTICAL) {
143 mLeftHandle.setVisibility(GONE);
144 mRightHandle.setVisibility(GONE);
Adam Cohen3cba7222011-03-02 19:03:11 -0800145 }
146
Sunny Goyalba776d52015-05-18 20:52:57 -0700147 mBackgroundPadding = getResources()
148 .getDimensionPixelSize(R.dimen.resize_frame_background_padding);
Adam Cohen3cba7222011-03-02 19:03:11 -0800149 mTouchTargetWidth = 2 * mBackgroundPadding;
Adam Cohenbebf0422012-04-11 18:06:28 -0700150
151 // When we create the resize frame, we first mark all cells as unoccupied. The appropriate
152 // cells (same if not resized, or different) will be marked as occupied when the resize
153 // frame is dismissed.
154 mCellLayout.markCellsAsUnoccupiedForView(mWidgetView);
Tony Wickham71255bb2016-02-10 16:18:15 -0800155
156 setOnKeyListener(this);
Adam Cohend4844c32011-02-18 19:25:06 -0800157 }
158
159 public boolean beginResizeIfPointInRegion(int x, int y) {
160 boolean horizontalActive = (mResizeMode & AppWidgetProviderInfo.RESIZE_HORIZONTAL) != 0;
161 boolean verticalActive = (mResizeMode & AppWidgetProviderInfo.RESIZE_VERTICAL) != 0;
Adam Cohen4459d6b2012-07-13 15:59:15 -0700162
Adam Cohen3cba7222011-03-02 19:03:11 -0800163 mLeftBorderActive = (x < mTouchTargetWidth) && horizontalActive;
164 mRightBorderActive = (x > getWidth() - mTouchTargetWidth) && horizontalActive;
Adam Cohen4459d6b2012-07-13 15:59:15 -0700165 mTopBorderActive = (y < mTouchTargetWidth + mTopTouchRegionAdjustment) && verticalActive;
166 mBottomBorderActive = (y > getHeight() - mTouchTargetWidth + mBottomTouchRegionAdjustment)
167 && verticalActive;
Adam Cohend4844c32011-02-18 19:25:06 -0800168
169 boolean anyBordersActive = mLeftBorderActive || mRightBorderActive
170 || mTopBorderActive || mBottomBorderActive;
171
172 mBaselineWidth = getMeasuredWidth();
173 mBaselineHeight = getMeasuredHeight();
174 mBaselineX = getLeft();
175 mBaselineY = getTop();
Adam Cohend4844c32011-02-18 19:25:06 -0800176
177 if (anyBordersActive) {
Adam Cohen3cba7222011-03-02 19:03:11 -0800178 mLeftHandle.setAlpha(mLeftBorderActive ? 1.0f : DIMMED_HANDLE_ALPHA);
179 mRightHandle.setAlpha(mRightBorderActive ? 1.0f :DIMMED_HANDLE_ALPHA);
180 mTopHandle.setAlpha(mTopBorderActive ? 1.0f : DIMMED_HANDLE_ALPHA);
181 mBottomHandle.setAlpha(mBottomBorderActive ? 1.0f : DIMMED_HANDLE_ALPHA);
Adam Cohend4844c32011-02-18 19:25:06 -0800182 }
Adam Cohend4844c32011-02-18 19:25:06 -0800183 return anyBordersActive;
184 }
185
Adam Cohen1b607ed2011-03-03 17:26:50 -0800186 /**
187 * Here we bound the deltas such that the frame cannot be stretched beyond the extents
188 * of the CellLayout, and such that the frame's borders can't cross.
189 */
Adam Cohend4844c32011-02-18 19:25:06 -0800190 public void updateDeltas(int deltaX, int deltaY) {
191 if (mLeftBorderActive) {
192 mDeltaX = Math.max(-mBaselineX, deltaX);
Adam Cohen3cba7222011-03-02 19:03:11 -0800193 mDeltaX = Math.min(mBaselineWidth - 2 * mTouchTargetWidth, mDeltaX);
Adam Cohend4844c32011-02-18 19:25:06 -0800194 } else if (mRightBorderActive) {
Adam Cohen67882692011-03-11 15:29:03 -0800195 mDeltaX = Math.min(mDragLayer.getWidth() - (mBaselineX + mBaselineWidth), deltaX);
Adam Cohen3cba7222011-03-02 19:03:11 -0800196 mDeltaX = Math.max(-mBaselineWidth + 2 * mTouchTargetWidth, mDeltaX);
Adam Cohend4844c32011-02-18 19:25:06 -0800197 }
198
199 if (mTopBorderActive) {
200 mDeltaY = Math.max(-mBaselineY, deltaY);
Adam Cohen3cba7222011-03-02 19:03:11 -0800201 mDeltaY = Math.min(mBaselineHeight - 2 * mTouchTargetWidth, mDeltaY);
Adam Cohend4844c32011-02-18 19:25:06 -0800202 } else if (mBottomBorderActive) {
Adam Cohen67882692011-03-11 15:29:03 -0800203 mDeltaY = Math.min(mDragLayer.getHeight() - (mBaselineY + mBaselineHeight), deltaY);
Adam Cohen3cba7222011-03-02 19:03:11 -0800204 mDeltaY = Math.max(-mBaselineHeight + 2 * mTouchTargetWidth, mDeltaY);
Adam Cohend4844c32011-02-18 19:25:06 -0800205 }
206 }
207
Adam Cohenbebf0422012-04-11 18:06:28 -0700208 public void visualizeResizeForDelta(int deltaX, int deltaY) {
209 visualizeResizeForDelta(deltaX, deltaY, false);
210 }
211
Adam Cohen1b607ed2011-03-03 17:26:50 -0800212 /**
213 * Based on the deltas, we resize the frame, and, if needed, we resize the widget.
214 */
Adam Cohenbebf0422012-04-11 18:06:28 -0700215 private void visualizeResizeForDelta(int deltaX, int deltaY, boolean onDismiss) {
Adam Cohend4844c32011-02-18 19:25:06 -0800216 updateDeltas(deltaX, deltaY);
Adam Cohen67882692011-03-11 15:29:03 -0800217 DragLayer.LayoutParams lp = (DragLayer.LayoutParams) getLayoutParams();
218
Adam Cohend4844c32011-02-18 19:25:06 -0800219 if (mLeftBorderActive) {
220 lp.x = mBaselineX + mDeltaX;
221 lp.width = mBaselineWidth - mDeltaX;
222 } else if (mRightBorderActive) {
223 lp.width = mBaselineWidth + mDeltaX;
224 }
225
226 if (mTopBorderActive) {
227 lp.y = mBaselineY + mDeltaY;
228 lp.height = mBaselineHeight - mDeltaY;
229 } else if (mBottomBorderActive) {
230 lp.height = mBaselineHeight + mDeltaY;
231 }
232
Adam Cohenbebf0422012-04-11 18:06:28 -0700233 resizeWidgetIfNeeded(onDismiss);
Adam Cohend4844c32011-02-18 19:25:06 -0800234 requestLayout();
235 }
236
Adam Cohen1b607ed2011-03-03 17:26:50 -0800237 /**
238 * Based on the current deltas, we determine if and how to resize the widget.
239 */
Adam Cohenbebf0422012-04-11 18:06:28 -0700240 private void resizeWidgetIfNeeded(boolean onDismiss) {
Adam Cohend4844c32011-02-18 19:25:06 -0800241 int xThreshold = mCellLayout.getCellWidth() + mCellLayout.getWidthGap();
242 int yThreshold = mCellLayout.getCellHeight() + mCellLayout.getHeightGap();
243
Adam Cohenbebf0422012-04-11 18:06:28 -0700244 int deltaX = mDeltaX + mDeltaXAddOn;
245 int deltaY = mDeltaY + mDeltaYAddOn;
246
247 float hSpanIncF = 1.0f * deltaX / xThreshold - mRunningHInc;
248 float vSpanIncF = 1.0f * deltaY / yThreshold - mRunningVInc;
Adam Cohene4b77292011-03-08 18:35:52 -0800249
250 int hSpanInc = 0;
251 int vSpanInc = 0;
Adam Cohend4844c32011-02-18 19:25:06 -0800252 int cellXInc = 0;
253 int cellYInc = 0;
254
Adam Cohenbebf0422012-04-11 18:06:28 -0700255 int countX = mCellLayout.getCountX();
256 int countY = mCellLayout.getCountY();
257
Adam Cohene4b77292011-03-08 18:35:52 -0800258 if (Math.abs(hSpanIncF) > RESIZE_THRESHOLD) {
259 hSpanInc = Math.round(hSpanIncF);
260 }
261 if (Math.abs(vSpanIncF) > RESIZE_THRESHOLD) {
262 vSpanInc = Math.round(vSpanIncF);
263 }
264
Adam Cohenbebf0422012-04-11 18:06:28 -0700265 if (!onDismiss && (hSpanInc == 0 && vSpanInc == 0)) return;
Adam Cohend4844c32011-02-18 19:25:06 -0800266
Adam Cohend4844c32011-02-18 19:25:06 -0800267
268 CellLayout.LayoutParams lp = (CellLayout.LayoutParams) mWidgetView.getLayoutParams();
Adam Cohen1b607ed2011-03-03 17:26:50 -0800269
Adam Cohenbebf0422012-04-11 18:06:28 -0700270 int spanX = lp.cellHSpan;
271 int spanY = lp.cellVSpan;
272 int cellX = lp.useTmpCoords ? lp.tmpCellX : lp.cellX;
273 int cellY = lp.useTmpCoords ? lp.tmpCellY : lp.cellY;
274
275 int hSpanDelta = 0;
276 int vSpanDelta = 0;
277
Adam Cohen1b607ed2011-03-03 17:26:50 -0800278 // For each border, we bound the resizing based on the minimum width, and the maximum
279 // expandability.
Adam Cohend4844c32011-02-18 19:25:06 -0800280 if (mLeftBorderActive) {
Adam Cohenbebf0422012-04-11 18:06:28 -0700281 cellXInc = Math.max(-cellX, hSpanInc);
Adam Cohend4844c32011-02-18 19:25:06 -0800282 cellXInc = Math.min(lp.cellHSpan - mMinHSpan, cellXInc);
283 hSpanInc *= -1;
Adam Cohenbebf0422012-04-11 18:06:28 -0700284 hSpanInc = Math.min(cellX, hSpanInc);
Adam Cohend4844c32011-02-18 19:25:06 -0800285 hSpanInc = Math.max(-(lp.cellHSpan - mMinHSpan), hSpanInc);
Adam Cohenbebf0422012-04-11 18:06:28 -0700286 hSpanDelta = -hSpanInc;
287
Adam Cohend4844c32011-02-18 19:25:06 -0800288 } else if (mRightBorderActive) {
Adam Cohenbebf0422012-04-11 18:06:28 -0700289 hSpanInc = Math.min(countX - (cellX + spanX), hSpanInc);
Adam Cohend4844c32011-02-18 19:25:06 -0800290 hSpanInc = Math.max(-(lp.cellHSpan - mMinHSpan), hSpanInc);
Adam Cohenbebf0422012-04-11 18:06:28 -0700291 hSpanDelta = hSpanInc;
Adam Cohend4844c32011-02-18 19:25:06 -0800292 }
293
294 if (mTopBorderActive) {
Adam Cohenbebf0422012-04-11 18:06:28 -0700295 cellYInc = Math.max(-cellY, vSpanInc);
Adam Cohend4844c32011-02-18 19:25:06 -0800296 cellYInc = Math.min(lp.cellVSpan - mMinVSpan, cellYInc);
297 vSpanInc *= -1;
Adam Cohenbebf0422012-04-11 18:06:28 -0700298 vSpanInc = Math.min(cellY, vSpanInc);
Adam Cohend4844c32011-02-18 19:25:06 -0800299 vSpanInc = Math.max(-(lp.cellVSpan - mMinVSpan), vSpanInc);
Adam Cohenbebf0422012-04-11 18:06:28 -0700300 vSpanDelta = -vSpanInc;
Adam Cohend4844c32011-02-18 19:25:06 -0800301 } else if (mBottomBorderActive) {
Adam Cohenbebf0422012-04-11 18:06:28 -0700302 vSpanInc = Math.min(countY - (cellY + spanY), vSpanInc);
Adam Cohend4844c32011-02-18 19:25:06 -0800303 vSpanInc = Math.max(-(lp.cellVSpan - mMinVSpan), vSpanInc);
Adam Cohenbebf0422012-04-11 18:06:28 -0700304 vSpanDelta = vSpanInc;
Adam Cohend4844c32011-02-18 19:25:06 -0800305 }
306
Adam Cohenbebf0422012-04-11 18:06:28 -0700307 mDirectionVector[0] = 0;
308 mDirectionVector[1] = 0;
Adam Cohend4844c32011-02-18 19:25:06 -0800309 // Update the widget's dimensions and position according to the deltas computed above
310 if (mLeftBorderActive || mRightBorderActive) {
Adam Cohenbebf0422012-04-11 18:06:28 -0700311 spanX += hSpanInc;
312 cellX += cellXInc;
Adam Cohene0489502012-08-27 15:18:53 -0700313 if (hSpanDelta != 0) {
314 mDirectionVector[0] = mLeftBorderActive ? -1 : 1;
315 }
Adam Cohend4844c32011-02-18 19:25:06 -0800316 }
317
318 if (mTopBorderActive || mBottomBorderActive) {
Adam Cohenbebf0422012-04-11 18:06:28 -0700319 spanY += vSpanInc;
320 cellY += cellYInc;
Adam Cohene0489502012-08-27 15:18:53 -0700321 if (vSpanDelta != 0) {
322 mDirectionVector[1] = mTopBorderActive ? -1 : 1;
323 }
Adam Cohend4844c32011-02-18 19:25:06 -0800324 }
325
Adam Cohenbebf0422012-04-11 18:06:28 -0700326 if (!onDismiss && vSpanDelta == 0 && hSpanDelta == 0) return;
Adam Cohend4844c32011-02-18 19:25:06 -0800327
Adam Cohene0489502012-08-27 15:18:53 -0700328 // We always want the final commit to match the feedback, so we make sure to use the
329 // last used direction vector when committing the resize / reorder.
330 if (onDismiss) {
331 mDirectionVector[0] = mLastDirectionVector[0];
332 mDirectionVector[1] = mLastDirectionVector[1];
333 } else {
334 mLastDirectionVector[0] = mDirectionVector[0];
335 mLastDirectionVector[1] = mDirectionVector[1];
336 }
337
Adam Cohenbebf0422012-04-11 18:06:28 -0700338 if (mCellLayout.createAreaForResize(cellX, cellY, spanX, spanY, mWidgetView,
339 mDirectionVector, onDismiss)) {
Sunny Goyale78e3d72015-09-24 11:23:31 -0700340 if (mStateAnnouncer != null && (lp.cellHSpan != spanX || lp.cellVSpan != spanY) ) {
341 mStateAnnouncer.announce(
342 mLauncher.getString(R.string.widget_resized, spanX, spanY));
343 }
344
Adam Cohenbebf0422012-04-11 18:06:28 -0700345 lp.tmpCellX = cellX;
346 lp.tmpCellY = cellY;
347 lp.cellHSpan = spanX;
348 lp.cellVSpan = spanY;
349 mRunningVInc += vSpanDelta;
350 mRunningHInc += hSpanDelta;
Sunny Goyale78e3d72015-09-24 11:23:31 -0700351
Adam Cohena897f392012-04-27 18:12:05 -0700352 if (!onDismiss) {
353 updateWidgetSizeRanges(mWidgetView, mLauncher, spanX, spanY);
354 }
Adam Cohenbebf0422012-04-11 18:06:28 -0700355 }
Adam Cohen67882692011-03-11 15:29:03 -0800356 mWidgetView.requestLayout();
Adam Cohend4844c32011-02-18 19:25:06 -0800357 }
358
Adam Cohena897f392012-04-27 18:12:05 -0700359 static void updateWidgetSizeRanges(AppWidgetHostView widgetView, Launcher launcher,
360 int spanX, int spanY) {
Sunny Goyalba776d52015-05-18 20:52:57 -0700361 getWidgetSizeRanges(launcher, spanX, spanY, sTmpRect);
362 widgetView.updateAppWidgetSize(null, sTmpRect.left, sTmpRect.top,
363 sTmpRect.right, sTmpRect.bottom);
Adam Cohen9e05a5e2012-09-10 15:53:09 -0700364 }
365
Sunny Goyal16466f12016-03-10 05:34:30 -0800366 public static Rect getWidgetSizeRanges(Context context, int spanX, int spanY, Rect rect) {
Sunny Goyal756cd262015-08-20 12:33:21 -0700367 if (sCellSize == null) {
368 InvariantDeviceProfile inv = LauncherAppState.getInstance().getInvariantDeviceProfile();
369
370 // Initiate cell sizes.
371 sCellSize = new Point[2];
372 sCellSize[0] = inv.landscapeProfile.getCellSize();
373 sCellSize[1] = inv.portraitProfile.getCellSize();
374 }
375
Adam Cohen9e05a5e2012-09-10 15:53:09 -0700376 if (rect == null) {
377 rect = new Rect();
378 }
Sunny Goyal16466f12016-03-10 05:34:30 -0800379 final float density = context.getResources().getDisplayMetrics().density;
Adam Cohena897f392012-04-27 18:12:05 -0700380
381 // Compute landscape size
Sunny Goyal756cd262015-08-20 12:33:21 -0700382 int landWidth = (int) ((spanX * sCellSize[0].x) / density);
383 int landHeight = (int) ((spanY * sCellSize[0].y) / density);
Adam Cohena897f392012-04-27 18:12:05 -0700384
385 // Compute portrait size
Sunny Goyal756cd262015-08-20 12:33:21 -0700386 int portWidth = (int) ((spanX * sCellSize[1].x) / density);
387 int portHeight = (int) ((spanY * sCellSize[1].y) / density);
Adam Cohen9e05a5e2012-09-10 15:53:09 -0700388 rect.set(portWidth, landHeight, landWidth, portHeight);
389 return rect;
Adam Cohena897f392012-04-27 18:12:05 -0700390 }
391
Adam Cohen1b607ed2011-03-03 17:26:50 -0800392 /**
393 * This is the final step of the resize. Here we save the new widget size and position
394 * to LauncherModel and animate the resize frame.
395 */
Adam Cohenbebf0422012-04-11 18:06:28 -0700396 public void commitResize() {
397 resizeWidgetIfNeeded(true);
398 requestLayout();
399 }
Adam Cohend4844c32011-02-18 19:25:06 -0800400
Adam Cohenbebf0422012-04-11 18:06:28 -0700401 public void onTouchUp() {
402 int xThreshold = mCellLayout.getCellWidth() + mCellLayout.getWidthGap();
403 int yThreshold = mCellLayout.getCellHeight() + mCellLayout.getHeightGap();
Adam Cohend4844c32011-02-18 19:25:06 -0800404
Adam Cohenbebf0422012-04-11 18:06:28 -0700405 mDeltaXAddOn = mRunningHInc * xThreshold;
406 mDeltaYAddOn = mRunningVInc * yThreshold;
407 mDeltaX = 0;
408 mDeltaY = 0;
409
Adam Cohend4844c32011-02-18 19:25:06 -0800410 post(new Runnable() {
Adam Cohenbebf0422012-04-11 18:06:28 -0700411 @Override
Adam Cohend4844c32011-02-18 19:25:06 -0800412 public void run() {
413 snapToWidget(true);
414 }
415 });
416 }
417
418 public void snapToWidget(boolean animate) {
Adam Cohen67882692011-03-11 15:29:03 -0800419 final DragLayer.LayoutParams lp = (DragLayer.LayoutParams) getLayoutParams();
Sunny Goyalba776d52015-05-18 20:52:57 -0700420 int newWidth = mWidgetView.getWidth() + 2 * mBackgroundPadding
421 - mWidgetPadding.left - mWidgetPadding.right;
422 int newHeight = mWidgetView.getHeight() + 2 * mBackgroundPadding
423 - mWidgetPadding.top - mWidgetPadding.bottom;
Adam Cohen37b59ff2011-06-13 17:13:42 -0700424
Adam Cohend6e7aa32013-07-09 15:32:37 -0700425 mTmpPt[0] = mWidgetView.getLeft();
426 mTmpPt[1] = mWidgetView.getTop();
427 mDragLayer.getDescendantCoordRelativeToSelf(mCellLayout.getShortcutsAndWidgets(), mTmpPt);
428
Sunny Goyalba776d52015-05-18 20:52:57 -0700429 int newX = mTmpPt[0] - mBackgroundPadding + mWidgetPadding.left;
430 int newY = mTmpPt[1] - mBackgroundPadding + mWidgetPadding.top;
Adam Cohen3cba7222011-03-02 19:03:11 -0800431
Sunny Goyalba776d52015-05-18 20:52:57 -0700432 // We need to make sure the frame's touchable regions lie fully within the bounds of the
Adam Cohen4459d6b2012-07-13 15:59:15 -0700433 // DragLayer. We allow the actual handles to be clipped, but we shift the touch regions
434 // down accordingly to provide a proper touch target.
Adam Cohen3cba7222011-03-02 19:03:11 -0800435 if (newY < 0) {
Adam Cohen4459d6b2012-07-13 15:59:15 -0700436 // In this case we shift the touch region down to start at the top of the DragLayer
437 mTopTouchRegionAdjustment = -newY;
438 } else {
439 mTopTouchRegionAdjustment = 0;
Adam Cohen3cba7222011-03-02 19:03:11 -0800440 }
Adam Cohen67882692011-03-11 15:29:03 -0800441 if (newY + newHeight > mDragLayer.getHeight()) {
Adam Cohen4459d6b2012-07-13 15:59:15 -0700442 // In this case we shift the touch region up to end at the bottom of the DragLayer
443 mBottomTouchRegionAdjustment = -(newY + newHeight - mDragLayer.getHeight());
444 } else {
445 mBottomTouchRegionAdjustment = 0;
Adam Cohen3cba7222011-03-02 19:03:11 -0800446 }
447
Adam Cohend4844c32011-02-18 19:25:06 -0800448 if (!animate) {
449 lp.width = newWidth;
450 lp.height = newHeight;
451 lp.x = newX;
452 lp.y = newY;
453 mLeftHandle.setAlpha(1.0f);
454 mRightHandle.setAlpha(1.0f);
455 mTopHandle.setAlpha(1.0f);
456 mBottomHandle.setAlpha(1.0f);
457 requestLayout();
458 } else {
459 PropertyValuesHolder width = PropertyValuesHolder.ofInt("width", lp.width, newWidth);
Adam Cohen1b607ed2011-03-03 17:26:50 -0800460 PropertyValuesHolder height = PropertyValuesHolder.ofInt("height", lp.height,
461 newHeight);
Adam Cohend4844c32011-02-18 19:25:06 -0800462 PropertyValuesHolder x = PropertyValuesHolder.ofInt("x", lp.x, newX);
463 PropertyValuesHolder y = PropertyValuesHolder.ofInt("y", lp.y, newY);
Michael Jurkaf1ad6082013-03-13 12:55:46 +0100464 ObjectAnimator oa =
465 LauncherAnimUtils.ofPropertyValuesHolder(lp, this, width, height, x, y);
Sunny Goyal5d2fc322015-07-06 22:52:49 -0700466 ObjectAnimator leftOa = LauncherAnimUtils.ofFloat(mLeftHandle, ALPHA, 1.0f);
467 ObjectAnimator rightOa = LauncherAnimUtils.ofFloat(mRightHandle, ALPHA, 1.0f);
468 ObjectAnimator topOa = LauncherAnimUtils.ofFloat(mTopHandle, ALPHA, 1.0f);
469 ObjectAnimator bottomOa = LauncherAnimUtils.ofFloat(mBottomHandle, ALPHA, 1.0f);
Adam Cohend4844c32011-02-18 19:25:06 -0800470 oa.addUpdateListener(new AnimatorUpdateListener() {
471 public void onAnimationUpdate(ValueAnimator animation) {
472 requestLayout();
473 }
474 });
Michael Jurka2ecf9952012-06-18 12:52:28 -0700475 AnimatorSet set = LauncherAnimUtils.createAnimatorSet();
Adam Cohend4844c32011-02-18 19:25:06 -0800476 if (mResizeMode == AppWidgetProviderInfo.RESIZE_VERTICAL) {
477 set.playTogether(oa, topOa, bottomOa);
478 } else if (mResizeMode == AppWidgetProviderInfo.RESIZE_HORIZONTAL) {
479 set.playTogether(oa, leftOa, rightOa);
480 } else {
481 set.playTogether(oa, leftOa, rightOa, topOa, bottomOa);
482 }
483
484 set.setDuration(SNAP_DURATION);
485 set.start();
486 }
Tony Wickham71255bb2016-02-10 16:18:15 -0800487
488 setFocusableInTouchMode(true);
489 requestFocus();
490 }
491
492 @Override
493 public boolean onKey(View v, int keyCode, KeyEvent event) {
494 // Clear the frame and give focus to the widget host view when a directional key is pressed.
495 if (FocusLogic.shouldConsume(keyCode)) {
496 mDragLayer.clearAllResizeFrames();
497 mWidgetView.requestFocus();
498 return true;
499 }
500 return false;
Adam Cohend4844c32011-02-18 19:25:06 -0800501 }
502}