blob: 939dc44de612e4d15ffbe1e241daf5b487242ab0 [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;
61 private int mOriginalX = -1;
62 private int mOriginalY = -1;
Adam Cohen073a46f2011-05-17 16:28:09 -070063
64 private int mFolderLocX;
65 private int mFolderLocY;
66 private float mOuterRingScale;
Adam Cohenf4b08912011-05-17 18:45:47 -070067 private float mInnerRingScale;
Adam Cohen2801caf2011-05-13 20:57:39 -070068
The Android Open Source Project31dd5032009-03-03 19:32:27 -080069 public FolderIcon(Context context, AttributeSet attrs) {
70 super(context, attrs);
71 }
72
73 public FolderIcon(Context context) {
74 super(context);
75 }
76
Michael Jurka0280c3b2010-09-17 15:00:07 -070077 public boolean isDropEnabled() {
Winson Chung7a1d1652011-03-18 15:56:01 -070078 final ViewGroup cellLayoutChildren = (ViewGroup) getParent();
79 final ViewGroup cellLayout = (ViewGroup) cellLayoutChildren.getParent();
80 final Workspace workspace = (Workspace) cellLayout.getParent();
81 return !workspace.isSmall();
Michael Jurka0280c3b2010-09-17 15:00:07 -070082 }
83
The Android Open Source Project31dd5032009-03-03 19:32:27 -080084 static FolderIcon fromXml(int resId, Launcher launcher, ViewGroup group,
Adam Cohendf2cc412011-04-27 16:56:57 -070085 FolderInfo folderInfo, IconCache iconCache) {
The Android Open Source Project31dd5032009-03-03 19:32:27 -080086
87 FolderIcon icon = (FolderIcon) LayoutInflater.from(launcher).inflate(resId, group, false);
88
89 final Resources resources = launcher.getResources();
Adam Cohen2801caf2011-05-13 20:57:39 -070090 Drawable d = iconCache.getFullResIcon(resources, R.drawable.portal_ring_inner_holo);
Adam Cohena9cf38f2011-05-02 15:36:58 -070091 icon.setBackgroundDrawable(d);
The Android Open Source Project31dd5032009-03-03 19:32:27 -080092 icon.setTag(folderInfo);
93 icon.setOnClickListener(launcher);
94 icon.mInfo = folderInfo;
95 icon.mLauncher = launcher;
Adam Cohena9cf38f2011-05-02 15:36:58 -070096
97 Folder folder = Folder.fromXml(launcher);
98 folder.setDragController(launcher.getDragController());
99 folder.setLauncher(launcher);
Adam Cohen2801caf2011-05-13 20:57:39 -0700100 folder.setFolderIcon(icon);
Adam Cohena9cf38f2011-05-02 15:36:58 -0700101 folder.bind(folderInfo);
102 icon.mFolder = folder;
103
104 folderInfo.addListener(icon);
Adam Cohen073a46f2011-05-17 16:28:09 -0700105 if (sFolderOuterRingDrawable == null) {
106 sFolderOuterRingDrawable =
107 launcher.getResources().getDrawable(R.drawable.portal_ring_outer_holo);
108 }
Adam Cohena9cf38f2011-05-02 15:36:58 -0700109
Adam Cohenf4b08912011-05-17 18:45:47 -0700110 if (sFolderInnerRingDrawable == null) {
111 sFolderInnerRingDrawable =
112 launcher.getResources().getDrawable(R.drawable.portal_ring_inner_holo);
113 }
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800114 return icon;
115 }
116
Adam Cohen073a46f2011-05-17 16:28:09 -0700117 private boolean willAcceptItem(ItemInfo item) {
118 final int itemType = item.itemType;
119 return ((itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION ||
120 itemType == LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT) &&
121 !mFolder.isFull() && item != mInfo);
122 }
123
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800124 public boolean acceptDrop(DragSource source, int x, int y, int xOffset, int yOffset,
Joe Onorato00acb122009-08-04 16:04:30 -0400125 DragView dragView, Object dragInfo) {
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800126 final ItemInfo item = (ItemInfo) dragInfo;
Adam Cohen073a46f2011-05-17 16:28:09 -0700127 return willAcceptItem(item);
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800128 }
129
Adam Cohendf035382011-04-11 17:22:04 -0700130 public void addItem(ShortcutInfo item) {
131 mInfo.add(item);
Adam Cohena9cf38f2011-05-02 15:36:58 -0700132 LauncherModel.addOrMoveItemInDatabase(mLauncher, item, mInfo.id, 0, item.cellX, item.cellY);
Adam Cohendf035382011-04-11 17:22:04 -0700133 }
134
Joe Onorato00acb122009-08-04 16:04:30 -0400135 public void onDrop(DragSource source, int x, int y, int xOffset, int yOffset,
136 DragView dragView, Object dragInfo) {
Joe Onorato0589f0f2010-02-08 13:44:00 -0800137 ShortcutInfo item;
138 if (dragInfo instanceof ApplicationInfo) {
139 // Came from all apps -- make a copy
140 item = ((ApplicationInfo)dragInfo).makeShortcut();
141 } else {
142 item = (ShortcutInfo)dragInfo;
143 }
Michael Jurka66d72172011-04-12 16:29:25 -0700144 item.cellX = -1;
145 item.cellY = -1;
Adam Cohendf035382011-04-11 17:22:04 -0700146 addItem(item);
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800147 }
148
Adam Cohen2801caf2011-05-13 20:57:39 -0700149 void saveState(CellLayout.LayoutParams lp) {
150 mOriginalWidth = lp.width;
151 mOriginalHeight = lp.height;
152 mOriginalX = lp.x;
153 mOriginalY = lp.y;
154 }
155
Adam Cohen073a46f2011-05-17 16:28:09 -0700156 private void animateToAcceptState() {
Adam Cohen2801caf2011-05-13 20:57:39 -0700157 CellLayout.LayoutParams lp = (CellLayout.LayoutParams) getLayoutParams();
Adam Cohen073a46f2011-05-17 16:28:09 -0700158
Adam Cohenf4b08912011-05-17 18:45:47 -0700159 ValueAnimator va = ValueAnimator.ofFloat(0f, 1f);
160 va.setDuration(CONSUMPTION_ANIMATION_DURATION);
161 va.addUpdateListener(new AnimatorUpdateListener() {
Adam Cohen073a46f2011-05-17 16:28:09 -0700162 public void onAnimationUpdate(ValueAnimator animation) {
163 final float percent = (Float) animation.getAnimatedValue();
164 mOuterRingScale = OUTER_RING_BASELINE_SCALE + percent * OUTER_RING_GROWTH_FACTOR;
Adam Cohenf4b08912011-05-17 18:45:47 -0700165 mInnerRingScale = INNER_RING_BASELINE_SCALE + percent * INNER_RING_GROWTH_FACTOR;
Adam Cohen073a46f2011-05-17 16:28:09 -0700166 mLauncher.getWorkspace().invalidate();
Adam Cohen073a46f2011-05-17 16:28:09 -0700167 invalidate();
168 }
169 });
Adam Cohenf4b08912011-05-17 18:45:47 -0700170 va.addListener(new AnimatorListenerAdapter() {
Adam Cohen073a46f2011-05-17 16:28:09 -0700171 @Override
172 public void onAnimationEnd(Animator animation) {
Adam Cohenf4b08912011-05-17 18:45:47 -0700173 // Instead of setting the background drawable to null, we set the color to
174 // transparent. Setting the background drawable to null results in onDraw
175 // not getting called.
176 setBackgroundColor(Color.TRANSPARENT);
177 requestLayout();
Adam Cohen073a46f2011-05-17 16:28:09 -0700178 }
179 });
Adam Cohenf4b08912011-05-17 18:45:47 -0700180 va.start();
181 }
Adam Cohen073a46f2011-05-17 16:28:09 -0700182
Adam Cohenf4b08912011-05-17 18:45:47 -0700183 private void animateToNaturalState() {
184 ValueAnimator va = ValueAnimator.ofFloat(0f, 1f);
185 va.setDuration(CONSUMPTION_ANIMATION_DURATION);
186 va.addUpdateListener(new AnimatorUpdateListener() {
Adam Cohen073a46f2011-05-17 16:28:09 -0700187 public void onAnimationUpdate(ValueAnimator animation) {
188 final float percent = (Float) animation.getAnimatedValue();
189 mOuterRingScale = OUTER_RING_BASELINE_SCALE + OUTER_RING_GROWTH_FACTOR
190 - percent * OUTER_RING_GROWTH_FACTOR;
Adam Cohenf4b08912011-05-17 18:45:47 -0700191 mInnerRingScale = INNER_RING_BASELINE_SCALE + INNER_RING_GROWTH_FACTOR
192 - percent * INNER_RING_GROWTH_FACTOR;
Adam Cohen073a46f2011-05-17 16:28:09 -0700193 mLauncher.getWorkspace().invalidate();
Adam Cohenf4b08912011-05-17 18:45:47 -0700194 invalidate();
Adam Cohen073a46f2011-05-17 16:28:09 -0700195 }
196 });
Adam Cohenf4b08912011-05-17 18:45:47 -0700197 va.addListener(new AnimatorListenerAdapter() {
198 @Override
199 public void onAnimationEnd(Animator animation) {
200 setBackgroundDrawable(sFolderInnerRingDrawable);
201 mLauncher.getWorkspace().hideFolderAccept(FolderIcon.this);
202 }
203 });
204 va.start();
Adam Cohen073a46f2011-05-17 16:28:09 -0700205 }
206
207 private void determineFolderLocationInWorkspace() {
208 int tvLocation[] = new int[2];
209 int wsLocation[] = new int[2];
210 getLocationOnScreen(tvLocation);
211 mLauncher.getWorkspace().getLocationOnScreen(wsLocation);
212 mFolderLocX = tvLocation[0] - wsLocation[0] + getMeasuredWidth() / 2;
213 mFolderLocY = tvLocation[1] - wsLocation[1] + getMeasuredHeight() / 2;
214 }
215
216 public void onDragEnter(DragSource source, int x, int y, int xOffset, int yOffset,
217 DragView dragView, Object dragInfo) {
218 if (!willAcceptItem((ItemInfo) dragInfo)) return;
219 determineFolderLocationInWorkspace();
220 mLauncher.getWorkspace().showFolderAccept(this);
221 animateToAcceptState();
222 }
223
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800224 public void onDragOver(DragSource source, int x, int y, int xOffset, int yOffset,
Joe Onorato00acb122009-08-04 16:04:30 -0400225 DragView dragView, Object dragInfo) {
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800226 }
227
228 public void onDragExit(DragSource source, int x, int y, int xOffset, int yOffset,
Joe Onorato00acb122009-08-04 16:04:30 -0400229 DragView dragView, Object dragInfo) {
Adam Cohen073a46f2011-05-17 16:28:09 -0700230 if (!willAcceptItem((ItemInfo) dragInfo)) return;
Adam Cohen073a46f2011-05-17 16:28:09 -0700231 animateToNaturalState();
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800232 }
Patrick Dubroy440c3602010-07-13 17:50:32 -0700233
234 @Override
235 public DropTarget getDropTargetDelegate(DragSource source, int x, int y, int xOffset, int yOffset,
236 DragView dragView, Object dragInfo) {
237 return null;
238 }
Adam Cohena9cf38f2011-05-02 15:36:58 -0700239
Adam Cohen073a46f2011-05-17 16:28:09 -0700240 public void getFolderLocation(int[] loc) {
241 loc[0] = mFolderLocX;
242 loc[1] = mFolderLocY;
243 }
244
245 public float getOuterRingScale() {
246 return mOuterRingScale;
247 }
248
Adam Cohenf4b08912011-05-17 18:45:47 -0700249 public float getInnerRingScale() {
250 return mInnerRingScale;
251 }
252
Adam Cohena9cf38f2011-05-02 15:36:58 -0700253 @Override
254 protected void onDraw(Canvas canvas) {
255 if (mFolder == null) return;
256 if (mFolder.getItemCount() == 0) return;
257
258 canvas.save();
259 TextView v = (TextView) mFolder.getItemAt(0);
260 Drawable d = v.getCompoundDrawables()[1];
261
Adam Cohen073a46f2011-05-17 16:28:09 -0700262 if (mOriginalWidth < 0 || mOriginalHeight < 0) {
263 mOriginalWidth = getMeasuredWidth();
264 mOriginalHeight = getMeasuredHeight();
265 }
Adam Cohena9cf38f2011-05-02 15:36:58 -0700266
Adam Cohen073a46f2011-05-17 16:28:09 -0700267 int xShift = (mOriginalWidth - d.getIntrinsicWidth()) / 2;
268 int yShift = (mOriginalHeight - d.getIntrinsicHeight()) / 2;
Adam Cohen073a46f2011-05-17 16:28:09 -0700269 canvas.translate(xShift, yShift);
Adam Cohena9cf38f2011-05-02 15:36:58 -0700270
Adam Cohen7c693212011-05-18 15:26:57 -0700271 ArrayList<View> items = mFolder.getItemsInReadingOrder();
272 int firstItemIndex = Math.max(0, items.size() - NUM_ITEMS_IN_PREVIEW);
273 for (int i = firstItemIndex; i < mFolder.getItemCount(); i++) {
274 v = (TextView) items.get(i);
Adam Cohena9cf38f2011-05-02 15:36:58 -0700275 d = v.getCompoundDrawables()[1];
276
Adam Cohenf4b08912011-05-17 18:45:47 -0700277 canvas.translate(d.getIntrinsicWidth() / 2, d.getIntrinsicHeight() / 2);
Adam Cohen7c693212011-05-18 15:26:57 -0700278 canvas.rotate(i == firstItemIndex ? ICON_ANGLE : -ICON_ANGLE);
Adam Cohenf4b08912011-05-17 18:45:47 -0700279 canvas.translate(-d.getIntrinsicWidth() / 2, -d.getIntrinsicHeight() / 2);
280
Adam Cohena9cf38f2011-05-02 15:36:58 -0700281 if (d != null) {
282 d.setBounds(0, 0, d.getIntrinsicWidth(), d.getIntrinsicHeight());
283 d.draw(canvas);
284 }
Adam Cohena9cf38f2011-05-02 15:36:58 -0700285 }
286
287 canvas.restore();
288 }
289
290 public void onAdd(ShortcutInfo item) {
291 invalidate();
292 requestLayout();
293 }
294
295 public void onRemove(ShortcutInfo item) {
296 invalidate();
297 requestLayout();
298 }
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800299}