blob: 0091a28abdad48aaa604c11bfdc7e69598fd1f78 [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 Cohen7c693212011-05-18 15:26:57 -070019import java.util.ArrayList;
20
Adam Cohen2801caf2011-05-13 20:57:39 -070021import android.animation.Animator;
22import android.animation.AnimatorListenerAdapter;
Adam Cohen2801caf2011-05-13 20:57:39 -070023import 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;
Adam Cohenf4b08912011-05-17 18:45:47 -070028import android.graphics.Color;
The Android Open Source Project31dd5032009-03-03 19:32:27 -080029import android.graphics.drawable.Drawable;
30import android.util.AttributeSet;
31import android.view.LayoutInflater;
Adam Cohen7c693212011-05-18 15:26:57 -070032import android.view.View;
The Android Open Source Project31dd5032009-03-03 19:32:27 -080033import android.view.ViewGroup;
Adam Cohena9cf38f2011-05-02 15:36:58 -070034import android.widget.FrameLayout;
35import android.widget.TextView;
The Android Open Source Project31dd5032009-03-03 19:32:27 -080036
Romain Guyedcce092010-03-04 13:03:17 -080037import com.android.launcher.R;
Adam Cohena9cf38f2011-05-02 15:36:58 -070038import com.android.launcher2.FolderInfo.FolderListener;
Romain Guyedcce092010-03-04 13:03:17 -080039
The Android Open Source Project31dd5032009-03-03 19:32:27 -080040/**
41 * An icon that can appear on in the workspace representing an {@link UserFolder}.
42 */
Adam Cohena9cf38f2011-05-02 15:36:58 -070043public class FolderIcon extends FrameLayout implements DropTarget, FolderListener {
The Android Open Source Project31dd5032009-03-03 19:32:27 -080044 private Launcher mLauncher;
Adam Cohena9cf38f2011-05-02 15:36:58 -070045 Folder mFolder;
46 FolderInfo mInfo;
47
48 private static final int NUM_ITEMS_IN_PREVIEW = 4;
49 private static final float ICON_ANGLE = 15f;
Adam Cohenf4b08912011-05-17 18:45:47 -070050 private static final int CONSUMPTION_ANIMATION_DURATION = 100;
Adam Cohen073a46f2011-05-17 16:28:09 -070051 private static final float INNER_RING_GROWTH_FACTOR = 0.1f;
52 private static final float OUTER_RING_BASELINE_SCALE = 0.7f;
53 private static final float OUTER_RING_GROWTH_FACTOR = 0.3f;
Adam Cohenf4b08912011-05-17 18:45:47 -070054 private static final float INNER_RING_BASELINE_SCALE = 1.0f;
The Android Open Source Project31dd5032009-03-03 19:32:27 -080055
Adam Cohen073a46f2011-05-17 16:28:09 -070056 public static Drawable sFolderOuterRingDrawable = null;
Adam Cohenf4b08912011-05-17 18:45:47 -070057 public static Drawable sFolderInnerRingDrawable = null;
Adam Cohen073a46f2011-05-17 16:28:09 -070058
59 private int mOriginalWidth = -1;
60 private int mOriginalHeight = -1;
Adam Cohen073a46f2011-05-17 16:28:09 -070061
62 private int mFolderLocX;
63 private int mFolderLocY;
64 private float mOuterRingScale;
Adam Cohenf4b08912011-05-17 18:45:47 -070065 private float mInnerRingScale;
Adam Cohen2801caf2011-05-13 20:57:39 -070066
The Android Open Source Project31dd5032009-03-03 19:32:27 -080067 public FolderIcon(Context context, AttributeSet attrs) {
68 super(context, attrs);
69 }
70
71 public FolderIcon(Context context) {
72 super(context);
73 }
74
Michael Jurka0280c3b2010-09-17 15:00:07 -070075 public boolean isDropEnabled() {
Winson Chung7a1d1652011-03-18 15:56:01 -070076 final ViewGroup cellLayoutChildren = (ViewGroup) getParent();
77 final ViewGroup cellLayout = (ViewGroup) cellLayoutChildren.getParent();
78 final Workspace workspace = (Workspace) cellLayout.getParent();
79 return !workspace.isSmall();
Michael Jurka0280c3b2010-09-17 15:00:07 -070080 }
81
The Android Open Source Project31dd5032009-03-03 19:32:27 -080082 static FolderIcon fromXml(int resId, Launcher launcher, ViewGroup group,
Adam Cohendf2cc412011-04-27 16:56:57 -070083 FolderInfo folderInfo, IconCache iconCache) {
The Android Open Source Project31dd5032009-03-03 19:32:27 -080084
85 FolderIcon icon = (FolderIcon) LayoutInflater.from(launcher).inflate(resId, group, false);
86
87 final Resources resources = launcher.getResources();
Adam Cohen2801caf2011-05-13 20:57:39 -070088 Drawable d = iconCache.getFullResIcon(resources, R.drawable.portal_ring_inner_holo);
Adam Cohena9cf38f2011-05-02 15:36:58 -070089 icon.setBackgroundDrawable(d);
The Android Open Source Project31dd5032009-03-03 19:32:27 -080090 icon.setTag(folderInfo);
91 icon.setOnClickListener(launcher);
92 icon.mInfo = folderInfo;
93 icon.mLauncher = launcher;
Adam Cohena9cf38f2011-05-02 15:36:58 -070094
95 Folder folder = Folder.fromXml(launcher);
96 folder.setDragController(launcher.getDragController());
97 folder.setLauncher(launcher);
Adam Cohen2801caf2011-05-13 20:57:39 -070098 folder.setFolderIcon(icon);
Adam Cohena9cf38f2011-05-02 15:36:58 -070099 folder.bind(folderInfo);
100 icon.mFolder = folder;
101
102 folderInfo.addListener(icon);
Adam Cohen073a46f2011-05-17 16:28:09 -0700103 if (sFolderOuterRingDrawable == null) {
104 sFolderOuterRingDrawable =
105 launcher.getResources().getDrawable(R.drawable.portal_ring_outer_holo);
106 }
Adam Cohena9cf38f2011-05-02 15:36:58 -0700107
Adam Cohenf4b08912011-05-17 18:45:47 -0700108 if (sFolderInnerRingDrawable == null) {
109 sFolderInnerRingDrawable =
110 launcher.getResources().getDrawable(R.drawable.portal_ring_inner_holo);
111 }
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800112 return icon;
113 }
114
Adam Cohen073a46f2011-05-17 16:28:09 -0700115 private boolean willAcceptItem(ItemInfo item) {
116 final int itemType = item.itemType;
117 return ((itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION ||
118 itemType == LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT) &&
119 !mFolder.isFull() && item != mInfo);
120 }
121
Adam Cohencb3382b2011-05-24 14:07:08 -0700122 public boolean acceptDrop(DragObject d) {
123 final ItemInfo item = (ItemInfo) d.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
Adam Cohencb3382b2011-05-24 14:07:08 -0700132 public void onDrop(DragObject d) {
Joe Onorato0589f0f2010-02-08 13:44:00 -0800133 ShortcutInfo item;
Adam Cohencb3382b2011-05-24 14:07:08 -0700134 if (d.dragInfo instanceof ApplicationInfo) {
Joe Onorato0589f0f2010-02-08 13:44:00 -0800135 // Came from all apps -- make a copy
Adam Cohencb3382b2011-05-24 14:07:08 -0700136 item = ((ApplicationInfo) d.dragInfo).makeShortcut();
Joe Onorato0589f0f2010-02-08 13:44:00 -0800137 } else {
Adam Cohencb3382b2011-05-24 14:07:08 -0700138 item = (ShortcutInfo) d.dragInfo;
Joe Onorato0589f0f2010-02-08 13:44:00 -0800139 }
Michael Jurka66d72172011-04-12 16:29:25 -0700140 item.cellX = -1;
141 item.cellY = -1;
Adam Cohendf035382011-04-11 17:22:04 -0700142 addItem(item);
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800143 }
144
Adam Cohen2801caf2011-05-13 20:57:39 -0700145 void saveState(CellLayout.LayoutParams lp) {
146 mOriginalWidth = lp.width;
147 mOriginalHeight = lp.height;
Adam Cohen2801caf2011-05-13 20:57:39 -0700148 }
149
Adam Cohen073a46f2011-05-17 16:28:09 -0700150 private void animateToAcceptState() {
Adam Cohen2801caf2011-05-13 20:57:39 -0700151 CellLayout.LayoutParams lp = (CellLayout.LayoutParams) getLayoutParams();
Adam Cohen073a46f2011-05-17 16:28:09 -0700152
Adam Cohenf4b08912011-05-17 18:45:47 -0700153 ValueAnimator va = ValueAnimator.ofFloat(0f, 1f);
154 va.setDuration(CONSUMPTION_ANIMATION_DURATION);
155 va.addUpdateListener(new AnimatorUpdateListener() {
Adam Cohen073a46f2011-05-17 16:28:09 -0700156 public void onAnimationUpdate(ValueAnimator animation) {
157 final float percent = (Float) animation.getAnimatedValue();
158 mOuterRingScale = OUTER_RING_BASELINE_SCALE + percent * OUTER_RING_GROWTH_FACTOR;
Adam Cohenf4b08912011-05-17 18:45:47 -0700159 mInnerRingScale = INNER_RING_BASELINE_SCALE + percent * INNER_RING_GROWTH_FACTOR;
Adam Cohen073a46f2011-05-17 16:28:09 -0700160 mLauncher.getWorkspace().invalidate();
Adam Cohen073a46f2011-05-17 16:28:09 -0700161 invalidate();
162 }
163 });
Adam Cohenf4b08912011-05-17 18:45:47 -0700164 va.addListener(new AnimatorListenerAdapter() {
Adam Cohen073a46f2011-05-17 16:28:09 -0700165 @Override
166 public void onAnimationEnd(Animator animation) {
Adam Cohenf4b08912011-05-17 18:45:47 -0700167 // Instead of setting the background drawable to null, we set the color to
168 // transparent. Setting the background drawable to null results in onDraw
169 // not getting called.
170 setBackgroundColor(Color.TRANSPARENT);
171 requestLayout();
Adam Cohen073a46f2011-05-17 16:28:09 -0700172 }
173 });
Adam Cohenf4b08912011-05-17 18:45:47 -0700174 va.start();
175 }
Adam Cohen073a46f2011-05-17 16:28:09 -0700176
Adam Cohenf4b08912011-05-17 18:45:47 -0700177 private void animateToNaturalState() {
178 ValueAnimator va = ValueAnimator.ofFloat(0f, 1f);
179 va.setDuration(CONSUMPTION_ANIMATION_DURATION);
180 va.addUpdateListener(new AnimatorUpdateListener() {
Adam Cohen073a46f2011-05-17 16:28:09 -0700181 public void onAnimationUpdate(ValueAnimator animation) {
182 final float percent = (Float) animation.getAnimatedValue();
183 mOuterRingScale = OUTER_RING_BASELINE_SCALE + OUTER_RING_GROWTH_FACTOR
184 - percent * OUTER_RING_GROWTH_FACTOR;
Adam Cohenf4b08912011-05-17 18:45:47 -0700185 mInnerRingScale = INNER_RING_BASELINE_SCALE + INNER_RING_GROWTH_FACTOR
186 - percent * INNER_RING_GROWTH_FACTOR;
Adam Cohen073a46f2011-05-17 16:28:09 -0700187 mLauncher.getWorkspace().invalidate();
Adam Cohenf4b08912011-05-17 18:45:47 -0700188 invalidate();
Adam Cohen073a46f2011-05-17 16:28:09 -0700189 }
190 });
Adam Cohenf4b08912011-05-17 18:45:47 -0700191 va.addListener(new AnimatorListenerAdapter() {
192 @Override
193 public void onAnimationEnd(Animator animation) {
194 setBackgroundDrawable(sFolderInnerRingDrawable);
195 mLauncher.getWorkspace().hideFolderAccept(FolderIcon.this);
196 }
197 });
198 va.start();
Adam Cohen073a46f2011-05-17 16:28:09 -0700199 }
200
201 private void determineFolderLocationInWorkspace() {
202 int tvLocation[] = new int[2];
203 int wsLocation[] = new int[2];
204 getLocationOnScreen(tvLocation);
205 mLauncher.getWorkspace().getLocationOnScreen(wsLocation);
206 mFolderLocX = tvLocation[0] - wsLocation[0] + getMeasuredWidth() / 2;
207 mFolderLocY = tvLocation[1] - wsLocation[1] + getMeasuredHeight() / 2;
208 }
209
Adam Cohencb3382b2011-05-24 14:07:08 -0700210 public void onDragEnter(DragObject d) {
211 if (!willAcceptItem((ItemInfo) d.dragInfo)) return;
Adam Cohen073a46f2011-05-17 16:28:09 -0700212 determineFolderLocationInWorkspace();
213 mLauncher.getWorkspace().showFolderAccept(this);
214 animateToAcceptState();
215 }
216
Adam Cohencb3382b2011-05-24 14:07:08 -0700217 public void onDragOver(DragObject d) {
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800218 }
219
Adam Cohencb3382b2011-05-24 14:07:08 -0700220 public void onDragExit(DragObject d) {
221 if (!willAcceptItem((ItemInfo) d.dragInfo)) return;
Adam Cohen073a46f2011-05-17 16:28:09 -0700222 animateToNaturalState();
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800223 }
Patrick Dubroy440c3602010-07-13 17:50:32 -0700224
Adam Cohencb3382b2011-05-24 14:07:08 -0700225 public DropTarget getDropTargetDelegate(DragObject d) {
Patrick Dubroy440c3602010-07-13 17:50:32 -0700226 return null;
227 }
Adam Cohena9cf38f2011-05-02 15:36:58 -0700228
Adam Cohen073a46f2011-05-17 16:28:09 -0700229 public void getFolderLocation(int[] loc) {
230 loc[0] = mFolderLocX;
231 loc[1] = mFolderLocY;
232 }
233
234 public float getOuterRingScale() {
235 return mOuterRingScale;
236 }
237
Adam Cohenf4b08912011-05-17 18:45:47 -0700238 public float getInnerRingScale() {
239 return mInnerRingScale;
240 }
241
Adam Cohena9cf38f2011-05-02 15:36:58 -0700242 @Override
243 protected void onDraw(Canvas canvas) {
244 if (mFolder == null) return;
245 if (mFolder.getItemCount() == 0) return;
246
247 canvas.save();
248 TextView v = (TextView) mFolder.getItemAt(0);
249 Drawable d = v.getCompoundDrawables()[1];
250
Adam Cohen073a46f2011-05-17 16:28:09 -0700251 if (mOriginalWidth < 0 || mOriginalHeight < 0) {
252 mOriginalWidth = getMeasuredWidth();
253 mOriginalHeight = getMeasuredHeight();
254 }
Adam Cohena9cf38f2011-05-02 15:36:58 -0700255
Adam Cohen073a46f2011-05-17 16:28:09 -0700256 int xShift = (mOriginalWidth - d.getIntrinsicWidth()) / 2;
257 int yShift = (mOriginalHeight - d.getIntrinsicHeight()) / 2;
Adam Cohen073a46f2011-05-17 16:28:09 -0700258 canvas.translate(xShift, yShift);
Adam Cohena9cf38f2011-05-02 15:36:58 -0700259
Adam Cohen7c693212011-05-18 15:26:57 -0700260 ArrayList<View> items = mFolder.getItemsInReadingOrder();
261 int firstItemIndex = Math.max(0, items.size() - NUM_ITEMS_IN_PREVIEW);
Adam Cohen4dbe6d92011-05-18 17:14:15 -0700262 for (int i = firstItemIndex; i < items.size(); i++) {
Adam Cohen7c693212011-05-18 15:26:57 -0700263 v = (TextView) items.get(i);
Adam Cohena9cf38f2011-05-02 15:36:58 -0700264 d = v.getCompoundDrawables()[1];
265
Adam Cohenf4b08912011-05-17 18:45:47 -0700266 canvas.translate(d.getIntrinsicWidth() / 2, d.getIntrinsicHeight() / 2);
Adam Cohen7c693212011-05-18 15:26:57 -0700267 canvas.rotate(i == firstItemIndex ? ICON_ANGLE : -ICON_ANGLE);
Adam Cohenf4b08912011-05-17 18:45:47 -0700268 canvas.translate(-d.getIntrinsicWidth() / 2, -d.getIntrinsicHeight() / 2);
269
Adam Cohena9cf38f2011-05-02 15:36:58 -0700270 if (d != null) {
271 d.setBounds(0, 0, d.getIntrinsicWidth(), d.getIntrinsicHeight());
272 d.draw(canvas);
273 }
Adam Cohena9cf38f2011-05-02 15:36:58 -0700274 }
275
276 canvas.restore();
277 }
278
279 public void onAdd(ShortcutInfo item) {
280 invalidate();
281 requestLayout();
282 }
283
284 public void onRemove(ShortcutInfo item) {
285 invalidate();
286 requestLayout();
287 }
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800288}