blob: 369f0d2fa6b2586ded3b6cf4ca3326bf789bbb9a [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
Chet Haase00397b12010-10-07 11:13:10 -070021import android.animation.TimeInterpolator;
Patrick Dubroyde7658b2010-09-27 11:15:43 -070022import android.animation.ValueAnimator;
23import android.animation.ValueAnimator.AnimatorUpdateListener;
Winson Chungaafa03c2010-06-11 17:34:16 -070024import android.app.WallpaperManager;
The Android Open Source Project31dd5032009-03-03 19:32:27 -080025import android.content.Context;
Joe Onorato79e56262009-09-21 15:23:04 -040026import android.content.res.Resources;
Winson Chungaafa03c2010-06-11 17:34:16 -070027import android.content.res.TypedArray;
28import android.graphics.Canvas;
Patrick Dubroyde7658b2010-09-27 11:15:43 -070029import android.graphics.Point;
30import android.graphics.PointF;
The Android Open Source Project31dd5032009-03-03 19:32:27 -080031import android.graphics.Rect;
32import android.graphics.RectF;
Patrick Dubroy6569f2c2010-07-12 14:25:18 -070033import android.graphics.drawable.Drawable;
The Android Open Source Project31dd5032009-03-03 19:32:27 -080034import android.util.AttributeSet;
35import android.view.ContextMenu;
36import android.view.MotionEvent;
37import android.view.View;
38import android.view.ViewDebug;
39import android.view.ViewGroup;
Winson Chungaafa03c2010-06-11 17:34:16 -070040import android.view.animation.Animation;
Winson Chung150fbab2010-09-29 17:14:26 -070041import android.view.animation.DecelerateInterpolator;
Winson Chungaafa03c2010-06-11 17:34:16 -070042import android.view.animation.LayoutAnimationController;
The Android Open Source Project31dd5032009-03-03 19:32:27 -080043
Adam Cohenf34bab52010-09-30 14:11:56 -070044public class CellLayout extends ViewGroup implements Dimmable {
Winson Chungaafa03c2010-06-11 17:34:16 -070045 static final String TAG = "CellLayout";
46
The Android Open Source Project31dd5032009-03-03 19:32:27 -080047 private int mCellWidth;
48 private int mCellHeight;
Winson Chungaafa03c2010-06-11 17:34:16 -070049
Winson Chungaafa03c2010-06-11 17:34:16 -070050 private int mLeftPadding;
51 private int mRightPadding;
52 private int mTopPadding;
53 private int mBottomPadding;
54
Adam Cohend22015c2010-07-26 22:02:18 -070055 private int mCountX;
56 private int mCountY;
The Android Open Source Project31dd5032009-03-03 19:32:27 -080057
58 private int mWidthGap;
59 private int mHeightGap;
60
61 private final Rect mRect = new Rect();
Patrick Dubroy8f86ddc2010-07-16 13:55:32 -070062 private final RectF mRectF = new RectF();
The Android Open Source Project31dd5032009-03-03 19:32:27 -080063 private final CellInfo mCellInfo = new CellInfo();
Winson Chungaafa03c2010-06-11 17:34:16 -070064
Patrick Dubroyde7658b2010-09-27 11:15:43 -070065 // These are temporary variables to prevent having to allocate a new object just to
66 // return an (x, y) value from helper functions. Do NOT use them to maintain other state.
Patrick Dubroy6569f2c2010-07-12 14:25:18 -070067 private final int[] mTmpCellXY = new int[2];
Patrick Dubroyde7658b2010-09-27 11:15:43 -070068 private final int[] mTmpPoint = new int[2];
69 private final PointF mTmpPointF = new PointF();
Patrick Dubroy6569f2c2010-07-12 14:25:18 -070070
The Android Open Source Project31dd5032009-03-03 19:32:27 -080071 boolean[][] mOccupied;
72
Michael Jurkadee05892010-07-27 10:01:56 -070073 private OnTouchListener mInterceptTouchListener;
74
Michael Jurka5f1c5092010-09-03 14:15:02 -070075 private float mBackgroundAlpha;
Adam Cohenf34bab52010-09-30 14:11:56 -070076
Michael Jurka5f1c5092010-09-03 14:15:02 -070077 private Drawable mBackground;
Adam Cohenf34bab52010-09-30 14:11:56 -070078 private Drawable mBackgroundMini;
79 private Drawable mBackgroundMiniHover;
Patrick Dubroy1262e362010-10-06 15:49:50 -070080 private Drawable mBackgroundHover;
81
82 // If we're actively dragging something over this screen, mHover is true
Michael Jurkaa63c4522010-08-19 13:52:27 -070083 private boolean mHover = false;
Michael Jurkadee05892010-07-27 10:01:56 -070084
Patrick Dubroyde7658b2010-09-27 11:15:43 -070085 private final Point mDragCenter = new Point();
Patrick Dubroy6569f2c2010-07-12 14:25:18 -070086
Patrick Dubroy6569f2c2010-07-12 14:25:18 -070087 private Drawable mDragRectDrawable;
88
Winson Chung150fbab2010-09-29 17:14:26 -070089 // These arrays are used to implement the drag visualization on x-large screens.
90 // They are used as circular arrays, indexed by mDragRectCurrent.
91 private Rect[] mDragRects = new Rect[8];
92 private int[] mDragRectAlphas = new int[mDragRects.length];
93 private InterruptibleInOutAnimator[] mDragRectAnims =
Patrick Dubroy49250ad2010-10-08 15:33:52 -070094 new InterruptibleInOutAnimator[mDragRects.length];
Winson Chung150fbab2010-09-29 17:14:26 -070095
96 // Used as an index into the above 3 arrays; indicates which is the most current value.
97 private int mDragRectCurrent = 0;
98
Patrick Dubroyde7658b2010-09-27 11:15:43 -070099 private Drawable mCrosshairsDrawable = null;
Patrick Dubroy49250ad2010-10-08 15:33:52 -0700100 private InterruptibleInOutAnimator mCrosshairsAnimator = null;
Patrick Dubroyde7658b2010-09-27 11:15:43 -0700101 private float mCrosshairsVisibility = 0.0f;
102
Patrick Dubroy6569f2c2010-07-12 14:25:18 -0700103 // When a drag operation is in progress, holds the nearest cell to the touch point
104 private final int[] mDragCell = new int[2];
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800105
Winson Chungaafa03c2010-06-11 17:34:16 -0700106 private final WallpaperManager mWallpaperManager;
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800107
108 public CellLayout(Context context) {
109 this(context, null);
110 }
111
112 public CellLayout(Context context, AttributeSet attrs) {
113 this(context, attrs, 0);
114 }
115
116 public CellLayout(Context context, AttributeSet attrs, int defStyle) {
117 super(context, attrs, defStyle);
Patrick Dubroy6569f2c2010-07-12 14:25:18 -0700118
119 // A ViewGroup usually does not draw, but CellLayout needs to draw a rectangle to show
120 // the user where a dragged item will land when dropped.
121 setWillNotDraw(false);
Michael Jurkaa63c4522010-08-19 13:52:27 -0700122
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800123 TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CellLayout, defStyle, 0);
124
125 mCellWidth = a.getDimensionPixelSize(R.styleable.CellLayout_cellWidth, 10);
126 mCellHeight = a.getDimensionPixelSize(R.styleable.CellLayout_cellHeight, 10);
Winson Chungaafa03c2010-06-11 17:34:16 -0700127
Adam Cohend22015c2010-07-26 22:02:18 -0700128 mLeftPadding =
129 a.getDimensionPixelSize(R.styleable.CellLayout_xAxisStartPadding, 10);
130 mRightPadding =
131 a.getDimensionPixelSize(R.styleable.CellLayout_xAxisEndPadding, 10);
132 mTopPadding =
133 a.getDimensionPixelSize(R.styleable.CellLayout_yAxisStartPadding, 10);
134 mBottomPadding =
135 a.getDimensionPixelSize(R.styleable.CellLayout_yAxisEndPadding, 10);
Winson Chungaafa03c2010-06-11 17:34:16 -0700136
Adam Cohend22015c2010-07-26 22:02:18 -0700137 mCountX = LauncherModel.getCellCountX();
138 mCountY = LauncherModel.getCellCountY();
Michael Jurka0280c3b2010-09-17 15:00:07 -0700139 mOccupied = new boolean[mCountX][mCountY];
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800140
141 a.recycle();
142
143 setAlwaysDrawnWithCacheEnabled(false);
144
Patrick Dubroyde7658b2010-09-27 11:15:43 -0700145 mWallpaperManager = WallpaperManager.getInstance(context);
146
Patrick Dubroy046e7eb2010-10-06 12:14:43 -0700147 final Resources res = getResources();
Patrick Dubroyde7658b2010-09-27 11:15:43 -0700148
Patrick Dubroy046e7eb2010-10-06 12:14:43 -0700149 if (LauncherApplication.isScreenXLarge()) {
Winson Chung150fbab2010-09-29 17:14:26 -0700150 mBackgroundMini = res.getDrawable(R.drawable.mini_home_screen_bg);
Adam Cohenf34bab52010-09-30 14:11:56 -0700151 mBackgroundMini.setFilterBitmap(true);
Winson Chung150fbab2010-09-29 17:14:26 -0700152 mBackground = res.getDrawable(R.drawable.home_screen_bg);
Patrick Dubroyde7658b2010-09-27 11:15:43 -0700153 mBackground.setFilterBitmap(true);
Winson Chung150fbab2010-09-29 17:14:26 -0700154 mBackgroundMiniHover = res.getDrawable(R.drawable.mini_home_screen_bg_hover);
Adam Cohenf34bab52010-09-30 14:11:56 -0700155 mBackgroundMiniHover.setFilterBitmap(true);
Patrick Dubroy1262e362010-10-06 15:49:50 -0700156 mBackgroundHover = res.getDrawable(R.drawable.home_screen_bg_hover);
157 mBackgroundHover.setFilterBitmap(true);
Patrick Dubroy046e7eb2010-10-06 12:14:43 -0700158 }
Patrick Dubroyde7658b2010-09-27 11:15:43 -0700159
Patrick Dubroy046e7eb2010-10-06 12:14:43 -0700160 // Initialize the data structures used for the drag visualization.
Winson Chung150fbab2010-09-29 17:14:26 -0700161
Patrick Dubroy046e7eb2010-10-06 12:14:43 -0700162 mDragRectDrawable = res.getDrawable(R.drawable.rounded_rect_green);
163 mCrosshairsDrawable = res.getDrawable(R.drawable.gardening_crosshairs);
Chet Haase00397b12010-10-07 11:13:10 -0700164 TimeInterpolator interp = new DecelerateInterpolator(2.5f); // Quint ease out
Patrick Dubroyde7658b2010-09-27 11:15:43 -0700165
Patrick Dubroy046e7eb2010-10-06 12:14:43 -0700166 // Set up the animation for fading the crosshairs in and out
167 int animDuration = res.getInteger(R.integer.config_crosshairsFadeInTime);
Patrick Dubroy49250ad2010-10-08 15:33:52 -0700168 mCrosshairsAnimator = new InterruptibleInOutAnimator(animDuration, 0.0f, 1.0f);
Patrick Dubroy046e7eb2010-10-06 12:14:43 -0700169 mCrosshairsAnimator.addUpdateListener(new AnimatorUpdateListener() {
170 public void onAnimationUpdate(ValueAnimator animation) {
171 mCrosshairsVisibility = ((Float) animation.getAnimatedValue()).floatValue();
172 CellLayout.this.invalidate();
173 }
174 });
175 mCrosshairsAnimator.setInterpolator(interp);
176
177 for (int i = 0; i < mDragRects.length; i++) {
178 mDragRects[i] = new Rect();
179 }
180
181 // When dragging things around the home screens, we show a green outline of
182 // where the item will land. The outlines gradually fade out, leaving a trail
183 // behind the drag path.
184 // Set up all the animations that are used to implement this fading.
185 final int duration = res.getInteger(R.integer.config_dragOutlineFadeTime);
186 final int fromAlphaValue = 0;
187 final int toAlphaValue = res.getInteger(R.integer.config_dragOutlineMaxAlpha);
188 for (int i = 0; i < mDragRectAnims.length; i++) {
189 final InterruptibleInOutAnimator anim =
190 new InterruptibleInOutAnimator(duration, fromAlphaValue, toAlphaValue);
191 anim.setInterpolator(interp);
192 final int thisIndex = i;
193 anim.addUpdateListener(new AnimatorUpdateListener() {
Patrick Dubroyde7658b2010-09-27 11:15:43 -0700194 public void onAnimationUpdate(ValueAnimator animation) {
Patrick Dubroy046e7eb2010-10-06 12:14:43 -0700195 mDragRectAlphas[thisIndex] = (Integer) animation.getAnimatedValue();
196 CellLayout.this.invalidate(mDragRects[thisIndex]);
Patrick Dubroyde7658b2010-09-27 11:15:43 -0700197 }
198 });
Patrick Dubroy046e7eb2010-10-06 12:14:43 -0700199 mDragRectAnims[i] = anim;
Patrick Dubroyde7658b2010-09-27 11:15:43 -0700200 }
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800201 }
202
Michael Jurkaa63c4522010-08-19 13:52:27 -0700203 public void setHover(boolean value) {
204 if (mHover != value) {
205 invalidate();
206 }
207 mHover = value;
208 }
209
Patrick Dubroy1262e362010-10-06 15:49:50 -0700210 public void drawChildren(Canvas canvas) {
211 super.dispatchDraw(canvas);
212 }
213
Jeff Sharkey83f111d2009-04-20 21:03:13 -0700214 @Override
Patrick Dubroy1262e362010-10-06 15:49:50 -0700215 protected void onDraw(Canvas canvas) {
Michael Jurka5f1c5092010-09-03 14:15:02 -0700216 if (mBackgroundAlpha > 0.0f) {
Adam Cohenf34bab52010-09-30 14:11:56 -0700217 Drawable bg;
Patrick Dubroy1262e362010-10-06 15:49:50 -0700218 if (getScaleX() < 0.5f) {
219 bg = mHover ? mBackgroundMiniHover : mBackgroundMini;
Adam Cohenf34bab52010-09-30 14:11:56 -0700220 } else {
Patrick Dubroy1262e362010-10-06 15:49:50 -0700221 bg = mHover ? mBackgroundHover : mBackground;
Adam Cohenf34bab52010-09-30 14:11:56 -0700222 }
Adam Cohen9c4949e2010-10-05 12:27:22 -0700223 if (bg != null) {
224 bg.setAlpha((int) (mBackgroundAlpha * 255));
225 bg.draw(canvas);
226 }
Michael Jurkaa63c4522010-08-19 13:52:27 -0700227 }
Romain Guya6abce82009-11-10 02:54:41 -0800228
Patrick Dubroyde7658b2010-09-27 11:15:43 -0700229 if (mCrosshairsVisibility > 0.0f) {
230 final int countX = mCountX;
231 final int countY = mCountY;
232
Patrick Dubroyde7658b2010-09-27 11:15:43 -0700233 final float MAX_ALPHA = 0.4f;
234 final int MAX_VISIBLE_DISTANCE = 600;
235 final float DISTANCE_MULTIPLIER = 0.002f;
236
237 final Drawable d = mCrosshairsDrawable;
238 final int width = d.getIntrinsicWidth();
239 final int height = d.getIntrinsicHeight();
240
241 int x = getLeftPadding() - (mWidthGap / 2) - (width / 2);
242 for (int col = 0; col <= countX; col++) {
243 int y = getTopPadding() - (mHeightGap / 2) - (height / 2);
244 for (int row = 0; row <= countY; row++) {
245 mTmpPointF.set(x - mDragCenter.x, y - mDragCenter.y);
246 float dist = mTmpPointF.length();
247 // Crosshairs further from the drag point are more faint
248 float alpha = Math.min(MAX_ALPHA,
249 DISTANCE_MULTIPLIER * (MAX_VISIBLE_DISTANCE - dist));
250 if (alpha > 0.0f) {
251 d.setBounds(x, y, x + width, y + height);
252 d.setAlpha((int) (alpha * 255 * mCrosshairsVisibility));
253 d.draw(canvas);
254 }
255 y += mCellHeight + mHeightGap;
256 }
257 x += mCellWidth + mWidthGap;
258 }
Winson Chung150fbab2010-09-29 17:14:26 -0700259
260 for (int i = 0; i < mDragRects.length; i++) {
261 int alpha = mDragRectAlphas[i];
262 if (alpha > 0) {
263 mDragRectDrawable.setAlpha(alpha);
264 mDragRectDrawable.setBounds(mDragRects[i]);
265 mDragRectDrawable.draw(canvas);
266 }
267 }
Patrick Dubroy6569f2c2010-07-12 14:25:18 -0700268 }
269 }
270
Adam Cohenf34bab52010-09-30 14:11:56 -0700271 public void setDimmableProgress(float progress) {
272 for (int i = 0; i < getChildCount(); i++) {
273 Dimmable d = (Dimmable) getChildAt(i);
274 d.setDimmableProgress(progress);
275 }
276 }
277
278 public float getDimmableProgress() {
279 if (getChildCount() > 0) {
280 return ((Dimmable) getChildAt(0)).getDimmableProgress();
281 }
282 return 0.0f;
283 }
284
Patrick Dubroy6569f2c2010-07-12 14:25:18 -0700285 @Override
Jeff Sharkey83f111d2009-04-20 21:03:13 -0700286 public void cancelLongPress() {
287 super.cancelLongPress();
288
289 // Cancel long press for all children
290 final int count = getChildCount();
291 for (int i = 0; i < count; i++) {
292 final View child = getChildAt(i);
293 child.cancelLongPress();
294 }
295 }
296
Michael Jurkadee05892010-07-27 10:01:56 -0700297 public void setOnInterceptTouchListener(View.OnTouchListener listener) {
298 mInterceptTouchListener = listener;
299 }
300
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800301 int getCountX() {
Adam Cohend22015c2010-07-26 22:02:18 -0700302 return mCountX;
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800303 }
304
305 int getCountY() {
Adam Cohend22015c2010-07-26 22:02:18 -0700306 return mCountY;
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800307 }
308
Winson Chungaafa03c2010-06-11 17:34:16 -0700309 public boolean addViewToCellLayout(View child, int index, int childId, LayoutParams params) {
310 final LayoutParams lp = params;
311
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800312 // Generate an id for each view, this assumes we have at most 256x256 cells
313 // per workspace screen
Adam Cohend22015c2010-07-26 22:02:18 -0700314 if (lp.cellX >= 0 && lp.cellX <= mCountX - 1 && lp.cellY >= 0 && lp.cellY <= mCountY - 1) {
Winson Chungaafa03c2010-06-11 17:34:16 -0700315 // If the horizontal or vertical span is set to -1, it is taken to
316 // mean that it spans the extent of the CellLayout
Adam Cohend22015c2010-07-26 22:02:18 -0700317 if (lp.cellHSpan < 0) lp.cellHSpan = mCountX;
318 if (lp.cellVSpan < 0) lp.cellVSpan = mCountY;
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800319
Winson Chungaafa03c2010-06-11 17:34:16 -0700320 child.setId(childId);
321
Michael Jurkadee05892010-07-27 10:01:56 -0700322 // We might be in the middle or end of shrinking/fading to a dimmed view
323 // Make sure this view's alpha is set the same as all the rest of the views
Michael Jurka5f1c5092010-09-03 14:15:02 -0700324 child.setAlpha(getAlpha());
Winson Chungaafa03c2010-06-11 17:34:16 -0700325 addView(child, index, lp);
Michael Jurkadee05892010-07-27 10:01:56 -0700326
Michael Jurka0280c3b2010-09-17 15:00:07 -0700327 markCellsAsOccupiedForView(child);
328
Winson Chungaafa03c2010-06-11 17:34:16 -0700329 return true;
330 }
331 return false;
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800332 }
333
334 @Override
Michael Jurka0280c3b2010-09-17 15:00:07 -0700335 public void removeAllViews() {
336 clearOccupiedCells();
337 }
338
339 @Override
340 public void removeAllViewsInLayout() {
341 clearOccupiedCells();
342 }
343
344 @Override
345 public void removeView(View view) {
346 markCellsAsUnoccupiedForView(view);
347 super.removeView(view);
348 }
349
350 @Override
351 public void removeViewAt(int index) {
352 markCellsAsUnoccupiedForView(getChildAt(index));
353 super.removeViewAt(index);
354 }
355
356 @Override
357 public void removeViewInLayout(View view) {
358 markCellsAsUnoccupiedForView(view);
359 super.removeViewInLayout(view);
360 }
361
362 @Override
363 public void removeViews(int start, int count) {
364 for (int i = start; i < start + count; i++) {
365 markCellsAsUnoccupiedForView(getChildAt(i));
366 }
367 super.removeViews(start, count);
368 }
369
370 @Override
371 public void removeViewsInLayout(int start, int count) {
372 for (int i = start; i < start + count; i++) {
373 markCellsAsUnoccupiedForView(getChildAt(i));
374 }
375 super.removeViewsInLayout(start, count);
376 }
377
378 @Override
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800379 public void requestChildFocus(View child, View focused) {
380 super.requestChildFocus(child, focused);
381 if (child != null) {
382 Rect r = new Rect();
383 child.getDrawingRect(r);
384 requestRectangleOnScreen(r);
385 }
386 }
387
388 @Override
389 protected void onAttachedToWindow() {
390 super.onAttachedToWindow();
391 mCellInfo.screen = ((ViewGroup) getParent()).indexOfChild(this);
392 }
393
Michael Jurkaaf442092010-06-10 17:01:57 -0700394 public void setTagToCellInfoForPoint(int touchX, int touchY) {
395 final CellInfo cellInfo = mCellInfo;
396 final Rect frame = mRect;
397 final int x = touchX + mScrollX;
398 final int y = touchY + mScrollY;
399 final int count = getChildCount();
400
401 boolean found = false;
402 for (int i = count - 1; i >= 0; i--) {
403 final View child = getChildAt(i);
404
405 if ((child.getVisibility()) == VISIBLE || child.getAnimation() != null) {
406 child.getHitRect(frame);
407 if (frame.contains(x, y)) {
408 final LayoutParams lp = (LayoutParams) child.getLayoutParams();
409 cellInfo.cell = child;
410 cellInfo.cellX = lp.cellX;
411 cellInfo.cellY = lp.cellY;
412 cellInfo.spanX = lp.cellHSpan;
413 cellInfo.spanY = lp.cellVSpan;
414 cellInfo.valid = true;
415 found = true;
Michael Jurkaaf442092010-06-10 17:01:57 -0700416 break;
417 }
418 }
419 }
Winson Chungaafa03c2010-06-11 17:34:16 -0700420
Michael Jurkaaf442092010-06-10 17:01:57 -0700421 if (!found) {
Patrick Dubroy6569f2c2010-07-12 14:25:18 -0700422 final int cellXY[] = mTmpCellXY;
Michael Jurkaaf442092010-06-10 17:01:57 -0700423 pointToCellExact(x, y, cellXY);
424
Michael Jurkaaf442092010-06-10 17:01:57 -0700425 cellInfo.cell = null;
426 cellInfo.cellX = cellXY[0];
427 cellInfo.cellY = cellXY[1];
428 cellInfo.spanX = 1;
429 cellInfo.spanY = 1;
Michael Jurka0280c3b2010-09-17 15:00:07 -0700430 cellInfo.valid = cellXY[0] >= 0 && cellXY[1] >= 0 && cellXY[0] < mCountX &&
431 cellXY[1] < mCountY && !mOccupied[cellXY[0]][cellXY[1]];
Michael Jurkaaf442092010-06-10 17:01:57 -0700432 }
433 setTag(cellInfo);
434 }
435
Winson Chungaafa03c2010-06-11 17:34:16 -0700436
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800437 @Override
438 public boolean onInterceptTouchEvent(MotionEvent ev) {
Michael Jurkadee05892010-07-27 10:01:56 -0700439 if (mInterceptTouchListener != null && mInterceptTouchListener.onTouch(this, ev)) {
440 return true;
441 }
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800442 final int action = ev.getAction();
443 final CellInfo cellInfo = mCellInfo;
444
445 if (action == MotionEvent.ACTION_DOWN) {
Michael Jurkaaf442092010-06-10 17:01:57 -0700446 setTagToCellInfoForPoint((int) ev.getX(), (int) ev.getY());
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800447 } else if (action == MotionEvent.ACTION_UP) {
448 cellInfo.cell = null;
449 cellInfo.cellX = -1;
450 cellInfo.cellY = -1;
451 cellInfo.spanX = 0;
452 cellInfo.spanY = 0;
453 cellInfo.valid = false;
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800454 setTag(cellInfo);
455 }
456
457 return false;
458 }
459
460 @Override
461 public CellInfo getTag() {
Michael Jurka0280c3b2010-09-17 15:00:07 -0700462 return (CellInfo) super.getTag();
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800463 }
464
Patrick Dubroy6569f2c2010-07-12 14:25:18 -0700465 /**
466 * Check if the row 'y' is empty from columns 'left' to 'right', inclusive.
467 */
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800468 private static boolean isRowEmpty(int y, int left, int right, boolean[][] occupied) {
469 for (int x = left; x <= right; x++) {
470 if (occupied[x][y]) {
471 return false;
472 }
473 }
474 return true;
475 }
476
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800477 /**
Winson Chungaafa03c2010-06-11 17:34:16 -0700478 * Given a point, return the cell that strictly encloses that point
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800479 * @param x X coordinate of the point
480 * @param y Y coordinate of the point
481 * @param result Array of 2 ints to hold the x and y coordinate of the cell
482 */
483 void pointToCellExact(int x, int y, int[] result) {
Winson Chungaafa03c2010-06-11 17:34:16 -0700484 final int hStartPadding = getLeftPadding();
485 final int vStartPadding = getTopPadding();
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800486
487 result[0] = (x - hStartPadding) / (mCellWidth + mWidthGap);
488 result[1] = (y - vStartPadding) / (mCellHeight + mHeightGap);
489
Adam Cohend22015c2010-07-26 22:02:18 -0700490 final int xAxis = mCountX;
491 final int yAxis = mCountY;
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800492
493 if (result[0] < 0) result[0] = 0;
494 if (result[0] >= xAxis) result[0] = xAxis - 1;
495 if (result[1] < 0) result[1] = 0;
496 if (result[1] >= yAxis) result[1] = yAxis - 1;
497 }
Winson Chungaafa03c2010-06-11 17:34:16 -0700498
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800499 /**
500 * Given a point, return the cell that most closely encloses that point
501 * @param x X coordinate of the point
502 * @param y Y coordinate of the point
503 * @param result Array of 2 ints to hold the x and y coordinate of the cell
504 */
505 void pointToCellRounded(int x, int y, int[] result) {
506 pointToCellExact(x + (mCellWidth / 2), y + (mCellHeight / 2), result);
507 }
508
509 /**
510 * Given a cell coordinate, return the point that represents the upper left corner of that cell
Winson Chungaafa03c2010-06-11 17:34:16 -0700511 *
512 * @param cellX X coordinate of the cell
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800513 * @param cellY Y coordinate of the cell
Winson Chungaafa03c2010-06-11 17:34:16 -0700514 *
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800515 * @param result Array of 2 ints to hold the x and y coordinate of the point
516 */
517 void cellToPoint(int cellX, int cellY, int[] result) {
Winson Chungaafa03c2010-06-11 17:34:16 -0700518 final int hStartPadding = getLeftPadding();
519 final int vStartPadding = getTopPadding();
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800520
521 result[0] = hStartPadding + cellX * (mCellWidth + mWidthGap);
522 result[1] = vStartPadding + cellY * (mCellHeight + mHeightGap);
523 }
524
Romain Guy84f296c2009-11-04 15:00:44 -0800525 int getCellWidth() {
526 return mCellWidth;
527 }
528
529 int getCellHeight() {
530 return mCellHeight;
531 }
532
Romain Guy1a304a12009-11-10 00:02:32 -0800533 int getLeftPadding() {
Winson Chungaafa03c2010-06-11 17:34:16 -0700534 return mLeftPadding;
Romain Guy1a304a12009-11-10 00:02:32 -0800535 }
536
537 int getTopPadding() {
Winson Chungaafa03c2010-06-11 17:34:16 -0700538 return mTopPadding;
Romain Guy1a304a12009-11-10 00:02:32 -0800539 }
540
541 int getRightPadding() {
Winson Chungaafa03c2010-06-11 17:34:16 -0700542 return mRightPadding;
Romain Guy1a304a12009-11-10 00:02:32 -0800543 }
544
545 int getBottomPadding() {
Winson Chungaafa03c2010-06-11 17:34:16 -0700546 return mBottomPadding;
Romain Guy1a304a12009-11-10 00:02:32 -0800547 }
548
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800549 @Override
550 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
551 // TODO: currently ignoring padding
Winson Chungaafa03c2010-06-11 17:34:16 -0700552
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800553 int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);
Winson Chungaafa03c2010-06-11 17:34:16 -0700554 int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec);
555
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800556 int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);
557 int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec);
Winson Chungaafa03c2010-06-11 17:34:16 -0700558
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800559 if (widthSpecMode == MeasureSpec.UNSPECIFIED || heightSpecMode == MeasureSpec.UNSPECIFIED) {
560 throw new RuntimeException("CellLayout cannot have UNSPECIFIED dimensions");
561 }
562
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800563 final int cellWidth = mCellWidth;
564 final int cellHeight = mCellHeight;
565
Adam Cohend22015c2010-07-26 22:02:18 -0700566 int numWidthGaps = mCountX - 1;
567 int numHeightGaps = mCountY - 1;
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800568
Michael Jurka0280c3b2010-09-17 15:00:07 -0700569 int vSpaceLeft = heightSpecSize - mTopPadding - mBottomPadding - (cellHeight * mCountY);
Adam Cohend22015c2010-07-26 22:02:18 -0700570 mHeightGap = vSpaceLeft / numHeightGaps;
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800571
Michael Jurka0280c3b2010-09-17 15:00:07 -0700572 int hSpaceLeft = widthSpecSize - mLeftPadding - mRightPadding - (cellWidth * mCountX);
Adam Cohend22015c2010-07-26 22:02:18 -0700573 mWidthGap = hSpaceLeft / numWidthGaps;
Winson Chungaafa03c2010-06-11 17:34:16 -0700574
Michael Jurka5f1c5092010-09-03 14:15:02 -0700575 // center it around the min gaps
576 int minGap = Math.min(mWidthGap, mHeightGap);
577 mWidthGap = mHeightGap = minGap;
578
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800579 int count = getChildCount();
580
581 for (int i = 0; i < count; i++) {
582 View child = getChildAt(i);
583 LayoutParams lp = (LayoutParams) child.getLayoutParams();
Winson Chungaafa03c2010-06-11 17:34:16 -0700584 lp.setup(cellWidth, cellHeight, mWidthGap, mHeightGap,
585 mLeftPadding, mTopPadding);
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800586
Michael Jurka0280c3b2010-09-17 15:00:07 -0700587 int childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(lp.width, MeasureSpec.EXACTLY);
Winson Chungaafa03c2010-06-11 17:34:16 -0700588 int childheightMeasureSpec = MeasureSpec.makeMeasureSpec(lp.height,
589 MeasureSpec.EXACTLY);
590
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800591 child.measure(childWidthMeasureSpec, childheightMeasureSpec);
592 }
Michael Jurka5f1c5092010-09-03 14:15:02 -0700593 if (widthSpecMode == MeasureSpec.AT_MOST) {
594 int newWidth = mLeftPadding + mRightPadding + (mCountX * cellWidth) +
595 ((mCountX - 1) * minGap);
596 int newHeight = mTopPadding + mBottomPadding + (mCountY * cellHeight) +
597 ((mCountY - 1) * minGap);
598 setMeasuredDimension(newWidth, newHeight);
599 } else if (widthSpecMode == MeasureSpec.EXACTLY) {
600 setMeasuredDimension(widthSpecSize, heightSpecSize);
601 }
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800602 }
603
604 @Override
Michael Jurka28750fb2010-09-24 17:43:49 -0700605 protected void onLayout(boolean changed, int l, int t, int r, int b) {
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800606 int count = getChildCount();
607
608 for (int i = 0; i < count; i++) {
609 View child = getChildAt(i);
610 if (child.getVisibility() != GONE) {
611
612 CellLayout.LayoutParams lp = (CellLayout.LayoutParams) child.getLayoutParams();
613
614 int childLeft = lp.x;
615 int childTop = lp.y;
616 child.layout(childLeft, childTop, childLeft + lp.width, childTop + lp.height);
Romain Guy84f296c2009-11-04 15:00:44 -0800617
618 if (lp.dropped) {
619 lp.dropped = false;
620
Patrick Dubroy6569f2c2010-07-12 14:25:18 -0700621 final int[] cellXY = mTmpCellXY;
Romain Guy06762ab2010-01-25 16:51:08 -0800622 getLocationOnScreen(cellXY);
Romain Guy84f296c2009-11-04 15:00:44 -0800623 mWallpaperManager.sendWallpaperCommand(getWindowToken(), "android.home.drop",
Romain Guy06762ab2010-01-25 16:51:08 -0800624 cellXY[0] + childLeft + lp.width / 2,
625 cellXY[1] + childTop + lp.height / 2, 0, null);
Romain Guy84f296c2009-11-04 15:00:44 -0800626 }
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800627 }
628 }
629 }
630
631 @Override
Michael Jurkadee05892010-07-27 10:01:56 -0700632 protected void onSizeChanged(int w, int h, int oldw, int oldh) {
633 super.onSizeChanged(w, h, oldw, oldh);
Michael Jurka5f1c5092010-09-03 14:15:02 -0700634 if (mBackground != null) {
Patrick Dubroy1262e362010-10-06 15:49:50 -0700635 mBackground.setBounds(0, 0, w, h);
636 }
637 if (mBackgroundHover != null) {
638 mBackgroundHover.setBounds(0, 0, w, h);
Michael Jurkaa63c4522010-08-19 13:52:27 -0700639 }
Adam Cohenf34bab52010-09-30 14:11:56 -0700640 if (mBackgroundMiniHover != null) {
Patrick Dubroy1262e362010-10-06 15:49:50 -0700641 mBackgroundMiniHover.setBounds(0, 0, w, h);
Adam Cohenf34bab52010-09-30 14:11:56 -0700642 }
643 if (mBackgroundMini != null) {
Patrick Dubroy1262e362010-10-06 15:49:50 -0700644 mBackgroundMini.setBounds(0, 0, w, h);
Michael Jurkaa63c4522010-08-19 13:52:27 -0700645 }
Michael Jurkadee05892010-07-27 10:01:56 -0700646 }
647
648 @Override
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800649 protected void setChildrenDrawingCacheEnabled(boolean enabled) {
650 final int count = getChildCount();
651 for (int i = 0; i < count; i++) {
652 final View view = getChildAt(i);
653 view.setDrawingCacheEnabled(enabled);
654 // Update the drawing caches
Adam Powellfefa0ce2010-05-03 10:23:50 -0700655 view.buildDrawingCache(true);
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800656 }
657 }
658
659 @Override
660 protected void setChildrenDrawnWithCacheEnabled(boolean enabled) {
661 super.setChildrenDrawnWithCacheEnabled(enabled);
662 }
663
Michael Jurka5f1c5092010-09-03 14:15:02 -0700664 public float getBackgroundAlpha() {
665 return mBackgroundAlpha;
Michael Jurkadee05892010-07-27 10:01:56 -0700666 }
667
Michael Jurka5f1c5092010-09-03 14:15:02 -0700668 public void setBackgroundAlpha(float alpha) {
669 mBackgroundAlpha = alpha;
Michael Jurka0142d492010-08-25 17:46:15 -0700670 invalidate();
Michael Jurkadee05892010-07-27 10:01:56 -0700671 }
672
Michael Jurka5f1c5092010-09-03 14:15:02 -0700673 // Need to return true to let the view system know we know how to handle alpha-- this is
674 // because when our children have an alpha of 0.0f, they are still rendering their "dimmed"
675 // versions
676 @Override
677 protected boolean onSetAlpha(int alpha) {
678 return true;
679 }
680
681 public void setAlpha(float alpha) {
682 setChildrenAlpha(alpha);
683 super.setAlpha(alpha);
684 }
685
Michael Jurkadee05892010-07-27 10:01:56 -0700686 private void setChildrenAlpha(float alpha) {
Michael Jurka0142d492010-08-25 17:46:15 -0700687 final int childCount = getChildCount();
688 for (int i = 0; i < childCount; i++) {
Michael Jurkadee05892010-07-27 10:01:56 -0700689 getChildAt(i).setAlpha(alpha);
690 }
691 }
692
Michael Jurka0280c3b2010-09-17 15:00:07 -0700693 private boolean isVacantIgnoring(
694 int originX, int originY, int spanX, int spanY, View ignoreView) {
695 if (ignoreView != null) {
696 markCellsAsUnoccupiedForView(ignoreView);
697 }
Michael Jurka28750fb2010-09-24 17:43:49 -0700698 boolean isVacant = true;
Patrick Dubroy6569f2c2010-07-12 14:25:18 -0700699 for (int i = 0; i < spanY; i++) {
700 if (!isRowEmpty(originY + i, originX, originX + spanX - 1, mOccupied)) {
Michael Jurka28750fb2010-09-24 17:43:49 -0700701 isVacant = false;
702 break;
Patrick Dubroy6569f2c2010-07-12 14:25:18 -0700703 }
704 }
Michael Jurka0280c3b2010-09-17 15:00:07 -0700705 if (ignoreView != null) {
706 markCellsAsOccupiedForView(ignoreView);
707 }
Michael Jurka28750fb2010-09-24 17:43:49 -0700708 return isVacant;
Patrick Dubroy6569f2c2010-07-12 14:25:18 -0700709 }
710
Michael Jurka0280c3b2010-09-17 15:00:07 -0700711 private boolean isVacant(int originX, int originY, int spanX, int spanY) {
712 return isVacantIgnoring(originX, originY, spanX, spanY, null);
713 }
714
Patrick Dubroy440c3602010-07-13 17:50:32 -0700715 public View getChildAt(int x, int y) {
716 final int count = getChildCount();
717 for (int i = 0; i < count; i++) {
718 View child = getChildAt(i);
719 LayoutParams lp = (LayoutParams) child.getLayoutParams();
720
721 if ((lp.cellX <= x) && (x < lp.cellX + lp.cellHSpan) &&
722 (lp.cellY <= y) && (y < lp.cellY + lp.cellHSpan)) {
723 return child;
724 }
725 }
726 return null;
727 }
728
Patrick Dubroy6569f2c2010-07-12 14:25:18 -0700729 /**
Patrick Dubroy8f86ddc2010-07-16 13:55:32 -0700730 * Estimate the size that a child with the given dimensions will take in the layout.
731 */
732 void estimateChildSize(int minWidth, int minHeight, int[] result) {
733 // Assuming it's placed at 0, 0, find where the bottom right cell will land
734 rectToCell(minWidth, minHeight, result);
735
736 // Then figure out the rect it will occupy
737 cellToRect(0, 0, result[0], result[1], mRectF);
738 result[0] = (int)mRectF.width();
739 result[1] = (int)mRectF.height();
740 }
741
742 /**
Patrick Dubroy6569f2c2010-07-12 14:25:18 -0700743 * Estimate where the top left cell of the dragged item will land if it is dropped.
744 *
745 * @param originX The X value of the top left corner of the item
746 * @param originY The Y value of the top left corner of the item
747 * @param spanX The number of horizontal cells that the item spans
748 * @param spanY The number of vertical cells that the item spans
749 * @param result The estimated drop cell X and Y.
750 */
751 void estimateDropCell(int originX, int originY, int spanX, int spanY, int[] result) {
Adam Cohend22015c2010-07-26 22:02:18 -0700752 final int countX = mCountX;
753 final int countY = mCountY;
Patrick Dubroy6569f2c2010-07-12 14:25:18 -0700754
Michael Jurkaa63c4522010-08-19 13:52:27 -0700755 // pointToCellRounded takes the top left of a cell but will pad that with
756 // cellWidth/2 and cellHeight/2 when finding the matching cell
757 pointToCellRounded(originX, originY, result);
Patrick Dubroy6569f2c2010-07-12 14:25:18 -0700758
759 // If the item isn't fully on this screen, snap to the edges
760 int rightOverhang = result[0] + spanX - countX;
761 if (rightOverhang > 0) {
762 result[0] -= rightOverhang; // Snap to right
763 }
764 result[0] = Math.max(0, result[0]); // Snap to left
765 int bottomOverhang = result[1] + spanY - countY;
766 if (bottomOverhang > 0) {
767 result[1] -= bottomOverhang; // Snap to bottom
768 }
769 result[1] = Math.max(0, result[1]); // Snap to top
770 }
771
Patrick Dubroyde7658b2010-09-27 11:15:43 -0700772 void visualizeDropLocation(View view, int originX, int originY, int spanX, int spanY) {
773 final int[] nearest = findNearestVacantArea(originX, originY, spanX, spanY, view, mDragCell);
774 mDragCenter.set(originX + (view.getWidth() / 2), originY + (view.getHeight() / 2));
Patrick Dubroy6569f2c2010-07-12 14:25:18 -0700775
Patrick Dubroyde7658b2010-09-27 11:15:43 -0700776 if (nearest != null) {
Patrick Dubroy6569f2c2010-07-12 14:25:18 -0700777 // Find the top left corner of the rect the object will occupy
Patrick Dubroyde7658b2010-09-27 11:15:43 -0700778 final int[] topLeft = mTmpPoint;
779 cellToPoint(nearest[0], nearest[1], topLeft);
780
781 // Need to copy these, because the next call to cellToPoint will overwrite them
Patrick Dubroy6569f2c2010-07-12 14:25:18 -0700782 final int left = topLeft[0];
783 final int top = topLeft[1];
784
Winson Chung150fbab2010-09-29 17:14:26 -0700785 final Rect dragRect = mDragRects[mDragRectCurrent];
786
787 if (dragRect.isEmpty() || left != dragRect.left || top != dragRect.top) {
788 // Now find the bottom right
789 final int[] bottomRight = mTmpPoint;
790 cellToPoint(nearest[0] + spanX - 1, nearest[1] + spanY - 1, bottomRight);
791 bottomRight[0] += mCellWidth;
792 bottomRight[1] += mCellHeight;
793
794 final int oldIndex = mDragRectCurrent;
795 mDragRectCurrent = (oldIndex + 1) % mDragRects.length;
796
797 mDragRects[mDragRectCurrent].set(left, top, bottomRight[0], bottomRight[1]);
798
799 mDragRectAnims[oldIndex].animateOut();
800 mDragRectAnims[mDragRectCurrent].animateIn();
801 }
Patrick Dubroy6569f2c2010-07-12 14:25:18 -0700802 }
Patrick Dubroy49250ad2010-10-08 15:33:52 -0700803
804 // If we are drawing crosshairs, the entire CellLayout needs to be invalidated
805 if (mCrosshairsDrawable != null) {
806 invalidate();
807 }
Patrick Dubroy6569f2c2010-07-12 14:25:18 -0700808 }
809
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800810 /**
Jeff Sharkey70864282009-04-07 21:08:40 -0700811 * Find a vacant area that will fit the given bounds nearest the requested
812 * cell location. Uses Euclidean distance to score multiple vacant areas.
Winson Chungaafa03c2010-06-11 17:34:16 -0700813 *
Romain Guy51afc022009-05-04 18:03:43 -0700814 * @param pixelX The X location at which you want to search for a vacant area.
815 * @param pixelY The Y location at which you want to search for a vacant area.
Jeff Sharkey70864282009-04-07 21:08:40 -0700816 * @param spanX Horizontal span of the object.
817 * @param spanY Vertical span of the object.
Patrick Dubroyde7658b2010-09-27 11:15:43 -0700818 * @param result Array in which to place the result, or null (in which case a new array will
819 * be allocated)
Jeff Sharkey70864282009-04-07 21:08:40 -0700820 * @return The X, Y cell of a vacant area that can contain this object,
821 * nearest the requested location.
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800822 */
Michael Jurka6a1435d2010-09-27 17:35:12 -0700823 int[] findNearestVacantArea(
Patrick Dubroyde7658b2010-09-27 11:15:43 -0700824 int pixelX, int pixelY, int spanX, int spanY, int[] result) {
825 return findNearestVacantArea(pixelX, pixelY, spanX, spanY, null, result);
Michael Jurka6a1435d2010-09-27 17:35:12 -0700826 }
Winson Chungaafa03c2010-06-11 17:34:16 -0700827
Michael Jurka6a1435d2010-09-27 17:35:12 -0700828 /**
829 * Find a vacant area that will fit the given bounds nearest the requested
830 * cell location. Uses Euclidean distance to score multiple vacant areas.
831 *
832 * @param pixelX The X location at which you want to search for a vacant area.
833 * @param pixelY The Y location at which you want to search for a vacant area.
834 * @param spanX Horizontal span of the object.
835 * @param spanY Vertical span of the object.
Michael Jurka6a1435d2010-09-27 17:35:12 -0700836 * @param ignoreView Considers space occupied by this view as unoccupied
Patrick Dubroyde7658b2010-09-27 11:15:43 -0700837 * @param result Previously returned value to possibly recycle.
Michael Jurka6a1435d2010-09-27 17:35:12 -0700838 * @return The X, Y cell of a vacant area that can contain this object,
839 * nearest the requested location.
840 */
841 int[] findNearestVacantArea(
Patrick Dubroyde7658b2010-09-27 11:15:43 -0700842 int pixelX, int pixelY, int spanX, int spanY, View ignoreView, int[] result) {
Michael Jurkac6ee42e2010-09-30 12:04:50 -0700843 // mark space take by ignoreView as available (method checks if ignoreView is null)
844 markCellsAsUnoccupiedForView(ignoreView);
845
Jeff Sharkey70864282009-04-07 21:08:40 -0700846 // Keep track of best-scoring drop area
Patrick Dubroyde7658b2010-09-27 11:15:43 -0700847 final int[] bestXY = result != null ? result : new int[2];
Jeff Sharkey70864282009-04-07 21:08:40 -0700848 double bestDistance = Double.MAX_VALUE;
Winson Chungaafa03c2010-06-11 17:34:16 -0700849
Patrick Dubroyde7658b2010-09-27 11:15:43 -0700850 final int countX = mCountX;
851 final int countY = mCountY;
852 final boolean[][] occupied = mOccupied;
853
854 for (int x = 0; x < countX - (spanX - 1); x++) {
Michael Jurkac28de512010-08-13 11:27:44 -0700855 inner:
Patrick Dubroyde7658b2010-09-27 11:15:43 -0700856 for (int y = 0; y < countY - (spanY - 1); y++) {
Michael Jurkac28de512010-08-13 11:27:44 -0700857 for (int i = 0; i < spanX; i++) {
858 for (int j = 0; j < spanY; j++) {
Patrick Dubroyde7658b2010-09-27 11:15:43 -0700859 if (occupied[x + i][y + j]) {
Michael Jurkac28de512010-08-13 11:27:44 -0700860 // small optimization: we can skip to below the row we just found
861 // an occupied cell
862 y += j;
863 continue inner;
864 }
865 }
866 }
867 final int[] cellXY = mTmpCellXY;
868 cellToPoint(x, y, cellXY);
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800869
Michael Jurkac28de512010-08-13 11:27:44 -0700870 double distance = Math.sqrt(Math.pow(cellXY[0] - pixelX, 2)
871 + Math.pow(cellXY[1] - pixelY, 2));
872 if (distance <= bestDistance) {
873 bestDistance = distance;
874 bestXY[0] = x;
875 bestXY[1] = y;
876 }
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800877 }
878 }
Michael Jurkac6ee42e2010-09-30 12:04:50 -0700879 // re-mark space taken by ignoreView as occupied
880 markCellsAsOccupiedForView(ignoreView);
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800881
Winson Chungaafa03c2010-06-11 17:34:16 -0700882 // Return null if no suitable location found
Jeff Sharkey70864282009-04-07 21:08:40 -0700883 if (bestDistance < Double.MAX_VALUE) {
884 return bestXY;
885 } else {
886 return null;
887 }
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800888 }
Winson Chungaafa03c2010-06-11 17:34:16 -0700889
Michael Jurka0280c3b2010-09-17 15:00:07 -0700890 boolean existsEmptyCell() {
891 return findCellForSpan(null, 1, 1);
892 }
893
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800894 /**
Michael Jurka0280c3b2010-09-17 15:00:07 -0700895 * Finds the upper-left coordinate of the first rectangle in the grid that can
896 * hold a cell of the specified dimensions. If intersectX and intersectY are not -1,
897 * then this method will only return coordinates for rectangles that contain the cell
898 * (intersectX, intersectY)
899 *
900 * @param cellXY The array that will contain the position of a vacant cell if such a cell
901 * can be found.
902 * @param spanX The horizontal span of the cell we want to find.
903 * @param spanY The vertical span of the cell we want to find.
904 *
905 * @return True if a vacant cell of the specified dimension was found, false otherwise.
Patrick Dubroy6569f2c2010-07-12 14:25:18 -0700906 */
Michael Jurka0280c3b2010-09-17 15:00:07 -0700907 boolean findCellForSpan(int[] cellXY, int spanX, int spanY) {
908 return findCellForSpanThatIntersectsIgnoring(cellXY, spanX, spanY, -1, -1, null);
909 }
910
911 /**
912 * Like above, but ignores any cells occupied by the item "ignoreView"
913 *
914 * @param cellXY The array that will contain the position of a vacant cell if such a cell
915 * can be found.
916 * @param spanX The horizontal span of the cell we want to find.
917 * @param spanY The vertical span of the cell we want to find.
918 * @param ignoreView The home screen item we should treat as not occupying any space
919 * @return
920 */
921 boolean findCellForSpanIgnoring(int[] cellXY, int spanX, int spanY, View ignoreView) {
922 return findCellForSpanThatIntersectsIgnoring(cellXY, spanX, spanY, -1, -1, ignoreView);
923 }
924
925 /**
926 * Like above, but if intersectX and intersectY are not -1, then this method will try to
927 * return coordinates for rectangles that contain the cell [intersectX, intersectY]
928 *
929 * @param spanX The horizontal span of the cell we want to find.
930 * @param spanY The vertical span of the cell we want to find.
931 * @param ignoreView The home screen item we should treat as not occupying any space
932 * @param intersectX The X coordinate of the cell that we should try to overlap
933 * @param intersectX The Y coordinate of the cell that we should try to overlap
934 *
935 * @return True if a vacant cell of the specified dimension was found, false otherwise.
936 */
937 boolean findCellForSpanThatIntersects(int[] cellXY, int spanX, int spanY,
938 int intersectX, int intersectY) {
939 return findCellForSpanThatIntersectsIgnoring(
940 cellXY, spanX, spanY, intersectX, intersectY, null);
941 }
942
943 /**
944 * The superset of the above two methods
945 */
946 boolean findCellForSpanThatIntersectsIgnoring(int[] cellXY, int spanX, int spanY,
947 int intersectX, int intersectY, View ignoreView) {
Michael Jurkac6ee42e2010-09-30 12:04:50 -0700948 // mark space take by ignoreView as available (method checks if ignoreView is null)
949 markCellsAsUnoccupiedForView(ignoreView);
Michael Jurka0280c3b2010-09-17 15:00:07 -0700950
Michael Jurka28750fb2010-09-24 17:43:49 -0700951 boolean foundCell = false;
Michael Jurka0280c3b2010-09-17 15:00:07 -0700952 while (true) {
953 int startX = 0;
954 if (intersectX >= 0) {
955 startX = Math.max(startX, intersectX - (spanX - 1));
956 }
957 int endX = mCountX - (spanX - 1);
958 if (intersectX >= 0) {
959 endX = Math.min(endX, intersectX + (spanX - 1) + (spanX == 1 ? 1 : 0));
960 }
961 int startY = 0;
962 if (intersectY >= 0) {
963 startY = Math.max(startY, intersectY - (spanY - 1));
964 }
965 int endY = mCountY - (spanY - 1);
966 if (intersectY >= 0) {
967 endY = Math.min(endY, intersectY + (spanY - 1) + (spanY == 1 ? 1 : 0));
968 }
969
970 for (int x = startX; x < endX; x++) {
971 inner:
972 for (int y = startY; y < endY; y++) {
973 for (int i = 0; i < spanX; i++) {
974 for (int j = 0; j < spanY; j++) {
975 if (mOccupied[x + i][y + j]) {
976 // small optimization: we can skip to below the row we just found
977 // an occupied cell
978 y += j;
979 continue inner;
980 }
981 }
982 }
983 if (cellXY != null) {
984 cellXY[0] = x;
985 cellXY[1] = y;
986 }
Michael Jurka28750fb2010-09-24 17:43:49 -0700987 foundCell = true;
988 break;
Michael Jurka0280c3b2010-09-17 15:00:07 -0700989 }
990 }
991 if (intersectX == -1 && intersectY == -1) {
992 break;
993 } else {
994 // if we failed to find anything, try again but without any requirements of
995 // intersecting
996 intersectX = -1;
997 intersectY = -1;
998 continue;
999 }
1000 }
1001
Michael Jurkac6ee42e2010-09-30 12:04:50 -07001002 // re-mark space taken by ignoreView as occupied
1003 markCellsAsOccupiedForView(ignoreView);
Michael Jurka28750fb2010-09-24 17:43:49 -07001004 return foundCell;
Michael Jurka0280c3b2010-09-17 15:00:07 -07001005 }
1006
1007 /**
1008 * Called when drag has left this CellLayout or has been completed (successfully or not)
1009 */
1010 void onDragExit() {
Patrick Dubroy6569f2c2010-07-12 14:25:18 -07001011 // Invalidate the drag data
1012 mDragCell[0] = -1;
1013 mDragCell[1] = -1;
1014
Michael Jurkaa63c4522010-08-19 13:52:27 -07001015 setHover(false);
Patrick Dubroyde7658b2010-09-27 11:15:43 -07001016
1017 // Fade out the drag indicators
1018 if (mCrosshairsAnimator != null) {
Patrick Dubroy49250ad2010-10-08 15:33:52 -07001019 mCrosshairsAnimator.animateOut();
Patrick Dubroyde7658b2010-09-27 11:15:43 -07001020 }
Winson Chung150fbab2010-09-29 17:14:26 -07001021
1022 mDragRectAnims[mDragRectCurrent].animateOut();
1023 mDragRectCurrent = (mDragRectCurrent + 1) % mDragRects.length;
1024 mDragRects[mDragRectCurrent].setEmpty();
Patrick Dubroy6569f2c2010-07-12 14:25:18 -07001025 }
1026
1027 /**
Winson Chungaafa03c2010-06-11 17:34:16 -07001028 * Mark a child as having been dropped.
Patrick Dubroyde7658b2010-09-27 11:15:43 -07001029 * At the beginning of the drag operation, the child may have been on another
1030 * screen, but it is reparented before this method is called.
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001031 *
1032 * @param child The child that is being dropped
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001033 */
Winson Chungaafa03c2010-06-11 17:34:16 -07001034 void onDropChild(View child) {
Romain Guyd94533d2009-08-17 10:01:15 -07001035 if (child != null) {
1036 LayoutParams lp = (LayoutParams) child.getLayoutParams();
Romain Guyd94533d2009-08-17 10:01:15 -07001037 lp.isDragging = false;
Romain Guy84f296c2009-11-04 15:00:44 -08001038 lp.dropped = true;
Romain Guyd94533d2009-08-17 10:01:15 -07001039 child.requestLayout();
Romain Guyd94533d2009-08-17 10:01:15 -07001040 }
Michael Jurka0280c3b2010-09-17 15:00:07 -07001041 onDragExit();
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001042 }
1043
1044 void onDropAborted(View child) {
1045 if (child != null) {
1046 ((LayoutParams) child.getLayoutParams()).isDragging = false;
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001047 }
Michael Jurka0280c3b2010-09-17 15:00:07 -07001048 onDragExit();
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001049 }
1050
1051 /**
1052 * Start dragging the specified child
Winson Chungaafa03c2010-06-11 17:34:16 -07001053 *
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001054 * @param child The child that is being dragged
1055 */
1056 void onDragChild(View child) {
1057 LayoutParams lp = (LayoutParams) child.getLayoutParams();
1058 lp.isDragging = true;
Patrick Dubroyde7658b2010-09-27 11:15:43 -07001059 }
1060
1061 /**
1062 * A drag event has begun over this layout.
1063 * It may have begun over this layout (in which case onDragChild is called first),
1064 * or it may have begun on another layout.
1065 */
1066 void onDragEnter(View dragView) {
Patrick Dubroyde7658b2010-09-27 11:15:43 -07001067 // Fade in the drag indicators
1068 if (mCrosshairsAnimator != null) {
Patrick Dubroy49250ad2010-10-08 15:33:52 -07001069 mCrosshairsAnimator.animateIn();
Patrick Dubroyde7658b2010-09-27 11:15:43 -07001070 }
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001071 }
Winson Chungaafa03c2010-06-11 17:34:16 -07001072
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001073 /**
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001074 * Computes a bounding rectangle for a range of cells
Winson Chungaafa03c2010-06-11 17:34:16 -07001075 *
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001076 * @param cellX X coordinate of upper left corner expressed as a cell position
1077 * @param cellY Y coordinate of upper left corner expressed as a cell position
Winson Chungaafa03c2010-06-11 17:34:16 -07001078 * @param cellHSpan Width in cells
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001079 * @param cellVSpan Height in cells
Patrick Dubroy6569f2c2010-07-12 14:25:18 -07001080 * @param resultRect Rect into which to put the results
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001081 */
Patrick Dubroy6569f2c2010-07-12 14:25:18 -07001082 public void cellToRect(int cellX, int cellY, int cellHSpan, int cellVSpan, RectF resultRect) {
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001083 final int cellWidth = mCellWidth;
1084 final int cellHeight = mCellHeight;
1085 final int widthGap = mWidthGap;
1086 final int heightGap = mHeightGap;
Winson Chungaafa03c2010-06-11 17:34:16 -07001087
1088 final int hStartPadding = getLeftPadding();
1089 final int vStartPadding = getTopPadding();
1090
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001091 int width = cellHSpan * cellWidth + ((cellHSpan - 1) * widthGap);
1092 int height = cellVSpan * cellHeight + ((cellVSpan - 1) * heightGap);
1093
1094 int x = hStartPadding + cellX * (cellWidth + widthGap);
1095 int y = vStartPadding + cellY * (cellHeight + heightGap);
Winson Chungaafa03c2010-06-11 17:34:16 -07001096
Patrick Dubroy6569f2c2010-07-12 14:25:18 -07001097 resultRect.set(x, y, x + width, y + height);
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001098 }
Winson Chungaafa03c2010-06-11 17:34:16 -07001099
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001100 /**
Winson Chungaafa03c2010-06-11 17:34:16 -07001101 * Computes the required horizontal and vertical cell spans to always
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001102 * fit the given rectangle.
Winson Chungaafa03c2010-06-11 17:34:16 -07001103 *
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001104 * @param width Width in pixels
1105 * @param height Height in pixels
Patrick Dubroy8f86ddc2010-07-16 13:55:32 -07001106 * @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 -08001107 */
Patrick Dubroy8f86ddc2010-07-16 13:55:32 -07001108 public int[] rectToCell(int width, int height, int[] result) {
Michael Jurka9987a5c2010-10-08 16:58:12 -07001109 return rectToCell(getResources(), width, height, result);
1110 }
1111
1112 public static int[] rectToCell(Resources resources, int width, int height, int[] result) {
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001113 // Always assume we're working with the smallest span to make sure we
1114 // reserve enough space in both orientations.
Joe Onorato79e56262009-09-21 15:23:04 -04001115 int actualWidth = resources.getDimensionPixelSize(R.dimen.workspace_cell_width);
1116 int actualHeight = resources.getDimensionPixelSize(R.dimen.workspace_cell_height);
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001117 int smallerSize = Math.min(actualWidth, actualHeight);
Joe Onorato79e56262009-09-21 15:23:04 -04001118
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001119 // Always round up to next largest cell
1120 int spanX = (width + smallerSize) / smallerSize;
1121 int spanY = (height + smallerSize) / smallerSize;
Joe Onorato79e56262009-09-21 15:23:04 -04001122
Patrick Dubroy8f86ddc2010-07-16 13:55:32 -07001123 if (result == null) {
1124 return new int[] { spanX, spanY };
1125 }
1126 result[0] = spanX;
1127 result[1] = spanY;
1128 return result;
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001129 }
1130
1131 /**
1132 * Find the first vacant cell, if there is one.
1133 *
1134 * @param vacant Holds the x and y coordinate of the vacant cell
1135 * @param spanX Horizontal cell span.
1136 * @param spanY Vertical cell span.
Winson Chungaafa03c2010-06-11 17:34:16 -07001137 *
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001138 * @return True if a vacant cell was found
1139 */
1140 public boolean getVacantCell(int[] vacant, int spanX, int spanY) {
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001141
Michael Jurka0280c3b2010-09-17 15:00:07 -07001142 return findVacantCell(vacant, spanX, spanY, mCountX, mCountY, mOccupied);
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001143 }
1144
1145 static boolean findVacantCell(int[] vacant, int spanX, int spanY,
1146 int xCount, int yCount, boolean[][] occupied) {
1147
1148 for (int x = 0; x < xCount; x++) {
1149 for (int y = 0; y < yCount; y++) {
1150 boolean available = !occupied[x][y];
1151out: for (int i = x; i < x + spanX - 1 && x < xCount; i++) {
1152 for (int j = y; j < y + spanY - 1 && y < yCount; j++) {
1153 available = available && !occupied[i][j];
1154 if (!available) break out;
1155 }
1156 }
1157
1158 if (available) {
1159 vacant[0] = x;
1160 vacant[1] = y;
1161 return true;
1162 }
1163 }
1164 }
1165
1166 return false;
1167 }
1168
Patrick Dubroy6569f2c2010-07-12 14:25:18 -07001169 /**
1170 * Update the array of occupied cells (mOccupied), and return a flattened copy of the array.
1171 */
1172 boolean[] getOccupiedCellsFlattened() {
Adam Cohend22015c2010-07-26 22:02:18 -07001173 final int xCount = mCountX;
1174 final int yCount = mCountY;
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001175 final boolean[][] occupied = mOccupied;
1176
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001177 final boolean[] flat = new boolean[xCount * yCount];
1178 for (int y = 0; y < yCount; y++) {
1179 for (int x = 0; x < xCount; x++) {
1180 flat[y * xCount + x] = occupied[x][y];
1181 }
1182 }
1183
1184 return flat;
1185 }
1186
Michael Jurka0280c3b2010-09-17 15:00:07 -07001187 private void clearOccupiedCells() {
1188 for (int x = 0; x < mCountX; x++) {
1189 for (int y = 0; y < mCountY; y++) {
1190 mOccupied[x][y] = false;
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001191 }
1192 }
Michael Jurka0280c3b2010-09-17 15:00:07 -07001193 }
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001194
Michael Jurka0280c3b2010-09-17 15:00:07 -07001195 public void onMove(View view, int newCellX, int newCellY) {
1196 LayoutParams lp = (LayoutParams) view.getLayoutParams();
1197 markCellsAsUnoccupiedForView(view);
1198 markCellsForView(newCellX, newCellY, lp.cellHSpan, lp.cellVSpan, true);
1199 }
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001200
Michael Jurka0280c3b2010-09-17 15:00:07 -07001201 private void markCellsAsOccupiedForView(View view) {
Michael Jurkac6ee42e2010-09-30 12:04:50 -07001202 if (view == null || view.getParent() != this) return;
Michael Jurka0280c3b2010-09-17 15:00:07 -07001203 LayoutParams lp = (LayoutParams) view.getLayoutParams();
1204 markCellsForView(lp.cellX, lp.cellY, lp.cellHSpan, lp.cellVSpan, true);
1205 }
1206
1207 private void markCellsAsUnoccupiedForView(View view) {
Michael Jurkac6ee42e2010-09-30 12:04:50 -07001208 if (view == null || view.getParent() != this) return;
Michael Jurka0280c3b2010-09-17 15:00:07 -07001209 LayoutParams lp = (LayoutParams) view.getLayoutParams();
1210 markCellsForView(lp.cellX, lp.cellY, lp.cellHSpan, lp.cellVSpan, false);
1211 }
1212
1213 private void markCellsForView(int cellX, int cellY, int spanX, int spanY, boolean value) {
1214 for (int x = cellX; x < cellX + spanX && x < mCountX; x++) {
1215 for (int y = cellY; y < cellY + spanY && y < mCountY; y++) {
1216 mOccupied[x][y] = value;
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001217 }
1218 }
1219 }
1220
1221 @Override
1222 public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) {
1223 return new CellLayout.LayoutParams(getContext(), attrs);
1224 }
1225
1226 @Override
1227 protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
1228 return p instanceof CellLayout.LayoutParams;
1229 }
1230
1231 @Override
1232 protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
1233 return new CellLayout.LayoutParams(p);
1234 }
1235
Winson Chungaafa03c2010-06-11 17:34:16 -07001236 public static class CellLayoutAnimationController extends LayoutAnimationController {
1237 public CellLayoutAnimationController(Animation animation, float delay) {
1238 super(animation, delay);
1239 }
1240
1241 @Override
1242 protected long getDelayForView(View view) {
1243 return (int) (Math.random() * 150);
1244 }
1245 }
1246
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001247 public static class LayoutParams extends ViewGroup.MarginLayoutParams {
1248 /**
1249 * Horizontal location of the item in the grid.
1250 */
1251 @ViewDebug.ExportedProperty
1252 public int cellX;
1253
1254 /**
1255 * Vertical location of the item in the grid.
1256 */
1257 @ViewDebug.ExportedProperty
1258 public int cellY;
1259
1260 /**
1261 * Number of cells spanned horizontally by the item.
1262 */
1263 @ViewDebug.ExportedProperty
1264 public int cellHSpan;
1265
1266 /**
1267 * Number of cells spanned vertically by the item.
1268 */
1269 @ViewDebug.ExportedProperty
1270 public int cellVSpan;
Winson Chungaafa03c2010-06-11 17:34:16 -07001271
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001272 /**
1273 * Is this item currently being dragged
1274 */
1275 public boolean isDragging;
1276
1277 // X coordinate of the view in the layout.
1278 @ViewDebug.ExportedProperty
1279 int x;
1280 // Y coordinate of the view in the layout.
1281 @ViewDebug.ExportedProperty
1282 int y;
1283
Romain Guy84f296c2009-11-04 15:00:44 -08001284 boolean dropped;
Romain Guyfcb9e712009-10-02 16:06:52 -07001285
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001286 public LayoutParams(Context c, AttributeSet attrs) {
1287 super(c, attrs);
1288 cellHSpan = 1;
1289 cellVSpan = 1;
1290 }
1291
1292 public LayoutParams(ViewGroup.LayoutParams source) {
1293 super(source);
1294 cellHSpan = 1;
1295 cellVSpan = 1;
1296 }
Winson Chungaafa03c2010-06-11 17:34:16 -07001297
1298 public LayoutParams(LayoutParams source) {
1299 super(source);
1300 this.cellX = source.cellX;
1301 this.cellY = source.cellY;
1302 this.cellHSpan = source.cellHSpan;
1303 this.cellVSpan = source.cellVSpan;
1304 }
1305
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001306 public LayoutParams(int cellX, int cellY, int cellHSpan, int cellVSpan) {
Romain Guy8f19cdd2010-01-08 15:07:00 -08001307 super(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001308 this.cellX = cellX;
1309 this.cellY = cellY;
1310 this.cellHSpan = cellHSpan;
1311 this.cellVSpan = cellVSpan;
1312 }
1313
1314 public void setup(int cellWidth, int cellHeight, int widthGap, int heightGap,
1315 int hStartPadding, int vStartPadding) {
Winson Chungaafa03c2010-06-11 17:34:16 -07001316
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001317 final int myCellHSpan = cellHSpan;
1318 final int myCellVSpan = cellVSpan;
1319 final int myCellX = cellX;
1320 final int myCellY = cellY;
Winson Chungaafa03c2010-06-11 17:34:16 -07001321
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001322 width = myCellHSpan * cellWidth + ((myCellHSpan - 1) * widthGap) -
1323 leftMargin - rightMargin;
1324 height = myCellVSpan * cellHeight + ((myCellVSpan - 1) * heightGap) -
1325 topMargin - bottomMargin;
1326
1327 x = hStartPadding + myCellX * (cellWidth + widthGap) + leftMargin;
1328 y = vStartPadding + myCellY * (cellHeight + heightGap) + topMargin;
1329 }
Winson Chungaafa03c2010-06-11 17:34:16 -07001330
1331 public String toString() {
1332 return "(" + this.cellX + ", " + this.cellY + ")";
1333 }
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001334 }
1335
Michael Jurka0280c3b2010-09-17 15:00:07 -07001336 // This class stores info for two purposes:
1337 // 1. When dragging items (mDragInfo in Workspace), we store the View, its cellX & cellY,
1338 // its spanX, spanY, and the screen it is on
1339 // 2. When long clicking on an empty cell in a CellLayout, we save information about the
1340 // cellX and cellY coordinates and which page was clicked. We then set this as a tag on
1341 // the CellLayout that was long clicked
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001342 static final class CellInfo implements ContextMenu.ContextMenuInfo {
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001343 View cell;
Michael Jurkaa63c4522010-08-19 13:52:27 -07001344 int cellX = -1;
1345 int cellY = -1;
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001346 int spanX;
1347 int spanY;
1348 int screen;
1349 boolean valid;
1350
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001351 @Override
1352 public String toString() {
Winson Chungaafa03c2010-06-11 17:34:16 -07001353 return "Cell[view=" + (cell == null ? "null" : cell.getClass())
1354 + ", x=" + cellX + ", y=" + cellY + "]";
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001355 }
1356 }
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001357}