blob: 952916d5f9b49f2fc4478b4eb4c18715318baece [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;
Adam Cohenbadf71e2011-05-26 19:08:29 -070027import android.graphics.PorterDuff;
Adam Cohen3e8f8112011-07-02 18:03:00 -070028import android.graphics.Rect;
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 Cohen3e8f8112011-07-02 18:03:00 -070034import android.view.animation.AccelerateInterpolator;
35import android.view.animation.DecelerateInterpolator;
Adam Cohen76fc0852011-06-17 13:26:23 -070036import android.widget.ImageView;
37import android.widget.LinearLayout;
Adam Cohena9cf38f2011-05-02 15:36:58 -070038import android.widget.TextView;
The Android Open Source Project31dd5032009-03-03 19:32:27 -080039
Romain Guyedcce092010-03-04 13:03:17 -080040import com.android.launcher.R;
Adam Cohenc0dcf592011-06-01 15:30:43 -070041import com.android.launcher2.DropTarget.DragObject;
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 * An icon that can appear on in the workspace representing an {@link UserFolder}.
48 */
Adam Cohen76fc0852011-06-17 13:26:23 -070049public class FolderIcon extends LinearLayout implements FolderListener {
The Android Open Source Project31dd5032009-03-03 19:32:27 -080050 private Launcher mLauncher;
Adam Cohena9cf38f2011-05-02 15:36:58 -070051 Folder mFolder;
52 FolderInfo mInfo;
53
Adam Cohenbadf71e2011-05-26 19:08:29 -070054 // The number of icons to display in the
Adam Cohen76fc0852011-06-17 13:26:23 -070055 private static final int NUM_ITEMS_IN_PREVIEW = 3;
Adam Cohenf4b08912011-05-17 18:45:47 -070056 private static final int CONSUMPTION_ANIMATION_DURATION = 100;
Adam Cohend0445262011-07-04 23:53:22 -070057 private static final int DROP_IN_ANIMATION_DURATION = 400;
Adam Cohen8dfcba42011-07-07 16:38:18 -070058 private static final int INITIAL_ITEM_ANIMATION_DURATION = 350;
Adam Cohenbadf71e2011-05-26 19:08:29 -070059
60 // The degree to which the inner ring grows when accepting drop
Adam Cohen69ce2e52011-07-03 19:25:21 -070061 private static final float INNER_RING_GROWTH_FACTOR = 0.15f;
Adam Cohenbadf71e2011-05-26 19:08:29 -070062
Adam Cohenbadf71e2011-05-26 19:08:29 -070063 // The degree to which the outer ring is scaled in its natural state
Adam Cohen69ce2e52011-07-03 19:25:21 -070064 private static final float OUTER_RING_GROWTH_FACTOR = 0.3f;
Adam Cohenbadf71e2011-05-26 19:08:29 -070065
66 // The amount of vertical spread between items in the stack [0...1]
Adam Cohen76fc0852011-06-17 13:26:23 -070067 private static final float PERSPECTIVE_SHIFT_FACTOR = 0.24f;
Adam Cohenbadf71e2011-05-26 19:08:29 -070068
69 // The degree to which the item in the back of the stack is scaled [0...1]
70 // (0 means it's not scaled at all, 1 means it's scaled to nothing)
Adam Cohen76fc0852011-06-17 13:26:23 -070071 private static final float PERSPECTIVE_SCALE_FACTOR = 0.35f;
Adam Cohenbadf71e2011-05-26 19:08:29 -070072
Adam Cohen76fc0852011-06-17 13:26:23 -070073 private ImageView mPreviewBackground;
74 private BubbleTextView mFolderName;
Adam Cohen073a46f2011-05-17 16:28:09 -070075
Adam Cohen19072da2011-05-31 14:30:45 -070076 FolderRingAnimator mFolderRingAnimator = null;
Adam Cohen2801caf2011-05-13 20:57:39 -070077
Adam Cohend0445262011-07-04 23:53:22 -070078 // These variables are all associated with the drawing of the preview; they are stored
79 // as member variables for shared usage and to avoid computation on each frame
80 private int mIntrinsicIconSize;
81 private float mBaselineIconScale;
82 private int mBaselineIconSize;
83 private int mAvailableSpaceInPreview;
84 private int mTotalWidth = -1;
85 private int mPreviewOffsetX;
86 private int mPreviewOffsetY;
87 private float mMaxPerspectiveShift;
88 boolean mAnimating = false;
89 private PreviewItemDrawingParams mParams = new PreviewItemDrawingParams(0, 0, 0, 0);
90 private PreviewItemDrawingParams mAnimParams = new PreviewItemDrawingParams(0, 0, 0, 0);
91
The Android Open Source Project31dd5032009-03-03 19:32:27 -080092 public FolderIcon(Context context, AttributeSet attrs) {
93 super(context, attrs);
94 }
95
96 public FolderIcon(Context context) {
97 super(context);
98 }
99
Michael Jurka0280c3b2010-09-17 15:00:07 -0700100 public boolean isDropEnabled() {
Winson Chung7a1d1652011-03-18 15:56:01 -0700101 final ViewGroup cellLayoutChildren = (ViewGroup) getParent();
102 final ViewGroup cellLayout = (ViewGroup) cellLayoutChildren.getParent();
103 final Workspace workspace = (Workspace) cellLayout.getParent();
104 return !workspace.isSmall();
Michael Jurka0280c3b2010-09-17 15:00:07 -0700105 }
106
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800107 static FolderIcon fromXml(int resId, Launcher launcher, ViewGroup group,
Adam Cohendf2cc412011-04-27 16:56:57 -0700108 FolderInfo folderInfo, IconCache iconCache) {
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800109
Adam Cohend0445262011-07-04 23:53:22 -0700110 if (INITIAL_ITEM_ANIMATION_DURATION >= DROP_IN_ANIMATION_DURATION) {
111 throw new IllegalStateException("DROP_IN_ANIMATION_DURATION must be greater than " +
112 "INITIAL_ITEM_ANIMATION_DURATION, as sequencing of adding first two items " +
113 "is dependent on this");
114 }
115
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800116 FolderIcon icon = (FolderIcon) LayoutInflater.from(launcher).inflate(resId, group, false);
117
Adam Cohen76fc0852011-06-17 13:26:23 -0700118 icon.mFolderName = (BubbleTextView) icon.findViewById(R.id.folder_name);
119 icon.mFolderName.setText(folderInfo.title);
120 icon.mPreviewBackground = (ImageView) icon.findViewById(R.id.preview_background);
Winson Chung6a0f57d2011-06-29 20:10:49 -0700121 icon.mPreviewBackground.setContentDescription(folderInfo.title);
Adam Cohen76fc0852011-06-17 13:26:23 -0700122
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800123 icon.setTag(folderInfo);
124 icon.setOnClickListener(launcher);
125 icon.mInfo = folderInfo;
126 icon.mLauncher = launcher;
Adam Cohena9cf38f2011-05-02 15:36:58 -0700127
128 Folder folder = Folder.fromXml(launcher);
129 folder.setDragController(launcher.getDragController());
Adam Cohen2801caf2011-05-13 20:57:39 -0700130 folder.setFolderIcon(icon);
Adam Cohena9cf38f2011-05-02 15:36:58 -0700131 folder.bind(folderInfo);
132 icon.mFolder = folder;
Adam Cohen19072da2011-05-31 14:30:45 -0700133 icon.mFolderRingAnimator = new FolderRingAnimator(launcher, icon);
Adam Cohen69ce2e52011-07-03 19:25:21 -0700134
Adam Cohena9cf38f2011-05-02 15:36:58 -0700135 folderInfo.addListener(icon);
Adam Cohen19072da2011-05-31 14:30:45 -0700136
137 return icon;
138 }
139
140 public static class FolderRingAnimator {
Adam Cohen69ce2e52011-07-03 19:25:21 -0700141 public int mCellX;
142 public int mCellY;
143 private CellLayout mCellLayout;
Adam Cohen76fc0852011-06-17 13:26:23 -0700144 public float mOuterRingSize;
145 public float mInnerRingSize;
Adam Cohen19072da2011-05-31 14:30:45 -0700146 public FolderIcon mFolderIcon = null;
Adam Cohenc0dcf592011-06-01 15:30:43 -0700147 public Drawable mOuterRingDrawable = null;
148 public Drawable mInnerRingDrawable = null;
149 public static Drawable sSharedOuterRingDrawable = null;
150 public static Drawable sSharedInnerRingDrawable = null;
Adam Cohen76fc0852011-06-17 13:26:23 -0700151 public static int sPreviewSize = -1;
152 public static int sPreviewPadding = -1;
153
Adam Cohenc0dcf592011-06-01 15:30:43 -0700154 private ValueAnimator mAcceptAnimator;
155 private ValueAnimator mNeutralAnimator;
Adam Cohen19072da2011-05-31 14:30:45 -0700156
157 public FolderRingAnimator(Launcher launcher, FolderIcon folderIcon) {
Adam Cohen19072da2011-05-31 14:30:45 -0700158 mFolderIcon = folderIcon;
Adam Cohen76fc0852011-06-17 13:26:23 -0700159 Resources res = launcher.getResources();
160 mOuterRingDrawable = res.getDrawable(R.drawable.portal_ring_outer_holo);
161 mInnerRingDrawable = res.getDrawable(R.drawable.portal_ring_inner_holo);
162
163 if (sPreviewSize < 0 || sPreviewPadding < 0) {
164 sPreviewSize = res.getDimensionPixelSize(R.dimen.folder_preview_size);
165 sPreviewPadding = res.getDimensionPixelSize(R.dimen.folder_preview_padding);
166 }
Adam Cohenc0dcf592011-06-01 15:30:43 -0700167 if (sSharedOuterRingDrawable == null) {
Adam Cohen76fc0852011-06-17 13:26:23 -0700168 sSharedOuterRingDrawable = res.getDrawable(R.drawable.portal_ring_outer_holo);
Adam Cohen19072da2011-05-31 14:30:45 -0700169 }
Adam Cohenc0dcf592011-06-01 15:30:43 -0700170 if (sSharedInnerRingDrawable == null) {
Adam Cohen76fc0852011-06-17 13:26:23 -0700171 sSharedInnerRingDrawable = res.getDrawable(R.drawable.portal_ring_inner_holo);
Adam Cohen19072da2011-05-31 14:30:45 -0700172 }
Adam Cohen073a46f2011-05-17 16:28:09 -0700173 }
Adam Cohena9cf38f2011-05-02 15:36:58 -0700174
Adam Cohen19072da2011-05-31 14:30:45 -0700175 public void animateToAcceptState() {
Adam Cohenc0dcf592011-06-01 15:30:43 -0700176 if (mNeutralAnimator != null) {
177 mNeutralAnimator.cancel();
178 }
179 mAcceptAnimator = ValueAnimator.ofFloat(0f, 1f);
180 mAcceptAnimator.setDuration(CONSUMPTION_ANIMATION_DURATION);
181 mAcceptAnimator.addUpdateListener(new AnimatorUpdateListener() {
Adam Cohen19072da2011-05-31 14:30:45 -0700182 public void onAnimationUpdate(ValueAnimator animation) {
183 final float percent = (Float) animation.getAnimatedValue();
Adam Cohen76fc0852011-06-17 13:26:23 -0700184 mOuterRingSize = (1 + percent * OUTER_RING_GROWTH_FACTOR) * sPreviewSize;
185 mInnerRingSize = (1 + percent * INNER_RING_GROWTH_FACTOR) * sPreviewSize;
Adam Cohen69ce2e52011-07-03 19:25:21 -0700186 if (mCellLayout != null) {
187 mCellLayout.invalidate();
Adam Cohen19072da2011-05-31 14:30:45 -0700188 }
189 }
190 });
Adam Cohenc0dcf592011-06-01 15:30:43 -0700191 mAcceptAnimator.addListener(new AnimatorListenerAdapter() {
Adam Cohen19072da2011-05-31 14:30:45 -0700192 @Override
Adam Cohenc0dcf592011-06-01 15:30:43 -0700193 public void onAnimationStart(Animator animation) {
Adam Cohen19072da2011-05-31 14:30:45 -0700194 if (mFolderIcon != null) {
Adam Cohen76fc0852011-06-17 13:26:23 -0700195 mFolderIcon.mPreviewBackground.setVisibility(INVISIBLE);
Adam Cohen19072da2011-05-31 14:30:45 -0700196 }
197 }
198 });
Adam Cohenc0dcf592011-06-01 15:30:43 -0700199 mAcceptAnimator.start();
Adam Cohen19072da2011-05-31 14:30:45 -0700200 }
201
202 public void animateToNaturalState() {
Adam Cohenc0dcf592011-06-01 15:30:43 -0700203 if (mAcceptAnimator != null) {
204 mAcceptAnimator.cancel();
205 }
206 mNeutralAnimator = ValueAnimator.ofFloat(0f, 1f);
207 mNeutralAnimator.setDuration(CONSUMPTION_ANIMATION_DURATION);
208 mNeutralAnimator.addUpdateListener(new AnimatorUpdateListener() {
Adam Cohen19072da2011-05-31 14:30:45 -0700209 public void onAnimationUpdate(ValueAnimator animation) {
210 final float percent = (Float) animation.getAnimatedValue();
Adam Cohen76fc0852011-06-17 13:26:23 -0700211 mOuterRingSize = (1 + (1 - percent) * OUTER_RING_GROWTH_FACTOR) * sPreviewSize;
212 mInnerRingSize = (1 + (1 - percent) * INNER_RING_GROWTH_FACTOR) * sPreviewSize;
Adam Cohen69ce2e52011-07-03 19:25:21 -0700213 if (mCellLayout != null) {
214 mCellLayout.invalidate();
Adam Cohen19072da2011-05-31 14:30:45 -0700215 }
216 }
217 });
Adam Cohenc0dcf592011-06-01 15:30:43 -0700218 mNeutralAnimator.addListener(new AnimatorListenerAdapter() {
Adam Cohen19072da2011-05-31 14:30:45 -0700219 @Override
220 public void onAnimationEnd(Animator animation) {
Adam Cohen69ce2e52011-07-03 19:25:21 -0700221 if (mCellLayout != null) {
222 mCellLayout.hideFolderAccept(FolderRingAnimator.this);
223 }
Adam Cohen19072da2011-05-31 14:30:45 -0700224 if (mFolderIcon != null) {
Adam Cohen76fc0852011-06-17 13:26:23 -0700225 mFolderIcon.mPreviewBackground.setVisibility(VISIBLE);
Adam Cohen19072da2011-05-31 14:30:45 -0700226 }
Adam Cohen19072da2011-05-31 14:30:45 -0700227 }
228 });
Adam Cohenc0dcf592011-06-01 15:30:43 -0700229 mNeutralAnimator.start();
Adam Cohen19072da2011-05-31 14:30:45 -0700230 }
231
Adam Cohenc0dcf592011-06-01 15:30:43 -0700232 // Location is expressed in window coordinates
Adam Cohen69ce2e52011-07-03 19:25:21 -0700233 public void getCell(int[] loc) {
234 loc[0] = mCellX;
235 loc[1] = mCellY;
236 }
237
238 // Location is expressed in window coordinates
239 public void setCell(int x, int y) {
240 mCellX = x;
241 mCellY = y;
242 }
243
244 public void setCellLayout(CellLayout layout) {
245 mCellLayout = layout;
Adam Cohen19072da2011-05-31 14:30:45 -0700246 }
247
Adam Cohen76fc0852011-06-17 13:26:23 -0700248 public float getOuterRingSize() {
249 return mOuterRingSize;
Adam Cohen19072da2011-05-31 14:30:45 -0700250 }
251
Adam Cohen76fc0852011-06-17 13:26:23 -0700252 public float getInnerRingSize() {
253 return mInnerRingSize;
Adam Cohen19072da2011-05-31 14:30:45 -0700254 }
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800255 }
256
Adam Cohen073a46f2011-05-17 16:28:09 -0700257 private boolean willAcceptItem(ItemInfo item) {
258 final int itemType = item.itemType;
259 return ((itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION ||
260 itemType == LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT) &&
261 !mFolder.isFull() && item != mInfo);
262 }
263
Adam Cohenc0dcf592011-06-01 15:30:43 -0700264 public boolean acceptDrop(Object dragInfo) {
265 final ItemInfo item = (ItemInfo) dragInfo;
Adam Cohen073a46f2011-05-17 16:28:09 -0700266 return willAcceptItem(item);
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800267 }
268
Adam Cohendf035382011-04-11 17:22:04 -0700269 public void addItem(ShortcutInfo item) {
270 mInfo.add(item);
Adam Cohena9cf38f2011-05-02 15:36:58 -0700271 LauncherModel.addOrMoveItemInDatabase(mLauncher, item, mInfo.id, 0, item.cellX, item.cellY);
Adam Cohendf035382011-04-11 17:22:04 -0700272 }
273
Adam Cohenc0dcf592011-06-01 15:30:43 -0700274 public void onDragEnter(Object dragInfo) {
275 if (!willAcceptItem((ItemInfo) dragInfo)) return;
Adam Cohen69ce2e52011-07-03 19:25:21 -0700276 CellLayout.LayoutParams lp = (CellLayout.LayoutParams) getLayoutParams();
277 CellLayout layout = (CellLayout) getParent().getParent();
278 mFolderRingAnimator.setCell(lp.cellX, lp.cellY);
279 mFolderRingAnimator.setCellLayout(layout);
Adam Cohen19072da2011-05-31 14:30:45 -0700280 mFolderRingAnimator.animateToAcceptState();
Adam Cohen69ce2e52011-07-03 19:25:21 -0700281 layout.showFolderAccept(mFolderRingAnimator);
Adam Cohen073a46f2011-05-17 16:28:09 -0700282 }
283
Adam Cohenc0dcf592011-06-01 15:30:43 -0700284 public void onDragOver(Object dragInfo) {
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800285 }
286
Adam Cohend0445262011-07-04 23:53:22 -0700287 public void performCreateAnimation(final ShortcutInfo destInfo, final View destView,
Winson Chung557d6ed2011-07-08 15:34:52 -0700288 final ShortcutInfo srcInfo, final View srcView, Rect dstRect,
289 Runnable postAnimationRunnable) {
Adam Cohend0445262011-07-04 23:53:22 -0700290
291 Drawable animateDrawable = ((TextView) destView).getCompoundDrawables()[1];
292 computePreviewDrawingParams(animateDrawable.getIntrinsicWidth(), destView.getMeasuredWidth());
293 // This will animate the dragView (srcView) into the new folder
Winson Chung557d6ed2011-07-08 15:34:52 -0700294 onDrop(srcInfo, srcView, dstRect, 1, postAnimationRunnable);
Adam Cohend0445262011-07-04 23:53:22 -0700295
296 // This will animate the first item from it's position as an icon into its
297 // position as the first item in the preview
Adam Cohen8dfcba42011-07-07 16:38:18 -0700298 animateFirstItem(animateDrawable, INITIAL_ITEM_ANIMATION_DURATION);
Adam Cohend0445262011-07-04 23:53:22 -0700299
300 postDelayed(new Runnable() {
301 public void run() {
302 addItem(destInfo);
303 }
304 }, INITIAL_ITEM_ANIMATION_DURATION);
305 }
306
Adam Cohenc0dcf592011-06-01 15:30:43 -0700307 public void onDragExit(Object dragInfo) {
308 if (!willAcceptItem((ItemInfo) dragInfo)) return;
Adam Cohen19072da2011-05-31 14:30:45 -0700309 mFolderRingAnimator.animateToNaturalState();
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800310 }
Patrick Dubroy440c3602010-07-13 17:50:32 -0700311
Winson Chung557d6ed2011-07-08 15:34:52 -0700312 private void onDrop(final ShortcutInfo item, View animateView, Rect finalRect, int index,
313 Runnable postAnimationRunnable) {
Adam Cohend0445262011-07-04 23:53:22 -0700314 item.cellX = -1;
315 item.cellY = -1;
316 DragLayer dragLayer = mLauncher.getDragLayer();
317 Rect from = new Rect();
318 dragLayer.getViewRectRelativeToSelf(animateView, from);
319 Rect to = finalRect;
320 if (to == null) {
321 to = new Rect();
322 dragLayer.getDescendantRectRelativeToSelf(this, to);
323 }
324
325 if (animateView.getMeasuredWidth() != to.width() ||
326 animateView.getMeasuredHeight() != to.height()) {
327 int offsetX = (animateView.getMeasuredWidth() - to.width()) / 2;
328 int offsetY = (animateView.getMeasuredHeight() - to.height()) / 2;
329 to.offset(-offsetX, -offsetY);
330 }
331 float scale = adjustFinalScreenRectForIndex(to, index);
332
333 float finalAlpha = index < NUM_ITEMS_IN_PREVIEW ? 0.5f : 0f;
334
335 dragLayer.animateView(animateView, from, to, finalAlpha, scale, DROP_IN_ANIMATION_DURATION,
Winson Chung557d6ed2011-07-08 15:34:52 -0700336 new DecelerateInterpolator(2), new AccelerateInterpolator(2), postAnimationRunnable,
337 false);
Adam Cohend0445262011-07-04 23:53:22 -0700338 postDelayed(new Runnable() {
339 public void run() {
340 addItem(item);
341 }
342 }, DROP_IN_ANIMATION_DURATION);
343 }
344
Adam Cohen3e8f8112011-07-02 18:03:00 -0700345 public void onDrop(DragObject d) {
Adam Cohenc0dcf592011-06-01 15:30:43 -0700346 ShortcutInfo item;
Adam Cohen3e8f8112011-07-02 18:03:00 -0700347 if (d.dragInfo instanceof ApplicationInfo) {
Adam Cohenc0dcf592011-06-01 15:30:43 -0700348 // Came from all apps -- make a copy
Adam Cohen3e8f8112011-07-02 18:03:00 -0700349 item = ((ApplicationInfo) d.dragInfo).makeShortcut();
Adam Cohenc0dcf592011-06-01 15:30:43 -0700350 } else {
Adam Cohen3e8f8112011-07-02 18:03:00 -0700351 item = (ShortcutInfo) d.dragInfo;
Adam Cohenc0dcf592011-06-01 15:30:43 -0700352 }
Winson Chung557d6ed2011-07-08 15:34:52 -0700353 onDrop(item, d.dragView, null, mInfo.contents.size(), d.postAnimationRunnable);
Adam Cohenc0dcf592011-06-01 15:30:43 -0700354 }
355
Adam Cohencb3382b2011-05-24 14:07:08 -0700356 public DropTarget getDropTargetDelegate(DragObject d) {
Patrick Dubroy440c3602010-07-13 17:50:32 -0700357 return null;
358 }
Adam Cohena9cf38f2011-05-02 15:36:58 -0700359
Adam Cohend0445262011-07-04 23:53:22 -0700360 private void computePreviewDrawingParams(int drawableSize, int totalSize) {
361 if (mIntrinsicIconSize != drawableSize || mTotalWidth != totalSize) {
362 mIntrinsicIconSize = drawableSize;
363 mTotalWidth = totalSize;
364
365 final int previewSize = FolderRingAnimator.sPreviewSize;
366 final int previewPadding = FolderRingAnimator.sPreviewPadding;
367
368 mAvailableSpaceInPreview = (previewSize - 2 * previewPadding);
369 // cos(45) = 0.707 + ~= 0.1) = 0.8f
370 int adjustedAvailableSpace = (int) ((mAvailableSpaceInPreview / 2) * (1 + 0.8f));
371
372 int unscaledHeight = (int) (mIntrinsicIconSize * (1 + PERSPECTIVE_SHIFT_FACTOR));
373 mBaselineIconScale = (1.0f * adjustedAvailableSpace / unscaledHeight);
374
375 mBaselineIconSize = (int) (mIntrinsicIconSize * mBaselineIconScale);
376 mMaxPerspectiveShift = mBaselineIconSize * PERSPECTIVE_SHIFT_FACTOR;
377
378 mPreviewOffsetX = (mTotalWidth - mAvailableSpaceInPreview) / 2;
379 mPreviewOffsetY = previewPadding;
380 }
381 }
382
383 private void computePreviewDrawingParams(Drawable d) {
384 computePreviewDrawingParams(d.getIntrinsicWidth(), getMeasuredWidth());
385 }
386
387 class PreviewItemDrawingParams {
388 PreviewItemDrawingParams(float transX, float transY, float scale, int overlayAlpha) {
389 this.transX = transX;
390 this.transY = transY;
391 this.scale = scale;
392 this.overlayAlpha = overlayAlpha;
393 }
394 float transX;
395 float transY;
396 float scale;
397 int overlayAlpha;
398 Drawable drawable;
399 }
400
401 private float adjustFinalScreenRectForIndex(Rect r, int index) {
402 mParams = computePreviewItemDrawingParams(Math.min(NUM_ITEMS_IN_PREVIEW, index), mParams);
403
404 mParams.transX += mPreviewOffsetX;
405 mParams.transY += mPreviewOffsetY;
406 float offsetX = mParams.transX + (mParams.scale * mIntrinsicIconSize) / 2 - mTotalWidth / 2;
407 float offsetY = mParams.transY + (mParams.scale * mIntrinsicIconSize) / 2 - mTotalWidth / 2;
408
409 r.offset((int) offsetX, (int) offsetY);
410 return mParams.scale;
411 }
412
413 private PreviewItemDrawingParams computePreviewItemDrawingParams(int index,
414 PreviewItemDrawingParams params) {
415 index = NUM_ITEMS_IN_PREVIEW - index - 1;
416 float r = (index * 1.0f) / (NUM_ITEMS_IN_PREVIEW - 1);
417 float scale = (1 - PERSPECTIVE_SCALE_FACTOR * (1 - r));
418
419 float offset = (1 - r) * mMaxPerspectiveShift;
420 float scaledSize = scale * mBaselineIconSize;
421 float scaleOffsetCorrection = (1 - scale) * mBaselineIconSize;
422
423 // We want to imagine our coordinates from the bottom left, growing up and to the
424 // right. This is natural for the x-axis, but for the y-axis, we have to invert things.
425 float transY = mAvailableSpaceInPreview - (offset + scaledSize + scaleOffsetCorrection);
426 float transX = offset + scaleOffsetCorrection;
427 float totalScale = mBaselineIconScale * scale;
428 final int overlayAlpha = (int) (80 * (1 - r));
429
430 if (params == null) {
431 params = new PreviewItemDrawingParams(transX, transY, totalScale, overlayAlpha);
432 } else {
433 params.transX = transX;
434 params.transY = transY;
435 params.scale = totalScale;
436 params.overlayAlpha = overlayAlpha;
437 }
438 return params;
439 }
440
441 private void drawPreviewItem(Canvas canvas, PreviewItemDrawingParams params) {
442 canvas.save();
443 canvas.translate(params.transX + mPreviewOffsetX, params.transY + mPreviewOffsetY);
444 canvas.scale(params.scale, params.scale);
445 Drawable d = params.drawable;
446
447 if (d != null) {
448 d.setBounds(0, 0, mIntrinsicIconSize, mIntrinsicIconSize);
449 d.setFilterBitmap(true);
450 d.setColorFilter(Color.argb(params.overlayAlpha, 0, 0, 0), PorterDuff.Mode.SRC_ATOP);
451 d.draw(canvas);
452 d.clearColorFilter();
453 d.setFilterBitmap(false);
454 }
455 canvas.restore();
456 }
457
Adam Cohena9cf38f2011-05-02 15:36:58 -0700458 @Override
Adam Cohenc0dcf592011-06-01 15:30:43 -0700459 protected void dispatchDraw(Canvas canvas) {
Adam Cohen76fc0852011-06-17 13:26:23 -0700460 super.dispatchDraw(canvas);
461
Adam Cohena9cf38f2011-05-02 15:36:58 -0700462 if (mFolder == null) return;
Adam Cohend0445262011-07-04 23:53:22 -0700463 if (mFolder.getItemCount() == 0 && !mAnimating) return;
Adam Cohena9cf38f2011-05-02 15:36:58 -0700464
Adam Cohen76078c42011-06-09 15:06:52 -0700465 ArrayList<View> items = mFolder.getItemsInReadingOrder(false);
Adam Cohend0445262011-07-04 23:53:22 -0700466 Drawable d;
467 TextView v;
Adam Cohenbadf71e2011-05-26 19:08:29 -0700468
Adam Cohend0445262011-07-04 23:53:22 -0700469 // Update our drawing parameters if necessary
470 if (mAnimating) {
471 computePreviewDrawingParams(mAnimParams.drawable);
472 } else {
473 v = (TextView) items.get(0);
Adam Cohena9cf38f2011-05-02 15:36:58 -0700474 d = v.getCompoundDrawables()[1];
Adam Cohend0445262011-07-04 23:53:22 -0700475 computePreviewDrawingParams(d);
Adam Cohena9cf38f2011-05-02 15:36:58 -0700476 }
Adam Cohend0445262011-07-04 23:53:22 -0700477
478 int nItemsInPreview = Math.min(items.size(), NUM_ITEMS_IN_PREVIEW);
479 if (!mAnimating) {
480 for (int i = nItemsInPreview - 1; i >= 0; i--) {
481 v = (TextView) items.get(i);
482 d = v.getCompoundDrawables()[1];
483
484 mParams = computePreviewItemDrawingParams(i, mParams);
485 mParams.drawable = d;
486 drawPreviewItem(canvas, mParams);
487 }
488 } else {
489 drawPreviewItem(canvas, mAnimParams);
490 }
491 }
492
493 private void animateFirstItem(final Drawable d, int duration) {
494 computePreviewDrawingParams(d);
495 final PreviewItemDrawingParams finalParams = computePreviewItemDrawingParams(0, null);
496
497 final float scale0 = 1.0f;
498 final float transX0 = 0;
499 final float transY0 = 0;
500 mAnimParams.drawable = d;
501
502 ValueAnimator va = ValueAnimator.ofFloat(0f, 1.0f);
503 va.addUpdateListener(new AnimatorUpdateListener(){
504 public void onAnimationUpdate(ValueAnimator animation) {
505 float progress = (Float) animation.getAnimatedValue();
506
507 mAnimParams.transX = transX0 + progress * (finalParams.transX - transX0);
508 mAnimParams.transY = transY0 + progress * (finalParams.transY - transY0);
509 mAnimParams.scale = scale0 + progress * (finalParams.scale - scale0);
510 invalidate();
511 }
512 });
513 va.addListener(new AnimatorListenerAdapter() {
514 @Override
515 public void onAnimationStart(Animator animation) {
516 mAnimating = true;
517 }
518 @Override
519 public void onAnimationEnd(Animator animation) {
520 mAnimating = false;
521 }
522 });
523 va.setDuration(duration);
524 va.start();
Adam Cohena9cf38f2011-05-02 15:36:58 -0700525 }
526
Adam Cohen76078c42011-06-09 15:06:52 -0700527 public void onItemsChanged() {
528 invalidate();
529 requestLayout();
530 }
531
Adam Cohena9cf38f2011-05-02 15:36:58 -0700532 public void onAdd(ShortcutInfo item) {
533 invalidate();
534 requestLayout();
535 }
536
537 public void onRemove(ShortcutInfo item) {
538 invalidate();
539 requestLayout();
540 }
Adam Cohen76fc0852011-06-17 13:26:23 -0700541
542 public void onTitleChanged(CharSequence title) {
Adam Cohend63cfa92011-06-24 14:17:17 -0700543 mFolderName.setText(title.toString());
Winson Chung6a0f57d2011-06-29 20:10:49 -0700544 mPreviewBackground.setContentDescription(title.toString());
Adam Cohen76fc0852011-06-17 13:26:23 -0700545 }
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800546}