blob: 0f1d46998b0f1a16c72a7b324949333c0ed05418 [file] [log] [blame]
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001/*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Joe Onoratoa5902522009-07-30 13:37:37 -070017package com.android.launcher2;
The Android Open Source Project31dd5032009-03-03 19:32:27 -080018
Patrick Dubroy6569f2c2010-07-12 14:25:18 -070019import com.android.launcher.R;
Winson Chungaafa03c2010-06-11 17:34:16 -070020
Patrick Dubroyde7658b2010-09-27 11:15:43 -070021import android.animation.ValueAnimator;
22import android.animation.ValueAnimator.AnimatorUpdateListener;
Winson Chungaafa03c2010-06-11 17:34:16 -070023import android.app.WallpaperManager;
The Android Open Source Project31dd5032009-03-03 19:32:27 -080024import android.content.Context;
Joe Onorato79e56262009-09-21 15:23:04 -040025import android.content.res.Resources;
Winson Chungaafa03c2010-06-11 17:34:16 -070026import android.content.res.TypedArray;
27import android.graphics.Canvas;
Patrick Dubroyde7658b2010-09-27 11:15:43 -070028import android.graphics.Point;
29import android.graphics.PointF;
The Android Open Source Project31dd5032009-03-03 19:32:27 -080030import android.graphics.Rect;
31import android.graphics.RectF;
Patrick Dubroy6569f2c2010-07-12 14:25:18 -070032import android.graphics.drawable.Drawable;
The Android Open Source Project31dd5032009-03-03 19:32:27 -080033import android.util.AttributeSet;
34import android.view.ContextMenu;
35import android.view.MotionEvent;
36import android.view.View;
37import android.view.ViewDebug;
38import android.view.ViewGroup;
Winson Chungaafa03c2010-06-11 17:34:16 -070039import android.view.animation.Animation;
Winson Chung150fbab2010-09-29 17:14:26 -070040import android.view.animation.DecelerateInterpolator;
41import android.view.animation.Interpolator;
Winson Chungaafa03c2010-06-11 17:34:16 -070042import android.view.animation.LayoutAnimationController;
The Android Open Source Project31dd5032009-03-03 19:32:27 -080043
Patrick Dubroy6569f2c2010-07-12 14:25:18 -070044import java.util.Arrays;
Romain Guyedcce092010-03-04 13:03:17 -080045
Adam Cohenf34bab52010-09-30 14:11:56 -070046public class CellLayout extends ViewGroup implements Dimmable {
Winson Chungaafa03c2010-06-11 17:34:16 -070047 static final String TAG = "CellLayout";
48
The Android Open Source Project31dd5032009-03-03 19:32:27 -080049 private int mCellWidth;
50 private int mCellHeight;
Winson Chungaafa03c2010-06-11 17:34:16 -070051
Winson Chungaafa03c2010-06-11 17:34:16 -070052 private int mLeftPadding;
53 private int mRightPadding;
54 private int mTopPadding;
55 private int mBottomPadding;
56
Adam Cohend22015c2010-07-26 22:02:18 -070057 private int mCountX;
58 private int mCountY;
The Android Open Source Project31dd5032009-03-03 19:32:27 -080059
60 private int mWidthGap;
61 private int mHeightGap;
62
63 private final Rect mRect = new Rect();
Patrick Dubroy8f86ddc2010-07-16 13:55:32 -070064 private final RectF mRectF = new RectF();
The Android Open Source Project31dd5032009-03-03 19:32:27 -080065 private final CellInfo mCellInfo = new CellInfo();
Winson Chungaafa03c2010-06-11 17:34:16 -070066
Patrick Dubroyde7658b2010-09-27 11:15:43 -070067 // These are temporary variables to prevent having to allocate a new object just to
68 // return an (x, y) value from helper functions. Do NOT use them to maintain other state.
Patrick Dubroy6569f2c2010-07-12 14:25:18 -070069 private final int[] mTmpCellXY = new int[2];
Patrick Dubroyde7658b2010-09-27 11:15:43 -070070 private final int[] mTmpPoint = new int[2];
71 private final PointF mTmpPointF = new PointF();
Patrick Dubroy6569f2c2010-07-12 14:25:18 -070072
The Android Open Source Project31dd5032009-03-03 19:32:27 -080073 boolean[][] mOccupied;
74
Michael Jurkadee05892010-07-27 10:01:56 -070075 private OnTouchListener mInterceptTouchListener;
76
Michael Jurka5f1c5092010-09-03 14:15:02 -070077 private float mBackgroundAlpha;
78 private final Rect mBackgroundLayoutRect = new Rect();
Adam Cohenf34bab52010-09-30 14:11:56 -070079
Michael Jurka5f1c5092010-09-03 14:15:02 -070080 private Drawable mBackground;
Adam Cohenf34bab52010-09-30 14:11:56 -070081 private Drawable mBackgroundMini;
82 private Drawable mBackgroundMiniHover;
Winson Chung150fbab2010-09-29 17:14:26 -070083 // If we're actively dragging something over this screen and it's small, mHover is true
Michael Jurkaa63c4522010-08-19 13:52:27 -070084 private boolean mHover = false;
Michael Jurkadee05892010-07-27 10:01:56 -070085
Patrick Dubroyde7658b2010-09-27 11:15:43 -070086 private final Point mDragCenter = new Point();
Patrick Dubroy6569f2c2010-07-12 14:25:18 -070087
Patrick Dubroy6569f2c2010-07-12 14:25:18 -070088 private Drawable mDragRectDrawable;
89
Winson Chung150fbab2010-09-29 17:14:26 -070090 // These arrays are used to implement the drag visualization on x-large screens.
91 // They are used as circular arrays, indexed by mDragRectCurrent.
92 private Rect[] mDragRects = new Rect[8];
93 private int[] mDragRectAlphas = new int[mDragRects.length];
94 private InterruptibleInOutAnimator[] mDragRectAnims =
95 new InterruptibleInOutAnimator[mDragRects.length];
96
97 // Used as an index into the above 3 arrays; indicates which is the most current value.
98 private int mDragRectCurrent = 0;
99
Patrick Dubroyde7658b2010-09-27 11:15:43 -0700100 private Drawable mCrosshairsDrawable = null;
101 private ValueAnimator mCrosshairsAnimator = null;
102 private float mCrosshairsVisibility = 0.0f;
103
Patrick Dubroy6569f2c2010-07-12 14:25:18 -0700104 // When a drag operation is in progress, holds the nearest cell to the touch point
105 private final int[] mDragCell = new int[2];
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800106
Winson Chungaafa03c2010-06-11 17:34:16 -0700107 private final WallpaperManager mWallpaperManager;
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800108
109 public CellLayout(Context context) {
110 this(context, null);
111 }
112
113 public CellLayout(Context context, AttributeSet attrs) {
114 this(context, attrs, 0);
115 }
116
117 public CellLayout(Context context, AttributeSet attrs, int defStyle) {
118 super(context, attrs, defStyle);
Patrick Dubroy6569f2c2010-07-12 14:25:18 -0700119
120 // A ViewGroup usually does not draw, but CellLayout needs to draw a rectangle to show
121 // the user where a dragged item will land when dropped.
122 setWillNotDraw(false);
Michael Jurkaa63c4522010-08-19 13:52:27 -0700123
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800124 TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CellLayout, defStyle, 0);
125
126 mCellWidth = a.getDimensionPixelSize(R.styleable.CellLayout_cellWidth, 10);
127 mCellHeight = a.getDimensionPixelSize(R.styleable.CellLayout_cellHeight, 10);
Winson Chungaafa03c2010-06-11 17:34:16 -0700128
Adam Cohend22015c2010-07-26 22:02:18 -0700129 mLeftPadding =
130 a.getDimensionPixelSize(R.styleable.CellLayout_xAxisStartPadding, 10);
131 mRightPadding =
132 a.getDimensionPixelSize(R.styleable.CellLayout_xAxisEndPadding, 10);
133 mTopPadding =
134 a.getDimensionPixelSize(R.styleable.CellLayout_yAxisStartPadding, 10);
135 mBottomPadding =
136 a.getDimensionPixelSize(R.styleable.CellLayout_yAxisEndPadding, 10);
Winson Chungaafa03c2010-06-11 17:34:16 -0700137
Adam Cohend22015c2010-07-26 22:02:18 -0700138 mCountX = LauncherModel.getCellCountX();
139 mCountY = LauncherModel.getCellCountY();
Michael Jurka0280c3b2010-09-17 15:00:07 -0700140 mOccupied = new boolean[mCountX][mCountY];
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800141
142 a.recycle();
143
144 setAlwaysDrawnWithCacheEnabled(false);
145
Patrick Dubroyde7658b2010-09-27 11:15:43 -0700146 mWallpaperManager = WallpaperManager.getInstance(context);
147
148 if (LauncherApplication.isScreenXLarge()) {
149 final Resources res = getResources();
150
Winson Chung150fbab2010-09-29 17:14:26 -0700151 mBackgroundMini = res.getDrawable(R.drawable.mini_home_screen_bg);
Adam Cohenf34bab52010-09-30 14:11:56 -0700152 mBackgroundMini.setFilterBitmap(true);
Winson Chung150fbab2010-09-29 17:14:26 -0700153 mBackground = res.getDrawable(R.drawable.home_screen_bg);
Patrick Dubroyde7658b2010-09-27 11:15:43 -0700154 mBackground.setFilterBitmap(true);
Winson Chung150fbab2010-09-29 17:14:26 -0700155 mBackgroundMiniHover = res.getDrawable(R.drawable.mini_home_screen_bg_hover);
Adam Cohenf34bab52010-09-30 14:11:56 -0700156 mBackgroundMiniHover.setFilterBitmap(true);
Patrick Dubroyde7658b2010-09-27 11:15:43 -0700157
Winson Chung150fbab2010-09-29 17:14:26 -0700158 // Initialize the data structures used for the drag visualization.
159
Patrick Dubroyde7658b2010-09-27 11:15:43 -0700160 mDragRectDrawable = res.getDrawable(R.drawable.rounded_rect_green);
161 mCrosshairsDrawable = res.getDrawable(R.drawable.gardening_crosshairs);
Winson Chung150fbab2010-09-29 17:14:26 -0700162 Interpolator interp = new DecelerateInterpolator(2.5f); // Quint ease out
Patrick Dubroyde7658b2010-09-27 11:15:43 -0700163
164 // Set up the animation for fading the crosshairs in and out
165 int animDuration = res.getInteger(R.integer.config_crosshairsFadeInTime);
166 mCrosshairsAnimator = new ValueAnimator<Float>(animDuration);
167 mCrosshairsAnimator.addUpdateListener(new AnimatorUpdateListener() {
168 public void onAnimationUpdate(ValueAnimator animation) {
169 mCrosshairsVisibility = ((Float) animation.getAnimatedValue()).floatValue();
170 CellLayout.this.invalidate();
171 }
172 });
Winson Chung150fbab2010-09-29 17:14:26 -0700173 mCrosshairsAnimator.setInterpolator(interp);
174
175 for (int i = 0; i < mDragRects.length; i++) {
176 mDragRects[i] = new Rect();
177 }
178
179 // When dragging things around the home screens, we show a green outline of
180 // where the item will land. The outlines gradually fade out, leaving a trail
181 // behind the drag path.
182 // Set up all the animations that are used to implement this fading.
183 final int duration = res.getInteger(R.integer.config_dragOutlineFadeTime);
184 final int fromAlphaValue = 0;
185 final int toAlphaValue = res.getInteger(R.integer.config_dragOutlineMaxAlpha);
186 for (int i = 0; i < mDragRectAnims.length; i++) {
187 final InterruptibleInOutAnimator anim =
188 new InterruptibleInOutAnimator(duration, fromAlphaValue, toAlphaValue);
189 anim.setInterpolator(interp);
190 final int thisIndex = i;
191 anim.addUpdateListener(new AnimatorUpdateListener() {
192 public void onAnimationUpdate(ValueAnimator animation) {
193 mDragRectAlphas[thisIndex] = (Integer) animation.getAnimatedValue();
194 CellLayout.this.invalidate(mDragRects[thisIndex]);
195 }
196 });
197 mDragRectAnims[i] = anim;
198 }
Patrick Dubroyde7658b2010-09-27 11:15:43 -0700199 }
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800200 }
201
Michael Jurkaa63c4522010-08-19 13:52:27 -0700202 public void setHover(boolean value) {
203 if (mHover != value) {
204 invalidate();
205 }
206 mHover = value;
207 }
208
Patrick Dubroyde7658b2010-09-27 11:15:43 -0700209 private void animateCrosshairsTo(float value) {
210 final ValueAnimator anim = mCrosshairsAnimator;
211 long fullDuration = getResources().getInteger(R.integer.config_crosshairsFadeInTime);
212 anim.setDuration(fullDuration - anim.getCurrentPlayTime());
213 anim.setValues(mCrosshairsVisibility, value);
214 anim.cancel();
215 anim.start();
216 }
217
Jeff Sharkey83f111d2009-04-20 21:03:13 -0700218 @Override
Romain Guya6abce82009-11-10 02:54:41 -0800219 public void dispatchDraw(Canvas canvas) {
Michael Jurka5f1c5092010-09-03 14:15:02 -0700220 if (mBackgroundAlpha > 0.0f) {
Adam Cohenf34bab52010-09-30 14:11:56 -0700221 Drawable bg;
222 if (mHover && getScaleX() < 0.5f) {
223 bg = mBackgroundMiniHover;
224 } else if (getScaleX() < 0.5f) {
225 bg = mBackgroundMini;
226 } else {
227 bg = mBackground;
228 }
Michael Jurka5f1c5092010-09-03 14:15:02 -0700229 bg.setAlpha((int) (mBackgroundAlpha * 255));
Michael Jurkaa63c4522010-08-19 13:52:27 -0700230 bg.draw(canvas);
231 }
Romain Guya6abce82009-11-10 02:54:41 -0800232 super.dispatchDraw(canvas);
233 }
234
235 @Override
Patrick Dubroy6569f2c2010-07-12 14:25:18 -0700236 protected void onDraw(Canvas canvas) {
Patrick Dubroyde7658b2010-09-27 11:15:43 -0700237 if (mCrosshairsVisibility > 0.0f) {
238 final int countX = mCountX;
239 final int countY = mCountY;
240
Patrick Dubroyde7658b2010-09-27 11:15:43 -0700241 final float MAX_ALPHA = 0.4f;
242 final int MAX_VISIBLE_DISTANCE = 600;
243 final float DISTANCE_MULTIPLIER = 0.002f;
244
245 final Drawable d = mCrosshairsDrawable;
246 final int width = d.getIntrinsicWidth();
247 final int height = d.getIntrinsicHeight();
248
249 int x = getLeftPadding() - (mWidthGap / 2) - (width / 2);
250 for (int col = 0; col <= countX; col++) {
251 int y = getTopPadding() - (mHeightGap / 2) - (height / 2);
252 for (int row = 0; row <= countY; row++) {
253 mTmpPointF.set(x - mDragCenter.x, y - mDragCenter.y);
254 float dist = mTmpPointF.length();
255 // Crosshairs further from the drag point are more faint
256 float alpha = Math.min(MAX_ALPHA,
257 DISTANCE_MULTIPLIER * (MAX_VISIBLE_DISTANCE - dist));
258 if (alpha > 0.0f) {
259 d.setBounds(x, y, x + width, y + height);
260 d.setAlpha((int) (alpha * 255 * mCrosshairsVisibility));
261 d.draw(canvas);
262 }
263 y += mCellHeight + mHeightGap;
264 }
265 x += mCellWidth + mWidthGap;
266 }
Winson Chung150fbab2010-09-29 17:14:26 -0700267
268 for (int i = 0; i < mDragRects.length; i++) {
269 int alpha = mDragRectAlphas[i];
270 if (alpha > 0) {
271 mDragRectDrawable.setAlpha(alpha);
272 mDragRectDrawable.setBounds(mDragRects[i]);
273 mDragRectDrawable.draw(canvas);
274 }
275 }
Patrick Dubroy6569f2c2010-07-12 14:25:18 -0700276 }
277 }
278
Adam Cohenf34bab52010-09-30 14:11:56 -0700279 public void setDimmableProgress(float progress) {
280 for (int i = 0; i < getChildCount(); i++) {
281 Dimmable d = (Dimmable) getChildAt(i);
282 d.setDimmableProgress(progress);
283 }
284 }
285
286 public float getDimmableProgress() {
287 if (getChildCount() > 0) {
288 return ((Dimmable) getChildAt(0)).getDimmableProgress();
289 }
290 return 0.0f;
291 }
292
Patrick Dubroy6569f2c2010-07-12 14:25:18 -0700293 @Override
Jeff Sharkey83f111d2009-04-20 21:03:13 -0700294 public void cancelLongPress() {
295 super.cancelLongPress();
296
297 // Cancel long press for all children
298 final int count = getChildCount();
299 for (int i = 0; i < count; i++) {
300 final View child = getChildAt(i);
301 child.cancelLongPress();
302 }
303 }
304
Michael Jurkadee05892010-07-27 10:01:56 -0700305 public void setOnInterceptTouchListener(View.OnTouchListener listener) {
306 mInterceptTouchListener = listener;
307 }
308
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800309 int getCountX() {
Adam Cohend22015c2010-07-26 22:02:18 -0700310 return mCountX;
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800311 }
312
313 int getCountY() {
Adam Cohend22015c2010-07-26 22:02:18 -0700314 return mCountY;
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800315 }
316
Winson Chungaafa03c2010-06-11 17:34:16 -0700317 public boolean addViewToCellLayout(View child, int index, int childId, LayoutParams params) {
318 final LayoutParams lp = params;
319
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800320 // Generate an id for each view, this assumes we have at most 256x256 cells
321 // per workspace screen
Adam Cohend22015c2010-07-26 22:02:18 -0700322 if (lp.cellX >= 0 && lp.cellX <= mCountX - 1 && lp.cellY >= 0 && lp.cellY <= mCountY - 1) {
Winson Chungaafa03c2010-06-11 17:34:16 -0700323 // If the horizontal or vertical span is set to -1, it is taken to
324 // mean that it spans the extent of the CellLayout
Adam Cohend22015c2010-07-26 22:02:18 -0700325 if (lp.cellHSpan < 0) lp.cellHSpan = mCountX;
326 if (lp.cellVSpan < 0) lp.cellVSpan = mCountY;
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800327
Winson Chungaafa03c2010-06-11 17:34:16 -0700328 child.setId(childId);
329
Michael Jurkadee05892010-07-27 10:01:56 -0700330 // We might be in the middle or end of shrinking/fading to a dimmed view
331 // Make sure this view's alpha is set the same as all the rest of the views
Michael Jurka5f1c5092010-09-03 14:15:02 -0700332 child.setAlpha(getAlpha());
Winson Chungaafa03c2010-06-11 17:34:16 -0700333 addView(child, index, lp);
Michael Jurkadee05892010-07-27 10:01:56 -0700334
Michael Jurka0280c3b2010-09-17 15:00:07 -0700335 markCellsAsOccupiedForView(child);
336
Winson Chungaafa03c2010-06-11 17:34:16 -0700337 return true;
338 }
339 return false;
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800340 }
341
342 @Override
Michael Jurka0280c3b2010-09-17 15:00:07 -0700343 public void removeAllViews() {
344 clearOccupiedCells();
345 }
346
347 @Override
348 public void removeAllViewsInLayout() {
349 clearOccupiedCells();
350 }
351
352 @Override
353 public void removeView(View view) {
354 markCellsAsUnoccupiedForView(view);
355 super.removeView(view);
356 }
357
358 @Override
359 public void removeViewAt(int index) {
360 markCellsAsUnoccupiedForView(getChildAt(index));
361 super.removeViewAt(index);
362 }
363
364 @Override
365 public void removeViewInLayout(View view) {
366 markCellsAsUnoccupiedForView(view);
367 super.removeViewInLayout(view);
368 }
369
370 @Override
371 public void removeViews(int start, int count) {
372 for (int i = start; i < start + count; i++) {
373 markCellsAsUnoccupiedForView(getChildAt(i));
374 }
375 super.removeViews(start, count);
376 }
377
378 @Override
379 public void removeViewsInLayout(int start, int count) {
380 for (int i = start; i < start + count; i++) {
381 markCellsAsUnoccupiedForView(getChildAt(i));
382 }
383 super.removeViewsInLayout(start, count);
384 }
385
386 @Override
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800387 public void requestChildFocus(View child, View focused) {
388 super.requestChildFocus(child, focused);
389 if (child != null) {
390 Rect r = new Rect();
391 child.getDrawingRect(r);
392 requestRectangleOnScreen(r);
393 }
394 }
395
396 @Override
397 protected void onAttachedToWindow() {
398 super.onAttachedToWindow();
399 mCellInfo.screen = ((ViewGroup) getParent()).indexOfChild(this);
400 }
401
Michael Jurkaaf442092010-06-10 17:01:57 -0700402 public void setTagToCellInfoForPoint(int touchX, int touchY) {
403 final CellInfo cellInfo = mCellInfo;
404 final Rect frame = mRect;
405 final int x = touchX + mScrollX;
406 final int y = touchY + mScrollY;
407 final int count = getChildCount();
408
409 boolean found = false;
410 for (int i = count - 1; i >= 0; i--) {
411 final View child = getChildAt(i);
412
413 if ((child.getVisibility()) == VISIBLE || child.getAnimation() != null) {
414 child.getHitRect(frame);
415 if (frame.contains(x, y)) {
416 final LayoutParams lp = (LayoutParams) child.getLayoutParams();
417 cellInfo.cell = child;
418 cellInfo.cellX = lp.cellX;
419 cellInfo.cellY = lp.cellY;
420 cellInfo.spanX = lp.cellHSpan;
421 cellInfo.spanY = lp.cellVSpan;
422 cellInfo.valid = true;
423 found = true;
Michael Jurkaaf442092010-06-10 17:01:57 -0700424 break;
425 }
426 }
427 }
Winson Chungaafa03c2010-06-11 17:34:16 -0700428
Michael Jurkaaf442092010-06-10 17:01:57 -0700429 if (!found) {
Patrick Dubroy6569f2c2010-07-12 14:25:18 -0700430 final int cellXY[] = mTmpCellXY;
Michael Jurkaaf442092010-06-10 17:01:57 -0700431 pointToCellExact(x, y, cellXY);
432
Michael Jurkaaf442092010-06-10 17:01:57 -0700433 cellInfo.cell = null;
434 cellInfo.cellX = cellXY[0];
435 cellInfo.cellY = cellXY[1];
436 cellInfo.spanX = 1;
437 cellInfo.spanY = 1;
Michael Jurka0280c3b2010-09-17 15:00:07 -0700438 cellInfo.valid = cellXY[0] >= 0 && cellXY[1] >= 0 && cellXY[0] < mCountX &&
439 cellXY[1] < mCountY && !mOccupied[cellXY[0]][cellXY[1]];
Michael Jurkaaf442092010-06-10 17:01:57 -0700440 }
441 setTag(cellInfo);
442 }
443
Winson Chungaafa03c2010-06-11 17:34:16 -0700444
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800445 @Override
446 public boolean onInterceptTouchEvent(MotionEvent ev) {
Michael Jurkadee05892010-07-27 10:01:56 -0700447 if (mInterceptTouchListener != null && mInterceptTouchListener.onTouch(this, ev)) {
448 return true;
449 }
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800450 final int action = ev.getAction();
451 final CellInfo cellInfo = mCellInfo;
452
453 if (action == MotionEvent.ACTION_DOWN) {
Michael Jurkaaf442092010-06-10 17:01:57 -0700454 setTagToCellInfoForPoint((int) ev.getX(), (int) ev.getY());
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800455 } else if (action == MotionEvent.ACTION_UP) {
456 cellInfo.cell = null;
457 cellInfo.cellX = -1;
458 cellInfo.cellY = -1;
459 cellInfo.spanX = 0;
460 cellInfo.spanY = 0;
461 cellInfo.valid = false;
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800462 setTag(cellInfo);
463 }
464
465 return false;
466 }
467
468 @Override
469 public CellInfo getTag() {
Michael Jurka0280c3b2010-09-17 15:00:07 -0700470 return (CellInfo) super.getTag();
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800471 }
472
Patrick Dubroy6569f2c2010-07-12 14:25:18 -0700473 /**
474 * Check if the row 'y' is empty from columns 'left' to 'right', inclusive.
475 */
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800476 private static boolean isRowEmpty(int y, int left, int right, boolean[][] occupied) {
477 for (int x = left; x <= right; x++) {
478 if (occupied[x][y]) {
479 return false;
480 }
481 }
482 return true;
483 }
484
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800485 /**
Winson Chungaafa03c2010-06-11 17:34:16 -0700486 * Given a point, return the cell that strictly encloses that point
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800487 * @param x X coordinate of the point
488 * @param y Y coordinate of the point
489 * @param result Array of 2 ints to hold the x and y coordinate of the cell
490 */
491 void pointToCellExact(int x, int y, int[] result) {
Winson Chungaafa03c2010-06-11 17:34:16 -0700492 final int hStartPadding = getLeftPadding();
493 final int vStartPadding = getTopPadding();
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800494
495 result[0] = (x - hStartPadding) / (mCellWidth + mWidthGap);
496 result[1] = (y - vStartPadding) / (mCellHeight + mHeightGap);
497
Adam Cohend22015c2010-07-26 22:02:18 -0700498 final int xAxis = mCountX;
499 final int yAxis = mCountY;
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800500
501 if (result[0] < 0) result[0] = 0;
502 if (result[0] >= xAxis) result[0] = xAxis - 1;
503 if (result[1] < 0) result[1] = 0;
504 if (result[1] >= yAxis) result[1] = yAxis - 1;
505 }
Winson Chungaafa03c2010-06-11 17:34:16 -0700506
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800507 /**
508 * Given a point, return the cell that most closely encloses that point
509 * @param x X coordinate of the point
510 * @param y Y coordinate of the point
511 * @param result Array of 2 ints to hold the x and y coordinate of the cell
512 */
513 void pointToCellRounded(int x, int y, int[] result) {
514 pointToCellExact(x + (mCellWidth / 2), y + (mCellHeight / 2), result);
515 }
516
517 /**
518 * Given a cell coordinate, return the point that represents the upper left corner of that cell
Winson Chungaafa03c2010-06-11 17:34:16 -0700519 *
520 * @param cellX X coordinate of the cell
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800521 * @param cellY Y coordinate of the cell
Winson Chungaafa03c2010-06-11 17:34:16 -0700522 *
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800523 * @param result Array of 2 ints to hold the x and y coordinate of the point
524 */
525 void cellToPoint(int cellX, int cellY, int[] result) {
Winson Chungaafa03c2010-06-11 17:34:16 -0700526 final int hStartPadding = getLeftPadding();
527 final int vStartPadding = getTopPadding();
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800528
529 result[0] = hStartPadding + cellX * (mCellWidth + mWidthGap);
530 result[1] = vStartPadding + cellY * (mCellHeight + mHeightGap);
531 }
532
Romain Guy84f296c2009-11-04 15:00:44 -0800533 int getCellWidth() {
534 return mCellWidth;
535 }
536
537 int getCellHeight() {
538 return mCellHeight;
539 }
540
Romain Guy1a304a12009-11-10 00:02:32 -0800541 int getLeftPadding() {
Winson Chungaafa03c2010-06-11 17:34:16 -0700542 return mLeftPadding;
Romain Guy1a304a12009-11-10 00:02:32 -0800543 }
544
545 int getTopPadding() {
Winson Chungaafa03c2010-06-11 17:34:16 -0700546 return mTopPadding;
Romain Guy1a304a12009-11-10 00:02:32 -0800547 }
548
549 int getRightPadding() {
Winson Chungaafa03c2010-06-11 17:34:16 -0700550 return mRightPadding;
Romain Guy1a304a12009-11-10 00:02:32 -0800551 }
552
553 int getBottomPadding() {
Winson Chungaafa03c2010-06-11 17:34:16 -0700554 return mBottomPadding;
Romain Guy1a304a12009-11-10 00:02:32 -0800555 }
556
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800557 @Override
558 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
559 // TODO: currently ignoring padding
Winson Chungaafa03c2010-06-11 17:34:16 -0700560
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800561 int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);
Winson Chungaafa03c2010-06-11 17:34:16 -0700562 int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec);
563
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800564 int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);
565 int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec);
Winson Chungaafa03c2010-06-11 17:34:16 -0700566
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800567 if (widthSpecMode == MeasureSpec.UNSPECIFIED || heightSpecMode == MeasureSpec.UNSPECIFIED) {
568 throw new RuntimeException("CellLayout cannot have UNSPECIFIED dimensions");
569 }
570
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800571 final int cellWidth = mCellWidth;
572 final int cellHeight = mCellHeight;
573
Adam Cohend22015c2010-07-26 22:02:18 -0700574 int numWidthGaps = mCountX - 1;
575 int numHeightGaps = mCountY - 1;
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800576
Michael Jurka0280c3b2010-09-17 15:00:07 -0700577 int vSpaceLeft = heightSpecSize - mTopPadding - mBottomPadding - (cellHeight * mCountY);
Adam Cohend22015c2010-07-26 22:02:18 -0700578 mHeightGap = vSpaceLeft / numHeightGaps;
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800579
Michael Jurka0280c3b2010-09-17 15:00:07 -0700580 int hSpaceLeft = widthSpecSize - mLeftPadding - mRightPadding - (cellWidth * mCountX);
Adam Cohend22015c2010-07-26 22:02:18 -0700581 mWidthGap = hSpaceLeft / numWidthGaps;
Winson Chungaafa03c2010-06-11 17:34:16 -0700582
Michael Jurka5f1c5092010-09-03 14:15:02 -0700583 // center it around the min gaps
584 int minGap = Math.min(mWidthGap, mHeightGap);
585 mWidthGap = mHeightGap = minGap;
586
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800587 int count = getChildCount();
588
589 for (int i = 0; i < count; i++) {
590 View child = getChildAt(i);
591 LayoutParams lp = (LayoutParams) child.getLayoutParams();
Winson Chungaafa03c2010-06-11 17:34:16 -0700592 lp.setup(cellWidth, cellHeight, mWidthGap, mHeightGap,
593 mLeftPadding, mTopPadding);
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800594
Michael Jurka0280c3b2010-09-17 15:00:07 -0700595 int childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(lp.width, MeasureSpec.EXACTLY);
Winson Chungaafa03c2010-06-11 17:34:16 -0700596 int childheightMeasureSpec = MeasureSpec.makeMeasureSpec(lp.height,
597 MeasureSpec.EXACTLY);
598
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800599 child.measure(childWidthMeasureSpec, childheightMeasureSpec);
600 }
Michael Jurka5f1c5092010-09-03 14:15:02 -0700601 if (widthSpecMode == MeasureSpec.AT_MOST) {
602 int newWidth = mLeftPadding + mRightPadding + (mCountX * cellWidth) +
603 ((mCountX - 1) * minGap);
604 int newHeight = mTopPadding + mBottomPadding + (mCountY * cellHeight) +
605 ((mCountY - 1) * minGap);
606 setMeasuredDimension(newWidth, newHeight);
607 } else if (widthSpecMode == MeasureSpec.EXACTLY) {
608 setMeasuredDimension(widthSpecSize, heightSpecSize);
609 }
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800610 }
611
612 @Override
Michael Jurka28750fb2010-09-24 17:43:49 -0700613 protected void onLayout(boolean changed, int l, int t, int r, int b) {
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800614 int count = getChildCount();
615
616 for (int i = 0; i < count; i++) {
617 View child = getChildAt(i);
618 if (child.getVisibility() != GONE) {
619
620 CellLayout.LayoutParams lp = (CellLayout.LayoutParams) child.getLayoutParams();
621
622 int childLeft = lp.x;
623 int childTop = lp.y;
624 child.layout(childLeft, childTop, childLeft + lp.width, childTop + lp.height);
Romain Guy84f296c2009-11-04 15:00:44 -0800625
626 if (lp.dropped) {
627 lp.dropped = false;
628
Patrick Dubroy6569f2c2010-07-12 14:25:18 -0700629 final int[] cellXY = mTmpCellXY;
Romain Guy06762ab2010-01-25 16:51:08 -0800630 getLocationOnScreen(cellXY);
Romain Guy84f296c2009-11-04 15:00:44 -0800631 mWallpaperManager.sendWallpaperCommand(getWindowToken(), "android.home.drop",
Romain Guy06762ab2010-01-25 16:51:08 -0800632 cellXY[0] + childLeft + lp.width / 2,
633 cellXY[1] + childTop + lp.height / 2, 0, null);
Romain Guy84f296c2009-11-04 15:00:44 -0800634 }
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800635 }
636 }
637 }
638
639 @Override
Michael Jurkadee05892010-07-27 10:01:56 -0700640 protected void onSizeChanged(int w, int h, int oldw, int oldh) {
641 super.onSizeChanged(w, h, oldw, oldh);
Michael Jurka5f1c5092010-09-03 14:15:02 -0700642 mBackgroundLayoutRect.set(0, 0, w, h);
643 if (mBackground != null) {
644 mBackground.setBounds(mBackgroundLayoutRect);
Michael Jurkaa63c4522010-08-19 13:52:27 -0700645 }
Adam Cohenf34bab52010-09-30 14:11:56 -0700646 if (mBackgroundMiniHover != null) {
647 mBackgroundMiniHover.setBounds(mBackgroundLayoutRect);
648 }
649 if (mBackgroundMini != null) {
650 mBackgroundMini.setBounds(mBackgroundLayoutRect);
Michael Jurkaa63c4522010-08-19 13:52:27 -0700651 }
Michael Jurkadee05892010-07-27 10:01:56 -0700652 }
653
654 @Override
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800655 protected void setChildrenDrawingCacheEnabled(boolean enabled) {
656 final int count = getChildCount();
657 for (int i = 0; i < count; i++) {
658 final View view = getChildAt(i);
659 view.setDrawingCacheEnabled(enabled);
660 // Update the drawing caches
Adam Powellfefa0ce2010-05-03 10:23:50 -0700661 view.buildDrawingCache(true);
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800662 }
663 }
664
665 @Override
666 protected void setChildrenDrawnWithCacheEnabled(boolean enabled) {
667 super.setChildrenDrawnWithCacheEnabled(enabled);
668 }
669
Michael Jurka5f1c5092010-09-03 14:15:02 -0700670 public float getBackgroundAlpha() {
671 return mBackgroundAlpha;
Michael Jurkadee05892010-07-27 10:01:56 -0700672 }
673
Michael Jurka5f1c5092010-09-03 14:15:02 -0700674 public void setBackgroundAlpha(float alpha) {
675 mBackgroundAlpha = alpha;
Michael Jurka0142d492010-08-25 17:46:15 -0700676 invalidate();
Michael Jurkadee05892010-07-27 10:01:56 -0700677 }
678
Michael Jurka5f1c5092010-09-03 14:15:02 -0700679 // Need to return true to let the view system know we know how to handle alpha-- this is
680 // because when our children have an alpha of 0.0f, they are still rendering their "dimmed"
681 // versions
682 @Override
683 protected boolean onSetAlpha(int alpha) {
684 return true;
685 }
686
687 public void setAlpha(float alpha) {
688 setChildrenAlpha(alpha);
689 super.setAlpha(alpha);
690 }
691
Michael Jurkadee05892010-07-27 10:01:56 -0700692 private void setChildrenAlpha(float alpha) {
Michael Jurka0142d492010-08-25 17:46:15 -0700693 final int childCount = getChildCount();
694 for (int i = 0; i < childCount; i++) {
Michael Jurkadee05892010-07-27 10:01:56 -0700695 getChildAt(i).setAlpha(alpha);
696 }
697 }
698
Michael Jurka0280c3b2010-09-17 15:00:07 -0700699 private boolean isVacantIgnoring(
700 int originX, int originY, int spanX, int spanY, View ignoreView) {
701 if (ignoreView != null) {
702 markCellsAsUnoccupiedForView(ignoreView);
703 }
Michael Jurka28750fb2010-09-24 17:43:49 -0700704 boolean isVacant = true;
Patrick Dubroy6569f2c2010-07-12 14:25:18 -0700705 for (int i = 0; i < spanY; i++) {
706 if (!isRowEmpty(originY + i, originX, originX + spanX - 1, mOccupied)) {
Michael Jurka28750fb2010-09-24 17:43:49 -0700707 isVacant = false;
708 break;
Patrick Dubroy6569f2c2010-07-12 14:25:18 -0700709 }
710 }
Michael Jurka0280c3b2010-09-17 15:00:07 -0700711 if (ignoreView != null) {
712 markCellsAsOccupiedForView(ignoreView);
713 }
Michael Jurka28750fb2010-09-24 17:43:49 -0700714 return isVacant;
Patrick Dubroy6569f2c2010-07-12 14:25:18 -0700715 }
716
Michael Jurka0280c3b2010-09-17 15:00:07 -0700717 private boolean isVacant(int originX, int originY, int spanX, int spanY) {
718 return isVacantIgnoring(originX, originY, spanX, spanY, null);
719 }
720
Patrick Dubroy440c3602010-07-13 17:50:32 -0700721 public View getChildAt(int x, int y) {
722 final int count = getChildCount();
723 for (int i = 0; i < count; i++) {
724 View child = getChildAt(i);
725 LayoutParams lp = (LayoutParams) child.getLayoutParams();
726
727 if ((lp.cellX <= x) && (x < lp.cellX + lp.cellHSpan) &&
728 (lp.cellY <= y) && (y < lp.cellY + lp.cellHSpan)) {
729 return child;
730 }
731 }
732 return null;
733 }
734
Patrick Dubroy6569f2c2010-07-12 14:25:18 -0700735 /**
Patrick Dubroy8f86ddc2010-07-16 13:55:32 -0700736 * Estimate the size that a child with the given dimensions will take in the layout.
737 */
738 void estimateChildSize(int minWidth, int minHeight, int[] result) {
739 // Assuming it's placed at 0, 0, find where the bottom right cell will land
740 rectToCell(minWidth, minHeight, result);
741
742 // Then figure out the rect it will occupy
743 cellToRect(0, 0, result[0], result[1], mRectF);
744 result[0] = (int)mRectF.width();
745 result[1] = (int)mRectF.height();
746 }
747
748 /**
Patrick Dubroy6569f2c2010-07-12 14:25:18 -0700749 * Estimate where the top left cell of the dragged item will land if it is dropped.
750 *
751 * @param originX The X value of the top left corner of the item
752 * @param originY The Y value of the top left corner of the item
753 * @param spanX The number of horizontal cells that the item spans
754 * @param spanY The number of vertical cells that the item spans
755 * @param result The estimated drop cell X and Y.
756 */
757 void estimateDropCell(int originX, int originY, int spanX, int spanY, int[] result) {
Adam Cohend22015c2010-07-26 22:02:18 -0700758 final int countX = mCountX;
759 final int countY = mCountY;
Patrick Dubroy6569f2c2010-07-12 14:25:18 -0700760
Michael Jurkaa63c4522010-08-19 13:52:27 -0700761 // pointToCellRounded takes the top left of a cell but will pad that with
762 // cellWidth/2 and cellHeight/2 when finding the matching cell
763 pointToCellRounded(originX, originY, result);
Patrick Dubroy6569f2c2010-07-12 14:25:18 -0700764
765 // If the item isn't fully on this screen, snap to the edges
766 int rightOverhang = result[0] + spanX - countX;
767 if (rightOverhang > 0) {
768 result[0] -= rightOverhang; // Snap to right
769 }
770 result[0] = Math.max(0, result[0]); // Snap to left
771 int bottomOverhang = result[1] + spanY - countY;
772 if (bottomOverhang > 0) {
773 result[1] -= bottomOverhang; // Snap to bottom
774 }
775 result[1] = Math.max(0, result[1]); // Snap to top
776 }
777
Patrick Dubroyde7658b2010-09-27 11:15:43 -0700778 void visualizeDropLocation(View view, int originX, int originY, int spanX, int spanY) {
779 final int[] nearest = findNearestVacantArea(originX, originY, spanX, spanY, view, mDragCell);
780 mDragCenter.set(originX + (view.getWidth() / 2), originY + (view.getHeight() / 2));
Patrick Dubroy6569f2c2010-07-12 14:25:18 -0700781
Patrick Dubroyde7658b2010-09-27 11:15:43 -0700782 if (nearest != null) {
Patrick Dubroy6569f2c2010-07-12 14:25:18 -0700783 // Find the top left corner of the rect the object will occupy
Patrick Dubroyde7658b2010-09-27 11:15:43 -0700784 final int[] topLeft = mTmpPoint;
785 cellToPoint(nearest[0], nearest[1], topLeft);
786
787 // Need to copy these, because the next call to cellToPoint will overwrite them
Patrick Dubroy6569f2c2010-07-12 14:25:18 -0700788 final int left = topLeft[0];
789 final int top = topLeft[1];
790
Winson Chung150fbab2010-09-29 17:14:26 -0700791 final Rect dragRect = mDragRects[mDragRectCurrent];
792
793 if (dragRect.isEmpty() || left != dragRect.left || top != dragRect.top) {
794 // Now find the bottom right
795 final int[] bottomRight = mTmpPoint;
796 cellToPoint(nearest[0] + spanX - 1, nearest[1] + spanY - 1, bottomRight);
797 bottomRight[0] += mCellWidth;
798 bottomRight[1] += mCellHeight;
799
800 final int oldIndex = mDragRectCurrent;
801 mDragRectCurrent = (oldIndex + 1) % mDragRects.length;
802
803 mDragRects[mDragRectCurrent].set(left, top, bottomRight[0], bottomRight[1]);
804
805 mDragRectAnims[oldIndex].animateOut();
806 mDragRectAnims[mDragRectCurrent].animateIn();
807 }
Patrick Dubroy6569f2c2010-07-12 14:25:18 -0700808 }
809 }
810
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800811 /**
Jeff Sharkey70864282009-04-07 21:08:40 -0700812 * Find a vacant area that will fit the given bounds nearest the requested
813 * cell location. Uses Euclidean distance to score multiple vacant areas.
Winson Chungaafa03c2010-06-11 17:34:16 -0700814 *
Romain Guy51afc022009-05-04 18:03:43 -0700815 * @param pixelX The X location at which you want to search for a vacant area.
816 * @param pixelY The Y location at which you want to search for a vacant area.
Jeff Sharkey70864282009-04-07 21:08:40 -0700817 * @param spanX Horizontal span of the object.
818 * @param spanY Vertical span of the object.
Patrick Dubroyde7658b2010-09-27 11:15:43 -0700819 * @param result Array in which to place the result, or null (in which case a new array will
820 * be allocated)
Jeff Sharkey70864282009-04-07 21:08:40 -0700821 * @return The X, Y cell of a vacant area that can contain this object,
822 * nearest the requested location.
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800823 */
Michael Jurka6a1435d2010-09-27 17:35:12 -0700824 int[] findNearestVacantArea(
Patrick Dubroyde7658b2010-09-27 11:15:43 -0700825 int pixelX, int pixelY, int spanX, int spanY, int[] result) {
826 return findNearestVacantArea(pixelX, pixelY, spanX, spanY, null, result);
Michael Jurka6a1435d2010-09-27 17:35:12 -0700827 }
Winson Chungaafa03c2010-06-11 17:34:16 -0700828
Michael Jurka6a1435d2010-09-27 17:35:12 -0700829 /**
830 * Find a vacant area that will fit the given bounds nearest the requested
831 * cell location. Uses Euclidean distance to score multiple vacant areas.
832 *
833 * @param pixelX The X location at which you want to search for a vacant area.
834 * @param pixelY The Y location at which you want to search for a vacant area.
835 * @param spanX Horizontal span of the object.
836 * @param spanY Vertical span of the object.
Michael Jurka6a1435d2010-09-27 17:35:12 -0700837 * @param ignoreView Considers space occupied by this view as unoccupied
Patrick Dubroyde7658b2010-09-27 11:15:43 -0700838 * @param result Previously returned value to possibly recycle.
Michael Jurka6a1435d2010-09-27 17:35:12 -0700839 * @return The X, Y cell of a vacant area that can contain this object,
840 * nearest the requested location.
841 */
842 int[] findNearestVacantArea(
Patrick Dubroyde7658b2010-09-27 11:15:43 -0700843 int pixelX, int pixelY, int spanX, int spanY, View ignoreView, int[] result) {
Michael Jurkac6ee42e2010-09-30 12:04:50 -0700844 // mark space take by ignoreView as available (method checks if ignoreView is null)
845 markCellsAsUnoccupiedForView(ignoreView);
846
Jeff Sharkey70864282009-04-07 21:08:40 -0700847 // Keep track of best-scoring drop area
Patrick Dubroyde7658b2010-09-27 11:15:43 -0700848 final int[] bestXY = result != null ? result : new int[2];
Jeff Sharkey70864282009-04-07 21:08:40 -0700849 double bestDistance = Double.MAX_VALUE;
Winson Chungaafa03c2010-06-11 17:34:16 -0700850
Patrick Dubroyde7658b2010-09-27 11:15:43 -0700851 final int countX = mCountX;
852 final int countY = mCountY;
853 final boolean[][] occupied = mOccupied;
854
855 for (int x = 0; x < countX - (spanX - 1); x++) {
Michael Jurkac28de512010-08-13 11:27:44 -0700856 inner:
Patrick Dubroyde7658b2010-09-27 11:15:43 -0700857 for (int y = 0; y < countY - (spanY - 1); y++) {
Michael Jurkac28de512010-08-13 11:27:44 -0700858 for (int i = 0; i < spanX; i++) {
859 for (int j = 0; j < spanY; j++) {
Patrick Dubroyde7658b2010-09-27 11:15:43 -0700860 if (occupied[x + i][y + j]) {
Michael Jurkac28de512010-08-13 11:27:44 -0700861 // small optimization: we can skip to below the row we just found
862 // an occupied cell
863 y += j;
864 continue inner;
865 }
866 }
867 }
868 final int[] cellXY = mTmpCellXY;
869 cellToPoint(x, y, cellXY);
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800870
Michael Jurkac28de512010-08-13 11:27:44 -0700871 double distance = Math.sqrt(Math.pow(cellXY[0] - pixelX, 2)
872 + Math.pow(cellXY[1] - pixelY, 2));
873 if (distance <= bestDistance) {
874 bestDistance = distance;
875 bestXY[0] = x;
876 bestXY[1] = y;
877 }
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800878 }
879 }
Michael Jurkac6ee42e2010-09-30 12:04:50 -0700880 // re-mark space taken by ignoreView as occupied
881 markCellsAsOccupiedForView(ignoreView);
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800882
Winson Chungaafa03c2010-06-11 17:34:16 -0700883 // Return null if no suitable location found
Jeff Sharkey70864282009-04-07 21:08:40 -0700884 if (bestDistance < Double.MAX_VALUE) {
885 return bestXY;
886 } else {
887 return null;
888 }
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800889 }
Winson Chungaafa03c2010-06-11 17:34:16 -0700890
Michael Jurka0280c3b2010-09-17 15:00:07 -0700891 boolean existsEmptyCell() {
892 return findCellForSpan(null, 1, 1);
893 }
894
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800895 /**
Michael Jurka0280c3b2010-09-17 15:00:07 -0700896 * Finds the upper-left coordinate of the first rectangle in the grid that can
897 * hold a cell of the specified dimensions. If intersectX and intersectY are not -1,
898 * then this method will only return coordinates for rectangles that contain the cell
899 * (intersectX, intersectY)
900 *
901 * @param cellXY The array that will contain the position of a vacant cell if such a cell
902 * can be found.
903 * @param spanX The horizontal span of the cell we want to find.
904 * @param spanY The vertical span of the cell we want to find.
905 *
906 * @return True if a vacant cell of the specified dimension was found, false otherwise.
Patrick Dubroy6569f2c2010-07-12 14:25:18 -0700907 */
Michael Jurka0280c3b2010-09-17 15:00:07 -0700908 boolean findCellForSpan(int[] cellXY, int spanX, int spanY) {
909 return findCellForSpanThatIntersectsIgnoring(cellXY, spanX, spanY, -1, -1, null);
910 }
911
912 /**
913 * Like above, but ignores any cells occupied by the item "ignoreView"
914 *
915 * @param cellXY The array that will contain the position of a vacant cell if such a cell
916 * can be found.
917 * @param spanX The horizontal span of the cell we want to find.
918 * @param spanY The vertical span of the cell we want to find.
919 * @param ignoreView The home screen item we should treat as not occupying any space
920 * @return
921 */
922 boolean findCellForSpanIgnoring(int[] cellXY, int spanX, int spanY, View ignoreView) {
923 return findCellForSpanThatIntersectsIgnoring(cellXY, spanX, spanY, -1, -1, ignoreView);
924 }
925
926 /**
927 * Like above, but if intersectX and intersectY are not -1, then this method will try to
928 * return coordinates for rectangles that contain the cell [intersectX, intersectY]
929 *
930 * @param spanX The horizontal span of the cell we want to find.
931 * @param spanY The vertical span of the cell we want to find.
932 * @param ignoreView The home screen item we should treat as not occupying any space
933 * @param intersectX The X coordinate of the cell that we should try to overlap
934 * @param intersectX The Y coordinate of the cell that we should try to overlap
935 *
936 * @return True if a vacant cell of the specified dimension was found, false otherwise.
937 */
938 boolean findCellForSpanThatIntersects(int[] cellXY, int spanX, int spanY,
939 int intersectX, int intersectY) {
940 return findCellForSpanThatIntersectsIgnoring(
941 cellXY, spanX, spanY, intersectX, intersectY, null);
942 }
943
944 /**
945 * The superset of the above two methods
946 */
947 boolean findCellForSpanThatIntersectsIgnoring(int[] cellXY, int spanX, int spanY,
948 int intersectX, int intersectY, View ignoreView) {
Michael Jurkac6ee42e2010-09-30 12:04:50 -0700949 // mark space take by ignoreView as available (method checks if ignoreView is null)
950 markCellsAsUnoccupiedForView(ignoreView);
Michael Jurka0280c3b2010-09-17 15:00:07 -0700951
Michael Jurka28750fb2010-09-24 17:43:49 -0700952 boolean foundCell = false;
Michael Jurka0280c3b2010-09-17 15:00:07 -0700953 while (true) {
954 int startX = 0;
955 if (intersectX >= 0) {
956 startX = Math.max(startX, intersectX - (spanX - 1));
957 }
958 int endX = mCountX - (spanX - 1);
959 if (intersectX >= 0) {
960 endX = Math.min(endX, intersectX + (spanX - 1) + (spanX == 1 ? 1 : 0));
961 }
962 int startY = 0;
963 if (intersectY >= 0) {
964 startY = Math.max(startY, intersectY - (spanY - 1));
965 }
966 int endY = mCountY - (spanY - 1);
967 if (intersectY >= 0) {
968 endY = Math.min(endY, intersectY + (spanY - 1) + (spanY == 1 ? 1 : 0));
969 }
970
971 for (int x = startX; x < endX; x++) {
972 inner:
973 for (int y = startY; y < endY; y++) {
974 for (int i = 0; i < spanX; i++) {
975 for (int j = 0; j < spanY; j++) {
976 if (mOccupied[x + i][y + j]) {
977 // small optimization: we can skip to below the row we just found
978 // an occupied cell
979 y += j;
980 continue inner;
981 }
982 }
983 }
984 if (cellXY != null) {
985 cellXY[0] = x;
986 cellXY[1] = y;
987 }
Michael Jurka28750fb2010-09-24 17:43:49 -0700988 foundCell = true;
989 break;
Michael Jurka0280c3b2010-09-17 15:00:07 -0700990 }
991 }
992 if (intersectX == -1 && intersectY == -1) {
993 break;
994 } else {
995 // if we failed to find anything, try again but without any requirements of
996 // intersecting
997 intersectX = -1;
998 intersectY = -1;
999 continue;
1000 }
1001 }
1002
Michael Jurkac6ee42e2010-09-30 12:04:50 -07001003 // re-mark space taken by ignoreView as occupied
1004 markCellsAsOccupiedForView(ignoreView);
Michael Jurka28750fb2010-09-24 17:43:49 -07001005 return foundCell;
Michael Jurka0280c3b2010-09-17 15:00:07 -07001006 }
1007
1008 /**
1009 * Called when drag has left this CellLayout or has been completed (successfully or not)
1010 */
1011 void onDragExit() {
Patrick Dubroy6569f2c2010-07-12 14:25:18 -07001012 // Invalidate the drag data
1013 mDragCell[0] = -1;
1014 mDragCell[1] = -1;
1015
Michael Jurkaa63c4522010-08-19 13:52:27 -07001016 setHover(false);
Patrick Dubroy6569f2c2010-07-12 14:25:18 -07001017 invalidate();
Patrick Dubroyde7658b2010-09-27 11:15:43 -07001018
1019 // Fade out the drag indicators
1020 if (mCrosshairsAnimator != null) {
1021 animateCrosshairsTo(0.0f);
1022 }
Winson Chung150fbab2010-09-29 17:14:26 -07001023
1024 mDragRectAnims[mDragRectCurrent].animateOut();
1025 mDragRectCurrent = (mDragRectCurrent + 1) % mDragRects.length;
1026 mDragRects[mDragRectCurrent].setEmpty();
Patrick Dubroy6569f2c2010-07-12 14:25:18 -07001027 }
1028
1029 /**
Winson Chungaafa03c2010-06-11 17:34:16 -07001030 * Mark a child as having been dropped.
Patrick Dubroyde7658b2010-09-27 11:15:43 -07001031 * At the beginning of the drag operation, the child may have been on another
1032 * screen, but it is reparented before this method is called.
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001033 *
1034 * @param child The child that is being dropped
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001035 */
Winson Chungaafa03c2010-06-11 17:34:16 -07001036 void onDropChild(View child) {
Romain Guyd94533d2009-08-17 10:01:15 -07001037 if (child != null) {
1038 LayoutParams lp = (LayoutParams) child.getLayoutParams();
Romain Guyd94533d2009-08-17 10:01:15 -07001039 lp.isDragging = false;
Romain Guy84f296c2009-11-04 15:00:44 -08001040 lp.dropped = true;
Romain Guyd94533d2009-08-17 10:01:15 -07001041 child.requestLayout();
Romain Guyd94533d2009-08-17 10:01:15 -07001042 }
Michael Jurka0280c3b2010-09-17 15:00:07 -07001043 onDragExit();
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001044 }
1045
1046 void onDropAborted(View child) {
1047 if (child != null) {
1048 ((LayoutParams) child.getLayoutParams()).isDragging = false;
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001049 }
Michael Jurka0280c3b2010-09-17 15:00:07 -07001050 onDragExit();
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001051 }
1052
1053 /**
1054 * Start dragging the specified child
Winson Chungaafa03c2010-06-11 17:34:16 -07001055 *
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001056 * @param child The child that is being dragged
1057 */
1058 void onDragChild(View child) {
1059 LayoutParams lp = (LayoutParams) child.getLayoutParams();
1060 lp.isDragging = true;
Patrick Dubroyde7658b2010-09-27 11:15:43 -07001061 }
1062
1063 /**
1064 * A drag event has begun over this layout.
1065 * It may have begun over this layout (in which case onDragChild is called first),
1066 * or it may have begun on another layout.
1067 */
1068 void onDragEnter(View dragView) {
Patrick Dubroyde7658b2010-09-27 11:15:43 -07001069 // Fade in the drag indicators
1070 if (mCrosshairsAnimator != null) {
1071 animateCrosshairsTo(1.0f);
1072 }
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001073 }
Winson Chungaafa03c2010-06-11 17:34:16 -07001074
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001075 /**
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001076 * Computes a bounding rectangle for a range of cells
Winson Chungaafa03c2010-06-11 17:34:16 -07001077 *
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001078 * @param cellX X coordinate of upper left corner expressed as a cell position
1079 * @param cellY Y coordinate of upper left corner expressed as a cell position
Winson Chungaafa03c2010-06-11 17:34:16 -07001080 * @param cellHSpan Width in cells
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001081 * @param cellVSpan Height in cells
Patrick Dubroy6569f2c2010-07-12 14:25:18 -07001082 * @param resultRect Rect into which to put the results
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001083 */
Patrick Dubroy6569f2c2010-07-12 14:25:18 -07001084 public void cellToRect(int cellX, int cellY, int cellHSpan, int cellVSpan, RectF resultRect) {
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001085 final int cellWidth = mCellWidth;
1086 final int cellHeight = mCellHeight;
1087 final int widthGap = mWidthGap;
1088 final int heightGap = mHeightGap;
Winson Chungaafa03c2010-06-11 17:34:16 -07001089
1090 final int hStartPadding = getLeftPadding();
1091 final int vStartPadding = getTopPadding();
1092
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001093 int width = cellHSpan * cellWidth + ((cellHSpan - 1) * widthGap);
1094 int height = cellVSpan * cellHeight + ((cellVSpan - 1) * heightGap);
1095
1096 int x = hStartPadding + cellX * (cellWidth + widthGap);
1097 int y = vStartPadding + cellY * (cellHeight + heightGap);
Winson Chungaafa03c2010-06-11 17:34:16 -07001098
Patrick Dubroy6569f2c2010-07-12 14:25:18 -07001099 resultRect.set(x, y, x + width, y + height);
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001100 }
Winson Chungaafa03c2010-06-11 17:34:16 -07001101
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001102 /**
Winson Chungaafa03c2010-06-11 17:34:16 -07001103 * Computes the required horizontal and vertical cell spans to always
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001104 * fit the given rectangle.
Winson Chungaafa03c2010-06-11 17:34:16 -07001105 *
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001106 * @param width Width in pixels
1107 * @param height Height in pixels
Patrick Dubroy8f86ddc2010-07-16 13:55:32 -07001108 * @param result An array of length 2 in which to store the result (may be null).
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001109 */
Patrick Dubroy8f86ddc2010-07-16 13:55:32 -07001110 public int[] rectToCell(int width, int height, int[] result) {
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001111 // Always assume we're working with the smallest span to make sure we
1112 // reserve enough space in both orientations.
Joe Onorato79e56262009-09-21 15:23:04 -04001113 final Resources resources = getResources();
1114 int actualWidth = resources.getDimensionPixelSize(R.dimen.workspace_cell_width);
1115 int actualHeight = resources.getDimensionPixelSize(R.dimen.workspace_cell_height);
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001116 int smallerSize = Math.min(actualWidth, actualHeight);
Joe Onorato79e56262009-09-21 15:23:04 -04001117
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001118 // Always round up to next largest cell
1119 int spanX = (width + smallerSize) / smallerSize;
1120 int spanY = (height + smallerSize) / smallerSize;
Joe Onorato79e56262009-09-21 15:23:04 -04001121
Patrick Dubroy8f86ddc2010-07-16 13:55:32 -07001122 if (result == null) {
1123 return new int[] { spanX, spanY };
1124 }
1125 result[0] = spanX;
1126 result[1] = spanY;
1127 return result;
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001128 }
1129
1130 /**
1131 * Find the first vacant cell, if there is one.
1132 *
1133 * @param vacant Holds the x and y coordinate of the vacant cell
1134 * @param spanX Horizontal cell span.
1135 * @param spanY Vertical cell span.
Winson Chungaafa03c2010-06-11 17:34:16 -07001136 *
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001137 * @return True if a vacant cell was found
1138 */
1139 public boolean getVacantCell(int[] vacant, int spanX, int spanY) {
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001140
Michael Jurka0280c3b2010-09-17 15:00:07 -07001141 return findVacantCell(vacant, spanX, spanY, mCountX, mCountY, mOccupied);
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001142 }
1143
1144 static boolean findVacantCell(int[] vacant, int spanX, int spanY,
1145 int xCount, int yCount, boolean[][] occupied) {
1146
1147 for (int x = 0; x < xCount; x++) {
1148 for (int y = 0; y < yCount; y++) {
1149 boolean available = !occupied[x][y];
1150out: for (int i = x; i < x + spanX - 1 && x < xCount; i++) {
1151 for (int j = y; j < y + spanY - 1 && y < yCount; j++) {
1152 available = available && !occupied[i][j];
1153 if (!available) break out;
1154 }
1155 }
1156
1157 if (available) {
1158 vacant[0] = x;
1159 vacant[1] = y;
1160 return true;
1161 }
1162 }
1163 }
1164
1165 return false;
1166 }
1167
Patrick Dubroy6569f2c2010-07-12 14:25:18 -07001168 /**
1169 * Update the array of occupied cells (mOccupied), and return a flattened copy of the array.
1170 */
1171 boolean[] getOccupiedCellsFlattened() {
Adam Cohend22015c2010-07-26 22:02:18 -07001172 final int xCount = mCountX;
1173 final int yCount = mCountY;
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001174 final boolean[][] occupied = mOccupied;
1175
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001176 final boolean[] flat = new boolean[xCount * yCount];
1177 for (int y = 0; y < yCount; y++) {
1178 for (int x = 0; x < xCount; x++) {
1179 flat[y * xCount + x] = occupied[x][y];
1180 }
1181 }
1182
1183 return flat;
1184 }
1185
Michael Jurka0280c3b2010-09-17 15:00:07 -07001186 private void clearOccupiedCells() {
1187 for (int x = 0; x < mCountX; x++) {
1188 for (int y = 0; y < mCountY; y++) {
1189 mOccupied[x][y] = false;
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001190 }
1191 }
Michael Jurka0280c3b2010-09-17 15:00:07 -07001192 }
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001193
Michael Jurka0280c3b2010-09-17 15:00:07 -07001194 public void onMove(View view, int newCellX, int newCellY) {
1195 LayoutParams lp = (LayoutParams) view.getLayoutParams();
1196 markCellsAsUnoccupiedForView(view);
1197 markCellsForView(newCellX, newCellY, lp.cellHSpan, lp.cellVSpan, true);
1198 }
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001199
Michael Jurka0280c3b2010-09-17 15:00:07 -07001200 private void markCellsAsOccupiedForView(View view) {
Michael Jurkac6ee42e2010-09-30 12:04:50 -07001201 if (view == null || view.getParent() != this) return;
Michael Jurka0280c3b2010-09-17 15:00:07 -07001202 LayoutParams lp = (LayoutParams) view.getLayoutParams();
1203 markCellsForView(lp.cellX, lp.cellY, lp.cellHSpan, lp.cellVSpan, true);
1204 }
1205
1206 private void markCellsAsUnoccupiedForView(View view) {
Michael Jurkac6ee42e2010-09-30 12:04:50 -07001207 if (view == null || view.getParent() != this) return;
Michael Jurka0280c3b2010-09-17 15:00:07 -07001208 LayoutParams lp = (LayoutParams) view.getLayoutParams();
1209 markCellsForView(lp.cellX, lp.cellY, lp.cellHSpan, lp.cellVSpan, false);
1210 }
1211
1212 private void markCellsForView(int cellX, int cellY, int spanX, int spanY, boolean value) {
1213 for (int x = cellX; x < cellX + spanX && x < mCountX; x++) {
1214 for (int y = cellY; y < cellY + spanY && y < mCountY; y++) {
1215 mOccupied[x][y] = value;
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001216 }
1217 }
1218 }
1219
1220 @Override
1221 public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) {
1222 return new CellLayout.LayoutParams(getContext(), attrs);
1223 }
1224
1225 @Override
1226 protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
1227 return p instanceof CellLayout.LayoutParams;
1228 }
1229
1230 @Override
1231 protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
1232 return new CellLayout.LayoutParams(p);
1233 }
1234
Winson Chungaafa03c2010-06-11 17:34:16 -07001235 public static class CellLayoutAnimationController extends LayoutAnimationController {
1236 public CellLayoutAnimationController(Animation animation, float delay) {
1237 super(animation, delay);
1238 }
1239
1240 @Override
1241 protected long getDelayForView(View view) {
1242 return (int) (Math.random() * 150);
1243 }
1244 }
1245
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001246 public static class LayoutParams extends ViewGroup.MarginLayoutParams {
1247 /**
1248 * Horizontal location of the item in the grid.
1249 */
1250 @ViewDebug.ExportedProperty
1251 public int cellX;
1252
1253 /**
1254 * Vertical location of the item in the grid.
1255 */
1256 @ViewDebug.ExportedProperty
1257 public int cellY;
1258
1259 /**
1260 * Number of cells spanned horizontally by the item.
1261 */
1262 @ViewDebug.ExportedProperty
1263 public int cellHSpan;
1264
1265 /**
1266 * Number of cells spanned vertically by the item.
1267 */
1268 @ViewDebug.ExportedProperty
1269 public int cellVSpan;
Winson Chungaafa03c2010-06-11 17:34:16 -07001270
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001271 /**
1272 * Is this item currently being dragged
1273 */
1274 public boolean isDragging;
1275
1276 // X coordinate of the view in the layout.
1277 @ViewDebug.ExportedProperty
1278 int x;
1279 // Y coordinate of the view in the layout.
1280 @ViewDebug.ExportedProperty
1281 int y;
1282
Romain Guy84f296c2009-11-04 15:00:44 -08001283 boolean dropped;
Romain Guyfcb9e712009-10-02 16:06:52 -07001284
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001285 public LayoutParams(Context c, AttributeSet attrs) {
1286 super(c, attrs);
1287 cellHSpan = 1;
1288 cellVSpan = 1;
1289 }
1290
1291 public LayoutParams(ViewGroup.LayoutParams source) {
1292 super(source);
1293 cellHSpan = 1;
1294 cellVSpan = 1;
1295 }
Winson Chungaafa03c2010-06-11 17:34:16 -07001296
1297 public LayoutParams(LayoutParams source) {
1298 super(source);
1299 this.cellX = source.cellX;
1300 this.cellY = source.cellY;
1301 this.cellHSpan = source.cellHSpan;
1302 this.cellVSpan = source.cellVSpan;
1303 }
1304
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001305 public LayoutParams(int cellX, int cellY, int cellHSpan, int cellVSpan) {
Romain Guy8f19cdd2010-01-08 15:07:00 -08001306 super(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001307 this.cellX = cellX;
1308 this.cellY = cellY;
1309 this.cellHSpan = cellHSpan;
1310 this.cellVSpan = cellVSpan;
1311 }
1312
1313 public void setup(int cellWidth, int cellHeight, int widthGap, int heightGap,
1314 int hStartPadding, int vStartPadding) {
Winson Chungaafa03c2010-06-11 17:34:16 -07001315
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001316 final int myCellHSpan = cellHSpan;
1317 final int myCellVSpan = cellVSpan;
1318 final int myCellX = cellX;
1319 final int myCellY = cellY;
Winson Chungaafa03c2010-06-11 17:34:16 -07001320
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001321 width = myCellHSpan * cellWidth + ((myCellHSpan - 1) * widthGap) -
1322 leftMargin - rightMargin;
1323 height = myCellVSpan * cellHeight + ((myCellVSpan - 1) * heightGap) -
1324 topMargin - bottomMargin;
1325
1326 x = hStartPadding + myCellX * (cellWidth + widthGap) + leftMargin;
1327 y = vStartPadding + myCellY * (cellHeight + heightGap) + topMargin;
1328 }
Winson Chungaafa03c2010-06-11 17:34:16 -07001329
1330 public String toString() {
1331 return "(" + this.cellX + ", " + this.cellY + ")";
1332 }
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001333 }
1334
Michael Jurka0280c3b2010-09-17 15:00:07 -07001335 // This class stores info for two purposes:
1336 // 1. When dragging items (mDragInfo in Workspace), we store the View, its cellX & cellY,
1337 // its spanX, spanY, and the screen it is on
1338 // 2. When long clicking on an empty cell in a CellLayout, we save information about the
1339 // cellX and cellY coordinates and which page was clicked. We then set this as a tag on
1340 // the CellLayout that was long clicked
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001341 static final class CellInfo implements ContextMenu.ContextMenuInfo {
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001342 View cell;
Michael Jurkaa63c4522010-08-19 13:52:27 -07001343 int cellX = -1;
1344 int cellY = -1;
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001345 int spanX;
1346 int spanY;
1347 int screen;
1348 boolean valid;
1349
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001350 @Override
1351 public String toString() {
Winson Chungaafa03c2010-06-11 17:34:16 -07001352 return "Cell[view=" + (cell == null ? "null" : cell.getClass())
1353 + ", x=" + cellX + ", y=" + cellY + "]";
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001354 }
1355 }
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001356}