blob: 31c5ea069312aab6d0d73a4159e10d84db78b225 [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 Cohen2801caf2011-05-13 20:57:39 -070019import android.animation.Animator;
20import android.animation.AnimatorListenerAdapter;
21import 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;
26import android.content.res.Resources;
Adam Cohena9cf38f2011-05-02 15:36:58 -070027import android.graphics.Canvas;
The Android Open Source Project31dd5032009-03-03 19:32:27 -080028import android.graphics.drawable.Drawable;
29import android.util.AttributeSet;
30import android.view.LayoutInflater;
31import android.view.ViewGroup;
Adam Cohena9cf38f2011-05-02 15:36:58 -070032import android.widget.FrameLayout;
33import android.widget.TextView;
The Android Open Source Project31dd5032009-03-03 19:32:27 -080034
Romain Guyedcce092010-03-04 13:03:17 -080035import com.android.launcher.R;
Adam Cohena9cf38f2011-05-02 15:36:58 -070036import com.android.launcher2.FolderInfo.FolderListener;
Romain Guyedcce092010-03-04 13:03:17 -080037
The Android Open Source Project31dd5032009-03-03 19:32:27 -080038/**
39 * An icon that can appear on in the workspace representing an {@link UserFolder}.
40 */
Adam Cohena9cf38f2011-05-02 15:36:58 -070041public class FolderIcon extends FrameLayout implements DropTarget, FolderListener {
The Android Open Source Project31dd5032009-03-03 19:32:27 -080042 private Launcher mLauncher;
Adam Cohena9cf38f2011-05-02 15:36:58 -070043 Folder mFolder;
44 FolderInfo mInfo;
45
46 private static final int NUM_ITEMS_IN_PREVIEW = 4;
47 private static final float ICON_ANGLE = 15f;
Adam Cohen073a46f2011-05-17 16:28:09 -070048 private static final int CONSUMPTION_ANIMATION_DURATION = 60;
49 private static final float INNER_RING_GROWTH_FACTOR = 0.1f;
50 private static final float OUTER_RING_BASELINE_SCALE = 0.7f;
51 private static final float OUTER_RING_GROWTH_FACTOR = 0.3f;
The Android Open Source Project31dd5032009-03-03 19:32:27 -080052
Adam Cohen073a46f2011-05-17 16:28:09 -070053 public static Drawable sFolderOuterRingDrawable = null;
54
55 private int mOriginalWidth = -1;
56 private int mOriginalHeight = -1;
57 private int mOriginalX = -1;
58 private int mOriginalY = -1;
59 private boolean mIsAnimating = false;
60
61 private int mFolderLocX;
62 private int mFolderLocY;
63 private float mOuterRingScale;
Adam Cohen2801caf2011-05-13 20:57:39 -070064
The Android Open Source Project31dd5032009-03-03 19:32:27 -080065 public FolderIcon(Context context, AttributeSet attrs) {
66 super(context, attrs);
67 }
68
69 public FolderIcon(Context context) {
70 super(context);
71 }
72
Michael Jurka0280c3b2010-09-17 15:00:07 -070073 public boolean isDropEnabled() {
Winson Chung7a1d1652011-03-18 15:56:01 -070074 final ViewGroup cellLayoutChildren = (ViewGroup) getParent();
75 final ViewGroup cellLayout = (ViewGroup) cellLayoutChildren.getParent();
76 final Workspace workspace = (Workspace) cellLayout.getParent();
77 return !workspace.isSmall();
Michael Jurka0280c3b2010-09-17 15:00:07 -070078 }
79
The Android Open Source Project31dd5032009-03-03 19:32:27 -080080 static FolderIcon fromXml(int resId, Launcher launcher, ViewGroup group,
Adam Cohendf2cc412011-04-27 16:56:57 -070081 FolderInfo folderInfo, IconCache iconCache) {
The Android Open Source Project31dd5032009-03-03 19:32:27 -080082
83 FolderIcon icon = (FolderIcon) LayoutInflater.from(launcher).inflate(resId, group, false);
84
85 final Resources resources = launcher.getResources();
Adam Cohen2801caf2011-05-13 20:57:39 -070086 Drawable d = iconCache.getFullResIcon(resources, R.drawable.portal_ring_inner_holo);
Adam Cohena9cf38f2011-05-02 15:36:58 -070087 icon.setBackgroundDrawable(d);
The Android Open Source Project31dd5032009-03-03 19:32:27 -080088 icon.setTag(folderInfo);
89 icon.setOnClickListener(launcher);
90 icon.mInfo = folderInfo;
91 icon.mLauncher = launcher;
Adam Cohena9cf38f2011-05-02 15:36:58 -070092
93 Folder folder = Folder.fromXml(launcher);
94 folder.setDragController(launcher.getDragController());
95 folder.setLauncher(launcher);
Adam Cohen2801caf2011-05-13 20:57:39 -070096 folder.setFolderIcon(icon);
Adam Cohena9cf38f2011-05-02 15:36:58 -070097 folder.bind(folderInfo);
98 icon.mFolder = folder;
99
100 folderInfo.addListener(icon);
Adam Cohen073a46f2011-05-17 16:28:09 -0700101 if (sFolderOuterRingDrawable == null) {
102 sFolderOuterRingDrawable =
103 launcher.getResources().getDrawable(R.drawable.portal_ring_outer_holo);
104 }
Adam Cohena9cf38f2011-05-02 15:36:58 -0700105
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800106 return icon;
107 }
108
Adam Cohen073a46f2011-05-17 16:28:09 -0700109 private boolean willAcceptItem(ItemInfo item) {
110 final int itemType = item.itemType;
111 return ((itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION ||
112 itemType == LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT) &&
113 !mFolder.isFull() && item != mInfo);
114 }
115
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800116 public boolean acceptDrop(DragSource source, int x, int y, int xOffset, int yOffset,
Joe Onorato00acb122009-08-04 16:04:30 -0400117 DragView dragView, Object dragInfo) {
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800118 final ItemInfo item = (ItemInfo) dragInfo;
Adam Cohen073a46f2011-05-17 16:28:09 -0700119 return willAcceptItem(item);
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800120 }
121
Adam Cohendf035382011-04-11 17:22:04 -0700122 public void addItem(ShortcutInfo item) {
123 mInfo.add(item);
Adam Cohena9cf38f2011-05-02 15:36:58 -0700124 LauncherModel.addOrMoveItemInDatabase(mLauncher, item, mInfo.id, 0, item.cellX, item.cellY);
Adam Cohendf035382011-04-11 17:22:04 -0700125 }
126
Joe Onorato00acb122009-08-04 16:04:30 -0400127 public void onDrop(DragSource source, int x, int y, int xOffset, int yOffset,
128 DragView dragView, Object dragInfo) {
Joe Onorato0589f0f2010-02-08 13:44:00 -0800129 ShortcutInfo item;
130 if (dragInfo instanceof ApplicationInfo) {
131 // Came from all apps -- make a copy
132 item = ((ApplicationInfo)dragInfo).makeShortcut();
133 } else {
134 item = (ShortcutInfo)dragInfo;
135 }
Michael Jurka66d72172011-04-12 16:29:25 -0700136 item.cellX = -1;
137 item.cellY = -1;
Adam Cohendf035382011-04-11 17:22:04 -0700138 addItem(item);
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800139 }
140
Adam Cohen2801caf2011-05-13 20:57:39 -0700141 void saveState(CellLayout.LayoutParams lp) {
142 mOriginalWidth = lp.width;
143 mOriginalHeight = lp.height;
144 mOriginalX = lp.x;
145 mOriginalY = lp.y;
146 }
147
Adam Cohen073a46f2011-05-17 16:28:09 -0700148 private void animateToAcceptState() {
Adam Cohen2801caf2011-05-13 20:57:39 -0700149 CellLayout.LayoutParams lp = (CellLayout.LayoutParams) getLayoutParams();
Adam Cohen073a46f2011-05-17 16:28:09 -0700150
Adam Cohen2801caf2011-05-13 20:57:39 -0700151 lp.isLockedToGrid = false;
152 saveState(lp);
153
Adam Cohen073a46f2011-05-17 16:28:09 -0700154 int newWidth = (int) ((1 + INNER_RING_GROWTH_FACTOR) * lp.width);
155 int newHeight = (int) ((1 + INNER_RING_GROWTH_FACTOR) * lp.width);
156 int newX = lp.x - (int) ((INNER_RING_GROWTH_FACTOR / 2) * lp.width);
157 int newY = lp.y - (int) ((INNER_RING_GROWTH_FACTOR / 2) * lp.height);
158 PropertyValuesHolder width = PropertyValuesHolder.ofInt("width", newWidth);
159 PropertyValuesHolder height = PropertyValuesHolder.ofInt("height",newHeight);
160 PropertyValuesHolder x = PropertyValuesHolder.ofInt("x", newX);
161 PropertyValuesHolder y = PropertyValuesHolder.ofInt("y", newY);
162 ObjectAnimator oa = ObjectAnimator.ofPropertyValuesHolder(lp, width, height, x, y);
163 oa.setDuration(CONSUMPTION_ANIMATION_DURATION);
Adam Cohen2801caf2011-05-13 20:57:39 -0700164 oa.addUpdateListener(new AnimatorUpdateListener() {
165 public void onAnimationUpdate(ValueAnimator animation) {
Adam Cohen2801caf2011-05-13 20:57:39 -0700166 requestLayout();
Adam Cohen073a46f2011-05-17 16:28:09 -0700167 invalidate();
Adam Cohen2801caf2011-05-13 20:57:39 -0700168 }
169 });
Adam Cohen073a46f2011-05-17 16:28:09 -0700170 oa.addListener(new AnimatorListenerAdapter() {
171 @Override
172 public void onAnimationStart(Animator animation) {
173 mIsAnimating = true;
174 }
175 });
176 ValueAnimator outerRingScale = ValueAnimator.ofFloat(0f, 1f);
177 outerRingScale.setDuration(CONSUMPTION_ANIMATION_DURATION);
178 outerRingScale.addUpdateListener(new AnimatorUpdateListener() {
179 public void onAnimationUpdate(ValueAnimator animation) {
180 final float percent = (Float) animation.getAnimatedValue();
181 mOuterRingScale = OUTER_RING_BASELINE_SCALE + percent * OUTER_RING_GROWTH_FACTOR;
182 mLauncher.getWorkspace().invalidate();
183 }
184 });
185
186 outerRingScale.start();
Adam Cohen2801caf2011-05-13 20:57:39 -0700187 oa.start();
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800188 }
189
Adam Cohen073a46f2011-05-17 16:28:09 -0700190 private void animateToNaturalState() {
191 final CellLayout.LayoutParams lp = (CellLayout.LayoutParams) getLayoutParams();
192 lp.isLockedToGrid = false;
193
194 PropertyValuesHolder width = PropertyValuesHolder.ofInt("width", mOriginalWidth);
195 PropertyValuesHolder height = PropertyValuesHolder.ofInt("height", mOriginalHeight);
196 PropertyValuesHolder x = PropertyValuesHolder.ofInt("x", mOriginalX);
197 PropertyValuesHolder y = PropertyValuesHolder.ofInt("y", mOriginalY);
198 ObjectAnimator oa = ObjectAnimator.ofPropertyValuesHolder(lp, width, height, x, y);
199 oa.addUpdateListener(new AnimatorUpdateListener() {
200 public void onAnimationUpdate(ValueAnimator animation) {
201 requestLayout();
202 invalidate();
203 }
204 });
205 oa.addListener(new AnimatorListenerAdapter() {
206 @Override
207 public void onAnimationEnd(Animator animation) {
208 lp.isLockedToGrid = true;
209 mIsAnimating = false;
210 }
211 });
212
213 ValueAnimator outerRingScale = ValueAnimator.ofFloat(0f, 1f);
214 outerRingScale.setDuration(CONSUMPTION_ANIMATION_DURATION);
215 outerRingScale.addUpdateListener(new AnimatorUpdateListener() {
216 public void onAnimationUpdate(ValueAnimator animation) {
217 final float percent = (Float) animation.getAnimatedValue();
218 mOuterRingScale = OUTER_RING_BASELINE_SCALE + OUTER_RING_GROWTH_FACTOR
219 - percent * OUTER_RING_GROWTH_FACTOR;
220 mLauncher.getWorkspace().invalidate();
221 }
222 });
223
224 oa.setDuration(CONSUMPTION_ANIMATION_DURATION);
225 oa.start();
226 }
227
228 private void determineFolderLocationInWorkspace() {
229 int tvLocation[] = new int[2];
230 int wsLocation[] = new int[2];
231 getLocationOnScreen(tvLocation);
232 mLauncher.getWorkspace().getLocationOnScreen(wsLocation);
233 mFolderLocX = tvLocation[0] - wsLocation[0] + getMeasuredWidth() / 2;
234 mFolderLocY = tvLocation[1] - wsLocation[1] + getMeasuredHeight() / 2;
235 }
236
237 public void onDragEnter(DragSource source, int x, int y, int xOffset, int yOffset,
238 DragView dragView, Object dragInfo) {
239 if (!willAcceptItem((ItemInfo) dragInfo)) return;
240 determineFolderLocationInWorkspace();
241 mLauncher.getWorkspace().showFolderAccept(this);
242 animateToAcceptState();
243 }
244
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800245 public void onDragOver(DragSource source, int x, int y, int xOffset, int yOffset,
Joe Onorato00acb122009-08-04 16:04:30 -0400246 DragView dragView, Object dragInfo) {
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800247 }
248
249 public void onDragExit(DragSource source, int x, int y, int xOffset, int yOffset,
Joe Onorato00acb122009-08-04 16:04:30 -0400250 DragView dragView, Object dragInfo) {
Adam Cohen073a46f2011-05-17 16:28:09 -0700251 if (!willAcceptItem((ItemInfo) dragInfo)) return;
252 mLauncher.getWorkspace().hideFolderAccept(this);
253 animateToNaturalState();
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800254 }
Patrick Dubroy440c3602010-07-13 17:50:32 -0700255
256 @Override
257 public DropTarget getDropTargetDelegate(DragSource source, int x, int y, int xOffset, int yOffset,
258 DragView dragView, Object dragInfo) {
259 return null;
260 }
Adam Cohena9cf38f2011-05-02 15:36:58 -0700261
Adam Cohen073a46f2011-05-17 16:28:09 -0700262 public void getFolderLocation(int[] loc) {
263 loc[0] = mFolderLocX;
264 loc[1] = mFolderLocY;
265 }
266
267 public float getOuterRingScale() {
268 return mOuterRingScale;
269 }
270
Adam Cohena9cf38f2011-05-02 15:36:58 -0700271 @Override
272 protected void onDraw(Canvas canvas) {
273 if (mFolder == null) return;
274 if (mFolder.getItemCount() == 0) return;
275
276 canvas.save();
277 TextView v = (TextView) mFolder.getItemAt(0);
278 Drawable d = v.getCompoundDrawables()[1];
279
Adam Cohen073a46f2011-05-17 16:28:09 -0700280 CellLayout.LayoutParams lp = (CellLayout.LayoutParams) getLayoutParams();
281 if (mOriginalWidth < 0 || mOriginalHeight < 0) {
282 mOriginalWidth = getMeasuredWidth();
283 mOriginalHeight = getMeasuredHeight();
284 }
Adam Cohena9cf38f2011-05-02 15:36:58 -0700285
Adam Cohen073a46f2011-05-17 16:28:09 -0700286 int xShift = (mOriginalWidth - d.getIntrinsicWidth()) / 2;
287 int yShift = (mOriginalHeight - d.getIntrinsicHeight()) / 2;
288
289 if (mIsAnimating) {
290 xShift -= lp.x - mOriginalX;
291 yShift -= lp.y - mOriginalY;
292 }
293
294 canvas.translate(xShift, yShift);
Adam Cohena9cf38f2011-05-02 15:36:58 -0700295 canvas.translate(d.getIntrinsicWidth() / 2, d.getIntrinsicHeight() / 2);
296 canvas.rotate(ICON_ANGLE);
Adam Cohena9cf38f2011-05-02 15:36:58 -0700297 canvas.translate(-d.getIntrinsicWidth() / 2, -d.getIntrinsicHeight() / 2);
298
299 for (int i = Math.max(0, mFolder.getItemCount() - NUM_ITEMS_IN_PREVIEW);
300 i < mFolder.getItemCount(); i++) {
301 v = (TextView) mFolder.getItemAt(i);
302 d = v.getCompoundDrawables()[1];
303
304 if (d != null) {
305 d.setBounds(0, 0, d.getIntrinsicWidth(), d.getIntrinsicHeight());
306 d.draw(canvas);
307 }
308
309 canvas.translate(d.getIntrinsicWidth() / 2, d.getIntrinsicHeight() / 2);
310 canvas.rotate(-ICON_ANGLE);
311 canvas.translate(-d.getIntrinsicWidth() / 2, -d.getIntrinsicHeight() / 2);
312 }
313
314 canvas.restore();
315 }
316
317 public void onAdd(ShortcutInfo item) {
318 invalidate();
319 requestLayout();
320 }
321
322 public void onRemove(ShortcutInfo item) {
323 invalidate();
324 requestLayout();
325 }
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800326}