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
17325dc23624160689e59fbac708cf6f222b20d025Daniel Sandlerpackage com.android.launcher3;
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;
3024ad0f0aad174b077e80b10d1f814ff9e9eb92e4Daniel Sandlerimport android.os.Looper;
31099f60d51f6310e1290687e83958e665b3324504Adam Cohenimport android.os.Parcelable;
3231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.util.AttributeSet;
3331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.view.LayoutInflater;
3488f334571fe41df620ba903ced9b2c69b0170d5cWinson Chungimport android.view.MotionEvent;
357c6932140dcbd2db88d7a809ba72ee04abb5bf26Adam Cohenimport android.view.View;
3602dd7aea3d8ac94126a8f8069e6762592ea60326Jason Monkimport android.view.ViewConfiguration;
3731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.view.ViewGroup;
383e8f811f31a2275e778244427271f77f4116c08bAdam Cohenimport android.view.animation.AccelerateInterpolator;
393e8f811f31a2275e778244427271f77f4116c08bAdam Cohenimport android.view.animation.DecelerateInterpolator;
406e1c0d34bb31cacc24c57c89ab01deaa8985814fWinson Chungimport android.widget.FrameLayout;
4134c2e6cf7af328aba25c98158161dbad15ae986dMichael Jurkaimport android.widget.ImageView;
42a9cf38f533d1e86269868f1e6a806ccffd4a78fcAdam Cohenimport android.widget.TextView;
4331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
44325dc23624160689e59fbac708cf6f222b20d025Daniel Sandlerimport com.android.launcher3.DropTarget.DragObject;
45325dc23624160689e59fbac708cf6f222b20d025Daniel Sandlerimport com.android.launcher3.FolderInfo.FolderListener;
46edcce099c98a6c40d10109ac092ab50f9d2668f3Romain Guy
47c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohenimport java.util.ArrayList;
48c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen
4931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project/**
5031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * An icon that can appear on in the workspace representing an {@link UserFolder}.
5131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project */
526e1c0d34bb31cacc24c57c89ab01deaa8985814fWinson Chungpublic class FolderIcon extends FrameLayout implements FolderListener {
5331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    private Launcher mLauncher;
54fb91f303f5e672f9b4c4f9f8a03486b224d60cd6Adam Cohen    private Folder mFolder;
55fb91f303f5e672f9b4c4f9f8a03486b224d60cd6Adam Cohen    private FolderInfo mInfo;
56099f60d51f6310e1290687e83958e665b3324504Adam Cohen    private static boolean sStaticValuesDirty = true;
57a9cf38f533d1e86269868f1e6a806ccffd4a78fcAdam Cohen
5888f334571fe41df620ba903ced9b2c69b0170d5cWinson Chung    private CheckLongPressHelper mLongPressHelper;
5988f334571fe41df620ba903ced9b2c69b0170d5cWinson Chung
60badf71e11fba2d6efa1d1bcca9542001f90a3777Adam Cohen    // The number of icons to display in the
6176fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen    private static final int NUM_ITEMS_IN_PREVIEW = 3;
62f4b08913677e18a8412930972237b91d5a946d95Adam Cohen    private static final int CONSUMPTION_ANIMATION_DURATION = 100;
63d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen    private static final int DROP_IN_ANIMATION_DURATION = 400;
648dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen    private static final int INITIAL_ITEM_ANIMATION_DURATION = 350;
65fb91f303f5e672f9b4c4f9f8a03486b224d60cd6Adam Cohen    private static final int FINAL_ITEM_ANIMATION_DURATION = 200;
66badf71e11fba2d6efa1d1bcca9542001f90a3777Adam Cohen
67badf71e11fba2d6efa1d1bcca9542001f90a3777Adam Cohen    // The degree to which the inner ring grows when accepting drop
6869ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen    private static final float INNER_RING_GROWTH_FACTOR = 0.15f;
69badf71e11fba2d6efa1d1bcca9542001f90a3777Adam Cohen
70badf71e11fba2d6efa1d1bcca9542001f90a3777Adam Cohen    // The degree to which the outer ring is scaled in its natural state
7169ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen    private static final float OUTER_RING_GROWTH_FACTOR = 0.3f;
72badf71e11fba2d6efa1d1bcca9542001f90a3777Adam Cohen
73badf71e11fba2d6efa1d1bcca9542001f90a3777Adam Cohen    // The amount of vertical spread between items in the stack [0...1]
7496bb79819ef9ddf2d1c0cb0b72c2c9f6db26b4fdAdam Cohen    private static final float PERSPECTIVE_SHIFT_FACTOR = 0.18f;
758edd2001417443c34a930be79b8ee8438dcff246Adam Cohen
765108bc0fd9f7e30c87c223fbb75f024e271b2103Adam Cohen    // Flag as to whether or not to draw an outer ring. Currently none is designed.
77b0e65f218ec7eb69fd527e5400f7c040742a1767Adam Cohen    public static final boolean HAS_OUTER_RING = true;
785108bc0fd9f7e30c87c223fbb75f024e271b2103Adam Cohen
7955bd9725d5c0373b89f7b9bbd9547550ea3bbc63Jorim Jaggi    // Flag whether the folder should open itself when an item is dragged over is enabled.
8055bd9725d5c0373b89f7b9bbd9547550ea3bbc63Jorim Jaggi    public static final boolean SPRING_LOADING_ENABLED = true;
8155bd9725d5c0373b89f7b9bbd9547550ea3bbc63Jorim Jaggi
82badf71e11fba2d6efa1d1bcca9542001f90a3777Adam Cohen    // The degree to which the item in the back of the stack is scaled [0...1]
83badf71e11fba2d6efa1d1bcca9542001f90a3777Adam Cohen    // (0 means it's not scaled at all, 1 means it's scaled to nothing)
8476fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen    private static final float PERSPECTIVE_SCALE_FACTOR = 0.35f;
8531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
8655bd9725d5c0373b89f7b9bbd9547550ea3bbc63Jorim Jaggi    // Delay when drag enters until the folder opens, in miliseconds.
8755bd9725d5c0373b89f7b9bbd9547550ea3bbc63Jorim Jaggi    private static final int ON_OPEN_DELAY = 800;
8855bd9725d5c0373b89f7b9bbd9547550ea3bbc63Jorim Jaggi
89c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen    public static Drawable sSharedFolderLeaveBehind = null;
90c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen
9176fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen    private ImageView mPreviewBackground;
9276fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen    private BubbleTextView mFolderName;
93073a46ff635d089cbcb15d939d1de42dd2b86c97Adam Cohen
9419072da7441e07d5e90026d9e9e1b38f11245e44Adam Cohen    FolderRingAnimator mFolderRingAnimator = null;
952801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen
96d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen    // These variables are all associated with the drawing of the preview; they are stored
97d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen    // as member variables for shared usage and to avoid computation on each frame
98d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen    private int mIntrinsicIconSize;
99d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen    private float mBaselineIconScale;
100d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen    private int mBaselineIconSize;
101d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen    private int mAvailableSpaceInPreview;
102d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen    private int mTotalWidth = -1;
103d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen    private int mPreviewOffsetX;
104d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen    private int mPreviewOffsetY;
105d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen    private float mMaxPerspectiveShift;
106d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen    boolean mAnimating = false;
107d4e53c882494f8cd7e4c0d44dbfc300d3610afcfWinson Chung    private Rect mOldBounds = new Rect();
108fb91f303f5e672f9b4c4f9f8a03486b224d60cd6Adam Cohen
10902dd7aea3d8ac94126a8f8069e6762592ea60326Jason Monk    private float mSlop;
11002dd7aea3d8ac94126a8f8069e6762592ea60326Jason Monk
111d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen    private PreviewItemDrawingParams mParams = new PreviewItemDrawingParams(0, 0, 0, 0);
112d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen    private PreviewItemDrawingParams mAnimParams = new PreviewItemDrawingParams(0, 0, 0, 0);
113fb91f303f5e672f9b4c4f9f8a03486b224d60cd6Adam Cohen    private ArrayList<ShortcutInfo> mHiddenItems = new ArrayList<ShortcutInfo>();
114d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen
11555bd9725d5c0373b89f7b9bbd9547550ea3bbc63Jorim Jaggi    private Alarm mOpenAlarm = new Alarm();
11655bd9725d5c0373b89f7b9bbd9547550ea3bbc63Jorim Jaggi    private ItemInfo mDragInfo;
11755bd9725d5c0373b89f7b9bbd9547550ea3bbc63Jorim Jaggi
11831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    public FolderIcon(Context context, AttributeSet attrs) {
11931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        super(context, attrs);
12088f334571fe41df620ba903ced9b2c69b0170d5cWinson Chung        init();
12131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
12231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
12331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    public FolderIcon(Context context) {
12431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        super(context);
12588f334571fe41df620ba903ced9b2c69b0170d5cWinson Chung        init();
12688f334571fe41df620ba903ced9b2c69b0170d5cWinson Chung    }
12788f334571fe41df620ba903ced9b2c69b0170d5cWinson Chung
12888f334571fe41df620ba903ced9b2c69b0170d5cWinson Chung    private void init() {
12988f334571fe41df620ba903ced9b2c69b0170d5cWinson Chung        mLongPressHelper = new CheckLongPressHelper(this);
13031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
13131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
1320280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    public boolean isDropEnabled() {
1337a1d16555d80135e61b90158ff3c1e3f963bd8b8Winson Chung        final ViewGroup cellLayoutChildren = (ViewGroup) getParent();
1347a1d16555d80135e61b90158ff3c1e3f963bd8b8Winson Chung        final ViewGroup cellLayout = (ViewGroup) cellLayoutChildren.getParent();
1357a1d16555d80135e61b90158ff3c1e3f963bd8b8Winson Chung        final Workspace workspace = (Workspace) cellLayout.getParent();
1366c5891a9fce95eee3d87823d11d21889743e9c68Adam Cohen        return !workspace.workspaceInModalState();
1370280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    }
1380280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka
13931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    static FolderIcon fromXml(int resId, Launcher launcher, ViewGroup group,
140df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen            FolderInfo folderInfo, IconCache iconCache) {
1413a9fcedbcd235372cd2ab64f825a0b5b3937f59eMichael Jurka        @SuppressWarnings("all") // suppress dead code warning
1423a9fcedbcd235372cd2ab64f825a0b5b3937f59eMichael Jurka        final boolean error = INITIAL_ITEM_ANIMATION_DURATION >= DROP_IN_ANIMATION_DURATION;
1433a9fcedbcd235372cd2ab64f825a0b5b3937f59eMichael Jurka        if (error) {
144d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen            throw new IllegalStateException("DROP_IN_ANIMATION_DURATION must be greater than " +
145d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen                    "INITIAL_ITEM_ANIMATION_DURATION, as sequencing of adding first two items " +
146d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen                    "is dependent on this");
147d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        }
1486e1c0d34bb31cacc24c57c89ab01deaa8985814fWinson Chung        LauncherAppState app = LauncherAppState.getInstance();
1496e1c0d34bb31cacc24c57c89ab01deaa8985814fWinson Chung        DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
150d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen
15131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        FolderIcon icon = (FolderIcon) LayoutInflater.from(launcher).inflate(resId, group, false);
1525f8afe6280eae34620067696173e71943e1a30a3Winson Chung        icon.setClipToPadding(false);
153d2eca6b66e654e71fb46ae718910af3ec6c2cf9cAdam Cohen        icon.mFolderName = (BubbleTextView) icon.findViewById(R.id.folder_icon_name);
15476fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen        icon.mFolderName.setText(folderInfo.title);
1556e1c0d34bb31cacc24c57c89ab01deaa8985814fWinson Chung        icon.mFolderName.setCompoundDrawablePadding(0);
1566e1c0d34bb31cacc24c57c89ab01deaa8985814fWinson Chung        FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) icon.mFolderName.getLayoutParams();
1576e1c0d34bb31cacc24c57c89ab01deaa8985814fWinson Chung        lp.topMargin = grid.iconSizePx + grid.iconDrawablePaddingPx;
1586e1c0d34bb31cacc24c57c89ab01deaa8985814fWinson Chung
1595f8afe6280eae34620067696173e71943e1a30a3Winson Chung        // Offset the preview background to center this view accordingly
1606e1c0d34bb31cacc24c57c89ab01deaa8985814fWinson Chung        icon.mPreviewBackground = (ImageView) icon.findViewById(R.id.preview_background);
1616e1c0d34bb31cacc24c57c89ab01deaa8985814fWinson Chung        lp = (FrameLayout.LayoutParams) icon.mPreviewBackground.getLayoutParams();
1625f8afe6280eae34620067696173e71943e1a30a3Winson Chung        lp.topMargin = grid.folderBackgroundOffset;
1635f8afe6280eae34620067696173e71943e1a30a3Winson Chung        lp.width = grid.folderIconSizePx;
1645f8afe6280eae34620067696173e71943e1a30a3Winson Chung        lp.height = grid.folderIconSizePx;
16576fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen
16631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        icon.setTag(folderInfo);
16731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        icon.setOnClickListener(launcher);
16831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        icon.mInfo = folderInfo;
16931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        icon.mLauncher = launcher;
1703371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen        icon.setContentDescription(String.format(launcher.getString(R.string.folder_name_format),
1713371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                folderInfo.title));
172a9cf38f533d1e86269868f1e6a806ccffd4a78fcAdam Cohen        Folder folder = Folder.fromXml(launcher);
173a9cf38f533d1e86269868f1e6a806ccffd4a78fcAdam Cohen        folder.setDragController(launcher.getDragController());
1742801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen        folder.setFolderIcon(icon);
175a9cf38f533d1e86269868f1e6a806ccffd4a78fcAdam Cohen        folder.bind(folderInfo);
176a9cf38f533d1e86269868f1e6a806ccffd4a78fcAdam Cohen        icon.mFolder = folder;
177099f60d51f6310e1290687e83958e665b3324504Adam Cohen
178099f60d51f6310e1290687e83958e665b3324504Adam Cohen        icon.mFolderRingAnimator = new FolderRingAnimator(launcher, icon);
179099f60d51f6310e1290687e83958e665b3324504Adam Cohen        folderInfo.addListener(icon);
180099f60d51f6310e1290687e83958e665b3324504Adam Cohen
181dcbcc86353e9ed52daac87f292aece667cd0ac71Sunny Goyal        icon.setOnFocusChangeListener(launcher.mFocusHandler);
18219072da7441e07d5e90026d9e9e1b38f11245e44Adam Cohen        return icon;
18319072da7441e07d5e90026d9e9e1b38f11245e44Adam Cohen    }
18419072da7441e07d5e90026d9e9e1b38f11245e44Adam Cohen
185099f60d51f6310e1290687e83958e665b3324504Adam Cohen    @Override
186099f60d51f6310e1290687e83958e665b3324504Adam Cohen    protected Parcelable onSaveInstanceState() {
187099f60d51f6310e1290687e83958e665b3324504Adam Cohen        sStaticValuesDirty = true;
188099f60d51f6310e1290687e83958e665b3324504Adam Cohen        return super.onSaveInstanceState();
189099f60d51f6310e1290687e83958e665b3324504Adam Cohen    }
190099f60d51f6310e1290687e83958e665b3324504Adam Cohen
19119072da7441e07d5e90026d9e9e1b38f11245e44Adam Cohen    public static class FolderRingAnimator {
19269ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen        public int mCellX;
19369ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen        public int mCellY;
19469ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen        private CellLayout mCellLayout;
19576fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen        public float mOuterRingSize;
19676fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen        public float mInnerRingSize;
19719072da7441e07d5e90026d9e9e1b38f11245e44Adam Cohen        public FolderIcon mFolderIcon = null;
198c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen        public static Drawable sSharedOuterRingDrawable = null;
199c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen        public static Drawable sSharedInnerRingDrawable = null;
20076fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen        public static int sPreviewSize = -1;
20176fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen        public static int sPreviewPadding = -1;
20276fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen
203c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen        private ValueAnimator mAcceptAnimator;
204c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen        private ValueAnimator mNeutralAnimator;
20519072da7441e07d5e90026d9e9e1b38f11245e44Adam Cohen
20619072da7441e07d5e90026d9e9e1b38f11245e44Adam Cohen        public FolderRingAnimator(Launcher launcher, FolderIcon folderIcon) {
20719072da7441e07d5e90026d9e9e1b38f11245e44Adam Cohen            mFolderIcon = folderIcon;
20876fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen            Resources res = launcher.getResources();
20976fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen
210099f60d51f6310e1290687e83958e665b3324504Adam Cohen            // We need to reload the static values when configuration changes in case they are
211099f60d51f6310e1290687e83958e665b3324504Adam Cohen            // different in another configuration
212099f60d51f6310e1290687e83958e665b3324504Adam Cohen            if (sStaticValuesDirty) {
21324ad0f0aad174b077e80b10d1f814ff9e9eb92e4Daniel Sandler                if (Looper.myLooper() != Looper.getMainLooper()) {
21424ad0f0aad174b077e80b10d1f814ff9e9eb92e4Daniel Sandler                    throw new RuntimeException("FolderRingAnimator loading drawables on non-UI thread "
21524ad0f0aad174b077e80b10d1f814ff9e9eb92e4Daniel Sandler                            + Thread.currentThread());
21624ad0f0aad174b077e80b10d1f814ff9e9eb92e4Daniel Sandler                }
2175f8afe6280eae34620067696173e71943e1a30a3Winson Chung
2185f8afe6280eae34620067696173e71943e1a30a3Winson Chung                LauncherAppState app = LauncherAppState.getInstance();
2195f8afe6280eae34620067696173e71943e1a30a3Winson Chung                DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
2205f8afe6280eae34620067696173e71943e1a30a3Winson Chung                sPreviewSize = grid.folderIconSizePx;
22176fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen                sPreviewPadding = res.getDimensionPixelSize(R.dimen.folder_preview_padding);
22276fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen                sSharedOuterRingDrawable = res.getDrawable(R.drawable.portal_ring_outer_holo);
2235108bc0fd9f7e30c87c223fbb75f024e271b2103Adam Cohen                sSharedInnerRingDrawable = res.getDrawable(R.drawable.portal_ring_inner_nolip_holo);
224df6af5740da6ee9f78e846218d71941b02fc0283Adam Cohen                sSharedFolderLeaveBehind = res.getDrawable(R.drawable.portal_ring_rest);
225099f60d51f6310e1290687e83958e665b3324504Adam Cohen                sStaticValuesDirty = false;
22619072da7441e07d5e90026d9e9e1b38f11245e44Adam Cohen            }
227073a46ff635d089cbcb15d939d1de42dd2b86c97Adam Cohen        }
228a9cf38f533d1e86269868f1e6a806ccffd4a78fcAdam Cohen
22919072da7441e07d5e90026d9e9e1b38f11245e44Adam Cohen        public void animateToAcceptState() {
230c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen            if (mNeutralAnimator != null) {
231c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen                mNeutralAnimator.cancel();
232c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen            }
233f1ad608c28c79c8e9b83d83ce9154f1b7284f412Michael Jurka            mAcceptAnimator = LauncherAnimUtils.ofFloat(mCellLayout, 0f, 1f);
234c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen            mAcceptAnimator.setDuration(CONSUMPTION_ANIMATION_DURATION);
235850d2e718560cb12ae73292e9d39f21a93d3c2c1Andrew Flynn
236850d2e718560cb12ae73292e9d39f21a93d3c2c1Andrew Flynn            final int previewSize = sPreviewSize;
237c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen            mAcceptAnimator.addUpdateListener(new AnimatorUpdateListener() {
23819072da7441e07d5e90026d9e9e1b38f11245e44Adam Cohen                public void onAnimationUpdate(ValueAnimator animation) {
23919072da7441e07d5e90026d9e9e1b38f11245e44Adam Cohen                    final float percent = (Float) animation.getAnimatedValue();
240850d2e718560cb12ae73292e9d39f21a93d3c2c1Andrew Flynn                    mOuterRingSize = (1 + percent * OUTER_RING_GROWTH_FACTOR) * previewSize;
241850d2e718560cb12ae73292e9d39f21a93d3c2c1Andrew Flynn                    mInnerRingSize = (1 + percent * INNER_RING_GROWTH_FACTOR) * previewSize;
24269ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen                    if (mCellLayout != null) {
24369ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen                        mCellLayout.invalidate();
24419072da7441e07d5e90026d9e9e1b38f11245e44Adam Cohen                    }
24519072da7441e07d5e90026d9e9e1b38f11245e44Adam Cohen                }
24619072da7441e07d5e90026d9e9e1b38f11245e44Adam Cohen            });
247c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen            mAcceptAnimator.addListener(new AnimatorListenerAdapter() {
24819072da7441e07d5e90026d9e9e1b38f11245e44Adam Cohen                @Override
249c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen                public void onAnimationStart(Animator animation) {
25019072da7441e07d5e90026d9e9e1b38f11245e44Adam Cohen                    if (mFolderIcon != null) {
25176fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen                        mFolderIcon.mPreviewBackground.setVisibility(INVISIBLE);
25219072da7441e07d5e90026d9e9e1b38f11245e44Adam Cohen                    }
25319072da7441e07d5e90026d9e9e1b38f11245e44Adam Cohen                }
25419072da7441e07d5e90026d9e9e1b38f11245e44Adam Cohen            });
255c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen            mAcceptAnimator.start();
25619072da7441e07d5e90026d9e9e1b38f11245e44Adam Cohen        }
25719072da7441e07d5e90026d9e9e1b38f11245e44Adam Cohen
25819072da7441e07d5e90026d9e9e1b38f11245e44Adam Cohen        public void animateToNaturalState() {
259c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen            if (mAcceptAnimator != null) {
260c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen                mAcceptAnimator.cancel();
261c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen            }
262f1ad608c28c79c8e9b83d83ce9154f1b7284f412Michael Jurka            mNeutralAnimator = LauncherAnimUtils.ofFloat(mCellLayout, 0f, 1f);
263c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen            mNeutralAnimator.setDuration(CONSUMPTION_ANIMATION_DURATION);
264850d2e718560cb12ae73292e9d39f21a93d3c2c1Andrew Flynn
265850d2e718560cb12ae73292e9d39f21a93d3c2c1Andrew Flynn            final int previewSize = sPreviewSize;
266c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen            mNeutralAnimator.addUpdateListener(new AnimatorUpdateListener() {
26719072da7441e07d5e90026d9e9e1b38f11245e44Adam Cohen                public void onAnimationUpdate(ValueAnimator animation) {
26819072da7441e07d5e90026d9e9e1b38f11245e44Adam Cohen                    final float percent = (Float) animation.getAnimatedValue();
269850d2e718560cb12ae73292e9d39f21a93d3c2c1Andrew Flynn                    mOuterRingSize = (1 + (1 - percent) * OUTER_RING_GROWTH_FACTOR) * previewSize;
270850d2e718560cb12ae73292e9d39f21a93d3c2c1Andrew Flynn                    mInnerRingSize = (1 + (1 - percent) * INNER_RING_GROWTH_FACTOR) * previewSize;
27169ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen                    if (mCellLayout != null) {
27269ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen                        mCellLayout.invalidate();
27319072da7441e07d5e90026d9e9e1b38f11245e44Adam Cohen                    }
27419072da7441e07d5e90026d9e9e1b38f11245e44Adam Cohen                }
27519072da7441e07d5e90026d9e9e1b38f11245e44Adam Cohen            });
276c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen            mNeutralAnimator.addListener(new AnimatorListenerAdapter() {
27719072da7441e07d5e90026d9e9e1b38f11245e44Adam Cohen                @Override
27819072da7441e07d5e90026d9e9e1b38f11245e44Adam Cohen                public void onAnimationEnd(Animator animation) {
27969ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen                    if (mCellLayout != null) {
28069ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen                        mCellLayout.hideFolderAccept(FolderRingAnimator.this);
28169ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen                    }
28219072da7441e07d5e90026d9e9e1b38f11245e44Adam Cohen                    if (mFolderIcon != null) {
28376fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen                        mFolderIcon.mPreviewBackground.setVisibility(VISIBLE);
28419072da7441e07d5e90026d9e9e1b38f11245e44Adam Cohen                    }
28519072da7441e07d5e90026d9e9e1b38f11245e44Adam Cohen                }
28619072da7441e07d5e90026d9e9e1b38f11245e44Adam Cohen            });
287c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen            mNeutralAnimator.start();
28819072da7441e07d5e90026d9e9e1b38f11245e44Adam Cohen        }
28919072da7441e07d5e90026d9e9e1b38f11245e44Adam Cohen
290c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen        // Location is expressed in window coordinates
29169ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen        public void getCell(int[] loc) {
29269ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            loc[0] = mCellX;
29369ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            loc[1] = mCellY;
29469ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen        }
29569ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen
29669ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen        // Location is expressed in window coordinates
29769ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen        public void setCell(int x, int y) {
29869ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            mCellX = x;
29969ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            mCellY = y;
30069ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen        }
30169ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen
30269ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen        public void setCellLayout(CellLayout layout) {
30369ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            mCellLayout = layout;
30419072da7441e07d5e90026d9e9e1b38f11245e44Adam Cohen        }
30519072da7441e07d5e90026d9e9e1b38f11245e44Adam Cohen
30676fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen        public float getOuterRingSize() {
30776fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen            return mOuterRingSize;
30819072da7441e07d5e90026d9e9e1b38f11245e44Adam Cohen        }
30919072da7441e07d5e90026d9e9e1b38f11245e44Adam Cohen
31076fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen        public float getInnerRingSize() {
31176fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen            return mInnerRingSize;
312f4b08913677e18a8412930972237b91d5a946d95Adam Cohen        }
31331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
31431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
315f05545fcc2df05518731f8d7ff048d797fe776d5Anjali Koppal    public Folder getFolder() {
316fb91f303f5e672f9b4c4f9f8a03486b224d60cd6Adam Cohen        return mFolder;
317fb91f303f5e672f9b4c4f9f8a03486b224d60cd6Adam Cohen    }
318fb91f303f5e672f9b4c4f9f8a03486b224d60cd6Adam Cohen
319fb91f303f5e672f9b4c4f9f8a03486b224d60cd6Adam Cohen    FolderInfo getFolderInfo() {
320fb91f303f5e672f9b4c4f9f8a03486b224d60cd6Adam Cohen        return mInfo;
321fb91f303f5e672f9b4c4f9f8a03486b224d60cd6Adam Cohen    }
322fb91f303f5e672f9b4c4f9f8a03486b224d60cd6Adam Cohen
323073a46ff635d089cbcb15d939d1de42dd2b86c97Adam Cohen    private boolean willAcceptItem(ItemInfo item) {
32431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        final int itemType = item.itemType;
3252801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen        return ((itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION ||
3262801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen                itemType == LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT) &&
327c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen                !mFolder.isFull() && item != mInfo && !mInfo.opened);
328073a46ff635d089cbcb15d939d1de42dd2b86c97Adam Cohen    }
329073a46ff635d089cbcb15d939d1de42dd2b86c97Adam Cohen
330c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen    public boolean acceptDrop(Object dragInfo) {
331c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen        final ItemInfo item = (ItemInfo) dragInfo;
332fb91f303f5e672f9b4c4f9f8a03486b224d60cd6Adam Cohen        return !mFolder.isDestroyed() && willAcceptItem(item);
33331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
33431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
335df0353815c629fc678824b07a234b89a1ff94208Adam Cohen    public void addItem(ShortcutInfo item) {
336df0353815c629fc678824b07a234b89a1ff94208Adam Cohen        mInfo.add(item);
337df0353815c629fc678824b07a234b89a1ff94208Adam Cohen    }
338df0353815c629fc678824b07a234b89a1ff94208Adam Cohen
339c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen    public void onDragEnter(Object dragInfo) {
340fb91f303f5e672f9b4c4f9f8a03486b224d60cd6Adam Cohen        if (mFolder.isDestroyed() || !willAcceptItem((ItemInfo) dragInfo)) return;
34169ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen        CellLayout.LayoutParams lp = (CellLayout.LayoutParams) getLayoutParams();
34269ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen        CellLayout layout = (CellLayout) getParent().getParent();
34369ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen        mFolderRingAnimator.setCell(lp.cellX, lp.cellY);
34469ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen        mFolderRingAnimator.setCellLayout(layout);
34519072da7441e07d5e90026d9e9e1b38f11245e44Adam Cohen        mFolderRingAnimator.animateToAcceptState();
34669ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen        layout.showFolderAccept(mFolderRingAnimator);
34755bd9725d5c0373b89f7b9bbd9547550ea3bbc63Jorim Jaggi        mOpenAlarm.setOnAlarmListener(mOnOpenListener);
348dedfca2aef7573624bdb421b1805ef5e04bee502Adam Cohen        if (SPRING_LOADING_ENABLED &&
349dedfca2aef7573624bdb421b1805ef5e04bee502Adam Cohen                ((dragInfo instanceof AppInfo) || (dragInfo instanceof ShortcutInfo))) {
350dedfca2aef7573624bdb421b1805ef5e04bee502Adam Cohen            // TODO: we currently don't support spring-loading for PendingAddShortcutInfos even
351dedfca2aef7573624bdb421b1805ef5e04bee502Adam Cohen            // though widget-style shortcuts can be added to folders. The issue is that we need
352dedfca2aef7573624bdb421b1805ef5e04bee502Adam Cohen            // to deal with configuration activities which are currently handled in
353dedfca2aef7573624bdb421b1805ef5e04bee502Adam Cohen            // Workspace#onDropExternal.
35455bd9725d5c0373b89f7b9bbd9547550ea3bbc63Jorim Jaggi            mOpenAlarm.setAlarm(ON_OPEN_DELAY);
35555bd9725d5c0373b89f7b9bbd9547550ea3bbc63Jorim Jaggi        }
35655bd9725d5c0373b89f7b9bbd9547550ea3bbc63Jorim Jaggi        mDragInfo = (ItemInfo) dragInfo;
357073a46ff635d089cbcb15d939d1de42dd2b86c97Adam Cohen    }
358073a46ff635d089cbcb15d939d1de42dd2b86c97Adam Cohen
359c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen    public void onDragOver(Object dragInfo) {
360073a46ff635d089cbcb15d939d1de42dd2b86c97Adam Cohen    }
361073a46ff635d089cbcb15d939d1de42dd2b86c97Adam Cohen
36255bd9725d5c0373b89f7b9bbd9547550ea3bbc63Jorim Jaggi    OnAlarmListener mOnOpenListener = new OnAlarmListener() {
36355bd9725d5c0373b89f7b9bbd9547550ea3bbc63Jorim Jaggi        public void onAlarm(Alarm alarm) {
36455bd9725d5c0373b89f7b9bbd9547550ea3bbc63Jorim Jaggi            ShortcutInfo item;
36555bd9725d5c0373b89f7b9bbd9547550ea3bbc63Jorim Jaggi            if (mDragInfo instanceof AppInfo) {
36655bd9725d5c0373b89f7b9bbd9547550ea3bbc63Jorim Jaggi                // Came from all apps -- make a copy.
36755bd9725d5c0373b89f7b9bbd9547550ea3bbc63Jorim Jaggi                item = ((AppInfo) mDragInfo).makeShortcut();
36855bd9725d5c0373b89f7b9bbd9547550ea3bbc63Jorim Jaggi                item.spanX = 1;
36955bd9725d5c0373b89f7b9bbd9547550ea3bbc63Jorim Jaggi                item.spanY = 1;
37055bd9725d5c0373b89f7b9bbd9547550ea3bbc63Jorim Jaggi            } else {
371dedfca2aef7573624bdb421b1805ef5e04bee502Adam Cohen                // ShortcutInfo
37255bd9725d5c0373b89f7b9bbd9547550ea3bbc63Jorim Jaggi                item = (ShortcutInfo) mDragInfo;
37355bd9725d5c0373b89f7b9bbd9547550ea3bbc63Jorim Jaggi            }
37455bd9725d5c0373b89f7b9bbd9547550ea3bbc63Jorim Jaggi            mFolder.beginExternalDrag(item);
37555bd9725d5c0373b89f7b9bbd9547550ea3bbc63Jorim Jaggi            mLauncher.openFolder(FolderIcon.this);
37655bd9725d5c0373b89f7b9bbd9547550ea3bbc63Jorim Jaggi        }
37755bd9725d5c0373b89f7b9bbd9547550ea3bbc63Jorim Jaggi    };
37855bd9725d5c0373b89f7b9bbd9547550ea3bbc63Jorim Jaggi
379d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen    public void performCreateAnimation(final ShortcutInfo destInfo, final View destView,
3807bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung            final ShortcutInfo srcInfo, final DragView srcView, Rect dstRect,
381ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen            float scaleRelativeToDragLayer, Runnable postAnimationRunnable) {
382d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen
383fb91f303f5e672f9b4c4f9f8a03486b224d60cd6Adam Cohen        // These correspond two the drawable and view that the icon was dropped _onto_
38495abbb330ce9bbaf23594245f0f8a795c8118038Sunny Goyal        Drawable animateDrawable = getTopDrawable((TextView) destView);
385fb91f303f5e672f9b4c4f9f8a03486b224d60cd6Adam Cohen        computePreviewDrawingParams(animateDrawable.getIntrinsicWidth(),
386fb91f303f5e672f9b4c4f9f8a03486b224d60cd6Adam Cohen                destView.getMeasuredWidth());
387fb91f303f5e672f9b4c4f9f8a03486b224d60cd6Adam Cohen
388fb91f303f5e672f9b4c4f9f8a03486b224d60cd6Adam Cohen        // This will animate the first item from it's position as an icon into its
389fb91f303f5e672f9b4c4f9f8a03486b224d60cd6Adam Cohen        // position as the first item in the preview
390fb91f303f5e672f9b4c4f9f8a03486b224d60cd6Adam Cohen        animateFirstItem(animateDrawable, INITIAL_ITEM_ANIMATION_DURATION, false, null);
391fb91f303f5e672f9b4c4f9f8a03486b224d60cd6Adam Cohen        addItem(destInfo);
392ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen
393d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        // This will animate the dragView (srcView) into the new folder
3947bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung        onDrop(srcInfo, srcView, dstRect, scaleRelativeToDragLayer, 1, postAnimationRunnable, null);
395fb91f303f5e672f9b4c4f9f8a03486b224d60cd6Adam Cohen    }
396fb91f303f5e672f9b4c4f9f8a03486b224d60cd6Adam Cohen
397fb91f303f5e672f9b4c4f9f8a03486b224d60cd6Adam Cohen    public void performDestroyAnimation(final View finalView, Runnable onCompleteRunnable) {
39895abbb330ce9bbaf23594245f0f8a795c8118038Sunny Goyal        Drawable animateDrawable = getTopDrawable((TextView) finalView);
39902dd7aea3d8ac94126a8f8069e6762592ea60326Jason Monk        computePreviewDrawingParams(animateDrawable.getIntrinsicWidth(),
400fb91f303f5e672f9b4c4f9f8a03486b224d60cd6Adam Cohen                finalView.getMeasuredWidth());
401d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen
402d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        // This will animate the first item from it's position as an icon into its
403d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        // position as the first item in the preview
404fb91f303f5e672f9b4c4f9f8a03486b224d60cd6Adam Cohen        animateFirstItem(animateDrawable, FINAL_ITEM_ANIMATION_DURATION, true,
405fb91f303f5e672f9b4c4f9f8a03486b224d60cd6Adam Cohen                onCompleteRunnable);
406d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen    }
407d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen
408c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen    public void onDragExit(Object dragInfo) {
409c6cc61d45836e4081920883cc4d448ccb0bb8417Adam Cohen        onDragExit();
410c6cc61d45836e4081920883cc4d448ccb0bb8417Adam Cohen    }
411c6cc61d45836e4081920883cc4d448ccb0bb8417Adam Cohen
412c6cc61d45836e4081920883cc4d448ccb0bb8417Adam Cohen    public void onDragExit() {
41319072da7441e07d5e90026d9e9e1b38f11245e44Adam Cohen        mFolderRingAnimator.animateToNaturalState();
41455bd9725d5c0373b89f7b9bbd9547550ea3bbc63Jorim Jaggi        mOpenAlarm.cancelAlarm();
415073a46ff635d089cbcb15d939d1de42dd2b86c97Adam Cohen    }
416073a46ff635d089cbcb15d939d1de42dd2b86c97Adam Cohen
4177bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung    private void onDrop(final ShortcutInfo item, DragView animateView, Rect finalRect,
4187bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung            float scaleRelativeToDragLayer, int index, Runnable postAnimationRunnable,
4197bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung            DragObject d) {
420d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        item.cellX = -1;
421d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        item.cellY = -1;
422d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen
423558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen        // Typically, the animateView corresponds to the DragView; however, if this is being done
424558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen        // after a configuration activity (ie. for a Shortcut being dragged from AllApps) we
425558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen        // will not have a view to animate
426558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen        if (animateView != null) {
427558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen            DragLayer dragLayer = mLauncher.getDragLayer();
428558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen            Rect from = new Rect();
429558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen            dragLayer.getViewRectRelativeToSelf(animateView, from);
430558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen            Rect to = finalRect;
431558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen            if (to == null) {
432558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen                to = new Rect();
433558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen                Workspace workspace = mLauncher.getWorkspace();
434558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen                // Set cellLayout and this to it's final state to compute final animation locations
435558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen                workspace.setFinalTransitionTransform((CellLayout) getParent().getParent());
436558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen                float scaleX = getScaleX();
437558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen                float scaleY = getScaleY();
438558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen                setScaleX(1.0f);
439558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen                setScaleY(1.0f);
440558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen                scaleRelativeToDragLayer = dragLayer.getDescendantRectRelativeToSelf(this, to);
441558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen                // Finished computing final animation locations, restore current state
442558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen                setScaleX(scaleX);
443558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen                setScaleY(scaleY);
444558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen                workspace.resetTransitionTransform((CellLayout) getParent().getParent());
445558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen            }
446ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen
447558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen            int[] center = new int[2];
448558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen            float scale = getLocalCenterForIndex(index, center);
449558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen            center[0] = (int) Math.round(scaleRelativeToDragLayer * center[0]);
450558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen            center[1] = (int) Math.round(scaleRelativeToDragLayer * center[1]);
451d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen
452558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen            to.offset(center[0] - animateView.getMeasuredWidth() / 2,
4535f8afe6280eae34620067696173e71943e1a30a3Winson Chung                      center[1] - animateView.getMeasuredHeight() / 2);
454d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen
455558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen            float finalAlpha = index < NUM_ITEMS_IN_PREVIEW ? 0.5f : 0f;
456558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen
457ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen            float finalScale = scale * scaleRelativeToDragLayer;
458558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen            dragLayer.animateView(animateView, from, to, finalAlpha,
459ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen                    1, 1, finalScale, finalScale, DROP_IN_ANIMATION_DURATION,
460558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen                    new DecelerateInterpolator(2), new AccelerateInterpolator(2),
461ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen                    postAnimationRunnable, DragLayer.ANIMATION_END_DISAPPEAR, null);
462fb91f303f5e672f9b4c4f9f8a03486b224d60cd6Adam Cohen            addItem(item);
463fb91f303f5e672f9b4c4f9f8a03486b224d60cd6Adam Cohen            mHiddenItems.add(item);
4647a8b82b5926e6a520df28e7f591b9a94ec605581Adam Cohen            mFolder.hideItem(item);
465558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen            postDelayed(new Runnable() {
466558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen                public void run() {
467fb91f303f5e672f9b4c4f9f8a03486b224d60cd6Adam Cohen                    mHiddenItems.remove(item);
4687a8b82b5926e6a520df28e7f591b9a94ec605581Adam Cohen                    mFolder.showItem(item);
469fb91f303f5e672f9b4c4f9f8a03486b224d60cd6Adam Cohen                    invalidate();
470558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen                }
471558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen            }, DROP_IN_ANIMATION_DURATION);
472558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen        } else {
473558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen            addItem(item);
474558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen        }
475d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen    }
476d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen
4773e8f811f31a2275e778244427271f77f4116c08bAdam Cohen    public void onDrop(DragObject d) {
478c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen        ShortcutInfo item;
479eadbfc564d84aaf1d800da3d0d6edf6312f89648Michael Jurka        if (d.dragInfo instanceof AppInfo) {
480c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen            // Came from all apps -- make a copy
481eadbfc564d84aaf1d800da3d0d6edf6312f89648Michael Jurka            item = ((AppInfo) d.dragInfo).makeShortcut();
482c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen        } else {
4833e8f811f31a2275e778244427271f77f4116c08bAdam Cohen            item = (ShortcutInfo) d.dragInfo;
484c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen        }
48567bd9ccf856840856944815a382e4bbb0e71e949Adam Cohen        mFolder.notifyDrop();
4867bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung        onDrop(item, d.dragView, null, 1.0f, mInfo.contents.size(), d.postAnimationRunnable, d);
487c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen    }
488c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen
489d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen    private void computePreviewDrawingParams(int drawableSize, int totalSize) {
490d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        if (mIntrinsicIconSize != drawableSize || mTotalWidth != totalSize) {
4915f8afe6280eae34620067696173e71943e1a30a3Winson Chung            LauncherAppState app = LauncherAppState.getInstance();
4925f8afe6280eae34620067696173e71943e1a30a3Winson Chung            DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
4935f8afe6280eae34620067696173e71943e1a30a3Winson Chung
494d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen            mIntrinsicIconSize = drawableSize;
495d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen            mTotalWidth = totalSize;
49676fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen
4975f8afe6280eae34620067696173e71943e1a30a3Winson Chung            final int previewSize = mPreviewBackground.getLayoutParams().height;
498d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen            final int previewPadding = FolderRingAnimator.sPreviewPadding;
499a9cf38f533d1e86269868f1e6a806ccffd4a78fcAdam Cohen
500d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen            mAvailableSpaceInPreview = (previewSize - 2 * previewPadding);
501d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen            // cos(45) = 0.707  + ~= 0.1) = 0.8f
502d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen            int adjustedAvailableSpace = (int) ((mAvailableSpaceInPreview / 2) * (1 + 0.8f));
503d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen
504d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen            int unscaledHeight = (int) (mIntrinsicIconSize * (1 + PERSPECTIVE_SHIFT_FACTOR));
50596bb79819ef9ddf2d1c0cb0b72c2c9f6db26b4fdAdam Cohen
506d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen            mBaselineIconScale = (1.0f * adjustedAvailableSpace / unscaledHeight);
507a9cf38f533d1e86269868f1e6a806ccffd4a78fcAdam Cohen
508d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen            mBaselineIconSize = (int) (mIntrinsicIconSize * mBaselineIconScale);
509d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen            mMaxPerspectiveShift = mBaselineIconSize * PERSPECTIVE_SHIFT_FACTOR;
510d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen
511d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen            mPreviewOffsetX = (mTotalWidth - mAvailableSpaceInPreview) / 2;
5125f8afe6280eae34620067696173e71943e1a30a3Winson Chung            mPreviewOffsetY = previewPadding + grid.folderBackgroundOffset;
513073a46ff635d089cbcb15d939d1de42dd2b86c97Adam Cohen        }
514d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen    }
51576fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen
516d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen    private void computePreviewDrawingParams(Drawable d) {
517d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        computePreviewDrawingParams(d.getIntrinsicWidth(), getMeasuredWidth());
518d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen    }
519073a46ff635d089cbcb15d939d1de42dd2b86c97Adam Cohen
520d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen    class PreviewItemDrawingParams {
521d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        PreviewItemDrawingParams(float transX, float transY, float scale, int overlayAlpha) {
522d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen            this.transX = transX;
523d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen            this.transY = transY;
524d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen            this.scale = scale;
525d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen            this.overlayAlpha = overlayAlpha;
526d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        }
527d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        float transX;
528d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        float transY;
529d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        float scale;
530d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        int overlayAlpha;
531d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        Drawable drawable;
532d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen    }
533badf71e11fba2d6efa1d1bcca9542001f90a3777Adam Cohen
534ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen    private float getLocalCenterForIndex(int index, int[] center) {
535d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        mParams = computePreviewItemDrawingParams(Math.min(NUM_ITEMS_IN_PREVIEW, index), mParams);
536a9cf38f533d1e86269868f1e6a806ccffd4a78fcAdam Cohen
537d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        mParams.transX += mPreviewOffsetX;
538d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        mParams.transY += mPreviewOffsetY;
539ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen        float offsetX = mParams.transX + (mParams.scale * mIntrinsicIconSize) / 2;
540ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen        float offsetY = mParams.transY + (mParams.scale * mIntrinsicIconSize) / 2;
541badf71e11fba2d6efa1d1bcca9542001f90a3777Adam Cohen
542ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen        center[0] = (int) Math.round(offsetX);
543ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen        center[1] = (int) Math.round(offsetY);
544d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        return mParams.scale;
545d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen    }
546badf71e11fba2d6efa1d1bcca9542001f90a3777Adam Cohen
547d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen    private PreviewItemDrawingParams computePreviewItemDrawingParams(int index,
548d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen            PreviewItemDrawingParams params) {
549d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        index = NUM_ITEMS_IN_PREVIEW - index - 1;
550d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        float r = (index * 1.0f) / (NUM_ITEMS_IN_PREVIEW - 1);
551d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        float scale = (1 - PERSPECTIVE_SCALE_FACTOR * (1 - r));
552d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen
553d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        float offset = (1 - r) * mMaxPerspectiveShift;
554d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        float scaledSize = scale * mBaselineIconSize;
555d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        float scaleOffsetCorrection = (1 - scale) * mBaselineIconSize;
556d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen
557d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        // We want to imagine our coordinates from the bottom left, growing up and to the
558d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        // right. This is natural for the x-axis, but for the y-axis, we have to invert things.
5595f8afe6280eae34620067696173e71943e1a30a3Winson Chung        float transY = mAvailableSpaceInPreview - (offset + scaledSize + scaleOffsetCorrection) + getPaddingTop();
56096bb79819ef9ddf2d1c0cb0b72c2c9f6db26b4fdAdam Cohen        float transX = (mAvailableSpaceInPreview - scaledSize) / 2;
561d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        float totalScale = mBaselineIconScale * scale;
562d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        final int overlayAlpha = (int) (80 * (1 - r));
563d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen
564d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        if (params == null) {
565d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen            params = new PreviewItemDrawingParams(transX, transY, totalScale, overlayAlpha);
566d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        } else {
567d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen            params.transX = transX;
568d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen            params.transY = transY;
569d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen            params.scale = totalScale;
570d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen            params.overlayAlpha = overlayAlpha;
571d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        }
572d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        return params;
573d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen    }
574badf71e11fba2d6efa1d1bcca9542001f90a3777Adam Cohen
575d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen    private void drawPreviewItem(Canvas canvas, PreviewItemDrawingParams params) {
576d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        canvas.save();
577d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        canvas.translate(params.transX + mPreviewOffsetX, params.transY + mPreviewOffsetY);
578d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        canvas.scale(params.scale, params.scale);
579d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        Drawable d = params.drawable;
580d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen
581d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        if (d != null) {
582d4e53c882494f8cd7e4c0d44dbfc300d3610afcfWinson Chung            mOldBounds.set(d.getBounds());
583d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen            d.setBounds(0, 0, mIntrinsicIconSize, mIntrinsicIconSize);
584c5c60ad3592f53549c9ffaa58e9a87b0480080e8Sunny Goyal            if (d instanceof FastBitmapDrawable) {
585c5c60ad3592f53549c9ffaa58e9a87b0480080e8Sunny Goyal                FastBitmapDrawable fd = (FastBitmapDrawable) d;
586508da15509224b46fcccabbe78f3e92fe69a67d8Sunny Goyal                int oldBrightness = fd.getBrightness();
587508da15509224b46fcccabbe78f3e92fe69a67d8Sunny Goyal                fd.setBrightness(params.overlayAlpha);
588c5c60ad3592f53549c9ffaa58e9a87b0480080e8Sunny Goyal                d.draw(canvas);
589508da15509224b46fcccabbe78f3e92fe69a67d8Sunny Goyal                fd.setBrightness(oldBrightness);
590c5c60ad3592f53549c9ffaa58e9a87b0480080e8Sunny Goyal            } else {
591c5c60ad3592f53549c9ffaa58e9a87b0480080e8Sunny Goyal                d.setColorFilter(Color.argb(params.overlayAlpha, 255, 255, 255),
592c5c60ad3592f53549c9ffaa58e9a87b0480080e8Sunny Goyal                        PorterDuff.Mode.SRC_ATOP);
593c5c60ad3592f53549c9ffaa58e9a87b0480080e8Sunny Goyal                d.draw(canvas);
594c5c60ad3592f53549c9ffaa58e9a87b0480080e8Sunny Goyal                d.clearColorFilter();
595c5c60ad3592f53549c9ffaa58e9a87b0480080e8Sunny Goyal            }
596d4e53c882494f8cd7e4c0d44dbfc300d3610afcfWinson Chung            d.setBounds(mOldBounds);
597d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        }
598d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        canvas.restore();
599d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen    }
60076fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen
601d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen    @Override
602d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen    protected void dispatchDraw(Canvas canvas) {
603d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        super.dispatchDraw(canvas);
604badf71e11fba2d6efa1d1bcca9542001f90a3777Adam Cohen
605d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        if (mFolder == null) return;
606d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        if (mFolder.getItemCount() == 0 && !mAnimating) return;
607d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen
6087a8b82b5926e6a520df28e7f591b9a94ec605581Adam Cohen        ArrayList<View> items = mFolder.getItemsInReadingOrder();
609d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        Drawable d;
610d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        TextView v;
611d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen
612d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        // Update our drawing parameters if necessary
613d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        if (mAnimating) {
614d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen            computePreviewDrawingParams(mAnimParams.drawable);
615d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        } else {
616d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen            v = (TextView) items.get(0);
6173484638cad97e255a412b0489a63873fb3ca4218Sunny Goyal            d = getTopDrawable(v);
618d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen            computePreviewDrawingParams(d);
619d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        }
620a9cf38f533d1e86269868f1e6a806ccffd4a78fcAdam Cohen
621d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        int nItemsInPreview = Math.min(items.size(), NUM_ITEMS_IN_PREVIEW);
622d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        if (!mAnimating) {
623d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen            for (int i = nItemsInPreview - 1; i >= 0; i--) {
624d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen                v = (TextView) items.get(i);
625fb91f303f5e672f9b4c4f9f8a03486b224d60cd6Adam Cohen                if (!mHiddenItems.contains(v.getTag())) {
6263484638cad97e255a412b0489a63873fb3ca4218Sunny Goyal                    d = getTopDrawable(v);
627fb91f303f5e672f9b4c4f9f8a03486b224d60cd6Adam Cohen                    mParams = computePreviewItemDrawingParams(i, mParams);
628fb91f303f5e672f9b4c4f9f8a03486b224d60cd6Adam Cohen                    mParams.drawable = d;
629fb91f303f5e672f9b4c4f9f8a03486b224d60cd6Adam Cohen                    drawPreviewItem(canvas, mParams);
630fb91f303f5e672f9b4c4f9f8a03486b224d60cd6Adam Cohen                }
631a9cf38f533d1e86269868f1e6a806ccffd4a78fcAdam Cohen            }
632d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        } else {
633d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen            drawPreviewItem(canvas, mAnimParams);
634a9cf38f533d1e86269868f1e6a806ccffd4a78fcAdam Cohen        }
635d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen    }
636d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen
6373484638cad97e255a412b0489a63873fb3ca4218Sunny Goyal    private Drawable getTopDrawable(TextView v) {
6383484638cad97e255a412b0489a63873fb3ca4218Sunny Goyal        Drawable d = v.getCompoundDrawables()[1];
6393484638cad97e255a412b0489a63873fb3ca4218Sunny Goyal        return (d instanceof PreloadIconDrawable) ? ((PreloadIconDrawable) d).mIcon : d;
6403484638cad97e255a412b0489a63873fb3ca4218Sunny Goyal    }
6413484638cad97e255a412b0489a63873fb3ca4218Sunny Goyal
642fb91f303f5e672f9b4c4f9f8a03486b224d60cd6Adam Cohen    private void animateFirstItem(final Drawable d, int duration, final boolean reverse,
643fb91f303f5e672f9b4c4f9f8a03486b224d60cd6Adam Cohen            final Runnable onCompleteRunnable) {
644d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        final PreviewItemDrawingParams finalParams = computePreviewItemDrawingParams(0, null);
645d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen
646d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        final float scale0 = 1.0f;
6471d4ee4e46218fb98a43cf584d8d4e3e569850f78Adam Cohen        final float transX0 = (mAvailableSpaceInPreview - d.getIntrinsicWidth()) / 2;
6485f8afe6280eae34620067696173e71943e1a30a3Winson Chung        final float transY0 = (mAvailableSpaceInPreview - d.getIntrinsicHeight()) / 2 + getPaddingTop();
649d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        mAnimParams.drawable = d;
650d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen
651f1ad608c28c79c8e9b83d83ce9154f1b7284f412Michael Jurka        ValueAnimator va = LauncherAnimUtils.ofFloat(this, 0f, 1.0f);
652d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        va.addUpdateListener(new AnimatorUpdateListener(){
653d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen            public void onAnimationUpdate(ValueAnimator animation) {
654d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen                float progress = (Float) animation.getAnimatedValue();
655fb91f303f5e672f9b4c4f9f8a03486b224d60cd6Adam Cohen                if (reverse) {
656fb91f303f5e672f9b4c4f9f8a03486b224d60cd6Adam Cohen                    progress = 1 - progress;
657fb91f303f5e672f9b4c4f9f8a03486b224d60cd6Adam Cohen                    mPreviewBackground.setAlpha(progress);
658fb91f303f5e672f9b4c4f9f8a03486b224d60cd6Adam Cohen                }
659d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen
660d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen                mAnimParams.transX = transX0 + progress * (finalParams.transX - transX0);
661d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen                mAnimParams.transY = transY0 + progress * (finalParams.transY - transY0);
662d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen                mAnimParams.scale = scale0 + progress * (finalParams.scale - scale0);
663d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen                invalidate();
664d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen            }
665d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        });
666d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        va.addListener(new AnimatorListenerAdapter() {
667d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen            @Override
668d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen            public void onAnimationStart(Animator animation) {
669d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen                mAnimating = true;
670d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen            }
671d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen            @Override
672d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen            public void onAnimationEnd(Animator animation) {
673d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen                mAnimating = false;
674fb91f303f5e672f9b4c4f9f8a03486b224d60cd6Adam Cohen                if (onCompleteRunnable != null) {
675fb91f303f5e672f9b4c4f9f8a03486b224d60cd6Adam Cohen                    onCompleteRunnable.run();
676fb91f303f5e672f9b4c4f9f8a03486b224d60cd6Adam Cohen                }
677d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen            }
678d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        });
679d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        va.setDuration(duration);
680d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        va.start();
681a9cf38f533d1e86269868f1e6a806ccffd4a78fcAdam Cohen    }
682a9cf38f533d1e86269868f1e6a806ccffd4a78fcAdam Cohen
683099f60d51f6310e1290687e83958e665b3324504Adam Cohen    public void setTextVisible(boolean visible) {
684099f60d51f6310e1290687e83958e665b3324504Adam Cohen        if (visible) {
685099f60d51f6310e1290687e83958e665b3324504Adam Cohen            mFolderName.setVisibility(VISIBLE);
686099f60d51f6310e1290687e83958e665b3324504Adam Cohen        } else {
687099f60d51f6310e1290687e83958e665b3324504Adam Cohen            mFolderName.setVisibility(INVISIBLE);
688099f60d51f6310e1290687e83958e665b3324504Adam Cohen        }
689099f60d51f6310e1290687e83958e665b3324504Adam Cohen    }
690099f60d51f6310e1290687e83958e665b3324504Adam Cohen
691099f60d51f6310e1290687e83958e665b3324504Adam Cohen    public boolean getTextVisible() {
692099f60d51f6310e1290687e83958e665b3324504Adam Cohen        return mFolderName.getVisibility() == VISIBLE;
693099f60d51f6310e1290687e83958e665b3324504Adam Cohen    }
694099f60d51f6310e1290687e83958e665b3324504Adam Cohen
69576078c4ef35b6e95fb6d8129a32cf52a36625e28Adam Cohen    public void onItemsChanged() {
69676078c4ef35b6e95fb6d8129a32cf52a36625e28Adam Cohen        invalidate();
69776078c4ef35b6e95fb6d8129a32cf52a36625e28Adam Cohen        requestLayout();
69876078c4ef35b6e95fb6d8129a32cf52a36625e28Adam Cohen    }
69976078c4ef35b6e95fb6d8129a32cf52a36625e28Adam Cohen
700a9cf38f533d1e86269868f1e6a806ccffd4a78fcAdam Cohen    public void onAdd(ShortcutInfo item) {
701a9cf38f533d1e86269868f1e6a806ccffd4a78fcAdam Cohen        invalidate();
702a9cf38f533d1e86269868f1e6a806ccffd4a78fcAdam Cohen        requestLayout();
703a9cf38f533d1e86269868f1e6a806ccffd4a78fcAdam Cohen    }
704a9cf38f533d1e86269868f1e6a806ccffd4a78fcAdam Cohen
705a9cf38f533d1e86269868f1e6a806ccffd4a78fcAdam Cohen    public void onRemove(ShortcutInfo item) {
706a9cf38f533d1e86269868f1e6a806ccffd4a78fcAdam Cohen        invalidate();
707a9cf38f533d1e86269868f1e6a806ccffd4a78fcAdam Cohen        requestLayout();
708a9cf38f533d1e86269868f1e6a806ccffd4a78fcAdam Cohen    }
70976fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen
71076fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen    public void onTitleChanged(CharSequence title) {
711d63cfa96814fa1a51490950b8df9853eef305cbbAdam Cohen        mFolderName.setText(title.toString());
7128b805b17158886035b38261eb611d8641701ae43Michael Jurka        setContentDescription(String.format(getContext().getString(R.string.folder_name_format),
7133371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                title));
71476fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen    }
71588f334571fe41df620ba903ced9b2c69b0170d5cWinson Chung
71688f334571fe41df620ba903ced9b2c69b0170d5cWinson Chung    @Override
71788f334571fe41df620ba903ced9b2c69b0170d5cWinson Chung    public boolean onTouchEvent(MotionEvent event) {
71888f334571fe41df620ba903ced9b2c69b0170d5cWinson Chung        // Call the superclass onTouchEvent first, because sometimes it changes the state to
71988f334571fe41df620ba903ced9b2c69b0170d5cWinson Chung        // isPressed() on an ACTION_UP
72088f334571fe41df620ba903ced9b2c69b0170d5cWinson Chung        boolean result = super.onTouchEvent(event);
72188f334571fe41df620ba903ced9b2c69b0170d5cWinson Chung
72288f334571fe41df620ba903ced9b2c69b0170d5cWinson Chung        switch (event.getAction()) {
72388f334571fe41df620ba903ced9b2c69b0170d5cWinson Chung            case MotionEvent.ACTION_DOWN:
72488f334571fe41df620ba903ced9b2c69b0170d5cWinson Chung                mLongPressHelper.postCheckForLongPress();
72588f334571fe41df620ba903ced9b2c69b0170d5cWinson Chung                break;
72688f334571fe41df620ba903ced9b2c69b0170d5cWinson Chung            case MotionEvent.ACTION_CANCEL:
72788f334571fe41df620ba903ced9b2c69b0170d5cWinson Chung            case MotionEvent.ACTION_UP:
72888f334571fe41df620ba903ced9b2c69b0170d5cWinson Chung                mLongPressHelper.cancelLongPress();
72988f334571fe41df620ba903ced9b2c69b0170d5cWinson Chung                break;
73002dd7aea3d8ac94126a8f8069e6762592ea60326Jason Monk            case MotionEvent.ACTION_MOVE:
73102dd7aea3d8ac94126a8f8069e6762592ea60326Jason Monk                if (!Utilities.pointInView(this, event.getX(), event.getY(), mSlop)) {
73202dd7aea3d8ac94126a8f8069e6762592ea60326Jason Monk                    mLongPressHelper.cancelLongPress();
73302dd7aea3d8ac94126a8f8069e6762592ea60326Jason Monk                }
73402dd7aea3d8ac94126a8f8069e6762592ea60326Jason Monk                break;
73588f334571fe41df620ba903ced9b2c69b0170d5cWinson Chung        }
73688f334571fe41df620ba903ced9b2c69b0170d5cWinson Chung        return result;
73788f334571fe41df620ba903ced9b2c69b0170d5cWinson Chung    }
73888f334571fe41df620ba903ced9b2c69b0170d5cWinson Chung
73988f334571fe41df620ba903ced9b2c69b0170d5cWinson Chung    @Override
74002dd7aea3d8ac94126a8f8069e6762592ea60326Jason Monk    protected void onAttachedToWindow() {
74102dd7aea3d8ac94126a8f8069e6762592ea60326Jason Monk        super.onAttachedToWindow();
74202dd7aea3d8ac94126a8f8069e6762592ea60326Jason Monk        mSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
74302dd7aea3d8ac94126a8f8069e6762592ea60326Jason Monk    }
74402dd7aea3d8ac94126a8f8069e6762592ea60326Jason Monk
74502dd7aea3d8ac94126a8f8069e6762592ea60326Jason Monk    @Override
74688f334571fe41df620ba903ced9b2c69b0170d5cWinson Chung    public void cancelLongPress() {
74788f334571fe41df620ba903ced9b2c69b0170d5cWinson Chung        super.cancelLongPress();
74888f334571fe41df620ba903ced9b2c69b0170d5cWinson Chung
74988f334571fe41df620ba903ced9b2c69b0170d5cWinson Chung        mLongPressHelper.cancelLongPress();
75088f334571fe41df620ba903ced9b2c69b0170d5cWinson Chung    }
75131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project}
752