blob: f49297eb1f885f3b506f00eb12335f5f55c4383f [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;
Adam Cohen2801caf2011-05-13 20:57:39 -070021import android.animation.ValueAnimator;
22import android.animation.ValueAnimator.AnimatorUpdateListener;
The Android Open Source Project31dd5032009-03-03 19:32:27 -080023import android.content.Context;
24import android.content.res.Resources;
Adam Cohena9cf38f2011-05-02 15:36:58 -070025import android.graphics.Canvas;
Adam Cohenf4b08912011-05-17 18:45:47 -070026import android.graphics.Color;
The Android Open Source Project31dd5032009-03-03 19:32:27 -080027import android.graphics.drawable.Drawable;
28import android.util.AttributeSet;
29import android.view.LayoutInflater;
30import android.view.ViewGroup;
Adam Cohena9cf38f2011-05-02 15:36:58 -070031import android.widget.FrameLayout;
32import android.widget.TextView;
The Android Open Source Project31dd5032009-03-03 19:32:27 -080033
Romain Guyedcce092010-03-04 13:03:17 -080034import com.android.launcher.R;
Adam Cohena9cf38f2011-05-02 15:36:58 -070035import com.android.launcher2.FolderInfo.FolderListener;
Romain Guyedcce092010-03-04 13:03:17 -080036
The Android Open Source Project31dd5032009-03-03 19:32:27 -080037/**
38 * An icon that can appear on in the workspace representing an {@link UserFolder}.
39 */
Adam Cohena9cf38f2011-05-02 15:36:58 -070040public class FolderIcon extends FrameLayout implements DropTarget, FolderListener {
The Android Open Source Project31dd5032009-03-03 19:32:27 -080041 private Launcher mLauncher;
Adam Cohena9cf38f2011-05-02 15:36:58 -070042 Folder mFolder;
43 FolderInfo mInfo;
44
45 private static final int NUM_ITEMS_IN_PREVIEW = 4;
46 private static final float ICON_ANGLE = 15f;
Adam Cohenf4b08912011-05-17 18:45:47 -070047 private static final int CONSUMPTION_ANIMATION_DURATION = 100;
Adam Cohen073a46f2011-05-17 16:28:09 -070048 private static final float INNER_RING_GROWTH_FACTOR = 0.1f;
49 private static final float OUTER_RING_BASELINE_SCALE = 0.7f;
50 private static final float OUTER_RING_GROWTH_FACTOR = 0.3f;
Adam Cohenf4b08912011-05-17 18:45:47 -070051 private static final float INNER_RING_BASELINE_SCALE = 1.0f;
The Android Open Source Project31dd5032009-03-03 19:32:27 -080052
Adam Cohen073a46f2011-05-17 16:28:09 -070053 public static Drawable sFolderOuterRingDrawable = null;
Adam Cohenf4b08912011-05-17 18:45:47 -070054 public static Drawable sFolderInnerRingDrawable = null;
Adam Cohen073a46f2011-05-17 16:28:09 -070055
56 private int mOriginalWidth = -1;
57 private int mOriginalHeight = -1;
58 private int mOriginalX = -1;
59 private int mOriginalY = -1;
Adam Cohen073a46f2011-05-17 16:28:09 -070060
61 private int mFolderLocX;
62 private int mFolderLocY;
63 private float mOuterRingScale;
Adam Cohenf4b08912011-05-17 18:45:47 -070064 private float mInnerRingScale;
Adam Cohen2801caf2011-05-13 20:57:39 -070065
The Android Open Source Project31dd5032009-03-03 19:32:27 -080066 public FolderIcon(Context context, AttributeSet attrs) {
67 super(context, attrs);
68 }
69
70 public FolderIcon(Context context) {
71 super(context);
72 }
73
Michael Jurka0280c3b2010-09-17 15:00:07 -070074 public boolean isDropEnabled() {
Winson Chung7a1d1652011-03-18 15:56:01 -070075 final ViewGroup cellLayoutChildren = (ViewGroup) getParent();
76 final ViewGroup cellLayout = (ViewGroup) cellLayoutChildren.getParent();
77 final Workspace workspace = (Workspace) cellLayout.getParent();
78 return !workspace.isSmall();
Michael Jurka0280c3b2010-09-17 15:00:07 -070079 }
80
The Android Open Source Project31dd5032009-03-03 19:32:27 -080081 static FolderIcon fromXml(int resId, Launcher launcher, ViewGroup group,
Adam Cohendf2cc412011-04-27 16:56:57 -070082 FolderInfo folderInfo, IconCache iconCache) {
The Android Open Source Project31dd5032009-03-03 19:32:27 -080083
84 FolderIcon icon = (FolderIcon) LayoutInflater.from(launcher).inflate(resId, group, false);
85
86 final Resources resources = launcher.getResources();
Adam Cohen2801caf2011-05-13 20:57:39 -070087 Drawable d = iconCache.getFullResIcon(resources, R.drawable.portal_ring_inner_holo);
Adam Cohena9cf38f2011-05-02 15:36:58 -070088 icon.setBackgroundDrawable(d);
The Android Open Source Project31dd5032009-03-03 19:32:27 -080089 icon.setTag(folderInfo);
90 icon.setOnClickListener(launcher);
91 icon.mInfo = folderInfo;
92 icon.mLauncher = launcher;
Adam Cohena9cf38f2011-05-02 15:36:58 -070093
94 Folder folder = Folder.fromXml(launcher);
95 folder.setDragController(launcher.getDragController());
96 folder.setLauncher(launcher);
Adam Cohen2801caf2011-05-13 20:57:39 -070097 folder.setFolderIcon(icon);
Adam Cohena9cf38f2011-05-02 15:36:58 -070098 folder.bind(folderInfo);
99 icon.mFolder = folder;
100
101 folderInfo.addListener(icon);
Adam Cohen073a46f2011-05-17 16:28:09 -0700102 if (sFolderOuterRingDrawable == null) {
103 sFolderOuterRingDrawable =
104 launcher.getResources().getDrawable(R.drawable.portal_ring_outer_holo);
105 }
Adam Cohena9cf38f2011-05-02 15:36:58 -0700106
Adam Cohenf4b08912011-05-17 18:45:47 -0700107 if (sFolderInnerRingDrawable == null) {
108 sFolderInnerRingDrawable =
109 launcher.getResources().getDrawable(R.drawable.portal_ring_inner_holo);
110 }
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800111 return icon;
112 }
113
Adam Cohen073a46f2011-05-17 16:28:09 -0700114 private boolean willAcceptItem(ItemInfo item) {
115 final int itemType = item.itemType;
116 return ((itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION ||
117 itemType == LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT) &&
118 !mFolder.isFull() && item != mInfo);
119 }
120
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800121 public boolean acceptDrop(DragSource source, int x, int y, int xOffset, int yOffset,
Joe Onorato00acb122009-08-04 16:04:30 -0400122 DragView dragView, Object dragInfo) {
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800123 final ItemInfo item = (ItemInfo) dragInfo;
Adam Cohen073a46f2011-05-17 16:28:09 -0700124 return willAcceptItem(item);
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800125 }
126
Adam Cohendf035382011-04-11 17:22:04 -0700127 public void addItem(ShortcutInfo item) {
128 mInfo.add(item);
Adam Cohena9cf38f2011-05-02 15:36:58 -0700129 LauncherModel.addOrMoveItemInDatabase(mLauncher, item, mInfo.id, 0, item.cellX, item.cellY);
Adam Cohendf035382011-04-11 17:22:04 -0700130 }
131
Joe Onorato00acb122009-08-04 16:04:30 -0400132 public void onDrop(DragSource source, int x, int y, int xOffset, int yOffset,
133 DragView dragView, Object dragInfo) {
Joe Onorato0589f0f2010-02-08 13:44:00 -0800134 ShortcutInfo item;
135 if (dragInfo instanceof ApplicationInfo) {
136 // Came from all apps -- make a copy
137 item = ((ApplicationInfo)dragInfo).makeShortcut();
138 } else {
139 item = (ShortcutInfo)dragInfo;
140 }
Michael Jurka66d72172011-04-12 16:29:25 -0700141 item.cellX = -1;
142 item.cellY = -1;
Adam Cohendf035382011-04-11 17:22:04 -0700143 addItem(item);
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800144 }
145
Adam Cohen2801caf2011-05-13 20:57:39 -0700146 void saveState(CellLayout.LayoutParams lp) {
147 mOriginalWidth = lp.width;
148 mOriginalHeight = lp.height;
149 mOriginalX = lp.x;
150 mOriginalY = lp.y;
151 }
152
Adam Cohen073a46f2011-05-17 16:28:09 -0700153 private void animateToAcceptState() {
Adam Cohen2801caf2011-05-13 20:57:39 -0700154 CellLayout.LayoutParams lp = (CellLayout.LayoutParams) getLayoutParams();
Adam Cohen073a46f2011-05-17 16:28:09 -0700155
Adam Cohenf4b08912011-05-17 18:45:47 -0700156 ValueAnimator va = ValueAnimator.ofFloat(0f, 1f);
157 va.setDuration(CONSUMPTION_ANIMATION_DURATION);
158 va.addUpdateListener(new AnimatorUpdateListener() {
Adam Cohen073a46f2011-05-17 16:28:09 -0700159 public void onAnimationUpdate(ValueAnimator animation) {
160 final float percent = (Float) animation.getAnimatedValue();
161 mOuterRingScale = OUTER_RING_BASELINE_SCALE + percent * OUTER_RING_GROWTH_FACTOR;
Adam Cohenf4b08912011-05-17 18:45:47 -0700162 mInnerRingScale = INNER_RING_BASELINE_SCALE + percent * INNER_RING_GROWTH_FACTOR;
Adam Cohen073a46f2011-05-17 16:28:09 -0700163 mLauncher.getWorkspace().invalidate();
Adam Cohen073a46f2011-05-17 16:28:09 -0700164 invalidate();
165 }
166 });
Adam Cohenf4b08912011-05-17 18:45:47 -0700167 va.addListener(new AnimatorListenerAdapter() {
Adam Cohen073a46f2011-05-17 16:28:09 -0700168 @Override
169 public void onAnimationEnd(Animator animation) {
Adam Cohenf4b08912011-05-17 18:45:47 -0700170 // Instead of setting the background drawable to null, we set the color to
171 // transparent. Setting the background drawable to null results in onDraw
172 // not getting called.
173 setBackgroundColor(Color.TRANSPARENT);
174 requestLayout();
Adam Cohen073a46f2011-05-17 16:28:09 -0700175 }
176 });
Adam Cohenf4b08912011-05-17 18:45:47 -0700177 va.start();
178 }
Adam Cohen073a46f2011-05-17 16:28:09 -0700179
Adam Cohenf4b08912011-05-17 18:45:47 -0700180 private void animateToNaturalState() {
181 ValueAnimator va = ValueAnimator.ofFloat(0f, 1f);
182 va.setDuration(CONSUMPTION_ANIMATION_DURATION);
183 va.addUpdateListener(new AnimatorUpdateListener() {
Adam Cohen073a46f2011-05-17 16:28:09 -0700184 public void onAnimationUpdate(ValueAnimator animation) {
185 final float percent = (Float) animation.getAnimatedValue();
186 mOuterRingScale = OUTER_RING_BASELINE_SCALE + OUTER_RING_GROWTH_FACTOR
187 - percent * OUTER_RING_GROWTH_FACTOR;
Adam Cohenf4b08912011-05-17 18:45:47 -0700188 mInnerRingScale = INNER_RING_BASELINE_SCALE + INNER_RING_GROWTH_FACTOR
189 - percent * INNER_RING_GROWTH_FACTOR;
Adam Cohen073a46f2011-05-17 16:28:09 -0700190 mLauncher.getWorkspace().invalidate();
Adam Cohenf4b08912011-05-17 18:45:47 -0700191 invalidate();
Adam Cohen073a46f2011-05-17 16:28:09 -0700192 }
193 });
Adam Cohenf4b08912011-05-17 18:45:47 -0700194 va.addListener(new AnimatorListenerAdapter() {
195 @Override
196 public void onAnimationEnd(Animator animation) {
197 setBackgroundDrawable(sFolderInnerRingDrawable);
198 mLauncher.getWorkspace().hideFolderAccept(FolderIcon.this);
199 }
200 });
201 va.start();
Adam Cohen073a46f2011-05-17 16:28:09 -0700202 }
203
204 private void determineFolderLocationInWorkspace() {
205 int tvLocation[] = new int[2];
206 int wsLocation[] = new int[2];
207 getLocationOnScreen(tvLocation);
208 mLauncher.getWorkspace().getLocationOnScreen(wsLocation);
209 mFolderLocX = tvLocation[0] - wsLocation[0] + getMeasuredWidth() / 2;
210 mFolderLocY = tvLocation[1] - wsLocation[1] + getMeasuredHeight() / 2;
211 }
212
213 public void onDragEnter(DragSource source, int x, int y, int xOffset, int yOffset,
214 DragView dragView, Object dragInfo) {
215 if (!willAcceptItem((ItemInfo) dragInfo)) return;
216 determineFolderLocationInWorkspace();
217 mLauncher.getWorkspace().showFolderAccept(this);
218 animateToAcceptState();
219 }
220
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800221 public void onDragOver(DragSource source, int x, int y, int xOffset, int yOffset,
Joe Onorato00acb122009-08-04 16:04:30 -0400222 DragView dragView, Object dragInfo) {
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800223 }
224
225 public void onDragExit(DragSource source, int x, int y, int xOffset, int yOffset,
Joe Onorato00acb122009-08-04 16:04:30 -0400226 DragView dragView, Object dragInfo) {
Adam Cohen073a46f2011-05-17 16:28:09 -0700227 if (!willAcceptItem((ItemInfo) dragInfo)) return;
Adam Cohen073a46f2011-05-17 16:28:09 -0700228 animateToNaturalState();
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800229 }
Patrick Dubroy440c3602010-07-13 17:50:32 -0700230
231 @Override
232 public DropTarget getDropTargetDelegate(DragSource source, int x, int y, int xOffset, int yOffset,
233 DragView dragView, Object dragInfo) {
234 return null;
235 }
Adam Cohena9cf38f2011-05-02 15:36:58 -0700236
Adam Cohen073a46f2011-05-17 16:28:09 -0700237 public void getFolderLocation(int[] loc) {
238 loc[0] = mFolderLocX;
239 loc[1] = mFolderLocY;
240 }
241
242 public float getOuterRingScale() {
243 return mOuterRingScale;
244 }
245
Adam Cohenf4b08912011-05-17 18:45:47 -0700246 public float getInnerRingScale() {
247 return mInnerRingScale;
248 }
249
Adam Cohena9cf38f2011-05-02 15:36:58 -0700250 @Override
251 protected void onDraw(Canvas canvas) {
252 if (mFolder == null) return;
253 if (mFolder.getItemCount() == 0) return;
254
255 canvas.save();
256 TextView v = (TextView) mFolder.getItemAt(0);
257 Drawable d = v.getCompoundDrawables()[1];
258
Adam Cohen073a46f2011-05-17 16:28:09 -0700259 if (mOriginalWidth < 0 || mOriginalHeight < 0) {
260 mOriginalWidth = getMeasuredWidth();
261 mOriginalHeight = getMeasuredHeight();
262 }
Adam Cohena9cf38f2011-05-02 15:36:58 -0700263
Adam Cohen073a46f2011-05-17 16:28:09 -0700264 int xShift = (mOriginalWidth - d.getIntrinsicWidth()) / 2;
265 int yShift = (mOriginalHeight - d.getIntrinsicHeight()) / 2;
Adam Cohen073a46f2011-05-17 16:28:09 -0700266 canvas.translate(xShift, yShift);
Adam Cohena9cf38f2011-05-02 15:36:58 -0700267
268 for (int i = Math.max(0, mFolder.getItemCount() - NUM_ITEMS_IN_PREVIEW);
269 i < mFolder.getItemCount(); i++) {
270 v = (TextView) mFolder.getItemAt(i);
271 d = v.getCompoundDrawables()[1];
272
Adam Cohenf4b08912011-05-17 18:45:47 -0700273 canvas.translate(d.getIntrinsicWidth() / 2, d.getIntrinsicHeight() / 2);
274 canvas.rotate(i == 0 ? ICON_ANGLE : -ICON_ANGLE);
275 canvas.translate(-d.getIntrinsicWidth() / 2, -d.getIntrinsicHeight() / 2);
276
Adam Cohena9cf38f2011-05-02 15:36:58 -0700277 if (d != null) {
278 d.setBounds(0, 0, d.getIntrinsicWidth(), d.getIntrinsicHeight());
279 d.draw(canvas);
280 }
Adam Cohena9cf38f2011-05-02 15:36:58 -0700281 }
282
283 canvas.restore();
284 }
285
286 public void onAdd(ShortcutInfo item) {
287 invalidate();
288 requestLayout();
289 }
290
291 public void onRemove(ShortcutInfo item) {
292 invalidate();
293 requestLayout();
294 }
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800295}