blob: 28bb78b9a54e3a71a4c0a296b9e6e739d1653336 [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 Jurkaabded662011-03-04 12:06:57 -080043 private boolean mAllowHardwareLayerCreation = false;
44 private boolean mCreateHardwareLayersIfAllowed = false;
Winson Chung321e9ee2010-08-09 13:37:56 -070045
Winson Chung321e9ee2010-08-09 13:37:56 -070046 public PagedViewCellLayout(Context context) {
47 this(context, null);
48 }
49
50 public PagedViewCellLayout(Context context, AttributeSet attrs) {
51 this(context, attrs, 0);
52 }
53
54 public PagedViewCellLayout(Context context, AttributeSet attrs, int defStyle) {
55 super(context, attrs, defStyle);
56
Winson Chung321e9ee2010-08-09 13:37:56 -070057 setAlwaysDrawnWithCacheEnabled(false);
58
59 // setup default cell parameters
60 mCellWidth = mCellHeight = sDefaultCellDimensions;
61 mCellCountX = LauncherModel.getCellCountX();
62 mCellCountY = LauncherModel.getCellCountY();
Winson Chungdf4b83d2010-10-20 17:49:27 -070063 mWidthGap = mHeightGap = -1;
Winson Chung321e9ee2010-08-09 13:37:56 -070064
Michael Jurka8245a862011-02-01 17:53:59 -080065 mChildren = new PagedViewCellLayoutChildren(context);
66 mChildren.setCellDimensions(mCellWidth, mCellHeight);
67 mChildren.setGap(mWidthGap, mHeightGap);
68
69 addView(mChildren);
70 mHolographicChildren = new PagedViewCellLayoutChildren(context);
71 mHolographicChildren.setAlpha(0f);
72 mHolographicChildren.setCellDimensions(mCellWidth, mCellHeight);
73 mHolographicChildren.setGap(mWidthGap, mHeightGap);
74
75 addView(mHolographicChildren);
Winson Chungb3347bb2010-08-19 14:51:28 -070076 }
Winson Chung321e9ee2010-08-09 13:37:56 -070077
Michael Jurkaabded662011-03-04 12:06:57 -080078 public void allowHardwareLayerCreation() {
79 // This is called after the first time we launch into All Apps. Before that point,
80 // there's no need for hardware layers here since there's a hardware layer set on the
81 // parent, AllAppsTabbed, during the AllApps transition -- creating hardware layers here
82 // before the animation is done slows down the animation
83 if (!mAllowHardwareLayerCreation) {
84 mAllowHardwareLayerCreation = true;
85 if (mCreateHardwareLayersIfAllowed) {
86 createHardwareLayers();
87 }
88 }
Michael Jurkac0759f52011-02-03 16:47:14 -080089 }
90
Winson Chungb3347bb2010-08-19 14:51:28 -070091 @Override
92 public void setAlpha(float alpha) {
Michael Jurka8245a862011-02-01 17:53:59 -080093 mChildren.setAlpha(alpha);
94 mHolographicChildren.setAlpha(1.0f - alpha);
Winson Chung321e9ee2010-08-09 13:37:56 -070095 }
96
Michael Jurkac0759f52011-02-03 16:47:14 -080097 void destroyHardwareLayers() {
Michael Jurkaabded662011-03-04 12:06:57 -080098 // called when a page is no longer visible (triggered by loadAssociatedPages ->
99 // removeAllViewsOnPage)
100 mCreateHardwareLayersIfAllowed = false;
101 if (mAllowHardwareLayerCreation) {
Michael Jurkac0759f52011-02-03 16:47:14 -0800102 mChildren.destroyHardwareLayer();
103 mHolographicChildren.destroyHardwareLayer();
104 }
105 }
106 void createHardwareLayers() {
Michael Jurkaabded662011-03-04 12:06:57 -0800107 // called when a page is visible (triggered by loadAssociatedPages -> syncPageItems)
108 mCreateHardwareLayersIfAllowed = true;
109 if (mAllowHardwareLayerCreation) {
Michael Jurkac0759f52011-02-03 16:47:14 -0800110 mChildren.createHardwareLayer();
111 mHolographicChildren.createHardwareLayer();
112 }
113 }
114
Winson Chung321e9ee2010-08-09 13:37:56 -0700115 @Override
116 public void cancelLongPress() {
117 super.cancelLongPress();
118
119 // Cancel long press for all children
120 final int count = getChildCount();
121 for (int i = 0; i < count; i++) {
122 final View child = getChildAt(i);
123 child.cancelLongPress();
124 }
125 }
126
127 public boolean addViewToCellLayout(View child, int index, int childId,
128 PagedViewCellLayout.LayoutParams params) {
129 final PagedViewCellLayout.LayoutParams lp = params;
130
131 // Generate an id for each view, this assumes we have at most 256x256 cells
132 // per workspace screen
133 if (lp.cellX >= 0 && lp.cellX <= (mCellCountX - 1) &&
134 lp.cellY >= 0 && (lp.cellY <= mCellCountY - 1)) {
135 // If the horizontal or vertical span is set to -1, it is taken to
136 // mean that it spans the extent of the CellLayout
137 if (lp.cellHSpan < 0) lp.cellHSpan = mCellCountX;
138 if (lp.cellVSpan < 0) lp.cellVSpan = mCellCountY;
139
140 child.setId(childId);
Michael Jurka8245a862011-02-01 17:53:59 -0800141 mChildren.addView(child, index, lp);
Winson Chung321e9ee2010-08-09 13:37:56 -0700142
Michael Jurka8245a862011-02-01 17:53:59 -0800143 if (child instanceof PagedViewIcon) {
144 PagedViewIcon pagedViewIcon = (PagedViewIcon) child;
Michael Jurkaabded662011-03-04 12:06:57 -0800145 if (mAllowHardwareLayerCreation) {
Michael Jurkac0759f52011-02-03 16:47:14 -0800146 pagedViewIcon.disableCache();
147 }
Michael Jurka8245a862011-02-01 17:53:59 -0800148 mHolographicChildren.addView(pagedViewIcon.getHolographicOutlineView(), index, lp);
149 }
Winson Chung321e9ee2010-08-09 13:37:56 -0700150 return true;
151 }
152 return false;
153 }
154
155 @Override
Michael Jurka8245a862011-02-01 17:53:59 -0800156 public void removeAllViewsOnPage() {
157 mChildren.removeAllViews();
158 mHolographicChildren.removeAllViews();
Michael Jurkac5e49022011-02-16 12:04:02 -0800159 destroyHardwareLayers();
Winson Chung321e9ee2010-08-09 13:37:56 -0700160 }
161
162 @Override
Michael Jurka8245a862011-02-01 17:53:59 -0800163 public void removeViewOnPageAt(int index) {
164 mChildren.removeViewAt(index);
165 mHolographicChildren.removeViewAt(index);
166 }
167
168 @Override
169 public int getPageChildCount() {
170 return mChildren.getChildCount();
171 }
172
173 @Override
174 public View getChildOnPageAt(int i) {
175 return mChildren.getChildAt(i);
176 }
177
178 @Override
179 public int indexOfChildOnPage(View v) {
180 return mChildren.indexOfChild(v);
181 }
182
Winson Chung321e9ee2010-08-09 13:37:56 -0700183 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
184 // TODO: currently ignoring padding
185
186 int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);
187 int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec);
188
189 int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);
190 int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec);
191
192 if (widthSpecMode == MeasureSpec.UNSPECIFIED || heightSpecMode == MeasureSpec.UNSPECIFIED) {
193 throw new RuntimeException("CellLayout cannot have UNSPECIFIED dimensions");
194 }
195
196 final int cellWidth = mCellWidth;
197 final int cellHeight = mCellHeight;
198
199 int numWidthGaps = mCellCountX - 1;
200 int numHeightGaps = mCellCountY - 1;
201
202 int vSpaceLeft = heightSpecSize - mPaddingTop
203 - mPaddingBottom - (cellHeight * mCellCountY);
204 int heightGap = vSpaceLeft / numHeightGaps;
205
206 int hSpaceLeft = widthSpecSize - mPaddingLeft
207 - mPaddingRight - (cellWidth * mCellCountX);
208 int widthGap = hSpaceLeft / numWidthGaps;
209
210 // center it around the min gaps
211 int minGap = Math.min(widthGap, heightGap);
Winson Chung321e9ee2010-08-09 13:37:56 -0700212 /*
213 if (minGap < heightGap) {
214 // vertical space has shrunken, so change padding accordingly
215 paddingTop += ((heightGap - minGap) * (mCellCountY - 1)) / 2;
216 } else if (minGap < widthGap) {
217 // horizontal space has shrunken, so change padding accordingly
218 paddingLeft += ((widthGap - minGap) * (mCellCountX - 1)) / 2;
219 }
220 */
Winson Chungdf4b83d2010-10-20 17:49:27 -0700221 if (mWidthGap > -1 && mHeightGap > -1) {
222 widthGap = mWidthGap;
223 heightGap = mHeightGap;
224 } else {
225 widthGap = heightGap = minGap;
226 }
Winson Chung321e9ee2010-08-09 13:37:56 -0700227
228 int newWidth = mPaddingLeft + mPaddingRight + (mCellCountX * cellWidth) +
Winson Chungdf4b83d2010-10-20 17:49:27 -0700229 ((mCellCountX - 1) * widthGap);
Winson Chung321e9ee2010-08-09 13:37:56 -0700230 int newHeight = mPaddingTop + mPaddingBottom + (mCellCountY * cellHeight) +
Winson Chungdf4b83d2010-10-20 17:49:27 -0700231 ((mCellCountY - 1) * heightGap);
Winson Chung321e9ee2010-08-09 13:37:56 -0700232
233 final int count = getChildCount();
234 for (int i = 0; i < count; i++) {
235 View child = getChildAt(i);
Michael Jurka8245a862011-02-01 17:53:59 -0800236 int childWidthMeasureSpec =
237 MeasureSpec.makeMeasureSpec(newWidth, MeasureSpec.EXACTLY);
238 int childheightMeasureSpec =
239 MeasureSpec.makeMeasureSpec(newHeight, MeasureSpec.EXACTLY);
Winson Chung321e9ee2010-08-09 13:37:56 -0700240 child.measure(childWidthMeasureSpec, childheightMeasureSpec);
241 }
242
243 setMeasuredDimension(newWidth, newHeight);
244 }
245
246 @Override
247 protected void onLayout(boolean changed, int l, int t, int r, int b) {
248 int count = getChildCount();
Winson Chung321e9ee2010-08-09 13:37:56 -0700249 for (int i = 0; i < count; i++) {
250 View child = getChildAt(i);
Michael Jurka8245a862011-02-01 17:53:59 -0800251 child.layout(0, 0, r - l, b - t);
Winson Chung321e9ee2010-08-09 13:37:56 -0700252 }
253 }
254
255 @Override
Winson Chung321e9ee2010-08-09 13:37:56 -0700256 public boolean onTouchEvent(MotionEvent event) {
257 return super.onTouchEvent(event) || true;
258 }
259
Winson Chung80baf5a2010-08-09 16:03:15 -0700260 public void enableCenteredContent(boolean enabled) {
Michael Jurka8245a862011-02-01 17:53:59 -0800261 mChildren.enableCenteredContent(enabled);
262 mHolographicChildren.enableCenteredContent(enabled);
Winson Chung80baf5a2010-08-09 16:03:15 -0700263 }
264
Winson Chung321e9ee2010-08-09 13:37:56 -0700265 @Override
266 protected void setChildrenDrawingCacheEnabled(boolean enabled) {
Michael Jurka8245a862011-02-01 17:53:59 -0800267 mChildren.setChildrenDrawingCacheEnabled(enabled);
268 mHolographicChildren.setChildrenDrawingCacheEnabled(enabled);
Winson Chung321e9ee2010-08-09 13:37:56 -0700269 }
270
271 public void setCellCount(int xCount, int yCount) {
272 mCellCountX = xCount;
273 mCellCountY = yCount;
274 requestLayout();
275 }
276
Winson Chungdf4b83d2010-10-20 17:49:27 -0700277 public void setGap(int widthGap, int heightGap) {
278 mWidthGap = widthGap;
279 mHeightGap = heightGap;
Michael Jurka8245a862011-02-01 17:53:59 -0800280 mChildren.setGap(widthGap, heightGap);
281 mHolographicChildren.setGap(widthGap, heightGap);
Winson Chungdf4b83d2010-10-20 17:49:27 -0700282 }
283
Winson Chunge3193b92010-09-10 11:44:42 -0700284 public void setCellDimensions(int width, int height) {
285 mCellWidth = width;
286 mCellHeight = height;
Michael Jurka8245a862011-02-01 17:53:59 -0800287 mChildren.setCellDimensions(width, height);
288 mHolographicChildren.setCellDimensions(width, height);
Winson Chunge3193b92010-09-10 11:44:42 -0700289 }
290
291 public int getDefaultCellDimensions() {
292 return sDefaultCellDimensions;
293 }
294
Winson Chung80baf5a2010-08-09 16:03:15 -0700295 public int[] getCellCountForDimensions(int width, int height) {
296 // Always assume we're working with the smallest span to make sure we
297 // reserve enough space in both orientations
298 int smallerSize = Math.min(mCellWidth, mCellHeight);
299
300 // Always round up to next largest cell
301 int spanX = (width + smallerSize) / smallerSize;
302 int spanY = (height + smallerSize) / smallerSize;
303
304 return new int[] { spanX, spanY };
305 }
306
Winson Chung321e9ee2010-08-09 13:37:56 -0700307 /**
308 * Start dragging the specified child
309 *
310 * @param child The child that is being dragged
311 */
312 void onDragChild(View child) {
313 PagedViewCellLayout.LayoutParams lp = (PagedViewCellLayout.LayoutParams) child.getLayoutParams();
314 lp.isDragging = true;
315 }
316
Winson Chunge3193b92010-09-10 11:44:42 -0700317 /**
318 * Estimates the number of cells that the specified width would take up.
319 */
Winson Chung80baf5a2010-08-09 16:03:15 -0700320 public int estimateCellHSpan(int width) {
Winson Chunge3193b92010-09-10 11:44:42 -0700321 // TODO: we need to take widthGap into effect
Winson Chung80baf5a2010-08-09 16:03:15 -0700322 return (width + mCellWidth) / mCellWidth;
323 }
Winson Chunge3193b92010-09-10 11:44:42 -0700324
325 /**
326 * Estimates the number of cells that the specified height would take up.
327 */
Winson Chung80baf5a2010-08-09 16:03:15 -0700328 public int estimateCellVSpan(int height) {
Winson Chunge3193b92010-09-10 11:44:42 -0700329 // TODO: we need to take heightGap into effect
Winson Chung80baf5a2010-08-09 16:03:15 -0700330 return (height + mCellHeight) / mCellHeight;
331 }
Winson Chunge3193b92010-09-10 11:44:42 -0700332
333 /**
334 * Estimates the width that the number of vSpan cells will take up.
335 */
336 public int estimateCellWidth(int hSpan) {
337 // TODO: we need to take widthGap into effect
338 return hSpan * mCellWidth;
339 }
340
341 /**
342 * Estimates the height that the number of vSpan cells will take up.
343 */
344 public int estimateCellHeight(int vSpan) {
345 // TODO: we need to take heightGap into effect
346 return vSpan * mCellHeight;
Winson Chung80baf5a2010-08-09 16:03:15 -0700347 }
348
Winson Chung321e9ee2010-08-09 13:37:56 -0700349 @Override
350 public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) {
351 return new PagedViewCellLayout.LayoutParams(getContext(), attrs);
352 }
353
354 @Override
355 protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
356 return p instanceof PagedViewCellLayout.LayoutParams;
357 }
358
359 @Override
360 protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
361 return new PagedViewCellLayout.LayoutParams(p);
362 }
363
364 public static class LayoutParams extends ViewGroup.MarginLayoutParams {
365 /**
366 * Horizontal location of the item in the grid.
367 */
368 @ViewDebug.ExportedProperty
369 public int cellX;
370
371 /**
372 * Vertical location of the item in the grid.
373 */
374 @ViewDebug.ExportedProperty
375 public int cellY;
376
377 /**
378 * Number of cells spanned horizontally by the item.
379 */
380 @ViewDebug.ExportedProperty
381 public int cellHSpan;
382
383 /**
384 * Number of cells spanned vertically by the item.
385 */
386 @ViewDebug.ExportedProperty
387 public int cellVSpan;
388
389 /**
390 * Is this item currently being dragged
391 */
392 public boolean isDragging;
393
Winson Chung80baf5a2010-08-09 16:03:15 -0700394 // a data object that you can bind to this layout params
395 private Object mTag;
396
Winson Chung321e9ee2010-08-09 13:37:56 -0700397 // X coordinate of the view in the layout.
398 @ViewDebug.ExportedProperty
399 int x;
400 // Y coordinate of the view in the layout.
401 @ViewDebug.ExportedProperty
402 int y;
403
Winson Chung80baf5a2010-08-09 16:03:15 -0700404 public LayoutParams() {
405 super(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
406 cellHSpan = 1;
407 cellVSpan = 1;
408 }
409
Winson Chung321e9ee2010-08-09 13:37:56 -0700410 public LayoutParams(Context c, AttributeSet attrs) {
411 super(c, attrs);
412 cellHSpan = 1;
413 cellVSpan = 1;
414 }
415
416 public LayoutParams(ViewGroup.LayoutParams source) {
417 super(source);
418 cellHSpan = 1;
419 cellVSpan = 1;
420 }
421
422 public LayoutParams(LayoutParams source) {
423 super(source);
424 this.cellX = source.cellX;
425 this.cellY = source.cellY;
426 this.cellHSpan = source.cellHSpan;
427 this.cellVSpan = source.cellVSpan;
428 }
429
430 public LayoutParams(int cellX, int cellY, int cellHSpan, int cellVSpan) {
431 super(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
432 this.cellX = cellX;
433 this.cellY = cellY;
434 this.cellHSpan = cellHSpan;
435 this.cellVSpan = cellVSpan;
436 }
437
438 public void setup(int cellWidth, int cellHeight, int widthGap, int heightGap,
439 int hStartPadding, int vStartPadding) {
440
441 final int myCellHSpan = cellHSpan;
442 final int myCellVSpan = cellVSpan;
443 final int myCellX = cellX;
444 final int myCellY = cellY;
445
446 width = myCellHSpan * cellWidth + ((myCellHSpan - 1) * widthGap) -
447 leftMargin - rightMargin;
448 height = myCellVSpan * cellHeight + ((myCellVSpan - 1) * heightGap) -
449 topMargin - bottomMargin;
450
451 x = hStartPadding + myCellX * (cellWidth + widthGap) + leftMargin;
452 y = vStartPadding + myCellY * (cellHeight + heightGap) + topMargin;
453 }
454
Winson Chung80baf5a2010-08-09 16:03:15 -0700455 public Object getTag() {
456 return mTag;
457 }
458
459 public void setTag(Object tag) {
460 mTag = tag;
461 }
462
Winson Chung321e9ee2010-08-09 13:37:56 -0700463 public String toString() {
Winson Chung80baf5a2010-08-09 16:03:15 -0700464 return "(" + this.cellX + ", " + this.cellY + ", " +
465 this.cellHSpan + ", " + this.cellVSpan + ")";
Winson Chung321e9ee2010-08-09 13:37:56 -0700466 }
467 }
468}
Michael Jurka8245a862011-02-01 17:53:59 -0800469
470interface Page {
471 public int getPageChildCount();
472 public View getChildOnPageAt(int i);
473 public void removeAllViewsOnPage();
474 public void removeViewOnPageAt(int i);
475 public int indexOfChildOnPage(View v);
476}