blob: 57d41fafff215eb74a07c40ff6d28f4000d6b1aa [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();
Michael Jurkac5e49022011-02-16 12:04:02 -0800144 destroyHardwareLayers();
Winson Chung321e9ee2010-08-09 13:37:56 -0700145 }
146
147 @Override
Michael Jurka8245a862011-02-01 17:53:59 -0800148 public void removeViewOnPageAt(int index) {
149 mChildren.removeViewAt(index);
150 mHolographicChildren.removeViewAt(index);
151 }
152
153 @Override
154 public int getPageChildCount() {
155 return mChildren.getChildCount();
156 }
157
158 @Override
159 public View getChildOnPageAt(int i) {
160 return mChildren.getChildAt(i);
161 }
162
163 @Override
164 public int indexOfChildOnPage(View v) {
165 return mChildren.indexOfChild(v);
166 }
167
Winson Chung321e9ee2010-08-09 13:37:56 -0700168 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
169 // TODO: currently ignoring padding
170
171 int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);
172 int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec);
173
174 int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);
175 int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec);
176
177 if (widthSpecMode == MeasureSpec.UNSPECIFIED || heightSpecMode == MeasureSpec.UNSPECIFIED) {
178 throw new RuntimeException("CellLayout cannot have UNSPECIFIED dimensions");
179 }
180
181 final int cellWidth = mCellWidth;
182 final int cellHeight = mCellHeight;
183
184 int numWidthGaps = mCellCountX - 1;
185 int numHeightGaps = mCellCountY - 1;
186
187 int vSpaceLeft = heightSpecSize - mPaddingTop
188 - mPaddingBottom - (cellHeight * mCellCountY);
189 int heightGap = vSpaceLeft / numHeightGaps;
190
191 int hSpaceLeft = widthSpecSize - mPaddingLeft
192 - mPaddingRight - (cellWidth * mCellCountX);
193 int widthGap = hSpaceLeft / numWidthGaps;
194
195 // center it around the min gaps
196 int minGap = Math.min(widthGap, heightGap);
Winson Chung321e9ee2010-08-09 13:37:56 -0700197 /*
198 if (minGap < heightGap) {
199 // vertical space has shrunken, so change padding accordingly
200 paddingTop += ((heightGap - minGap) * (mCellCountY - 1)) / 2;
201 } else if (minGap < widthGap) {
202 // horizontal space has shrunken, so change padding accordingly
203 paddingLeft += ((widthGap - minGap) * (mCellCountX - 1)) / 2;
204 }
205 */
Winson Chungdf4b83d2010-10-20 17:49:27 -0700206 if (mWidthGap > -1 && mHeightGap > -1) {
207 widthGap = mWidthGap;
208 heightGap = mHeightGap;
209 } else {
210 widthGap = heightGap = minGap;
211 }
Winson Chung321e9ee2010-08-09 13:37:56 -0700212
213 int newWidth = mPaddingLeft + mPaddingRight + (mCellCountX * cellWidth) +
Winson Chungdf4b83d2010-10-20 17:49:27 -0700214 ((mCellCountX - 1) * widthGap);
Winson Chung321e9ee2010-08-09 13:37:56 -0700215 int newHeight = mPaddingTop + mPaddingBottom + (mCellCountY * cellHeight) +
Winson Chungdf4b83d2010-10-20 17:49:27 -0700216 ((mCellCountY - 1) * heightGap);
Winson Chung321e9ee2010-08-09 13:37:56 -0700217
218 final int count = getChildCount();
219 for (int i = 0; i < count; i++) {
220 View child = getChildAt(i);
Michael Jurka8245a862011-02-01 17:53:59 -0800221 int childWidthMeasureSpec =
222 MeasureSpec.makeMeasureSpec(newWidth, MeasureSpec.EXACTLY);
223 int childheightMeasureSpec =
224 MeasureSpec.makeMeasureSpec(newHeight, MeasureSpec.EXACTLY);
Winson Chung321e9ee2010-08-09 13:37:56 -0700225 child.measure(childWidthMeasureSpec, childheightMeasureSpec);
226 }
227
228 setMeasuredDimension(newWidth, newHeight);
229 }
230
231 @Override
232 protected void onLayout(boolean changed, int l, int t, int r, int b) {
233 int count = getChildCount();
Winson Chung321e9ee2010-08-09 13:37:56 -0700234 for (int i = 0; i < count; i++) {
235 View child = getChildAt(i);
Michael Jurka8245a862011-02-01 17:53:59 -0800236 child.layout(0, 0, r - l, b - t);
Winson Chung321e9ee2010-08-09 13:37:56 -0700237 }
238 }
239
240 @Override
Winson Chung321e9ee2010-08-09 13:37:56 -0700241 public boolean onTouchEvent(MotionEvent event) {
242 return super.onTouchEvent(event) || true;
243 }
244
Winson Chung80baf5a2010-08-09 16:03:15 -0700245 public void enableCenteredContent(boolean enabled) {
Michael Jurka8245a862011-02-01 17:53:59 -0800246 mChildren.enableCenteredContent(enabled);
247 mHolographicChildren.enableCenteredContent(enabled);
Winson Chung80baf5a2010-08-09 16:03:15 -0700248 }
249
Winson Chung321e9ee2010-08-09 13:37:56 -0700250 @Override
251 protected void setChildrenDrawingCacheEnabled(boolean enabled) {
Michael Jurka8245a862011-02-01 17:53:59 -0800252 mChildren.setChildrenDrawingCacheEnabled(enabled);
253 mHolographicChildren.setChildrenDrawingCacheEnabled(enabled);
Winson Chung321e9ee2010-08-09 13:37:56 -0700254 }
255
256 public void setCellCount(int xCount, int yCount) {
257 mCellCountX = xCount;
258 mCellCountY = yCount;
259 requestLayout();
260 }
261
Winson Chungdf4b83d2010-10-20 17:49:27 -0700262 public void setGap(int widthGap, int heightGap) {
263 mWidthGap = widthGap;
264 mHeightGap = heightGap;
Michael Jurka8245a862011-02-01 17:53:59 -0800265 mChildren.setGap(widthGap, heightGap);
266 mHolographicChildren.setGap(widthGap, heightGap);
Winson Chungdf4b83d2010-10-20 17:49:27 -0700267 }
268
Winson Chunge3193b92010-09-10 11:44:42 -0700269 public void setCellDimensions(int width, int height) {
270 mCellWidth = width;
271 mCellHeight = height;
Michael Jurka8245a862011-02-01 17:53:59 -0800272 mChildren.setCellDimensions(width, height);
273 mHolographicChildren.setCellDimensions(width, height);
Winson Chunge3193b92010-09-10 11:44:42 -0700274 }
275
276 public int getDefaultCellDimensions() {
277 return sDefaultCellDimensions;
278 }
279
Winson Chung80baf5a2010-08-09 16:03:15 -0700280 public int[] getCellCountForDimensions(int width, int height) {
281 // Always assume we're working with the smallest span to make sure we
282 // reserve enough space in both orientations
283 int smallerSize = Math.min(mCellWidth, mCellHeight);
284
285 // Always round up to next largest cell
286 int spanX = (width + smallerSize) / smallerSize;
287 int spanY = (height + smallerSize) / smallerSize;
288
289 return new int[] { spanX, spanY };
290 }
291
Winson Chung321e9ee2010-08-09 13:37:56 -0700292 /**
293 * Start dragging the specified child
294 *
295 * @param child The child that is being dragged
296 */
297 void onDragChild(View child) {
298 PagedViewCellLayout.LayoutParams lp = (PagedViewCellLayout.LayoutParams) child.getLayoutParams();
299 lp.isDragging = true;
300 }
301
Winson Chunge3193b92010-09-10 11:44:42 -0700302 /**
303 * Estimates the number of cells that the specified width would take up.
304 */
Winson Chung80baf5a2010-08-09 16:03:15 -0700305 public int estimateCellHSpan(int width) {
Winson Chunge3193b92010-09-10 11:44:42 -0700306 // TODO: we need to take widthGap into effect
Winson Chung80baf5a2010-08-09 16:03:15 -0700307 return (width + mCellWidth) / mCellWidth;
308 }
Winson Chunge3193b92010-09-10 11:44:42 -0700309
310 /**
311 * Estimates the number of cells that the specified height would take up.
312 */
Winson Chung80baf5a2010-08-09 16:03:15 -0700313 public int estimateCellVSpan(int height) {
Winson Chunge3193b92010-09-10 11:44:42 -0700314 // TODO: we need to take heightGap into effect
Winson Chung80baf5a2010-08-09 16:03:15 -0700315 return (height + mCellHeight) / mCellHeight;
316 }
Winson Chunge3193b92010-09-10 11:44:42 -0700317
318 /**
319 * Estimates the width that the number of vSpan cells will take up.
320 */
321 public int estimateCellWidth(int hSpan) {
322 // TODO: we need to take widthGap into effect
323 return hSpan * mCellWidth;
324 }
325
326 /**
327 * Estimates the height that the number of vSpan cells will take up.
328 */
329 public int estimateCellHeight(int vSpan) {
330 // TODO: we need to take heightGap into effect
331 return vSpan * mCellHeight;
Winson Chung80baf5a2010-08-09 16:03:15 -0700332 }
333
Winson Chung321e9ee2010-08-09 13:37:56 -0700334 @Override
335 public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) {
336 return new PagedViewCellLayout.LayoutParams(getContext(), attrs);
337 }
338
339 @Override
340 protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
341 return p instanceof PagedViewCellLayout.LayoutParams;
342 }
343
344 @Override
345 protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
346 return new PagedViewCellLayout.LayoutParams(p);
347 }
348
349 public static class LayoutParams extends ViewGroup.MarginLayoutParams {
350 /**
351 * Horizontal location of the item in the grid.
352 */
353 @ViewDebug.ExportedProperty
354 public int cellX;
355
356 /**
357 * Vertical location of the item in the grid.
358 */
359 @ViewDebug.ExportedProperty
360 public int cellY;
361
362 /**
363 * Number of cells spanned horizontally by the item.
364 */
365 @ViewDebug.ExportedProperty
366 public int cellHSpan;
367
368 /**
369 * Number of cells spanned vertically by the item.
370 */
371 @ViewDebug.ExportedProperty
372 public int cellVSpan;
373
374 /**
375 * Is this item currently being dragged
376 */
377 public boolean isDragging;
378
Winson Chung80baf5a2010-08-09 16:03:15 -0700379 // a data object that you can bind to this layout params
380 private Object mTag;
381
Winson Chung321e9ee2010-08-09 13:37:56 -0700382 // X coordinate of the view in the layout.
383 @ViewDebug.ExportedProperty
384 int x;
385 // Y coordinate of the view in the layout.
386 @ViewDebug.ExportedProperty
387 int y;
388
Winson Chung80baf5a2010-08-09 16:03:15 -0700389 public LayoutParams() {
390 super(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
391 cellHSpan = 1;
392 cellVSpan = 1;
393 }
394
Winson Chung321e9ee2010-08-09 13:37:56 -0700395 public LayoutParams(Context c, AttributeSet attrs) {
396 super(c, attrs);
397 cellHSpan = 1;
398 cellVSpan = 1;
399 }
400
401 public LayoutParams(ViewGroup.LayoutParams source) {
402 super(source);
403 cellHSpan = 1;
404 cellVSpan = 1;
405 }
406
407 public LayoutParams(LayoutParams source) {
408 super(source);
409 this.cellX = source.cellX;
410 this.cellY = source.cellY;
411 this.cellHSpan = source.cellHSpan;
412 this.cellVSpan = source.cellVSpan;
413 }
414
415 public LayoutParams(int cellX, int cellY, int cellHSpan, int cellVSpan) {
416 super(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
417 this.cellX = cellX;
418 this.cellY = cellY;
419 this.cellHSpan = cellHSpan;
420 this.cellVSpan = cellVSpan;
421 }
422
423 public void setup(int cellWidth, int cellHeight, int widthGap, int heightGap,
424 int hStartPadding, int vStartPadding) {
425
426 final int myCellHSpan = cellHSpan;
427 final int myCellVSpan = cellVSpan;
428 final int myCellX = cellX;
429 final int myCellY = cellY;
430
431 width = myCellHSpan * cellWidth + ((myCellHSpan - 1) * widthGap) -
432 leftMargin - rightMargin;
433 height = myCellVSpan * cellHeight + ((myCellVSpan - 1) * heightGap) -
434 topMargin - bottomMargin;
435
436 x = hStartPadding + myCellX * (cellWidth + widthGap) + leftMargin;
437 y = vStartPadding + myCellY * (cellHeight + heightGap) + topMargin;
438 }
439
Winson Chung80baf5a2010-08-09 16:03:15 -0700440 public Object getTag() {
441 return mTag;
442 }
443
444 public void setTag(Object tag) {
445 mTag = tag;
446 }
447
Winson Chung321e9ee2010-08-09 13:37:56 -0700448 public String toString() {
Winson Chung80baf5a2010-08-09 16:03:15 -0700449 return "(" + this.cellX + ", " + this.cellY + ", " +
450 this.cellHSpan + ", " + this.cellVSpan + ")";
Winson Chung321e9ee2010-08-09 13:37:56 -0700451 }
452 }
453}
Michael Jurka8245a862011-02-01 17:53:59 -0800454
455interface Page {
456 public int getPageChildCount();
457 public View getChildOnPageAt(int i);
458 public void removeAllViewsOnPage();
459 public void removeViewOnPageAt(int i);
460 public int indexOfChildOnPage(View v);
461}