blob: d6be3072c3219e55fb892453ac03c90e0474cdbb [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
Adam Cohendf2cc412011-04-27 16:56:57 -070019import android.animation.Animator;
20import android.animation.AnimatorListenerAdapter;
Adam Cohendf2cc412011-04-27 16:56:57 -070021import android.animation.ObjectAnimator;
22import android.animation.PropertyValuesHolder;
23import android.animation.ValueAnimator;
24import android.animation.ValueAnimator.AnimatorUpdateListener;
The Android Open Source Project31dd5032009-03-03 19:32:27 -080025import android.content.Context;
Romain Guyfb5411e2010-02-24 10:04:17 -080026import android.graphics.Rect;
Adam Cohenbadf71e2011-05-26 19:08:29 -070027import android.graphics.drawable.Drawable;
The Android Open Source Project31dd5032009-03-03 19:32:27 -080028import android.util.AttributeSet;
Adam Cohendf2cc412011-04-27 16:56:57 -070029import android.view.LayoutInflater;
Adam Cohen0c872ba2011-05-05 10:34:16 -070030import android.view.MotionEvent;
The Android Open Source Project31dd5032009-03-03 19:32:27 -080031import android.view.View;
32import android.view.View.OnClickListener;
Adam Cohen2801caf2011-05-13 20:57:39 -070033import android.view.animation.AccelerateInterpolator;
34import android.view.animation.DecelerateInterpolator;
The Android Open Source Project31dd5032009-03-03 19:32:27 -080035import android.widget.AdapterView;
The Android Open Source Project31dd5032009-03-03 19:32:27 -080036import android.widget.LinearLayout;
Adam Cohendf2cc412011-04-27 16:56:57 -070037import android.widget.TextView;
The Android Open Source Project31dd5032009-03-03 19:32:27 -080038import android.widget.AdapterView.OnItemClickListener;
39import android.widget.AdapterView.OnItemLongClickListener;
40
Romain Guyedcce092010-03-04 13:03:17 -080041import com.android.launcher.R;
Adam Cohena9cf38f2011-05-02 15:36:58 -070042import com.android.launcher2.FolderInfo.FolderListener;
Romain Guyedcce092010-03-04 13:03:17 -080043
Adam Cohenc0dcf592011-06-01 15:30:43 -070044import java.util.ArrayList;
45
The Android Open Source Project31dd5032009-03-03 19:32:27 -080046/**
47 * Represents a set of icons chosen by the user or generated by the system.
48 */
49public class Folder extends LinearLayout implements DragSource, OnItemLongClickListener,
Adam Cohena9cf38f2011-05-02 15:36:58 -070050 OnItemClickListener, OnClickListener, View.OnLongClickListener, DropTarget, FolderListener {
The Android Open Source Project31dd5032009-03-03 19:32:27 -080051
Joe Onorato00acb122009-08-04 16:04:30 -040052 protected DragController mDragController;
Adam Cohendf2cc412011-04-27 16:56:57 -070053
The Android Open Source Project31dd5032009-03-03 19:32:27 -080054 protected Launcher mLauncher;
55
The Android Open Source Project31dd5032009-03-03 19:32:27 -080056 protected FolderInfo mInfo;
57
58 /**
59 * Which item is being dragged
60 */
Joe Onorato0589f0f2010-02-08 13:44:00 -080061 protected ShortcutInfo mDragItem;
The Android Open Source Project31dd5032009-03-03 19:32:27 -080062
Adam Cohendf2cc412011-04-27 16:56:57 -070063 private static final String TAG = "Launcher.Folder";
64
65 static final int STATE_NONE = -1;
66 static final int STATE_SMALL = 0;
67 static final int STATE_ANIMATING = 1;
68 static final int STATE_OPEN = 2;
69
70 private int mExpandDuration;
71 protected CellLayout mContent;
72 private final LayoutInflater mInflater;
73 private final IconCache mIconCache;
74 private int mState = STATE_NONE;
Adam Cohena9cf38f2011-05-02 15:36:58 -070075 private int[] mDragItemPosition = new int[2];
Adam Cohen2801caf2011-05-13 20:57:39 -070076 private static final int FULL_GROW = 0;
77 private static final int PARTIAL_GROW = 1;
78 private int mMode = PARTIAL_GROW;
79 private boolean mRearrangeOnClose = false;
80 private FolderIcon mFolderIcon;
81 private int mMaxCountX;
82 private int mMaxCountY;
83 private Rect mNewSize = new Rect();
Adam Cohen7c693212011-05-18 15:26:57 -070084 private ArrayList<View> mItemsInReadingOrder = new ArrayList<View>();
Adam Cohenbadf71e2011-05-26 19:08:29 -070085 private Drawable mIconDrawable;
Adam Cohen7c693212011-05-18 15:26:57 -070086 boolean mItemsInvalidated = false;
Adam Cohen76078c42011-06-09 15:06:52 -070087 ShortcutInfo mCurrentDragInfo;
Adam Cohendf2cc412011-04-27 16:56:57 -070088
The Android Open Source Project31dd5032009-03-03 19:32:27 -080089 /**
90 * Used to inflate the Workspace from XML.
91 *
92 * @param context The application's context.
93 * @param attrs The attribtues set containing the Workspace's customization values.
94 */
95 public Folder(Context context, AttributeSet attrs) {
96 super(context, attrs);
97 setAlwaysDrawnWithCacheEnabled(false);
Adam Cohendf2cc412011-04-27 16:56:57 -070098 mInflater = LayoutInflater.from(context);
99 mIconCache = ((LauncherApplication)context.getApplicationContext()).getIconCache();
100 mExpandDuration = getResources().getInteger(R.integer.config_folderAnimDuration);
Adam Cohen2801caf2011-05-13 20:57:39 -0700101
102 mMaxCountX = LauncherModel.getCellCountX() - 1;
103 mMaxCountY = LauncherModel.getCellCountY() - 1;
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800104 }
105
106 @Override
107 protected void onFinishInflate() {
108 super.onFinishInflate();
Adam Cohendf2cc412011-04-27 16:56:57 -0700109 mContent = (CellLayout) findViewById(R.id.folder_content);
Adam Cohen2801caf2011-05-13 20:57:39 -0700110 mContent.setGridSize(0, 0);
111 mContent.enableHardwareLayers();
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800112 }
Adam Cohen2801caf2011-05-13 20:57:39 -0700113
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800114 public void onItemClick(AdapterView parent, View v, int position, long id) {
Joe Onorato0589f0f2010-02-08 13:44:00 -0800115 ShortcutInfo app = (ShortcutInfo) parent.getItemAtPosition(position);
Romain Guyfb5411e2010-02-24 10:04:17 -0800116 int[] pos = new int[2];
117 v.getLocationOnScreen(pos);
118 app.intent.setSourceBounds(new Rect(pos[0], pos[1],
119 pos[0] + v.getWidth(), pos[1] + v.getHeight()));
Joe Onoratof984e852010-03-25 09:47:45 -0700120 mLauncher.startActivitySafely(app.intent, app);
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800121 }
122
123 public void onClick(View v) {
Adam Cohendf2cc412011-04-27 16:56:57 -0700124 Object tag = v.getTag();
125 if (tag instanceof ShortcutInfo) {
126 // refactor this code from Folder
127 ShortcutInfo item = (ShortcutInfo) tag;
128 int[] pos = new int[2];
129 v.getLocationOnScreen(pos);
130 item.intent.setSourceBounds(new Rect(pos[0], pos[1],
131 pos[0] + v.getWidth(), pos[1] + v.getHeight()));
132 mLauncher.startActivitySafely(item.intent, item);
Adam Cohendf2cc412011-04-27 16:56:57 -0700133 }
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800134 }
135
136 public boolean onLongClick(View v) {
Adam Cohendf2cc412011-04-27 16:56:57 -0700137 Object tag = v.getTag();
138 if (tag instanceof ShortcutInfo) {
Adam Cohen2801caf2011-05-13 20:57:39 -0700139 mLauncher.closeFolder(this);
140
Adam Cohendf2cc412011-04-27 16:56:57 -0700141 ShortcutInfo item = (ShortcutInfo) tag;
142 if (!v.isInTouchMode()) {
143 return false;
144 }
145
146 mLauncher.getWorkspace().onDragStartedWithItem(v);
147 mDragController.startDrag(v, this, item, DragController.DRAG_ACTION_COPY);
Adam Cohena9cf38f2011-05-02 15:36:58 -0700148 mDragItemPosition[0] = item.cellX;
149 mDragItemPosition[1] = item.cellY;
Adam Cohenbadf71e2011-05-26 19:08:29 -0700150 mIconDrawable = ((TextView) v).getCompoundDrawables()[1];
Adam Cohen76078c42011-06-09 15:06:52 -0700151
152 mCurrentDragInfo = item;
153 mItemsInvalidated = true;
154 mInfo.itemsChanged();
Adam Cohen2801caf2011-05-13 20:57:39 -0700155
Adam Cohendf2cc412011-04-27 16:56:57 -0700156 mDragItem = item;
157 } else {
158 mLauncher.closeFolder(this);
159 mLauncher.showRenameDialog(mInfo);
160 }
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800161 return true;
162 }
163
Adam Cohenbadf71e2011-05-26 19:08:29 -0700164 public Drawable getDragDrawable() {
165 return mIconDrawable;
166 }
167
Adam Cohen0c872ba2011-05-05 10:34:16 -0700168 /**
169 * We need to handle touch events to prevent them from falling through to the workspace below.
170 */
171 @Override
172 public boolean onTouchEvent(MotionEvent ev) {
173 return true;
174 }
175
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800176 public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
177 if (!view.isInTouchMode()) {
178 return false;
179 }
180
Joe Onorato0589f0f2010-02-08 13:44:00 -0800181 ShortcutInfo app = (ShortcutInfo) parent.getItemAtPosition(position);
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800182
Joe Onorato00acb122009-08-04 16:04:30 -0400183 mDragController.startDrag(view, this, app, DragController.DRAG_ACTION_COPY);
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800184 mLauncher.closeFolder(this);
185 mDragItem = app;
186
187 return true;
188 }
189
Joe Onorato00acb122009-08-04 16:04:30 -0400190 public void setDragController(DragController dragController) {
191 mDragController = dragController;
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800192 }
193
Patrick Dubroya669d792010-11-23 14:40:33 -0800194 public void onDragViewVisible() {
195 }
196
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800197 void setLauncher(Launcher launcher) {
198 mLauncher = launcher;
199 }
Adam Cohen2801caf2011-05-13 20:57:39 -0700200
201 void setFolderIcon(FolderIcon icon) {
202 mFolderIcon = icon;
203 }
204
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800205 /**
206 * @return the FolderInfo object associated with this folder
207 */
208 FolderInfo getInfo() {
209 return mInfo;
210 }
211
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800212 void onOpen() {
Adam Cohendf2cc412011-04-27 16:56:57 -0700213 // When the folder opens, we need to refresh the GridView's selection by
214 // forcing a layout
215 // TODO: find out if this is still necessary
216 mContent.requestLayout();
217 requestFocus();
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800218 }
219
220 void onClose() {
221 final Workspace workspace = mLauncher.getWorkspace();
Michael Jurka0142d492010-08-25 17:46:15 -0700222 workspace.getChildAt(workspace.getCurrentPage()).requestFocus();
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800223 }
224
225 void bind(FolderInfo info) {
226 mInfo = info;
Adam Cohendf2cc412011-04-27 16:56:57 -0700227 ArrayList<ShortcutInfo> children = info.contents;
Adam Cohen7c693212011-05-18 15:26:57 -0700228 setupContentForNumItems(children.size());
Adam Cohendf2cc412011-04-27 16:56:57 -0700229 for (int i = 0; i < children.size(); i++) {
230 ShortcutInfo child = (ShortcutInfo) children.get(i);
Adam Cohen7c693212011-05-18 15:26:57 -0700231 createAndAddShortcut(child);
Adam Cohendf2cc412011-04-27 16:56:57 -0700232 }
Adam Cohen4dbe6d92011-05-18 17:14:15 -0700233 mItemsInvalidated = true;
Adam Cohena9cf38f2011-05-02 15:36:58 -0700234 mInfo.addListener(this);
Adam Cohendf2cc412011-04-27 16:56:57 -0700235 }
236
237 /**
238 * Creates a new UserFolder, inflated from R.layout.user_folder.
239 *
240 * @param context The application's context.
241 *
242 * @return A new UserFolder.
243 */
244 static Folder fromXml(Context context) {
245 return (Folder) LayoutInflater.from(context).inflate(R.layout.user_folder, null);
246 }
247
248 /**
249 * This method is intended to make the UserFolder to be visually identical in size and position
250 * to its associated FolderIcon. This allows for a seamless transition into the expanded state.
251 */
252 private void positionAndSizeAsIcon() {
253 if (!(getParent() instanceof CellLayoutChildren)) return;
254
Adam Cohen2801caf2011-05-13 20:57:39 -0700255 CellLayout.LayoutParams iconLp = (CellLayout.LayoutParams) mFolderIcon.getLayoutParams();
Adam Cohendf2cc412011-04-27 16:56:57 -0700256 CellLayout.LayoutParams lp = (CellLayout.LayoutParams) getLayoutParams();
257
Adam Cohen2801caf2011-05-13 20:57:39 -0700258 if (mMode == PARTIAL_GROW) {
259 setScaleX(0.8f);
260 setScaleY(0.8f);
261 setAlpha(0f);
262 } else {
263 lp.width = iconLp.width;
264 lp.height = iconLp.height;
265 lp.x = iconLp.x;
266 lp.y = iconLp.y;
267 mContent.setAlpha(0);
268 }
Adam Cohendf2cc412011-04-27 16:56:57 -0700269 mState = STATE_SMALL;
270 }
271
272 public void animateOpen() {
273 if (mState != STATE_SMALL) {
274 positionAndSizeAsIcon();
275 }
276 if (!(getParent() instanceof CellLayoutChildren)) return;
277
Adam Cohen2801caf2011-05-13 20:57:39 -0700278 ObjectAnimator oa;
Adam Cohendf2cc412011-04-27 16:56:57 -0700279 CellLayout.LayoutParams lp = (CellLayout.LayoutParams) getLayoutParams();
280
Adam Cohen2801caf2011-05-13 20:57:39 -0700281 centerAboutIcon();
282 if (mMode == PARTIAL_GROW) {
283 PropertyValuesHolder alpha = PropertyValuesHolder.ofFloat("alpha", 1);
284 PropertyValuesHolder scaleX = PropertyValuesHolder.ofFloat("scaleX", 1.0f);
285 PropertyValuesHolder scaleY = PropertyValuesHolder.ofFloat("scaleY", 1.0f);
286 oa = ObjectAnimator.ofPropertyValuesHolder(this, alpha, scaleX, scaleY);
287 } else {
288 PropertyValuesHolder width = PropertyValuesHolder.ofInt("width", mNewSize.width());
289 PropertyValuesHolder height = PropertyValuesHolder.ofInt("height", mNewSize.height());
290 PropertyValuesHolder x = PropertyValuesHolder.ofInt("x", mNewSize.left);
291 PropertyValuesHolder y = PropertyValuesHolder.ofInt("y", mNewSize.top);
292 oa = ObjectAnimator.ofPropertyValuesHolder(lp, width, height, x, y);
293 oa.addUpdateListener(new AnimatorUpdateListener() {
294 public void onAnimationUpdate(ValueAnimator animation) {
295 requestLayout();
296 }
297 });
Adam Cohendf2cc412011-04-27 16:56:57 -0700298
Adam Cohen2801caf2011-05-13 20:57:39 -0700299 PropertyValuesHolder alpha = PropertyValuesHolder.ofFloat("alpha", 1.0f);
300 ObjectAnimator alphaOa = ObjectAnimator.ofPropertyValuesHolder(mContent, alpha);
301 alphaOa.setDuration(mExpandDuration);
302 alphaOa.setInterpolator(new AccelerateInterpolator(2.0f));
303 alphaOa.start();
304 }
Adam Cohendf2cc412011-04-27 16:56:57 -0700305
Adam Cohen2801caf2011-05-13 20:57:39 -0700306 oa.addListener(new AnimatorListenerAdapter() {
Adam Cohendf2cc412011-04-27 16:56:57 -0700307 @Override
308 public void onAnimationStart(Animator animation) {
309 mState = STATE_ANIMATING;
310 }
311 @Override
312 public void onAnimationEnd(Animator animation) {
Adam Cohen2801caf2011-05-13 20:57:39 -0700313 mState = STATE_OPEN;
Adam Cohendf2cc412011-04-27 16:56:57 -0700314 }
315 });
Adam Cohen2801caf2011-05-13 20:57:39 -0700316 oa.setDuration(mExpandDuration);
317 oa.start();
Adam Cohendf2cc412011-04-27 16:56:57 -0700318 }
319
320 public void animateClosed() {
321 if (!(getParent() instanceof CellLayoutChildren)) return;
322
323 CellLayoutChildren clc = (CellLayoutChildren) getParent();
324 final CellLayout cellLayout = (CellLayout) clc.getParent();
Adam Cohen2801caf2011-05-13 20:57:39 -0700325 ObjectAnimator oa;
Adam Cohendf2cc412011-04-27 16:56:57 -0700326
Adam Cohen2801caf2011-05-13 20:57:39 -0700327 if (mMode == PARTIAL_GROW) {
328 PropertyValuesHolder alpha = PropertyValuesHolder.ofFloat("alpha", 0);
329 PropertyValuesHolder scaleX = PropertyValuesHolder.ofFloat("scaleX", 0.9f);
330 PropertyValuesHolder scaleY = PropertyValuesHolder.ofFloat("scaleY", 0.9f);
331 oa = ObjectAnimator.ofPropertyValuesHolder(this, alpha, scaleX, scaleY);
332 } else {
333 CellLayout.LayoutParams iconLp = (CellLayout.LayoutParams) mFolderIcon.getLayoutParams();
334 CellLayout.LayoutParams lp = (CellLayout.LayoutParams) getLayoutParams();
Adam Cohendf2cc412011-04-27 16:56:57 -0700335
Adam Cohen2801caf2011-05-13 20:57:39 -0700336 PropertyValuesHolder width = PropertyValuesHolder.ofInt("width", iconLp.width);
337 PropertyValuesHolder height = PropertyValuesHolder.ofInt("height", iconLp.height);
338 PropertyValuesHolder x = PropertyValuesHolder.ofInt("x",iconLp.x);
339 PropertyValuesHolder y = PropertyValuesHolder.ofInt("y", iconLp.y);
340 oa = ObjectAnimator.ofPropertyValuesHolder(lp, width, height, x, y);
341 oa.addUpdateListener(new AnimatorUpdateListener() {
342 public void onAnimationUpdate(ValueAnimator animation) {
343 requestLayout();
344 }
345 });
Adam Cohendf2cc412011-04-27 16:56:57 -0700346
Adam Cohen2801caf2011-05-13 20:57:39 -0700347 PropertyValuesHolder alpha = PropertyValuesHolder.ofFloat("alpha", 0f);
348 ObjectAnimator alphaOa = ObjectAnimator.ofPropertyValuesHolder(mContent, alpha);
349 alphaOa.setDuration(mExpandDuration);
350 alphaOa.setInterpolator(new DecelerateInterpolator(2.0f));
351 alphaOa.start();
352 }
Adam Cohendf2cc412011-04-27 16:56:57 -0700353
Adam Cohen2801caf2011-05-13 20:57:39 -0700354 oa.addListener(new AnimatorListenerAdapter() {
Adam Cohendf2cc412011-04-27 16:56:57 -0700355 @Override
356 public void onAnimationEnd(Animator animation) {
Adam Cohen2801caf2011-05-13 20:57:39 -0700357 onCloseComplete();
Adam Cohendf2cc412011-04-27 16:56:57 -0700358 cellLayout.removeViewWithoutMarkingCells(Folder.this);
Adam Cohen2801caf2011-05-13 20:57:39 -0700359 mState = STATE_SMALL;
Adam Cohendf2cc412011-04-27 16:56:57 -0700360 }
361 @Override
362 public void onAnimationStart(Animator animation) {
363 mState = STATE_ANIMATING;
364 }
365 });
Adam Cohen2801caf2011-05-13 20:57:39 -0700366 oa.setDuration(mExpandDuration);
367 oa.start();
Adam Cohendf2cc412011-04-27 16:56:57 -0700368 }
369
370 void notifyDataSetChanged() {
371 // recreate all the children if the data set changes under us. We may want to do this more
372 // intelligently (ie just removing the views that should no longer exist)
373 mContent.removeAllViewsInLayout();
374 bind(mInfo);
375 }
376
Adam Cohencb3382b2011-05-24 14:07:08 -0700377 public boolean acceptDrop(DragObject d) {
378 final ItemInfo item = (ItemInfo) d.dragInfo;
Adam Cohendf2cc412011-04-27 16:56:57 -0700379 final int itemType = item.itemType;
Adam Cohen2801caf2011-05-13 20:57:39 -0700380 return ((itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION ||
381 itemType == LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT) &&
382 !isFull());
Adam Cohendf2cc412011-04-27 16:56:57 -0700383 }
384
Adam Cohencb3382b2011-05-24 14:07:08 -0700385 public void onDrop(DragObject d) {
Adam Cohendf2cc412011-04-27 16:56:57 -0700386 ShortcutInfo item;
Adam Cohencb3382b2011-05-24 14:07:08 -0700387 if (d.dragInfo instanceof ApplicationInfo) {
Adam Cohendf2cc412011-04-27 16:56:57 -0700388 // Came from all apps -- make a copy
Adam Cohencb3382b2011-05-24 14:07:08 -0700389 item = ((ApplicationInfo) d.dragInfo).makeShortcut();
Adam Cohendf2cc412011-04-27 16:56:57 -0700390 item.spanX = 1;
391 item.spanY = 1;
392 } else {
Adam Cohencb3382b2011-05-24 14:07:08 -0700393 item = (ShortcutInfo) d.dragInfo;
Adam Cohendf2cc412011-04-27 16:56:57 -0700394 }
Adam Cohen76078c42011-06-09 15:06:52 -0700395
396 // Dragged from self onto self
397 if (item == mCurrentDragInfo) {
398 mInfo.remove(item);
399 }
400
Adam Cohendf2cc412011-04-27 16:56:57 -0700401 mInfo.add(item);
Adam Cohendf2cc412011-04-27 16:56:57 -0700402 }
403
404 protected boolean findAndSetEmptyCells(ShortcutInfo item) {
405 int[] emptyCell = new int[2];
406 if (mContent.findCellForSpan(emptyCell, item.spanX, item.spanY)) {
407 item.cellX = emptyCell[0];
408 item.cellY = emptyCell[1];
Adam Cohendf2cc412011-04-27 16:56:57 -0700409 return true;
410 } else {
411 return false;
412 }
413 }
414
415 protected void createAndAddShortcut(ShortcutInfo item) {
416 final TextView textView =
417 (TextView) mInflater.inflate(R.layout.application_boxed, this, false);
418 textView.setCompoundDrawablesWithIntrinsicBounds(null,
419 new FastBitmapDrawable(item.getIcon(mIconCache)), null, null);
420 textView.setText(item.title);
421 textView.setTag(item);
422
423 textView.setOnClickListener(this);
424 textView.setOnLongClickListener(this);
425
426 CellLayout.LayoutParams lp =
427 new CellLayout.LayoutParams(item.cellX, item.cellY, item.spanX, item.spanY);
428 boolean insert = false;
429 mContent.addViewToCellLayout(textView, insert ? 0 : -1, (int)item.id, lp, true);
430 }
431
Adam Cohencb3382b2011-05-24 14:07:08 -0700432 public void onDragEnter(DragObject d) {
Adam Cohen2801caf2011-05-13 20:57:39 -0700433 mContent.onDragEnter();
Adam Cohendf2cc412011-04-27 16:56:57 -0700434 }
435
Adam Cohencb3382b2011-05-24 14:07:08 -0700436 public void onDragOver(DragObject d) {
437 float[] r = mapPointFromScreenToContent(d.x, d.y, null);
Adam Cohen2801caf2011-05-13 20:57:39 -0700438 mContent.visualizeDropLocation(null, null, (int) r[0], (int) r[1], 1, 1);
Adam Cohendf2cc412011-04-27 16:56:57 -0700439 }
440
Adam Cohencb3382b2011-05-24 14:07:08 -0700441 public void onDragExit(DragObject d) {
Adam Cohen2801caf2011-05-13 20:57:39 -0700442 mContent.onDragExit();
443 }
444
445 public float[] mapPointFromScreenToContent(int x, int y, float[] r) {
446 if (r == null) {
447 r = new float[2];
448 }
449
450 int[] screenLocation = new int[2];
451 mContent.getLocationOnScreen(screenLocation);
452
453 r[0] = x - screenLocation[0];
454 r[1] = y - screenLocation[1];
455 return r;
Adam Cohendf2cc412011-04-27 16:56:57 -0700456 }
457
Adam Cohenc0dcf592011-06-01 15:30:43 -0700458 public void onDropCompleted(View target, DragObject d, boolean success) {
Adam Cohen76078c42011-06-09 15:06:52 -0700459 if (!success) {
460 if (d.dragView != null) {
461 if (target instanceof CellLayout) {
462 // TODO: we should animate the item back to the folder in this case
463 }
464 }
465 mCurrentDragInfo = null;
466 mItemsInvalidated = true;
467 mInfo.itemsChanged();
468 } else {
469 if (target != this) {
470 mInfo.remove(mCurrentDragInfo);
471 mCurrentDragInfo = null;
472 }
473 }
Adam Cohendf2cc412011-04-27 16:56:57 -0700474 }
475
476 public boolean isDropEnabled() {
477 return true;
478 }
479
Adam Cohencb3382b2011-05-24 14:07:08 -0700480 public DropTarget getDropTargetDelegate(DragObject d) {
Adam Cohendf2cc412011-04-27 16:56:57 -0700481 return null;
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800482 }
Adam Cohena9cf38f2011-05-02 15:36:58 -0700483
Adam Cohen2801caf2011-05-13 20:57:39 -0700484 private void setupContentDimension(int count) {
485 ArrayList<View> list = getItemsInReadingOrder();
486
487 int countX = mContent.getCountX();
488 int countY = mContent.getCountY();
Adam Cohen7c693212011-05-18 15:26:57 -0700489 boolean done = false;
Adam Cohen2801caf2011-05-13 20:57:39 -0700490
Adam Cohen7c693212011-05-18 15:26:57 -0700491 while (!done) {
492 int oldCountX = countX;
493 int oldCountY = countY;
494 if (countX * countY < count) {
495 // Current grid is too small, expand it
496 if (countX <= countY && countX < mMaxCountX) {
497 countX++;
498 } else if (countY < mMaxCountY) {
499 countY++;
500 }
501 if (countY == 0) countY++;
502 } else if ((countY - 1) * countX >= count && countY >= countX) {
503 countY = Math.max(0, countY - 1);
504 } else if ((countX - 1) * countY >= count) {
505 countX = Math.max(0, countX - 1);
Adam Cohen2801caf2011-05-13 20:57:39 -0700506 }
Adam Cohen7c693212011-05-18 15:26:57 -0700507 done = countX == oldCountX && countY == oldCountY;
Adam Cohen2801caf2011-05-13 20:57:39 -0700508 }
Adam Cohen7c693212011-05-18 15:26:57 -0700509 mContent.setGridSize(countX, countY);
Adam Cohen2801caf2011-05-13 20:57:39 -0700510 arrangeChildren(list);
511 }
512
513 public boolean isFull() {
514 return getItemCount() >= mMaxCountX * mMaxCountY;
515 }
516
517 private void centerAboutIcon() {
518 CellLayout.LayoutParams iconLp = (CellLayout.LayoutParams) mFolderIcon.getLayoutParams();
519 CellLayout.LayoutParams lp = (CellLayout.LayoutParams) getLayoutParams();
520
521 int width = getPaddingLeft() + getPaddingRight() + mContent.getDesiredWidth();
522 int height = getPaddingTop() + getPaddingBottom() + mContent.getDesiredHeight();
523
524 int centerX = iconLp.x + iconLp.width / 2;
525 int centerY = iconLp.y + iconLp.height / 2;
526 int centeredLeft = centerX - width / 2;
527 int centeredTop = centerY - height / 2;
528
529 CellLayoutChildren clc = (CellLayoutChildren) getParent();
530 int parentWidth = 0;
531 int parentHeight = 0;
532 if (clc != null) {
533 parentWidth = clc.getMeasuredWidth();
534 parentHeight = clc.getMeasuredHeight();
535 }
536
537 int left = Math.min(Math.max(0, centeredLeft), parentWidth - width);
538 int top = Math.min(Math.max(0, centeredTop), parentHeight - height);
539
540 int folderPivotX = width / 2 + (centeredLeft - left);
541 int folderPivotY = height / 2 + (centeredTop - top);
542 setPivotX(folderPivotX);
543 setPivotY(folderPivotY);
544 int folderIconPivotX = (int) (mFolderIcon.getMeasuredWidth() *
545 (1.0f * folderPivotX / width));
546 int folderIconPivotY = (int) (mFolderIcon.getMeasuredHeight() *
547 (1.0f * folderPivotY / height));
548 mFolderIcon.setPivotX(folderIconPivotX);
549 mFolderIcon.setPivotY(folderIconPivotY);
550
551 if (mMode == PARTIAL_GROW) {
552 lp.width = width;
553 lp.height = height;
554 lp.x = left;
555 lp.y = top;
556 } else {
557 mNewSize.set(left, top, left + width, top + height);
558 }
559 }
560
561 private void setupContentForNumItems(int count) {
Adam Cohen2801caf2011-05-13 20:57:39 -0700562 setupContentDimension(count);
563
564 CellLayout.LayoutParams lp = (CellLayout.LayoutParams) getLayoutParams();
565 if (lp == null) {
566 lp = new CellLayout.LayoutParams(0, 0, -1, -1);
567 lp.isLockedToGrid = false;
568 setLayoutParams(lp);
569 }
570 centerAboutIcon();
571 }
572
573 private void arrangeChildren(ArrayList<View> list) {
574 int[] vacant = new int[2];
575 if (list == null) {
576 list = getItemsInReadingOrder();
577 }
578 mContent.removeAllViews();
579
580 for (int i = 0; i < list.size(); i++) {
581 View v = list.get(i);
582 mContent.getVacantCell(vacant, 1, 1);
583 CellLayout.LayoutParams lp = (CellLayout.LayoutParams) v.getLayoutParams();
584 lp.cellX = vacant[0];
585 lp.cellY = vacant[1];
586 ItemInfo info = (ItemInfo) v.getTag();
587 info.cellX = vacant[0];
588 info.cellY = vacant[1];
589 boolean insert = false;
590 mContent.addViewToCellLayout(v, insert ? 0 : -1, (int)info.id, lp, true);
Adam Cohen7c693212011-05-18 15:26:57 -0700591 LauncherModel.addOrMoveItemInDatabase(mLauncher, info, mInfo.id, 0,
592 info.cellX, info.cellY);
Adam Cohen2801caf2011-05-13 20:57:39 -0700593 }
Adam Cohen7c693212011-05-18 15:26:57 -0700594 mItemsInvalidated = true;
Adam Cohen2801caf2011-05-13 20:57:39 -0700595 }
596
Adam Cohena9cf38f2011-05-02 15:36:58 -0700597 public void onAdd(ShortcutInfo item) {
Adam Cohen7c693212011-05-18 15:26:57 -0700598 mItemsInvalidated = true;
Adam Cohen2801caf2011-05-13 20:57:39 -0700599 if (!findAndSetEmptyCells(item)) {
600 // The current layout is full, can we expand it?
601 setupContentForNumItems(getItemCount() + 1);
Adam Cohena9cf38f2011-05-02 15:36:58 -0700602 findAndSetEmptyCells(item);
603 }
604 createAndAddShortcut(item);
Adam Cohen76078c42011-06-09 15:06:52 -0700605 LauncherModel.addOrMoveItemInDatabase(
606 mLauncher, item, mInfo.id, 0, item.cellX, item.cellY);
Adam Cohena9cf38f2011-05-02 15:36:58 -0700607 }
608
609 public int getItemCount() {
610 return mContent.getChildrenLayout().getChildCount();
611 }
612
613 public View getItemAt(int index) {
614 return mContent.getChildrenLayout().getChildAt(index);
615 }
616
Adam Cohen2801caf2011-05-13 20:57:39 -0700617 private void onCloseComplete() {
618 if (mRearrangeOnClose) {
619 setupContentForNumItems(getItemCount());
620 mRearrangeOnClose = false;
621 }
622 }
623
Adam Cohena9cf38f2011-05-02 15:36:58 -0700624 public void onRemove(ShortcutInfo item) {
Adam Cohen7c693212011-05-18 15:26:57 -0700625 mItemsInvalidated = true;
Adam Cohena9cf38f2011-05-02 15:36:58 -0700626 View v = mContent.getChildAt(mDragItemPosition[0], mDragItemPosition[1]);
627 mContent.removeView(v);
Adam Cohen2801caf2011-05-13 20:57:39 -0700628 if (mState == STATE_ANIMATING) {
629 mRearrangeOnClose = true;
630 } else {
631 setupContentForNumItems(getItemCount());
632 }
Adam Cohena9cf38f2011-05-02 15:36:58 -0700633 }
Adam Cohen7c693212011-05-18 15:26:57 -0700634
Adam Cohen76078c42011-06-09 15:06:52 -0700635 public void onItemsChanged() {
636 }
637
Adam Cohen7c693212011-05-18 15:26:57 -0700638 public ArrayList<View> getItemsInReadingOrder() {
Adam Cohen76078c42011-06-09 15:06:52 -0700639 return getItemsInReadingOrder(true);
640 }
641
642 public ArrayList<View> getItemsInReadingOrder(boolean includeCurrentDragItem) {
Adam Cohen7c693212011-05-18 15:26:57 -0700643 if (mItemsInvalidated) {
644 mItemsInReadingOrder.clear();
645 for (int j = 0; j < mContent.getCountY(); j++) {
646 for (int i = 0; i < mContent.getCountX(); i++) {
647 View v = mContent.getChildAt(i, j);
648 if (v != null) {
Adam Cohen76078c42011-06-09 15:06:52 -0700649 ShortcutInfo info = (ShortcutInfo) v.getTag();
650 if (info != mCurrentDragInfo || includeCurrentDragItem) {
651 mItemsInReadingOrder.add(v);
652 }
Adam Cohen7c693212011-05-18 15:26:57 -0700653 }
654 }
655 }
656 mItemsInvalidated = false;
657 }
658 return mItemsInReadingOrder;
659 }
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800660}