blob: d64f3c901a6f761e52d02f632ec4f21848a6f1e1 [file] [log] [blame]
Winson Chung321e9ee2010-08-09 13:37:56 -07001/*
2 * Copyright (C) 2010 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
17package com.android.launcher2;
18
19import android.content.Context;
Winson Chung321e9ee2010-08-09 13:37:56 -070020import android.util.AttributeSet;
Winson Chung321e9ee2010-08-09 13:37:56 -070021import android.view.MotionEvent;
22import android.view.View;
23import android.view.ViewDebug;
24import android.view.ViewGroup;
25
26/**
27 * An abstraction of the original CellLayout which supports laying out items
28 * which span multiple cells into a grid-like layout. Also supports dimming
29 * to give a preview of its contents.
30 */
Michael Jurka8245a862011-02-01 17:53:59 -080031public class PagedViewCellLayout extends ViewGroup implements Page {
Winson Chung321e9ee2010-08-09 13:37:56 -070032 static final String TAG = "PagedViewCellLayout";
33
Winson Chung321e9ee2010-08-09 13:37:56 -070034 private int mCellCountX;
35 private int mCellCountY;
36 private int mCellWidth;
37 private int mCellHeight;
Winson Chungdf4b83d2010-10-20 17:49:27 -070038 private int mWidthGap;
39 private int mHeightGap;
Winson Chung321e9ee2010-08-09 13:37:56 -070040 private static int sDefaultCellDimensions = 96;
Michael Jurka8245a862011-02-01 17:53:59 -080041 protected PagedViewCellLayoutChildren mChildren;
42 private PagedViewCellLayoutChildren mHolographicChildren;
Michael Jurkac0759f52011-02-03 16:47:14 -080043 private boolean mUseHardwareLayers = false;
Winson Chung321e9ee2010-08-09 13:37:56 -070044
Winson Chung321e9ee2010-08-09 13:37:56 -070045 public PagedViewCellLayout(Context context) {
46 this(context, null);
47 }
48
49 public PagedViewCellLayout(Context context, AttributeSet attrs) {
50 this(context, attrs, 0);
51 }
52
53 public PagedViewCellLayout(Context context, AttributeSet attrs, int defStyle) {
54 super(context, attrs, defStyle);
55
Winson Chung321e9ee2010-08-09 13:37:56 -070056 setAlwaysDrawnWithCacheEnabled(false);
57
58 // setup default cell parameters
59 mCellWidth = mCellHeight = sDefaultCellDimensions;
60 mCellCountX = LauncherModel.getCellCountX();
61 mCellCountY = LauncherModel.getCellCountY();
Winson Chungdf4b83d2010-10-20 17:49:27 -070062 mWidthGap = mHeightGap = -1;
Winson Chung321e9ee2010-08-09 13:37:56 -070063
Michael Jurka8245a862011-02-01 17:53:59 -080064 mChildren = new PagedViewCellLayoutChildren(context);
65 mChildren.setCellDimensions(mCellWidth, mCellHeight);
66 mChildren.setGap(mWidthGap, mHeightGap);
67
68 addView(mChildren);
69 mHolographicChildren = new PagedViewCellLayoutChildren(context);
70 mHolographicChildren.setAlpha(0f);
71 mHolographicChildren.setCellDimensions(mCellWidth, mCellHeight);
72 mHolographicChildren.setGap(mWidthGap, mHeightGap);
73
74 addView(mHolographicChildren);
Winson Chungb3347bb2010-08-19 14:51:28 -070075 }
Winson Chung321e9ee2010-08-09 13:37:56 -070076
Michael Jurkac0759f52011-02-03 16:47:14 -080077 public void enableHardwareLayers() {
78 mUseHardwareLayers = true;
79 }
80
Winson Chungb3347bb2010-08-19 14:51:28 -070081 @Override
82 public void setAlpha(float alpha) {
Michael Jurka8245a862011-02-01 17:53:59 -080083 mChildren.setAlpha(alpha);
84 mHolographicChildren.setAlpha(1.0f - alpha);
Winson Chung321e9ee2010-08-09 13:37:56 -070085 }
86
Michael Jurkac0759f52011-02-03 16:47:14 -080087 void destroyHardwareLayers() {
88 if (mUseHardwareLayers) {
89 mChildren.destroyHardwareLayer();
90 mHolographicChildren.destroyHardwareLayer();
91 }
92 }
93 void createHardwareLayers() {
94 if (mUseHardwareLayers) {
95 mChildren.createHardwareLayer();
96 mHolographicChildren.createHardwareLayer();
97 }
98 }
99
Winson Chung321e9ee2010-08-09 13:37:56 -0700100 @Override
101 public void cancelLongPress() {
102 super.cancelLongPress();
103
104 // Cancel long press for all children
105 final int count = getChildCount();
106 for (int i = 0; i < count; i++) {
107 final View child = getChildAt(i);
108 child.cancelLongPress();
109 }
110 }
111
112 public boolean addViewToCellLayout(View child, int index, int childId,
113 PagedViewCellLayout.LayoutParams params) {
114 final PagedViewCellLayout.LayoutParams lp = params;
115
116 // Generate an id for each view, this assumes we have at most 256x256 cells
117 // per workspace screen
118 if (lp.cellX >= 0 && lp.cellX <= (mCellCountX - 1) &&
119 lp.cellY >= 0 && (lp.cellY <= mCellCountY - 1)) {
120 // If the horizontal or vertical span is set to -1, it is taken to
121 // mean that it spans the extent of the CellLayout
122 if (lp.cellHSpan < 0) lp.cellHSpan = mCellCountX;
123 if (lp.cellVSpan < 0) lp.cellVSpan = mCellCountY;
124
125 child.setId(childId);
Michael Jurka8245a862011-02-01 17:53:59 -0800126 mChildren.addView(child, index, lp);
Winson Chung321e9ee2010-08-09 13:37:56 -0700127
Michael Jurka8245a862011-02-01 17:53:59 -0800128 if (child instanceof PagedViewIcon) {
129 PagedViewIcon pagedViewIcon = (PagedViewIcon) child;
Michael Jurkac0759f52011-02-03 16:47:14 -0800130 if (mUseHardwareLayers) {
131 pagedViewIcon.disableCache();
132 }
Michael Jurka8245a862011-02-01 17:53:59 -0800133 mHolographicChildren.addView(pagedViewIcon.getHolographicOutlineView(), index, lp);
134 }
Winson Chung321e9ee2010-08-09 13:37:56 -0700135 return true;
136 }
137 return false;
138 }
139
140 @Override
Michael Jurka8245a862011-02-01 17:53:59 -0800141 public void removeAllViewsOnPage() {
142 mChildren.removeAllViews();
143 mHolographicChildren.removeAllViews();
Winson Chung321e9ee2010-08-09 13:37:56 -0700144 }
145
146 @Override
Michael Jurka8245a862011-02-01 17:53:59 -0800147 public void removeViewOnPageAt(int index) {
148 mChildren.removeViewAt(index);
149 mHolographicChildren.removeViewAt(index);
150 }
151
152 @Override
153 public int getPageChildCount() {
154 return mChildren.getChildCount();
155 }
156
157 @Override
158 public View getChildOnPageAt(int i) {
159 return mChildren.getChildAt(i);
160 }
161
162 @Override
163 public int indexOfChildOnPage(View v) {
164 return mChildren.indexOfChild(v);
165 }
166
Winson Chung321e9ee2010-08-09 13:37:56 -0700167 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
168 // TODO: currently ignoring padding
169
170 int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);
171 int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec);
172
173 int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);
174 int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec);
175
176 if (widthSpecMode == MeasureSpec.UNSPECIFIED || heightSpecMode == MeasureSpec.UNSPECIFIED) {
177 throw new RuntimeException("CellLayout cannot have UNSPECIFIED dimensions");
178 }
179
180 final int cellWidth = mCellWidth;
181 final int cellHeight = mCellHeight;
182
183 int numWidthGaps = mCellCountX - 1;
184 int numHeightGaps = mCellCountY - 1;
185
186 int vSpaceLeft = heightSpecSize - mPaddingTop
187 - mPaddingBottom - (cellHeight * mCellCountY);
188 int heightGap = vSpaceLeft / numHeightGaps;
189
190 int hSpaceLeft = widthSpecSize - mPaddingLeft
191 - mPaddingRight - (cellWidth * mCellCountX);
192 int widthGap = hSpaceLeft / numWidthGaps;
193
194 // center it around the min gaps
195 int minGap = Math.min(widthGap, heightGap);
Winson Chung321e9ee2010-08-09 13:37:56 -0700196 /*
197 if (minGap < heightGap) {
198 // vertical space has shrunken, so change padding accordingly
199 paddingTop += ((heightGap - minGap) * (mCellCountY - 1)) / 2;
200 } else if (minGap < widthGap) {
201 // horizontal space has shrunken, so change padding accordingly
202 paddingLeft += ((widthGap - minGap) * (mCellCountX - 1)) / 2;
203 }
204 */
Winson Chungdf4b83d2010-10-20 17:49:27 -0700205 if (mWidthGap > -1 && mHeightGap > -1) {
206 widthGap = mWidthGap;
207 heightGap = mHeightGap;
208 } else {
209 widthGap = heightGap = minGap;
210 }
Winson Chung321e9ee2010-08-09 13:37:56 -0700211
212 int newWidth = mPaddingLeft + mPaddingRight + (mCellCountX * cellWidth) +
Winson Chungdf4b83d2010-10-20 17:49:27 -0700213 ((mCellCountX - 1) * widthGap);
Winson Chung321e9ee2010-08-09 13:37:56 -0700214 int newHeight = mPaddingTop + mPaddingBottom + (mCellCountY * cellHeight) +
Winson Chungdf4b83d2010-10-20 17:49:27 -0700215 ((mCellCountY - 1) * heightGap);
Winson Chung321e9ee2010-08-09 13:37:56 -0700216
217 final int count = getChildCount();
218 for (int i = 0; i < count; i++) {
219 View child = getChildAt(i);
Michael Jurka8245a862011-02-01 17:53:59 -0800220 int childWidthMeasureSpec =
221 MeasureSpec.makeMeasureSpec(newWidth, MeasureSpec.EXACTLY);
222 int childheightMeasureSpec =
223 MeasureSpec.makeMeasureSpec(newHeight, MeasureSpec.EXACTLY);
Winson Chung321e9ee2010-08-09 13:37:56 -0700224 child.measure(childWidthMeasureSpec, childheightMeasureSpec);
225 }
226
227 setMeasuredDimension(newWidth, newHeight);
228 }
229
230 @Override
231 protected void onLayout(boolean changed, int l, int t, int r, int b) {
232 int count = getChildCount();
Winson Chung321e9ee2010-08-09 13:37:56 -0700233 for (int i = 0; i < count; i++) {
234 View child = getChildAt(i);
Michael Jurka8245a862011-02-01 17:53:59 -0800235 child.layout(0, 0, r - l, b - t);
Winson Chung321e9ee2010-08-09 13:37:56 -0700236 }
237 }
238
239 @Override
Winson Chung321e9ee2010-08-09 13:37:56 -0700240 public boolean onTouchEvent(MotionEvent event) {
241 return super.onTouchEvent(event) || true;
242 }
243
Winson Chung80baf5a2010-08-09 16:03:15 -0700244 public void enableCenteredContent(boolean enabled) {
Michael Jurka8245a862011-02-01 17:53:59 -0800245 mChildren.enableCenteredContent(enabled);
246 mHolographicChildren.enableCenteredContent(enabled);
Winson Chung80baf5a2010-08-09 16:03:15 -0700247 }
248
Winson Chung321e9ee2010-08-09 13:37:56 -0700249 @Override
250 protected void setChildrenDrawingCacheEnabled(boolean enabled) {
Michael Jurka8245a862011-02-01 17:53:59 -0800251 mChildren.setChildrenDrawingCacheEnabled(enabled);
252 mHolographicChildren.setChildrenDrawingCacheEnabled(enabled);
Winson Chung321e9ee2010-08-09 13:37:56 -0700253 }
254
255 public void setCellCount(int xCount, int yCount) {
256 mCellCountX = xCount;
257 mCellCountY = yCount;
258 requestLayout();
259 }
260
Winson Chungdf4b83d2010-10-20 17:49:27 -0700261 public void setGap(int widthGap, int heightGap) {
262 mWidthGap = widthGap;
263 mHeightGap = heightGap;
Michael Jurka8245a862011-02-01 17:53:59 -0800264 mChildren.setGap(widthGap, heightGap);
265 mHolographicChildren.setGap(widthGap, heightGap);
Winson Chungdf4b83d2010-10-20 17:49:27 -0700266 }
267
Winson Chunge3193b92010-09-10 11:44:42 -0700268 public void setCellDimensions(int width, int height) {
269 mCellWidth = width;
270 mCellHeight = height;
Michael Jurka8245a862011-02-01 17:53:59 -0800271 mChildren.setCellDimensions(width, height);
272 mHolographicChildren.setCellDimensions(width, height);
Winson Chunge3193b92010-09-10 11:44:42 -0700273 }
274
275 public int getDefaultCellDimensions() {
276 return sDefaultCellDimensions;
277 }
278
Winson Chung80baf5a2010-08-09 16:03:15 -0700279 public int[] getCellCountForDimensions(int width, int height) {
280 // Always assume we're working with the smallest span to make sure we
281 // reserve enough space in both orientations
282 int smallerSize = Math.min(mCellWidth, mCellHeight);
283
284 // Always round up to next largest cell
285 int spanX = (width + smallerSize) / smallerSize;
286 int spanY = (height + smallerSize) / smallerSize;
287
288 return new int[] { spanX, spanY };
289 }
290
Winson Chung321e9ee2010-08-09 13:37:56 -0700291 /**
292 * Start dragging the specified child
293 *
294 * @param child The child that is being dragged
295 */
296 void onDragChild(View child) {
297 PagedViewCellLayout.LayoutParams lp = (PagedViewCellLayout.LayoutParams) child.getLayoutParams();
298 lp.isDragging = true;
299 }
300
Winson Chunge3193b92010-09-10 11:44:42 -0700301 /**
302 * Estimates the number of cells that the specified width would take up.
303 */
Winson Chung80baf5a2010-08-09 16:03:15 -0700304 public int estimateCellHSpan(int width) {
Winson Chunge3193b92010-09-10 11:44:42 -0700305 // TODO: we need to take widthGap into effect
Winson Chung80baf5a2010-08-09 16:03:15 -0700306 return (width + mCellWidth) / mCellWidth;
307 }
Winson Chunge3193b92010-09-10 11:44:42 -0700308
309 /**
310 * Estimates the number of cells that the specified height would take up.
311 */
Winson Chung80baf5a2010-08-09 16:03:15 -0700312 public int estimateCellVSpan(int height) {
Winson Chunge3193b92010-09-10 11:44:42 -0700313 // TODO: we need to take heightGap into effect
Winson Chung80baf5a2010-08-09 16:03:15 -0700314 return (height + mCellHeight) / mCellHeight;
315 }
Winson Chunge3193b92010-09-10 11:44:42 -0700316
317 /**
318 * Estimates the width that the number of vSpan cells will take up.
319 */
320 public int estimateCellWidth(int hSpan) {
321 // TODO: we need to take widthGap into effect
322 return hSpan * mCellWidth;
323 }
324
325 /**
326 * Estimates the height that the number of vSpan cells will take up.
327 */
328 public int estimateCellHeight(int vSpan) {
329 // TODO: we need to take heightGap into effect
330 return vSpan * mCellHeight;
Winson Chung80baf5a2010-08-09 16:03:15 -0700331 }
332
Winson Chung321e9ee2010-08-09 13:37:56 -0700333 @Override
334 public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) {
335 return new PagedViewCellLayout.LayoutParams(getContext(), attrs);
336 }
337
338 @Override
339 protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
340 return p instanceof PagedViewCellLayout.LayoutParams;
341 }
342
343 @Override
344 protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
345 return new PagedViewCellLayout.LayoutParams(p);
346 }
347
348 public static class LayoutParams extends ViewGroup.MarginLayoutParams {
349 /**
350 * Horizontal location of the item in the grid.
351 */
352 @ViewDebug.ExportedProperty
353 public int cellX;
354
355 /**
356 * Vertical location of the item in the grid.
357 */
358 @ViewDebug.ExportedProperty
359 public int cellY;
360
361 /**
362 * Number of cells spanned horizontally by the item.
363 */
364 @ViewDebug.ExportedProperty
365 public int cellHSpan;
366
367 /**
368 * Number of cells spanned vertically by the item.
369 */
370 @ViewDebug.ExportedProperty
371 public int cellVSpan;
372
373 /**
374 * Is this item currently being dragged
375 */
376 public boolean isDragging;
377
Winson Chung80baf5a2010-08-09 16:03:15 -0700378 // a data object that you can bind to this layout params
379 private Object mTag;
380
Winson Chung321e9ee2010-08-09 13:37:56 -0700381 // X coordinate of the view in the layout.
382 @ViewDebug.ExportedProperty
383 int x;
384 // Y coordinate of the view in the layout.
385 @ViewDebug.ExportedProperty
386 int y;
387
Winson Chung80baf5a2010-08-09 16:03:15 -0700388 public LayoutParams() {
389 super(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
390 cellHSpan = 1;
391 cellVSpan = 1;
392 }
393
Winson Chung321e9ee2010-08-09 13:37:56 -0700394 public LayoutParams(Context c, AttributeSet attrs) {
395 super(c, attrs);
396 cellHSpan = 1;
397 cellVSpan = 1;
398 }
399
400 public LayoutParams(ViewGroup.LayoutParams source) {
401 super(source);
402 cellHSpan = 1;
403 cellVSpan = 1;
404 }
405
406 public LayoutParams(LayoutParams source) {
407 super(source);
408 this.cellX = source.cellX;
409 this.cellY = source.cellY;
410 this.cellHSpan = source.cellHSpan;
411 this.cellVSpan = source.cellVSpan;
412 }
413
414 public LayoutParams(int cellX, int cellY, int cellHSpan, int cellVSpan) {
415 super(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
416 this.cellX = cellX;
417 this.cellY = cellY;
418 this.cellHSpan = cellHSpan;
419 this.cellVSpan = cellVSpan;
420 }
421
422 public void setup(int cellWidth, int cellHeight, int widthGap, int heightGap,
423 int hStartPadding, int vStartPadding) {
424
425 final int myCellHSpan = cellHSpan;
426 final int myCellVSpan = cellVSpan;
427 final int myCellX = cellX;
428 final int myCellY = cellY;
429
430 width = myCellHSpan * cellWidth + ((myCellHSpan - 1) * widthGap) -
431 leftMargin - rightMargin;
432 height = myCellVSpan * cellHeight + ((myCellVSpan - 1) * heightGap) -
433 topMargin - bottomMargin;
434
435 x = hStartPadding + myCellX * (cellWidth + widthGap) + leftMargin;
436 y = vStartPadding + myCellY * (cellHeight + heightGap) + topMargin;
437 }
438
Winson Chung80baf5a2010-08-09 16:03:15 -0700439 public Object getTag() {
440 return mTag;
441 }
442
443 public void setTag(Object tag) {
444 mTag = tag;
445 }
446
Winson Chung321e9ee2010-08-09 13:37:56 -0700447 public String toString() {
Winson Chung80baf5a2010-08-09 16:03:15 -0700448 return "(" + this.cellX + ", " + this.cellY + ", " +
449 this.cellHSpan + ", " + this.cellVSpan + ")";
Winson Chung321e9ee2010-08-09 13:37:56 -0700450 }
451 }
452}
Michael Jurka8245a862011-02-01 17:53:59 -0800453
454interface Page {
455 public int getPageChildCount();
456 public View getChildOnPageAt(int i);
457 public void removeAllViewsOnPage();
458 public void removeViewOnPageAt(int i);
459 public int indexOfChildOnPage(View v);
460}