FolderIcon.java revision df6af5740da6ee9f78e846218d71941b02fc0283
131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project/*
231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * Copyright (C) 2008 The Android Open Source Project
331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project *
431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * you may not use this file except in compliance with the License.
631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * You may obtain a copy of the License at
731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project *
831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project *
1031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
1131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
1231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * See the License for the specific language governing permissions and
1431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * limitations under the License.
1531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project */
1631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
17a5902524d4403885eb4c50360bf3465c6be796efJoe Onoratopackage com.android.launcher2;
1831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
192801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohenimport android.animation.Animator;
202801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohenimport android.animation.AnimatorListenerAdapter;
212801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohenimport android.animation.ValueAnimator;
222801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohenimport android.animation.ValueAnimator.AnimatorUpdateListener;
2331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.content.Context;
2431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.content.res.Resources;
25a9cf38f533d1e86269868f1e6a806ccffd4a78fcAdam Cohenimport android.graphics.Canvas;
26f4b08913677e18a8412930972237b91d5a946d95Adam Cohenimport android.graphics.Color;
27badf71e11fba2d6efa1d1bcca9542001f90a3777Adam Cohenimport android.graphics.PorterDuff;
283e8f811f31a2275e778244427271f77f4116c08bAdam Cohenimport android.graphics.Rect;
2931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.graphics.drawable.Drawable;
30099f60d51f6310e1290687e83958e665b3324504Adam Cohenimport android.os.Parcelable;
3131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.util.AttributeSet;
3231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.view.LayoutInflater;
337c6932140dcbd2db88d7a809ba72ee04abb5bf26Adam Cohenimport android.view.View;
3431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.view.ViewGroup;
353e8f811f31a2275e778244427271f77f4116c08bAdam Cohenimport android.view.animation.AccelerateInterpolator;
363e8f811f31a2275e778244427271f77f4116c08bAdam Cohenimport android.view.animation.DecelerateInterpolator;
3776fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohenimport android.widget.ImageView;
3876fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohenimport android.widget.LinearLayout;
39a9cf38f533d1e86269868f1e6a806ccffd4a78fcAdam Cohenimport android.widget.TextView;
4031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
41edcce099c98a6c40d10109ac092ab50f9d2668f3Romain Guyimport com.android.launcher.R;
42c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohenimport com.android.launcher2.DropTarget.DragObject;
43a9cf38f533d1e86269868f1e6a806ccffd4a78fcAdam Cohenimport com.android.launcher2.FolderInfo.FolderListener;
44edcce099c98a6c40d10109ac092ab50f9d2668f3Romain Guy
45c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohenimport java.util.ArrayList;
46c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen
4731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project/**
4831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * An icon that can appear on in the workspace representing an {@link UserFolder}.
4931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project */
5076fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohenpublic class FolderIcon extends LinearLayout implements FolderListener {
5131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    private Launcher mLauncher;
52a9cf38f533d1e86269868f1e6a806ccffd4a78fcAdam Cohen    Folder mFolder;
53a9cf38f533d1e86269868f1e6a806ccffd4a78fcAdam Cohen    FolderInfo mInfo;
54099f60d51f6310e1290687e83958e665b3324504Adam Cohen    private static boolean sStaticValuesDirty = true;
55a9cf38f533d1e86269868f1e6a806ccffd4a78fcAdam Cohen
56badf71e11fba2d6efa1d1bcca9542001f90a3777Adam Cohen    // The number of icons to display in the
5776fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen    private static final int NUM_ITEMS_IN_PREVIEW = 3;
58f4b08913677e18a8412930972237b91d5a946d95Adam Cohen    private static final int CONSUMPTION_ANIMATION_DURATION = 100;
59d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen    private static final int DROP_IN_ANIMATION_DURATION = 400;
608dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen    private static final int INITIAL_ITEM_ANIMATION_DURATION = 350;
61badf71e11fba2d6efa1d1bcca9542001f90a3777Adam Cohen
62badf71e11fba2d6efa1d1bcca9542001f90a3777Adam Cohen    // The degree to which the inner ring grows when accepting drop
6369ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen    private static final float INNER_RING_GROWTH_FACTOR = 0.15f;
64badf71e11fba2d6efa1d1bcca9542001f90a3777Adam Cohen
65badf71e11fba2d6efa1d1bcca9542001f90a3777Adam Cohen    // The degree to which the outer ring is scaled in its natural state
6669ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen    private static final float OUTER_RING_GROWTH_FACTOR = 0.3f;
67badf71e11fba2d6efa1d1bcca9542001f90a3777Adam Cohen
68badf71e11fba2d6efa1d1bcca9542001f90a3777Adam Cohen    // The amount of vertical spread between items in the stack [0...1]
6976fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen    private static final float PERSPECTIVE_SHIFT_FACTOR = 0.24f;
70badf71e11fba2d6efa1d1bcca9542001f90a3777Adam Cohen
71badf71e11fba2d6efa1d1bcca9542001f90a3777Adam Cohen    // The degree to which the item in the back of the stack is scaled [0...1]
72badf71e11fba2d6efa1d1bcca9542001f90a3777Adam Cohen    // (0 means it's not scaled at all, 1 means it's scaled to nothing)
7376fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen    private static final float PERSPECTIVE_SCALE_FACTOR = 0.35f;
7431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
75c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen    public static Drawable sSharedFolderLeaveBehind = null;
76c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen
7776fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen    private ImageView mPreviewBackground;
7876fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen    private BubbleTextView mFolderName;
79073a46ff635d089cbcb15d939d1de42dd2b86c97Adam Cohen
8019072da7441e07d5e90026d9e9e1b38f11245e44Adam Cohen    FolderRingAnimator mFolderRingAnimator = null;
812801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen
82d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen    // These variables are all associated with the drawing of the preview; they are stored
83d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen    // as member variables for shared usage and to avoid computation on each frame
84d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen    private int mIntrinsicIconSize;
85d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen    private float mBaselineIconScale;
86d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen    private int mBaselineIconSize;
87d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen    private int mAvailableSpaceInPreview;
88d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen    private int mTotalWidth = -1;
89d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen    private int mPreviewOffsetX;
90d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen    private int mPreviewOffsetY;
91d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen    private float mMaxPerspectiveShift;
92d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen    boolean mAnimating = false;
93d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen    private PreviewItemDrawingParams mParams = new PreviewItemDrawingParams(0, 0, 0, 0);
94d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen    private PreviewItemDrawingParams mAnimParams = new PreviewItemDrawingParams(0, 0, 0, 0);
95d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen
9631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    public FolderIcon(Context context, AttributeSet attrs) {
9731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        super(context, attrs);
9831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
9931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
10031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    public FolderIcon(Context context) {
10131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        super(context);
10231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
10331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
1040280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    public boolean isDropEnabled() {
1057a1d16555d80135e61b90158ff3c1e3f963bd8b8Winson Chung        final ViewGroup cellLayoutChildren = (ViewGroup) getParent();
1067a1d16555d80135e61b90158ff3c1e3f963bd8b8Winson Chung        final ViewGroup cellLayout = (ViewGroup) cellLayoutChildren.getParent();
1077a1d16555d80135e61b90158ff3c1e3f963bd8b8Winson Chung        final Workspace workspace = (Workspace) cellLayout.getParent();
1087a1d16555d80135e61b90158ff3c1e3f963bd8b8Winson Chung        return !workspace.isSmall();
1090280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    }
1100280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka
11131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    static FolderIcon fromXml(int resId, Launcher launcher, ViewGroup group,
112df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen            FolderInfo folderInfo, IconCache iconCache) {
11331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
114d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        if (INITIAL_ITEM_ANIMATION_DURATION >= DROP_IN_ANIMATION_DURATION) {
115d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen            throw new IllegalStateException("DROP_IN_ANIMATION_DURATION must be greater than " +
116d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen                    "INITIAL_ITEM_ANIMATION_DURATION, as sequencing of adding first two items " +
117d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen                    "is dependent on this");
118d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        }
119d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen
12031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        FolderIcon icon = (FolderIcon) LayoutInflater.from(launcher).inflate(resId, group, false);
12131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
122d2eca6b66e654e71fb46ae718910af3ec6c2cf9cAdam Cohen        icon.mFolderName = (BubbleTextView) icon.findViewById(R.id.folder_icon_name);
12376fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen        icon.mFolderName.setText(folderInfo.title);
12476fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen        icon.mPreviewBackground = (ImageView) icon.findViewById(R.id.preview_background);
1256a0f57dfafced837a2a282d8feec28d5418be3b9Winson Chung        icon.mPreviewBackground.setContentDescription(folderInfo.title);
12676fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen
12731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        icon.setTag(folderInfo);
12831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        icon.setOnClickListener(launcher);
12931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        icon.mInfo = folderInfo;
13031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        icon.mLauncher = launcher;
131a9cf38f533d1e86269868f1e6a806ccffd4a78fcAdam Cohen
132a9cf38f533d1e86269868f1e6a806ccffd4a78fcAdam Cohen        Folder folder = Folder.fromXml(launcher);
133a9cf38f533d1e86269868f1e6a806ccffd4a78fcAdam Cohen        folder.setDragController(launcher.getDragController());
1342801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen        folder.setFolderIcon(icon);
135a9cf38f533d1e86269868f1e6a806ccffd4a78fcAdam Cohen        folder.bind(folderInfo);
136a9cf38f533d1e86269868f1e6a806ccffd4a78fcAdam Cohen        icon.mFolder = folder;
137c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen        Resources res = launcher.getResources();
138099f60d51f6310e1290687e83958e665b3324504Adam Cohen
139099f60d51f6310e1290687e83958e665b3324504Adam Cohen        icon.mFolderRingAnimator = new FolderRingAnimator(launcher, icon);
140099f60d51f6310e1290687e83958e665b3324504Adam Cohen        folderInfo.addListener(icon);
141099f60d51f6310e1290687e83958e665b3324504Adam Cohen
14219072da7441e07d5e90026d9e9e1b38f11245e44Adam Cohen        return icon;
14319072da7441e07d5e90026d9e9e1b38f11245e44Adam Cohen    }
14419072da7441e07d5e90026d9e9e1b38f11245e44Adam Cohen
145099f60d51f6310e1290687e83958e665b3324504Adam Cohen    @Override
146099f60d51f6310e1290687e83958e665b3324504Adam Cohen    protected Parcelable onSaveInstanceState() {
147099f60d51f6310e1290687e83958e665b3324504Adam Cohen        sStaticValuesDirty = true;
148099f60d51f6310e1290687e83958e665b3324504Adam Cohen        return super.onSaveInstanceState();
149099f60d51f6310e1290687e83958e665b3324504Adam Cohen    }
150099f60d51f6310e1290687e83958e665b3324504Adam Cohen
15119072da7441e07d5e90026d9e9e1b38f11245e44Adam Cohen    public static class FolderRingAnimator {
15269ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen        public int mCellX;
15369ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen        public int mCellY;
15469ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen        private CellLayout mCellLayout;
15576fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen        public float mOuterRingSize;
15676fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen        public float mInnerRingSize;
15719072da7441e07d5e90026d9e9e1b38f11245e44Adam Cohen        public FolderIcon mFolderIcon = null;
158c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen        public Drawable mOuterRingDrawable = null;
159c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen        public Drawable mInnerRingDrawable = null;
160c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen        public static Drawable sSharedOuterRingDrawable = null;
161c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen        public static Drawable sSharedInnerRingDrawable = null;
16276fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen        public static int sPreviewSize = -1;
16376fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen        public static int sPreviewPadding = -1;
16476fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen
165c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen        private ValueAnimator mAcceptAnimator;
166c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen        private ValueAnimator mNeutralAnimator;
16719072da7441e07d5e90026d9e9e1b38f11245e44Adam Cohen
16819072da7441e07d5e90026d9e9e1b38f11245e44Adam Cohen        public FolderRingAnimator(Launcher launcher, FolderIcon folderIcon) {
16919072da7441e07d5e90026d9e9e1b38f11245e44Adam Cohen            mFolderIcon = folderIcon;
17076fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen            Resources res = launcher.getResources();
17176fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen            mOuterRingDrawable = res.getDrawable(R.drawable.portal_ring_outer_holo);
17276fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen            mInnerRingDrawable = res.getDrawable(R.drawable.portal_ring_inner_holo);
17376fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen
174099f60d51f6310e1290687e83958e665b3324504Adam Cohen            // We need to reload the static values when configuration changes in case they are
175099f60d51f6310e1290687e83958e665b3324504Adam Cohen            // different in another configuration
176099f60d51f6310e1290687e83958e665b3324504Adam Cohen            if (sStaticValuesDirty) {
17776fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen                sPreviewSize = res.getDimensionPixelSize(R.dimen.folder_preview_size);
17876fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen                sPreviewPadding = res.getDimensionPixelSize(R.dimen.folder_preview_padding);
17976fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen                sSharedOuterRingDrawable = res.getDrawable(R.drawable.portal_ring_outer_holo);
18076fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen                sSharedInnerRingDrawable = res.getDrawable(R.drawable.portal_ring_inner_holo);
181df6af5740da6ee9f78e846218d71941b02fc0283Adam Cohen                sSharedFolderLeaveBehind = res.getDrawable(R.drawable.portal_ring_rest);
182099f60d51f6310e1290687e83958e665b3324504Adam Cohen                sStaticValuesDirty = false;
18319072da7441e07d5e90026d9e9e1b38f11245e44Adam Cohen            }
184073a46ff635d089cbcb15d939d1de42dd2b86c97Adam Cohen        }
185a9cf38f533d1e86269868f1e6a806ccffd4a78fcAdam Cohen
18619072da7441e07d5e90026d9e9e1b38f11245e44Adam Cohen        public void animateToAcceptState() {
187c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen            if (mNeutralAnimator != null) {
188c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen                mNeutralAnimator.cancel();
189c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen            }
190c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen            mAcceptAnimator = ValueAnimator.ofFloat(0f, 1f);
191c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen            mAcceptAnimator.setDuration(CONSUMPTION_ANIMATION_DURATION);
192c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen            mAcceptAnimator.addUpdateListener(new AnimatorUpdateListener() {
19319072da7441e07d5e90026d9e9e1b38f11245e44Adam Cohen                public void onAnimationUpdate(ValueAnimator animation) {
19419072da7441e07d5e90026d9e9e1b38f11245e44Adam Cohen                    final float percent = (Float) animation.getAnimatedValue();
19576fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen                    mOuterRingSize = (1 + percent * OUTER_RING_GROWTH_FACTOR) * sPreviewSize;
19676fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen                    mInnerRingSize = (1 + percent * INNER_RING_GROWTH_FACTOR) * sPreviewSize;
19769ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen                    if (mCellLayout != null) {
19869ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen                        mCellLayout.invalidate();
19919072da7441e07d5e90026d9e9e1b38f11245e44Adam Cohen                    }
20019072da7441e07d5e90026d9e9e1b38f11245e44Adam Cohen                }
20119072da7441e07d5e90026d9e9e1b38f11245e44Adam Cohen            });
202c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen            mAcceptAnimator.addListener(new AnimatorListenerAdapter() {
20319072da7441e07d5e90026d9e9e1b38f11245e44Adam Cohen                @Override
204c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen                public void onAnimationStart(Animator animation) {
20519072da7441e07d5e90026d9e9e1b38f11245e44Adam Cohen                    if (mFolderIcon != null) {
20676fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen                        mFolderIcon.mPreviewBackground.setVisibility(INVISIBLE);
20719072da7441e07d5e90026d9e9e1b38f11245e44Adam Cohen                    }
20819072da7441e07d5e90026d9e9e1b38f11245e44Adam Cohen                }
20919072da7441e07d5e90026d9e9e1b38f11245e44Adam Cohen            });
210c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen            mAcceptAnimator.start();
21119072da7441e07d5e90026d9e9e1b38f11245e44Adam Cohen        }
21219072da7441e07d5e90026d9e9e1b38f11245e44Adam Cohen
21319072da7441e07d5e90026d9e9e1b38f11245e44Adam Cohen        public void animateToNaturalState() {
214c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen            if (mAcceptAnimator != null) {
215c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen                mAcceptAnimator.cancel();
216c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen            }
217c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen            mNeutralAnimator = ValueAnimator.ofFloat(0f, 1f);
218c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen            mNeutralAnimator.setDuration(CONSUMPTION_ANIMATION_DURATION);
219c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen            mNeutralAnimator.addUpdateListener(new AnimatorUpdateListener() {
22019072da7441e07d5e90026d9e9e1b38f11245e44Adam Cohen                public void onAnimationUpdate(ValueAnimator animation) {
22119072da7441e07d5e90026d9e9e1b38f11245e44Adam Cohen                    final float percent = (Float) animation.getAnimatedValue();
22276fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen                    mOuterRingSize = (1 + (1 - percent) * OUTER_RING_GROWTH_FACTOR) * sPreviewSize;
22376fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen                    mInnerRingSize = (1 + (1 - percent) * INNER_RING_GROWTH_FACTOR) * sPreviewSize;
22469ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen                    if (mCellLayout != null) {
22569ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen                        mCellLayout.invalidate();
22619072da7441e07d5e90026d9e9e1b38f11245e44Adam Cohen                    }
22719072da7441e07d5e90026d9e9e1b38f11245e44Adam Cohen                }
22819072da7441e07d5e90026d9e9e1b38f11245e44Adam Cohen            });
229c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen            mNeutralAnimator.addListener(new AnimatorListenerAdapter() {
23019072da7441e07d5e90026d9e9e1b38f11245e44Adam Cohen                @Override
23119072da7441e07d5e90026d9e9e1b38f11245e44Adam Cohen                public void onAnimationEnd(Animator animation) {
23269ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen                    if (mCellLayout != null) {
23369ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen                        mCellLayout.hideFolderAccept(FolderRingAnimator.this);
23469ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen                    }
23519072da7441e07d5e90026d9e9e1b38f11245e44Adam Cohen                    if (mFolderIcon != null) {
23676fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen                        mFolderIcon.mPreviewBackground.setVisibility(VISIBLE);
23719072da7441e07d5e90026d9e9e1b38f11245e44Adam Cohen                    }
23819072da7441e07d5e90026d9e9e1b38f11245e44Adam Cohen                }
23919072da7441e07d5e90026d9e9e1b38f11245e44Adam Cohen            });
240c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen            mNeutralAnimator.start();
24119072da7441e07d5e90026d9e9e1b38f11245e44Adam Cohen        }
24219072da7441e07d5e90026d9e9e1b38f11245e44Adam Cohen
243c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen        // Location is expressed in window coordinates
24469ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen        public void getCell(int[] loc) {
24569ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            loc[0] = mCellX;
24669ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            loc[1] = mCellY;
24769ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen        }
24869ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen
24969ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen        // Location is expressed in window coordinates
25069ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen        public void setCell(int x, int y) {
25169ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            mCellX = x;
25269ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            mCellY = y;
25369ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen        }
25469ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen
25569ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen        public void setCellLayout(CellLayout layout) {
25669ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            mCellLayout = layout;
25719072da7441e07d5e90026d9e9e1b38f11245e44Adam Cohen        }
25819072da7441e07d5e90026d9e9e1b38f11245e44Adam Cohen
25976fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen        public float getOuterRingSize() {
26076fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen            return mOuterRingSize;
26119072da7441e07d5e90026d9e9e1b38f11245e44Adam Cohen        }
26219072da7441e07d5e90026d9e9e1b38f11245e44Adam Cohen
26376fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen        public float getInnerRingSize() {
26476fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen            return mInnerRingSize;
265f4b08913677e18a8412930972237b91d5a946d95Adam Cohen        }
26631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
26731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
268073a46ff635d089cbcb15d939d1de42dd2b86c97Adam Cohen    private boolean willAcceptItem(ItemInfo item) {
26931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        final int itemType = item.itemType;
2702801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen        return ((itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION ||
2712801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen                itemType == LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT) &&
272c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen                !mFolder.isFull() && item != mInfo && !mInfo.opened);
273073a46ff635d089cbcb15d939d1de42dd2b86c97Adam Cohen    }
274073a46ff635d089cbcb15d939d1de42dd2b86c97Adam Cohen
275c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen    public boolean acceptDrop(Object dragInfo) {
276c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen        final ItemInfo item = (ItemInfo) dragInfo;
277073a46ff635d089cbcb15d939d1de42dd2b86c97Adam Cohen        return willAcceptItem(item);
27831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
27931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
280df0353815c629fc678824b07a234b89a1ff94208Adam Cohen    public void addItem(ShortcutInfo item) {
281df0353815c629fc678824b07a234b89a1ff94208Adam Cohen        mInfo.add(item);
282a9cf38f533d1e86269868f1e6a806ccffd4a78fcAdam Cohen        LauncherModel.addOrMoveItemInDatabase(mLauncher, item, mInfo.id, 0, item.cellX, item.cellY);
283df0353815c629fc678824b07a234b89a1ff94208Adam Cohen    }
284df0353815c629fc678824b07a234b89a1ff94208Adam Cohen
285c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen    public void onDragEnter(Object dragInfo) {
286c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen        if (!willAcceptItem((ItemInfo) dragInfo)) return;
28769ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen        CellLayout.LayoutParams lp = (CellLayout.LayoutParams) getLayoutParams();
28869ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen        CellLayout layout = (CellLayout) getParent().getParent();
28969ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen        mFolderRingAnimator.setCell(lp.cellX, lp.cellY);
29069ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen        mFolderRingAnimator.setCellLayout(layout);
29119072da7441e07d5e90026d9e9e1b38f11245e44Adam Cohen        mFolderRingAnimator.animateToAcceptState();
29269ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen        layout.showFolderAccept(mFolderRingAnimator);
293073a46ff635d089cbcb15d939d1de42dd2b86c97Adam Cohen    }
294073a46ff635d089cbcb15d939d1de42dd2b86c97Adam Cohen
295c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen    public void onDragOver(Object dragInfo) {
296073a46ff635d089cbcb15d939d1de42dd2b86c97Adam Cohen    }
297073a46ff635d089cbcb15d939d1de42dd2b86c97Adam Cohen
298d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen    public void performCreateAnimation(final ShortcutInfo destInfo, final View destView,
299557d6ed50cc6560163440aa134870ef0bb11415bWinson Chung            final ShortcutInfo srcInfo, final View srcView, Rect dstRect,
300ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen            float scaleRelativeToDragLayer, Runnable postAnimationRunnable) {
301d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen
302d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        Drawable animateDrawable = ((TextView) destView).getCompoundDrawables()[1];
303d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        computePreviewDrawingParams(animateDrawable.getIntrinsicWidth(), destView.getMeasuredWidth());
304ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen
305d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        // This will animate the dragView (srcView) into the new folder
306ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen        onDrop(srcInfo, srcView, dstRect, scaleRelativeToDragLayer, 1, postAnimationRunnable);
307d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen
308d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        // This will animate the first item from it's position as an icon into its
309d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        // position as the first item in the preview
3108dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        animateFirstItem(animateDrawable, INITIAL_ITEM_ANIMATION_DURATION);
311d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen
312d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        postDelayed(new Runnable() {
313d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen            public void run() {
314d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen                addItem(destInfo);
315d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen            }
316d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        }, INITIAL_ITEM_ANIMATION_DURATION);
317d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen    }
318d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen
319c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen    public void onDragExit(Object dragInfo) {
320c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen        if (!willAcceptItem((ItemInfo) dragInfo)) return;
32119072da7441e07d5e90026d9e9e1b38f11245e44Adam Cohen        mFolderRingAnimator.animateToNaturalState();
322073a46ff635d089cbcb15d939d1de42dd2b86c97Adam Cohen    }
323073a46ff635d089cbcb15d939d1de42dd2b86c97Adam Cohen
324ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen    private void onDrop(final ShortcutInfo item, View animateView, Rect finalRect,
325ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen            float scaleRelativeToDragLayer, int index, Runnable postAnimationRunnable) {
326d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        item.cellX = -1;
327d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        item.cellY = -1;
328d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen
329558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen        // Typically, the animateView corresponds to the DragView; however, if this is being done
330558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen        // after a configuration activity (ie. for a Shortcut being dragged from AllApps) we
331558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen        // will not have a view to animate
332558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen        if (animateView != null) {
333558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen            DragLayer dragLayer = mLauncher.getDragLayer();
334558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen            Rect from = new Rect();
335558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen            dragLayer.getViewRectRelativeToSelf(animateView, from);
336558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen            Rect to = finalRect;
337558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen            if (to == null) {
338558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen                to = new Rect();
339558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen                Workspace workspace = mLauncher.getWorkspace();
340558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen                // Set cellLayout and this to it's final state to compute final animation locations
341558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen                workspace.setFinalTransitionTransform((CellLayout) getParent().getParent());
342558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen                float scaleX = getScaleX();
343558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen                float scaleY = getScaleY();
344558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen                setScaleX(1.0f);
345558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen                setScaleY(1.0f);
346558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen                scaleRelativeToDragLayer = dragLayer.getDescendantRectRelativeToSelf(this, to);
347558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen                // Finished computing final animation locations, restore current state
348558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen                setScaleX(scaleX);
349558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen                setScaleY(scaleY);
350558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen                workspace.resetTransitionTransform((CellLayout) getParent().getParent());
351558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen            }
352ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen
353558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen            int[] center = new int[2];
354558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen            float scale = getLocalCenterForIndex(index, center);
355558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen            center[0] = (int) Math.round(scaleRelativeToDragLayer * center[0]);
356558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen            center[1] = (int) Math.round(scaleRelativeToDragLayer * center[1]);
357d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen
358558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen            to.offset(center[0] - animateView.getMeasuredWidth() / 2,
359558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen                    center[1] - animateView.getMeasuredHeight() / 2);
360d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen
361558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen            float finalAlpha = index < NUM_ITEMS_IN_PREVIEW ? 0.5f : 0f;
362558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen
363558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen            dragLayer.animateView(animateView, from, to, finalAlpha,
364558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen                    scale * scaleRelativeToDragLayer, DROP_IN_ANIMATION_DURATION,
365558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen                    new DecelerateInterpolator(2), new AccelerateInterpolator(2),
366558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen                    postAnimationRunnable, false);
367558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen            postDelayed(new Runnable() {
368558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen                public void run() {
369558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen                    addItem(item);
370558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen                }
371558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen            }, DROP_IN_ANIMATION_DURATION);
372558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen        } else {
373558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen            addItem(item);
374558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen        }
375d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen    }
376d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen
3773e8f811f31a2275e778244427271f77f4116c08bAdam Cohen    public void onDrop(DragObject d) {
378c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen        ShortcutInfo item;
3793e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        if (d.dragInfo instanceof ApplicationInfo) {
380c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen            // Came from all apps -- make a copy
3813e8f811f31a2275e778244427271f77f4116c08bAdam Cohen            item = ((ApplicationInfo) d.dragInfo).makeShortcut();
382c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen        } else {
3833e8f811f31a2275e778244427271f77f4116c08bAdam Cohen            item = (ShortcutInfo) d.dragInfo;
384c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen        }
38567bd9ccf856840856944815a382e4bbb0e71e949Adam Cohen        mFolder.notifyDrop();
386ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen        onDrop(item, d.dragView, null, 1.0f, mInfo.contents.size(), d.postAnimationRunnable);
387c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen    }
388c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen
389cb3382b1bfe1a534b1b44f5c4def9b2db605ac90Adam Cohen    public DropTarget getDropTargetDelegate(DragObject d) {
390440c360bc395c43683fa9ca226e59f9e35f9e926Patrick Dubroy        return null;
391440c360bc395c43683fa9ca226e59f9e35f9e926Patrick Dubroy    }
392a9cf38f533d1e86269868f1e6a806ccffd4a78fcAdam Cohen
393d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen    private void computePreviewDrawingParams(int drawableSize, int totalSize) {
394d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        if (mIntrinsicIconSize != drawableSize || mTotalWidth != totalSize) {
395d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen            mIntrinsicIconSize = drawableSize;
396d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen            mTotalWidth = totalSize;
39776fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen
398d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen            final int previewSize = FolderRingAnimator.sPreviewSize;
399d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen            final int previewPadding = FolderRingAnimator.sPreviewPadding;
400a9cf38f533d1e86269868f1e6a806ccffd4a78fcAdam Cohen
401d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen            mAvailableSpaceInPreview = (previewSize - 2 * previewPadding);
402d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen            // cos(45) = 0.707  + ~= 0.1) = 0.8f
403d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen            int adjustedAvailableSpace = (int) ((mAvailableSpaceInPreview / 2) * (1 + 0.8f));
404d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen
405d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen            int unscaledHeight = (int) (mIntrinsicIconSize * (1 + PERSPECTIVE_SHIFT_FACTOR));
406d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen            mBaselineIconScale = (1.0f * adjustedAvailableSpace / unscaledHeight);
407a9cf38f533d1e86269868f1e6a806ccffd4a78fcAdam Cohen
408d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen            mBaselineIconSize = (int) (mIntrinsicIconSize * mBaselineIconScale);
409d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen            mMaxPerspectiveShift = mBaselineIconSize * PERSPECTIVE_SHIFT_FACTOR;
410d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen
411d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen            mPreviewOffsetX = (mTotalWidth - mAvailableSpaceInPreview) / 2;
412d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen            mPreviewOffsetY = previewPadding;
413073a46ff635d089cbcb15d939d1de42dd2b86c97Adam Cohen        }
414d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen    }
41576fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen
416d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen    private void computePreviewDrawingParams(Drawable d) {
417d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        computePreviewDrawingParams(d.getIntrinsicWidth(), getMeasuredWidth());
418d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen    }
419073a46ff635d089cbcb15d939d1de42dd2b86c97Adam Cohen
420d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen    class PreviewItemDrawingParams {
421d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        PreviewItemDrawingParams(float transX, float transY, float scale, int overlayAlpha) {
422d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen            this.transX = transX;
423d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen            this.transY = transY;
424d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen            this.scale = scale;
425d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen            this.overlayAlpha = overlayAlpha;
426d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        }
427d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        float transX;
428d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        float transY;
429d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        float scale;
430d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        int overlayAlpha;
431d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        Drawable drawable;
432d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen    }
433badf71e11fba2d6efa1d1bcca9542001f90a3777Adam Cohen
434ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen    private float getLocalCenterForIndex(int index, int[] center) {
435d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        mParams = computePreviewItemDrawingParams(Math.min(NUM_ITEMS_IN_PREVIEW, index), mParams);
436a9cf38f533d1e86269868f1e6a806ccffd4a78fcAdam Cohen
437d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        mParams.transX += mPreviewOffsetX;
438d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        mParams.transY += mPreviewOffsetY;
439ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen        float offsetX = mParams.transX + (mParams.scale * mIntrinsicIconSize) / 2;
440ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen        float offsetY = mParams.transY + (mParams.scale * mIntrinsicIconSize) / 2;
441badf71e11fba2d6efa1d1bcca9542001f90a3777Adam Cohen
442ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen        center[0] = (int) Math.round(offsetX);
443ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen        center[1] = (int) Math.round(offsetY);
444d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        return mParams.scale;
445d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen    }
446badf71e11fba2d6efa1d1bcca9542001f90a3777Adam Cohen
447d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen    private PreviewItemDrawingParams computePreviewItemDrawingParams(int index,
448d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen            PreviewItemDrawingParams params) {
449d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        index = NUM_ITEMS_IN_PREVIEW - index - 1;
450d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        float r = (index * 1.0f) / (NUM_ITEMS_IN_PREVIEW - 1);
451d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        float scale = (1 - PERSPECTIVE_SCALE_FACTOR * (1 - r));
452d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen
453d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        float offset = (1 - r) * mMaxPerspectiveShift;
454d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        float scaledSize = scale * mBaselineIconSize;
455d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        float scaleOffsetCorrection = (1 - scale) * mBaselineIconSize;
456d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen
457d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        // We want to imagine our coordinates from the bottom left, growing up and to the
458d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        // right. This is natural for the x-axis, but for the y-axis, we have to invert things.
459d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        float transY = mAvailableSpaceInPreview - (offset + scaledSize + scaleOffsetCorrection);
460d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        float transX = offset + scaleOffsetCorrection;
461d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        float totalScale = mBaselineIconScale * scale;
462d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        final int overlayAlpha = (int) (80 * (1 - r));
463d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen
464d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        if (params == null) {
465d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen            params = new PreviewItemDrawingParams(transX, transY, totalScale, overlayAlpha);
466d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        } else {
467d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen            params.transX = transX;
468d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen            params.transY = transY;
469d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen            params.scale = totalScale;
470d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen            params.overlayAlpha = overlayAlpha;
471d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        }
472d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        return params;
473d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen    }
474badf71e11fba2d6efa1d1bcca9542001f90a3777Adam Cohen
475d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen    private void drawPreviewItem(Canvas canvas, PreviewItemDrawingParams params) {
476d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        canvas.save();
477d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        canvas.translate(params.transX + mPreviewOffsetX, params.transY + mPreviewOffsetY);
478d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        canvas.scale(params.scale, params.scale);
479d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        Drawable d = params.drawable;
480d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen
481d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        if (d != null) {
482d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen            d.setBounds(0, 0, mIntrinsicIconSize, mIntrinsicIconSize);
483d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen            d.setFilterBitmap(true);
484d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen            d.setColorFilter(Color.argb(params.overlayAlpha, 0, 0, 0), PorterDuff.Mode.SRC_ATOP);
485d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen            d.draw(canvas);
486d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen            d.clearColorFilter();
487d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen            d.setFilterBitmap(false);
488d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        }
489d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        canvas.restore();
490d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen    }
49176fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen
492d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen    @Override
493d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen    protected void dispatchDraw(Canvas canvas) {
494d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        super.dispatchDraw(canvas);
495badf71e11fba2d6efa1d1bcca9542001f90a3777Adam Cohen
496d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        if (mFolder == null) return;
497d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        if (mFolder.getItemCount() == 0 && !mAnimating) return;
498d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen
499d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        ArrayList<View> items = mFolder.getItemsInReadingOrder(false);
500d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        Drawable d;
501d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        TextView v;
502d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen
503d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        // Update our drawing parameters if necessary
504d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        if (mAnimating) {
505d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen            computePreviewDrawingParams(mAnimParams.drawable);
506d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        } else {
507d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen            v = (TextView) items.get(0);
508a9cf38f533d1e86269868f1e6a806ccffd4a78fcAdam Cohen            d = v.getCompoundDrawables()[1];
509d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen            computePreviewDrawingParams(d);
510d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        }
511a9cf38f533d1e86269868f1e6a806ccffd4a78fcAdam Cohen
512d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        int nItemsInPreview = Math.min(items.size(), NUM_ITEMS_IN_PREVIEW);
513d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        if (!mAnimating) {
514d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen            for (int i = nItemsInPreview - 1; i >= 0; i--) {
515d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen                v = (TextView) items.get(i);
516d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen                d = v.getCompoundDrawables()[1];
517d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen
518d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen                mParams = computePreviewItemDrawingParams(i, mParams);
519d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen                mParams.drawable = d;
520d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen                drawPreviewItem(canvas, mParams);
521a9cf38f533d1e86269868f1e6a806ccffd4a78fcAdam Cohen            }
522d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        } else {
523d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen            drawPreviewItem(canvas, mAnimParams);
524a9cf38f533d1e86269868f1e6a806ccffd4a78fcAdam Cohen        }
525d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen    }
526d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen
527d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen    private void animateFirstItem(final Drawable d, int duration) {
528d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        computePreviewDrawingParams(d);
529d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        final PreviewItemDrawingParams finalParams = computePreviewItemDrawingParams(0, null);
530d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen
531d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        final float scale0 = 1.0f;
5321d4ee4e46218fb98a43cf584d8d4e3e569850f78Adam Cohen        final float transX0 = (mAvailableSpaceInPreview - d.getIntrinsicWidth()) / 2;
5331d4ee4e46218fb98a43cf584d8d4e3e569850f78Adam Cohen        final float transY0 = (mAvailableSpaceInPreview - d.getIntrinsicHeight()) / 2;
534d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        mAnimParams.drawable = d;
535d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen
536d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        ValueAnimator va = ValueAnimator.ofFloat(0f, 1.0f);
537d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        va.addUpdateListener(new AnimatorUpdateListener(){
538d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen            public void onAnimationUpdate(ValueAnimator animation) {
539d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen                float progress = (Float) animation.getAnimatedValue();
540d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen
541d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen                mAnimParams.transX = transX0 + progress * (finalParams.transX - transX0);
542d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen                mAnimParams.transY = transY0 + progress * (finalParams.transY - transY0);
543d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen                mAnimParams.scale = scale0 + progress * (finalParams.scale - scale0);
544d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen                invalidate();
545d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen            }
546d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        });
547d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        va.addListener(new AnimatorListenerAdapter() {
548d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen            @Override
549d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen            public void onAnimationStart(Animator animation) {
550d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen                mAnimating = true;
551d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen            }
552d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen            @Override
553d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen            public void onAnimationEnd(Animator animation) {
554d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen                mAnimating = false;
555d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen            }
556d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        });
557d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        va.setDuration(duration);
558d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        va.start();
559a9cf38f533d1e86269868f1e6a806ccffd4a78fcAdam Cohen    }
560a9cf38f533d1e86269868f1e6a806ccffd4a78fcAdam Cohen
561099f60d51f6310e1290687e83958e665b3324504Adam Cohen    public void setTextVisible(boolean visible) {
562099f60d51f6310e1290687e83958e665b3324504Adam Cohen        if (visible) {
563099f60d51f6310e1290687e83958e665b3324504Adam Cohen            mFolderName.setVisibility(VISIBLE);
564099f60d51f6310e1290687e83958e665b3324504Adam Cohen        } else {
565099f60d51f6310e1290687e83958e665b3324504Adam Cohen            mFolderName.setVisibility(INVISIBLE);
566099f60d51f6310e1290687e83958e665b3324504Adam Cohen        }
567099f60d51f6310e1290687e83958e665b3324504Adam Cohen    }
568099f60d51f6310e1290687e83958e665b3324504Adam Cohen
569099f60d51f6310e1290687e83958e665b3324504Adam Cohen    public boolean getTextVisible() {
570099f60d51f6310e1290687e83958e665b3324504Adam Cohen        return mFolderName.getVisibility() == VISIBLE;
571099f60d51f6310e1290687e83958e665b3324504Adam Cohen    }
572099f60d51f6310e1290687e83958e665b3324504Adam Cohen
57376078c4ef35b6e95fb6d8129a32cf52a36625e28Adam Cohen    public void onItemsChanged() {
57476078c4ef35b6e95fb6d8129a32cf52a36625e28Adam Cohen        invalidate();
57576078c4ef35b6e95fb6d8129a32cf52a36625e28Adam Cohen        requestLayout();
57676078c4ef35b6e95fb6d8129a32cf52a36625e28Adam Cohen    }
57776078c4ef35b6e95fb6d8129a32cf52a36625e28Adam Cohen
578a9cf38f533d1e86269868f1e6a806ccffd4a78fcAdam Cohen    public void onAdd(ShortcutInfo item) {
579a9cf38f533d1e86269868f1e6a806ccffd4a78fcAdam Cohen        invalidate();
580a9cf38f533d1e86269868f1e6a806ccffd4a78fcAdam Cohen        requestLayout();
581a9cf38f533d1e86269868f1e6a806ccffd4a78fcAdam Cohen    }
582a9cf38f533d1e86269868f1e6a806ccffd4a78fcAdam Cohen
583a9cf38f533d1e86269868f1e6a806ccffd4a78fcAdam Cohen    public void onRemove(ShortcutInfo item) {
584a9cf38f533d1e86269868f1e6a806ccffd4a78fcAdam Cohen        invalidate();
585a9cf38f533d1e86269868f1e6a806ccffd4a78fcAdam Cohen        requestLayout();
586a9cf38f533d1e86269868f1e6a806ccffd4a78fcAdam Cohen    }
58776fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen
58876fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen    public void onTitleChanged(CharSequence title) {
589d63cfa96814fa1a51490950b8df9853eef305cbbAdam Cohen        mFolderName.setText(title.toString());
5906a0f57dfafced837a2a282d8feec28d5418be3b9Winson Chung        mPreviewBackground.setContentDescription(title.toString());
59176fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen    }
59231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project}
593