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
17261194387beebaa7927ec4e310274218b651494dSunny Goyalpackage com.android.launcher3.folder;
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;
24a9cf38f533d1e86269868f1e6a806ccffd4a78fcAdam Cohenimport android.graphics.Canvas;
25f4b08913677e18a8412930972237b91d5a946d95Adam Cohenimport android.graphics.Color;
26efca0279eb927faebffc38c8382818df67fcd159Adam Cohenimport android.graphics.Paint;
27119e8982ab6a0cf00e31e8744f27b72ba8bf7b20Adam Cohenimport android.graphics.Path;
28badf71e11fba2d6efa1d1bcca9542001f90a3777Adam Cohenimport android.graphics.PorterDuff;
293e8f811f31a2275e778244427271f77f4116c08bAdam Cohenimport android.graphics.Rect;
30efca0279eb927faebffc38c8382818df67fcd159Adam Cohenimport android.graphics.Region;
3131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.graphics.drawable.Drawable;
32099f60d51f6310e1290687e83958e665b3324504Adam Cohenimport android.os.Parcelable;
3331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.util.AttributeSet;
34efca0279eb927faebffc38c8382818df67fcd159Adam Cohenimport android.util.DisplayMetrics;
3531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.view.LayoutInflater;
3688f334571fe41df620ba903ced9b2c69b0170d5cWinson Chungimport android.view.MotionEvent;
377c6932140dcbd2db88d7a809ba72ee04abb5bf26Adam Cohenimport android.view.View;
3802dd7aea3d8ac94126a8f8069e6762592ea60326Jason Monkimport android.view.ViewConfiguration;
3931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.view.ViewGroup;
403e8f811f31a2275e778244427271f77f4116c08bAdam Cohenimport android.view.animation.AccelerateInterpolator;
413e8f811f31a2275e778244427271f77f4116c08bAdam Cohenimport android.view.animation.DecelerateInterpolator;
426e1c0d34bb31cacc24c57c89ab01deaa8985814fWinson Chungimport android.widget.FrameLayout;
43a9cf38f533d1e86269868f1e6a806ccffd4a78fcAdam Cohenimport android.widget.TextView;
4431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
45261194387beebaa7927ec4e310274218b651494dSunny Goyalimport com.android.launcher3.Alarm;
46261194387beebaa7927ec4e310274218b651494dSunny Goyalimport com.android.launcher3.AppInfo;
47261194387beebaa7927ec4e310274218b651494dSunny Goyalimport com.android.launcher3.BubbleTextView;
48261194387beebaa7927ec4e310274218b651494dSunny Goyalimport com.android.launcher3.CellLayout;
49261194387beebaa7927ec4e310274218b651494dSunny Goyalimport com.android.launcher3.CheckLongPressHelper;
50261194387beebaa7927ec4e310274218b651494dSunny Goyalimport com.android.launcher3.DeviceProfile;
51325dc23624160689e59fbac708cf6f222b20d025Daniel Sandlerimport com.android.launcher3.DropTarget.DragObject;
52261194387beebaa7927ec4e310274218b651494dSunny Goyalimport com.android.launcher3.FastBitmapDrawable;
53261194387beebaa7927ec4e310274218b651494dSunny Goyalimport com.android.launcher3.FolderInfo;
54325dc23624160689e59fbac708cf6f222b20d025Daniel Sandlerimport com.android.launcher3.FolderInfo.FolderListener;
55261194387beebaa7927ec4e310274218b651494dSunny Goyalimport com.android.launcher3.IconCache;
56261194387beebaa7927ec4e310274218b651494dSunny Goyalimport com.android.launcher3.ItemInfo;
57261194387beebaa7927ec4e310274218b651494dSunny Goyalimport com.android.launcher3.Launcher;
58261194387beebaa7927ec4e310274218b651494dSunny Goyalimport com.android.launcher3.LauncherAnimUtils;
59261194387beebaa7927ec4e310274218b651494dSunny Goyalimport com.android.launcher3.LauncherAppState;
60261194387beebaa7927ec4e310274218b651494dSunny Goyalimport com.android.launcher3.LauncherSettings;
61261194387beebaa7927ec4e310274218b651494dSunny Goyalimport com.android.launcher3.OnAlarmListener;
62261194387beebaa7927ec4e310274218b651494dSunny Goyalimport com.android.launcher3.PreloadIconDrawable;
63261194387beebaa7927ec4e310274218b651494dSunny Goyalimport com.android.launcher3.R;
64261194387beebaa7927ec4e310274218b651494dSunny Goyalimport com.android.launcher3.ShortcutInfo;
65261194387beebaa7927ec4e310274218b651494dSunny Goyalimport com.android.launcher3.SimpleOnStylusPressListener;
66261194387beebaa7927ec4e310274218b651494dSunny Goyalimport com.android.launcher3.StylusEventHelper;
67261194387beebaa7927ec4e310274218b651494dSunny Goyalimport com.android.launcher3.Utilities;
68261194387beebaa7927ec4e310274218b651494dSunny Goyalimport com.android.launcher3.Workspace;
69119e8982ab6a0cf00e31e8744f27b72ba8bf7b20Adam Cohenimport com.android.launcher3.config.FeatureFlags;
70fedca43d396d6fd7c46fbb2f37dfa7cfe3b31834Vadim Tryshevimport com.android.launcher3.dragndrop.DragLayer;
71fedca43d396d6fd7c46fbb2f37dfa7cfe3b31834Vadim Tryshevimport com.android.launcher3.dragndrop.DragView;
72091440a9cb9d4f42406631004aa484cbb79214caAdam Cohenimport com.android.launcher3.util.Thunk;
73edcce099c98a6c40d10109ac092ab50f9d2668f3Romain Guy
74c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohenimport java.util.ArrayList;
75c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen
7631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project/**
77f9c184a619e4e4b82cf9e0bf318ca6d8deaaaee7Adam Cohen * An icon that can appear on in the workspace representing an {@link Folder}.
7831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project */
796e1c0d34bb31cacc24c57c89ab01deaa8985814fWinson Chungpublic class FolderIcon extends FrameLayout implements FolderListener {
80efca0279eb927faebffc38c8382818df67fcd159Adam Cohen    @Thunk Launcher mLauncher;
81091440a9cb9d4f42406631004aa484cbb79214caAdam Cohen    @Thunk Folder mFolder;
82fb91f303f5e672f9b4c4f9f8a03486b224d60cd6Adam Cohen    private FolderInfo mInfo;
83091440a9cb9d4f42406631004aa484cbb79214caAdam Cohen    @Thunk static boolean sStaticValuesDirty = true;
84a9cf38f533d1e86269868f1e6a806ccffd4a78fcAdam Cohen
85efca0279eb927faebffc38c8382818df67fcd159Adam Cohen    public static final int NUM_ITEMS_IN_PREVIEW = FeatureFlags.LAUNCHER3_LEGACY_FOLDER_ICON ?
86efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            StackFolderIconLayoutRule.MAX_NUM_ITEMS_IN_PREVIEW :
87efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            ClippedFolderIconLayoutRule.MAX_NUM_ITEMS_IN_PREVIEW;
88f9c184a619e4e4b82cf9e0bf318ca6d8deaaaee7Adam Cohen
8988f334571fe41df620ba903ced9b2c69b0170d5cWinson Chung    private CheckLongPressHelper mLongPressHelper;
90ef044dd380ac3abf354027750efdc16d5d48ac70Mady Mellor    private StylusEventHelper mStylusEventHelper;
9188f334571fe41df620ba903ced9b2c69b0170d5cWinson Chung
92badf71e11fba2d6efa1d1bcca9542001f90a3777Adam Cohen    // The number of icons to display in the
93f4b08913677e18a8412930972237b91d5a946d95Adam Cohen    private static final int CONSUMPTION_ANIMATION_DURATION = 100;
94d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen    private static final int DROP_IN_ANIMATION_DURATION = 400;
958dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen    private static final int INITIAL_ITEM_ANIMATION_DURATION = 350;
96fb91f303f5e672f9b4c4f9f8a03486b224d60cd6Adam Cohen    private static final int FINAL_ITEM_ANIMATION_DURATION = 200;
97badf71e11fba2d6efa1d1bcca9542001f90a3777Adam Cohen
9855bd9725d5c0373b89f7b9bbd9547550ea3bbc63Jorim Jaggi    // Flag whether the folder should open itself when an item is dragged over is enabled.
9955bd9725d5c0373b89f7b9bbd9547550ea3bbc63Jorim Jaggi    public static final boolean SPRING_LOADING_ENABLED = true;
10055bd9725d5c0373b89f7b9bbd9547550ea3bbc63Jorim Jaggi
10155bd9725d5c0373b89f7b9bbd9547550ea3bbc63Jorim Jaggi    // Delay when drag enters until the folder opens, in miliseconds.
10255bd9725d5c0373b89f7b9bbd9547550ea3bbc63Jorim Jaggi    private static final int ON_OPEN_DELAY = 800;
10355bd9725d5c0373b89f7b9bbd9547550ea3bbc63Jorim Jaggi
104efca0279eb927faebffc38c8382818df67fcd159Adam Cohen    @Thunk BubbleTextView mFolderName;
1052801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen
106d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen    // These variables are all associated with the drawing of the preview; they are stored
107d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen    // as member variables for shared usage and to avoid computation on each frame
108aa2542a461072a57058ce45946ff6f5552ecce8aAdam Cohen    private int mIntrinsicIconSize = -1;
109aa2542a461072a57058ce45946ff6f5552ecce8aAdam Cohen    private int mTotalWidth = -1;
110aa2542a461072a57058ce45946ff6f5552ecce8aAdam Cohen    private int mPrevTopPadding = -1;
111aa2542a461072a57058ce45946ff6f5552ecce8aAdam Cohen
112efca0279eb927faebffc38c8382818df67fcd159Adam Cohen    PreviewBackground mBackground = new PreviewBackground();
113f9c184a619e4e4b82cf9e0bf318ca6d8deaaaee7Adam Cohen
114f9c184a619e4e4b82cf9e0bf318ca6d8deaaaee7Adam Cohen    private PreviewLayoutRule mPreviewLayoutRule;
115f9c184a619e4e4b82cf9e0bf318ca6d8deaaaee7Adam Cohen
116d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen    boolean mAnimating = false;
117d4e53c882494f8cd7e4c0d44dbfc300d3610afcfWinson Chung    private Rect mOldBounds = new Rect();
118fb91f303f5e672f9b4c4f9f8a03486b224d60cd6Adam Cohen
11902dd7aea3d8ac94126a8f8069e6762592ea60326Jason Monk    private float mSlop;
12002dd7aea3d8ac94126a8f8069e6762592ea60326Jason Monk
1214f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen    private PreviewItemDrawingParams mTmpParams = new PreviewItemDrawingParams(0, 0, 0, 0);
1224f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen    private ArrayList<PreviewItemDrawingParams> mDrawingParams = new ArrayList<PreviewItemDrawingParams>();
1234f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen    private Drawable mReferenceDrawable = null;
124d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen
125efca0279eb927faebffc38c8382818df67fcd159Adam Cohen    Paint mBgPaint = new Paint();
126efca0279eb927faebffc38c8382818df67fcd159Adam Cohen
12755bd9725d5c0373b89f7b9bbd9547550ea3bbc63Jorim Jaggi    private Alarm mOpenAlarm = new Alarm();
12855bd9725d5c0373b89f7b9bbd9547550ea3bbc63Jorim Jaggi
12931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    public FolderIcon(Context context, AttributeSet attrs) {
13031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        super(context, attrs);
13188f334571fe41df620ba903ced9b2c69b0170d5cWinson Chung        init();
13231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
13331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
13431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    public FolderIcon(Context context) {
13531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        super(context);
13688f334571fe41df620ba903ced9b2c69b0170d5cWinson Chung        init();
13788f334571fe41df620ba903ced9b2c69b0170d5cWinson Chung    }
13888f334571fe41df620ba903ced9b2c69b0170d5cWinson Chung
13988f334571fe41df620ba903ced9b2c69b0170d5cWinson Chung    private void init() {
14088f334571fe41df620ba903ced9b2c69b0170d5cWinson Chung        mLongPressHelper = new CheckLongPressHelper(this);
141bb83520a620919a8f19472ba4426585d007d1abaMady Mellor        mStylusEventHelper = new StylusEventHelper(new SimpleOnStylusPressListener(this), this);
142efca0279eb927faebffc38c8382818df67fcd159Adam Cohen        mPreviewLayoutRule = FeatureFlags.LAUNCHER3_LEGACY_FOLDER_ICON ?
143efca0279eb927faebffc38c8382818df67fcd159Adam Cohen                new StackFolderIconLayoutRule() :
144efca0279eb927faebffc38c8382818df67fcd159Adam Cohen                new ClippedFolderIconLayoutRule();
1450280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    }
1460280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka
147f9c184a619e4e4b82cf9e0bf318ca6d8deaaaee7Adam Cohen    public static FolderIcon fromXml(int resId, Launcher launcher, ViewGroup group,
148df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen            FolderInfo folderInfo, IconCache iconCache) {
1493a9fcedbcd235372cd2ab64f825a0b5b3937f59eMichael Jurka        @SuppressWarnings("all") // suppress dead code warning
1503a9fcedbcd235372cd2ab64f825a0b5b3937f59eMichael Jurka        final boolean error = INITIAL_ITEM_ANIMATION_DURATION >= DROP_IN_ANIMATION_DURATION;
1513a9fcedbcd235372cd2ab64f825a0b5b3937f59eMichael Jurka        if (error) {
152d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen            throw new IllegalStateException("DROP_IN_ANIMATION_DURATION must be greater than " +
153d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen                    "INITIAL_ITEM_ANIMATION_DURATION, as sequencing of adding first two items " +
154d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen                    "is dependent on this");
155d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        }
1562e6da1539bc7286336b3c24d96ab76434939ce4dAdam Cohen
1572e6da1539bc7286336b3c24d96ab76434939ce4dAdam Cohen        DeviceProfile grid = launcher.getDeviceProfile();
15831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        FolderIcon icon = (FolderIcon) LayoutInflater.from(launcher).inflate(resId, group, false);
159efca0279eb927faebffc38c8382818df67fcd159Adam Cohen
160efca0279eb927faebffc38c8382818df67fcd159Adam Cohen        // For performance and compatibility reasons we render the preview using a software layer.
161efca0279eb927faebffc38c8382818df67fcd159Adam Cohen        // In particular, hardware path clipping has spotty ecosystem support and bad performance.
162efca0279eb927faebffc38c8382818df67fcd159Adam Cohen        // Software rendering also allows us to use shadow layers.
163efca0279eb927faebffc38c8382818df67fcd159Adam Cohen        icon.setLayerType(LAYER_TYPE_SOFTWARE, new Paint(Paint.FILTER_BITMAP_FLAG));
164efca0279eb927faebffc38c8382818df67fcd159Adam Cohen
1655f8afe6280eae34620067696173e71943e1a30a3Winson Chung        icon.setClipToPadding(false);
166d2eca6b66e654e71fb46ae718910af3ec6c2cf9cAdam Cohen        icon.mFolderName = (BubbleTextView) icon.findViewById(R.id.folder_icon_name);
16776fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen        icon.mFolderName.setText(folderInfo.title);
1686e1c0d34bb31cacc24c57c89ab01deaa8985814fWinson Chung        icon.mFolderName.setCompoundDrawablePadding(0);
1696e1c0d34bb31cacc24c57c89ab01deaa8985814fWinson Chung        FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) icon.mFolderName.getLayoutParams();
1706e1c0d34bb31cacc24c57c89ab01deaa8985814fWinson Chung        lp.topMargin = grid.iconSizePx + grid.iconDrawablePaddingPx;
1716e1c0d34bb31cacc24c57c89ab01deaa8985814fWinson Chung
17231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        icon.setTag(folderInfo);
17331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        icon.setOnClickListener(launcher);
17431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        icon.mInfo = folderInfo;
17531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        icon.mLauncher = launcher;
176f4f89ef608245d39bbddda05f291361d2ae06667Sunny Goyal        icon.setContentDescription(launcher.getString(R.string.folder_name_format, folderInfo.title));
177a9cf38f533d1e86269868f1e6a806ccffd4a78fcAdam Cohen        Folder folder = Folder.fromXml(launcher);
178a9cf38f533d1e86269868f1e6a806ccffd4a78fcAdam Cohen        folder.setDragController(launcher.getDragController());
1792801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen        folder.setFolderIcon(icon);
180a9cf38f533d1e86269868f1e6a806ccffd4a78fcAdam Cohen        folder.bind(folderInfo);
1814f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen        icon.setFolder(folder);
182ae50284e0a838139c67caf0064a0977c871497faSunny Goyal        icon.setAccessibilityDelegate(launcher.getAccessibilityDelegate());
183e48644a6cc3024399ee2c9509d42ef6c2770ef61Sunny Goyal
18490cb3e51af988d526912aed7a532745d729a844cSunny Goyal        folderInfo.addListener(icon);
18590cb3e51af988d526912aed7a532745d729a844cSunny Goyal
18690cb3e51af988d526912aed7a532745d729a844cSunny Goyal        icon.setOnFocusChangeListener(launcher.mFocusHandler);
18719072da7441e07d5e90026d9e9e1b38f11245e44Adam Cohen        return icon;
18819072da7441e07d5e90026d9e9e1b38f11245e44Adam Cohen    }
18919072da7441e07d5e90026d9e9e1b38f11245e44Adam Cohen
190099f60d51f6310e1290687e83958e665b3324504Adam Cohen    @Override
191099f60d51f6310e1290687e83958e665b3324504Adam Cohen    protected Parcelable onSaveInstanceState() {
192099f60d51f6310e1290687e83958e665b3324504Adam Cohen        sStaticValuesDirty = true;
193099f60d51f6310e1290687e83958e665b3324504Adam Cohen        return super.onSaveInstanceState();
194099f60d51f6310e1290687e83958e665b3324504Adam Cohen    }
195099f60d51f6310e1290687e83958e665b3324504Adam Cohen
196f05545fcc2df05518731f8d7ff048d797fe776d5Anjali Koppal    public Folder getFolder() {
197fb91f303f5e672f9b4c4f9f8a03486b224d60cd6Adam Cohen        return mFolder;
198fb91f303f5e672f9b4c4f9f8a03486b224d60cd6Adam Cohen    }
199fb91f303f5e672f9b4c4f9f8a03486b224d60cd6Adam Cohen
2004f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen    private void setFolder(Folder folder) {
2014f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen        mFolder = folder;
2024f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen        updateItemDrawingParams(false);
2034f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen    }
2044f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen
205f9c184a619e4e4b82cf9e0bf318ca6d8deaaaee7Adam Cohen    public FolderInfo getFolderInfo() {
206fb91f303f5e672f9b4c4f9f8a03486b224d60cd6Adam Cohen        return mInfo;
207fb91f303f5e672f9b4c4f9f8a03486b224d60cd6Adam Cohen    }
208fb91f303f5e672f9b4c4f9f8a03486b224d60cd6Adam Cohen
209073a46ff635d089cbcb15d939d1de42dd2b86c97Adam Cohen    private boolean willAcceptItem(ItemInfo item) {
21031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        final int itemType = item.itemType;
2112801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen        return ((itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION ||
212bfbf7f9f4a0b300613f0ff27a4eb592d88c08325Tony Wickham                itemType == LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT ||
213bfbf7f9f4a0b300613f0ff27a4eb592d88c08325Tony Wickham                itemType == LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT) &&
214c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen                !mFolder.isFull() && item != mInfo && !mInfo.opened);
215073a46ff635d089cbcb15d939d1de42dd2b86c97Adam Cohen    }
216073a46ff635d089cbcb15d939d1de42dd2b86c97Adam Cohen
217aa8ef119f18864f4ab41c12f9c2ad6d7f643a0a9Sunny Goyal    public boolean acceptDrop(ItemInfo dragInfo) {
218aa8ef119f18864f4ab41c12f9c2ad6d7f643a0a9Sunny Goyal        final ItemInfo item = dragInfo;
219fb91f303f5e672f9b4c4f9f8a03486b224d60cd6Adam Cohen        return !mFolder.isDestroyed() && willAcceptItem(item);
22031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
22131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
222df0353815c629fc678824b07a234b89a1ff94208Adam Cohen    public void addItem(ShortcutInfo item) {
223c52ba710053e4c6927937dd1a26d1abe06b6fa99Sunny Goyal        mInfo.add(item, true);
224df0353815c629fc678824b07a234b89a1ff94208Adam Cohen    }
225df0353815c629fc678824b07a234b89a1ff94208Adam Cohen
226aa8ef119f18864f4ab41c12f9c2ad6d7f643a0a9Sunny Goyal    public void onDragEnter(ItemInfo dragInfo) {
227aa8ef119f18864f4ab41c12f9c2ad6d7f643a0a9Sunny Goyal        if (mFolder.isDestroyed() || !willAcceptItem(dragInfo)) return;
22869ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen        CellLayout.LayoutParams lp = (CellLayout.LayoutParams) getLayoutParams();
229efca0279eb927faebffc38c8382818df67fcd159Adam Cohen        CellLayout cl = (CellLayout) getParent().getParent();
230efca0279eb927faebffc38c8382818df67fcd159Adam Cohen
231efca0279eb927faebffc38c8382818df67fcd159Adam Cohen        mBackground.animateToAccept(cl, lp.cellX, lp.cellY);
23255bd9725d5c0373b89f7b9bbd9547550ea3bbc63Jorim Jaggi        mOpenAlarm.setOnAlarmListener(mOnOpenListener);
233dedfca2aef7573624bdb421b1805ef5e04bee502Adam Cohen        if (SPRING_LOADING_ENABLED &&
234dedfca2aef7573624bdb421b1805ef5e04bee502Adam Cohen                ((dragInfo instanceof AppInfo) || (dragInfo instanceof ShortcutInfo))) {
235dedfca2aef7573624bdb421b1805ef5e04bee502Adam Cohen            // TODO: we currently don't support spring-loading for PendingAddShortcutInfos even
236dedfca2aef7573624bdb421b1805ef5e04bee502Adam Cohen            // though widget-style shortcuts can be added to folders. The issue is that we need
237dedfca2aef7573624bdb421b1805ef5e04bee502Adam Cohen            // to deal with configuration activities which are currently handled in
238dedfca2aef7573624bdb421b1805ef5e04bee502Adam Cohen            // Workspace#onDropExternal.
23955bd9725d5c0373b89f7b9bbd9547550ea3bbc63Jorim Jaggi            mOpenAlarm.setAlarm(ON_OPEN_DELAY);
24055bd9725d5c0373b89f7b9bbd9547550ea3bbc63Jorim Jaggi        }
241073a46ff635d089cbcb15d939d1de42dd2b86c97Adam Cohen    }
242073a46ff635d089cbcb15d939d1de42dd2b86c97Adam Cohen
24355bd9725d5c0373b89f7b9bbd9547550ea3bbc63Jorim Jaggi    OnAlarmListener mOnOpenListener = new OnAlarmListener() {
24455bd9725d5c0373b89f7b9bbd9547550ea3bbc63Jorim Jaggi        public void onAlarm(Alarm alarm) {
245e393d3af369c452f3b5f5d9c0a23a83aa3aa736bSunny Goyal            mFolder.beginExternalDrag();
24637b2a496ebd6a985c210abaa6ca745a860f5f9d2Adam Cohen            mLauncher.openFolder(FolderIcon.this);
24755bd9725d5c0373b89f7b9bbd9547550ea3bbc63Jorim Jaggi        }
24855bd9725d5c0373b89f7b9bbd9547550ea3bbc63Jorim Jaggi    };
24955bd9725d5c0373b89f7b9bbd9547550ea3bbc63Jorim Jaggi
2508f288aac99a11d52fd9747f360a8ce3bb521b17aWinson    public Drawable prepareCreate(final View destView) {
2518f288aac99a11d52fd9747f360a8ce3bb521b17aWinson        Drawable animateDrawable = getTopDrawable((TextView) destView);
2528f288aac99a11d52fd9747f360a8ce3bb521b17aWinson        computePreviewDrawingParams(animateDrawable.getIntrinsicWidth(),
2538f288aac99a11d52fd9747f360a8ce3bb521b17aWinson                destView.getMeasuredWidth());
2548f288aac99a11d52fd9747f360a8ce3bb521b17aWinson        return animateDrawable;
2558f288aac99a11d52fd9747f360a8ce3bb521b17aWinson    }
2568f288aac99a11d52fd9747f360a8ce3bb521b17aWinson
257d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen    public void performCreateAnimation(final ShortcutInfo destInfo, final View destView,
2587bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung            final ShortcutInfo srcInfo, final DragView srcView, Rect dstRect,
259ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen            float scaleRelativeToDragLayer, Runnable postAnimationRunnable) {
260d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen
261fb91f303f5e672f9b4c4f9f8a03486b224d60cd6Adam Cohen        // These correspond two the drawable and view that the icon was dropped _onto_
2628f288aac99a11d52fd9747f360a8ce3bb521b17aWinson        Drawable animateDrawable = prepareCreate(destView);
263fb91f303f5e672f9b4c4f9f8a03486b224d60cd6Adam Cohen
2644f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen        mReferenceDrawable = animateDrawable;
2654f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen
2664f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen        addItem(destInfo);
267fb91f303f5e672f9b4c4f9f8a03486b224d60cd6Adam Cohen        // This will animate the first item from it's position as an icon into its
268fb91f303f5e672f9b4c4f9f8a03486b224d60cd6Adam Cohen        // position as the first item in the preview
269fb91f303f5e672f9b4c4f9f8a03486b224d60cd6Adam Cohen        animateFirstItem(animateDrawable, INITIAL_ITEM_ANIMATION_DURATION, false, null);
270ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen
271d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        // This will animate the dragView (srcView) into the new folder
272e393d3af369c452f3b5f5d9c0a23a83aa3aa736bSunny Goyal        onDrop(srcInfo, srcView, dstRect, scaleRelativeToDragLayer, 1, postAnimationRunnable);
273fb91f303f5e672f9b4c4f9f8a03486b224d60cd6Adam Cohen    }
274fb91f303f5e672f9b4c4f9f8a03486b224d60cd6Adam Cohen
275fb91f303f5e672f9b4c4f9f8a03486b224d60cd6Adam Cohen    public void performDestroyAnimation(final View finalView, Runnable onCompleteRunnable) {
27695abbb330ce9bbaf23594245f0f8a795c8118038Sunny Goyal        Drawable animateDrawable = getTopDrawable((TextView) finalView);
27702dd7aea3d8ac94126a8f8069e6762592ea60326Jason Monk        computePreviewDrawingParams(animateDrawable.getIntrinsicWidth(),
278fb91f303f5e672f9b4c4f9f8a03486b224d60cd6Adam Cohen                finalView.getMeasuredWidth());
279d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen
280d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        // This will animate the first item from it's position as an icon into its
281d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        // position as the first item in the preview
282fb91f303f5e672f9b4c4f9f8a03486b224d60cd6Adam Cohen        animateFirstItem(animateDrawable, FINAL_ITEM_ANIMATION_DURATION, true,
283fb91f303f5e672f9b4c4f9f8a03486b224d60cd6Adam Cohen                onCompleteRunnable);
284d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen    }
285d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen
286c6cc61d45836e4081920883cc4d448ccb0bb8417Adam Cohen    public void onDragExit() {
287efca0279eb927faebffc38c8382818df67fcd159Adam Cohen        mBackground.animateToRest();
28855bd9725d5c0373b89f7b9bbd9547550ea3bbc63Jorim Jaggi        mOpenAlarm.cancelAlarm();
289073a46ff635d089cbcb15d939d1de42dd2b86c97Adam Cohen    }
290073a46ff635d089cbcb15d939d1de42dd2b86c97Adam Cohen
2917bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung    private void onDrop(final ShortcutInfo item, DragView animateView, Rect finalRect,
292e393d3af369c452f3b5f5d9c0a23a83aa3aa736bSunny Goyal            float scaleRelativeToDragLayer, int index, Runnable postAnimationRunnable) {
293d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        item.cellX = -1;
294d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        item.cellY = -1;
295d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen
296558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen        // Typically, the animateView corresponds to the DragView; however, if this is being done
297558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen        // after a configuration activity (ie. for a Shortcut being dragged from AllApps) we
298558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen        // will not have a view to animate
299558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen        if (animateView != null) {
300558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen            DragLayer dragLayer = mLauncher.getDragLayer();
301558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen            Rect from = new Rect();
302558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen            dragLayer.getViewRectRelativeToSelf(animateView, from);
303558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen            Rect to = finalRect;
304558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen            if (to == null) {
305558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen                to = new Rect();
306558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen                Workspace workspace = mLauncher.getWorkspace();
307558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen                // Set cellLayout and this to it's final state to compute final animation locations
308558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen                workspace.setFinalTransitionTransform((CellLayout) getParent().getParent());
309558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen                float scaleX = getScaleX();
310558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen                float scaleY = getScaleY();
311558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen                setScaleX(1.0f);
312558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen                setScaleY(1.0f);
313558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen                scaleRelativeToDragLayer = dragLayer.getDescendantRectRelativeToSelf(this, to);
314558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen                // Finished computing final animation locations, restore current state
315558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen                setScaleX(scaleX);
316558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen                setScaleY(scaleY);
317558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen                workspace.resetTransitionTransform((CellLayout) getParent().getParent());
318558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen            }
319ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen
320558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen            int[] center = new int[2];
321119e8982ab6a0cf00e31e8744f27b72ba8bf7b20Adam Cohen            float scale = getLocalCenterForIndex(index, index + 1, center);
322558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen            center[0] = (int) Math.round(scaleRelativeToDragLayer * center[0]);
323558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen            center[1] = (int) Math.round(scaleRelativeToDragLayer * center[1]);
324d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen
325558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen            to.offset(center[0] - animateView.getMeasuredWidth() / 2,
3265f8afe6280eae34620067696173e71943e1a30a3Winson Chung                      center[1] - animateView.getMeasuredHeight() / 2);
327d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen
328f9c184a619e4e4b82cf9e0bf318ca6d8deaaaee7Adam Cohen            float finalAlpha = index < mPreviewLayoutRule.numItems() ? 0.5f : 0f;
329558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen
330ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen            float finalScale = scale * scaleRelativeToDragLayer;
331558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen            dragLayer.animateView(animateView, from, to, finalAlpha,
332ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen                    1, 1, finalScale, finalScale, DROP_IN_ANIMATION_DURATION,
333558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen                    new DecelerateInterpolator(2), new AccelerateInterpolator(2),
334ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen                    postAnimationRunnable, DragLayer.ANIMATION_END_DISAPPEAR, null);
335fb91f303f5e672f9b4c4f9f8a03486b224d60cd6Adam Cohen            addItem(item);
3367a8b82b5926e6a520df28e7f591b9a94ec605581Adam Cohen            mFolder.hideItem(item);
3374f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen
3384f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen            final PreviewItemDrawingParams params = index < mDrawingParams.size() ?
3394f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen                    mDrawingParams.get(index) : null;
3404f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen            if (params != null) params.hidden = true;
341558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen            postDelayed(new Runnable() {
342558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen                public void run() {
3434f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen                    if (params != null) params.hidden = false;
3447a8b82b5926e6a520df28e7f591b9a94ec605581Adam Cohen                    mFolder.showItem(item);
345fb91f303f5e672f9b4c4f9f8a03486b224d60cd6Adam Cohen                    invalidate();
346558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen                }
347558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen            }, DROP_IN_ANIMATION_DURATION);
348558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen        } else {
349558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen            addItem(item);
350558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen        }
351d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen    }
352d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen
3533e8f811f31a2275e778244427271f77f4116c08bAdam Cohen    public void onDrop(DragObject d) {
354c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen        ShortcutInfo item;
355eadbfc564d84aaf1d800da3d0d6edf6312f89648Michael Jurka        if (d.dragInfo instanceof AppInfo) {
356c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen            // Came from all apps -- make a copy
357eadbfc564d84aaf1d800da3d0d6edf6312f89648Michael Jurka            item = ((AppInfo) d.dragInfo).makeShortcut();
358c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen        } else {
3593e8f811f31a2275e778244427271f77f4116c08bAdam Cohen            item = (ShortcutInfo) d.dragInfo;
360c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen        }
36167bd9ccf856840856944815a382e4bbb0e71e949Adam Cohen        mFolder.notifyDrop();
362e393d3af369c452f3b5f5d9c0a23a83aa3aa736bSunny Goyal        onDrop(item, d.dragView, null, 1.0f, mInfo.contents.size(), d.postAnimationRunnable);
363c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen    }
364c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen
365d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen    private void computePreviewDrawingParams(int drawableSize, int totalSize) {
366aa2542a461072a57058ce45946ff6f5552ecce8aAdam Cohen        if (mIntrinsicIconSize != drawableSize || mTotalWidth != totalSize ||
367aa2542a461072a57058ce45946ff6f5552ecce8aAdam Cohen                mPrevTopPadding != getPaddingTop()) {
3682e6da1539bc7286336b3c24d96ab76434939ce4dAdam Cohen            DeviceProfile grid = mLauncher.getDeviceProfile();
3695f8afe6280eae34620067696173e71943e1a30a3Winson Chung
370d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen            mIntrinsicIconSize = drawableSize;
371d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen            mTotalWidth = totalSize;
372aa2542a461072a57058ce45946ff6f5552ecce8aAdam Cohen            mPrevTopPadding = getPaddingTop();
37376fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen
374efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            mBackground.setup(getResources().getDisplayMetrics(), grid, this, mTotalWidth,
375efca0279eb927faebffc38c8382818df67fcd159Adam Cohen                    getPaddingTop());
376efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            mPreviewLayoutRule.init(mBackground.previewSize, mIntrinsicIconSize,
377119e8982ab6a0cf00e31e8744f27b72ba8bf7b20Adam Cohen                    Utilities.isRtl(getResources()));
378efca0279eb927faebffc38c8382818df67fcd159Adam Cohen
3794f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen            updateItemDrawingParams(false);
380073a46ff635d089cbcb15d939d1de42dd2b86c97Adam Cohen        }
381d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen    }
38276fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen
383d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen    private void computePreviewDrawingParams(Drawable d) {
384d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        computePreviewDrawingParams(d.getIntrinsicWidth(), getMeasuredWidth());
385d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen    }
386073a46ff635d089cbcb15d939d1de42dd2b86c97Adam Cohen
387261194387beebaa7927ec4e310274218b651494dSunny Goyal    static class PreviewItemDrawingParams {
388261194387beebaa7927ec4e310274218b651494dSunny Goyal        PreviewItemDrawingParams(float transX, float transY, float scale, float overlayAlpha) {
389d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen            this.transX = transX;
390d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen            this.transY = transY;
391d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen            this.scale = scale;
392d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen            this.overlayAlpha = overlayAlpha;
393d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        }
3944f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen
3954f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen        public void update(float transX, float transY, float scale) {
3964f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen            // We ensure the update will not interfere with an animation on the layout params
3974f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen            // If the final values differ, we cancel the animation.
3984f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen            if (anim != null) {
3994f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen                if (anim.finalTransX == transX || anim.finalTransY == transY
4004f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen                        || anim.finalScale == scale) {
4014f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen                    return;
4024f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen                }
4034f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen                anim.cancel();
4044f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen            }
4054f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen
4064f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen            this.transX = transX;
4074f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen            this.transY = transY;
4084f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen            this.scale = scale;
4094f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen        }
4104f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen
411261194387beebaa7927ec4e310274218b651494dSunny Goyal        float transX;
412261194387beebaa7927ec4e310274218b651494dSunny Goyal        float transY;
413261194387beebaa7927ec4e310274218b651494dSunny Goyal        float scale;
4144f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen        public float overlayAlpha;
4154f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen        boolean hidden;
4164f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen        FolderPreviewItemAnim anim;
417261194387beebaa7927ec4e310274218b651494dSunny Goyal        Drawable drawable;
418d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen    }
419badf71e11fba2d6efa1d1bcca9542001f90a3777Adam Cohen
420119e8982ab6a0cf00e31e8744f27b72ba8bf7b20Adam Cohen    private float getLocalCenterForIndex(int index, int curNumItems, int[] center) {
4214f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen        mTmpParams = computePreviewItemDrawingParams(Math.min(mPreviewLayoutRule.numItems(), index),
4224f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen                curNumItems, mTmpParams);
423a9cf38f533d1e86269868f1e6a806ccffd4a78fcAdam Cohen
424efca0279eb927faebffc38c8382818df67fcd159Adam Cohen        mTmpParams.transX += mBackground.basePreviewOffsetX;
425efca0279eb927faebffc38c8382818df67fcd159Adam Cohen        mTmpParams.transY += mBackground.basePreviewOffsetY;
4264f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen        float offsetX = mTmpParams.transX + (mTmpParams.scale * mIntrinsicIconSize) / 2;
4274f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen        float offsetY = mTmpParams.transY + (mTmpParams.scale * mIntrinsicIconSize) / 2;
428badf71e11fba2d6efa1d1bcca9542001f90a3777Adam Cohen
429ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen        center[0] = (int) Math.round(offsetX);
430ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen        center[1] = (int) Math.round(offsetY);
4314f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen        return mTmpParams.scale;
432d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen    }
433badf71e11fba2d6efa1d1bcca9542001f90a3777Adam Cohen
434119e8982ab6a0cf00e31e8744f27b72ba8bf7b20Adam Cohen    private PreviewItemDrawingParams computePreviewItemDrawingParams(int index, int curNumItems,
435d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen            PreviewItemDrawingParams params) {
4364f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen        // We use an index of -1 to represent an icon on the workspace for the destroy and
4374f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen        // create animations
4384f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen        if (index == -1) {
4394f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen            return getFinalIconParams(params);
4404f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen        }
441119e8982ab6a0cf00e31e8744f27b72ba8bf7b20Adam Cohen        return mPreviewLayoutRule.computePreviewItemDrawingParams(index, curNumItems, params);
442d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen    }
443badf71e11fba2d6efa1d1bcca9542001f90a3777Adam Cohen
4444f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen    private PreviewItemDrawingParams getFinalIconParams(PreviewItemDrawingParams params) {
4454f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen        float iconSize = mLauncher.getDeviceProfile().iconSizePx;
4464f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen
4474f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen        final float scale = iconSize / mReferenceDrawable.getIntrinsicWidth();
448efca0279eb927faebffc38c8382818df67fcd159Adam Cohen        final float trans = (mBackground.previewSize - iconSize) / 2;
4494f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen
4504f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen        params.update(trans, trans, scale);
4514f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen        return params;
4524f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen    }
4534f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen
454d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen    private void drawPreviewItem(Canvas canvas, PreviewItemDrawingParams params) {
455d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        canvas.save();
456119e8982ab6a0cf00e31e8744f27b72ba8bf7b20Adam Cohen        canvas.translate(params.transX, params.transY);
457d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        canvas.scale(params.scale, params.scale);
458d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        Drawable d = params.drawable;
459d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen
460d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        if (d != null) {
461d4e53c882494f8cd7e4c0d44dbfc300d3610afcfWinson Chung            mOldBounds.set(d.getBounds());
462d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen            d.setBounds(0, 0, mIntrinsicIconSize, mIntrinsicIconSize);
463c5c60ad3592f53549c9ffaa58e9a87b0480080e8Sunny Goyal            if (d instanceof FastBitmapDrawable) {
464c5c60ad3592f53549c9ffaa58e9a87b0480080e8Sunny Goyal                FastBitmapDrawable fd = (FastBitmapDrawable) d;
465c088049113c261331b5685e64050d14a31cd72dfWinson                float oldBrightness = fd.getBrightness();
466508da15509224b46fcccabbe78f3e92fe69a67d8Sunny Goyal                fd.setBrightness(params.overlayAlpha);
467c5c60ad3592f53549c9ffaa58e9a87b0480080e8Sunny Goyal                d.draw(canvas);
468508da15509224b46fcccabbe78f3e92fe69a67d8Sunny Goyal                fd.setBrightness(oldBrightness);
469c5c60ad3592f53549c9ffaa58e9a87b0480080e8Sunny Goyal            } else {
470c088049113c261331b5685e64050d14a31cd72dfWinson                d.setColorFilter(Color.argb((int) (params.overlayAlpha * 255), 255, 255, 255),
471c5c60ad3592f53549c9ffaa58e9a87b0480080e8Sunny Goyal                        PorterDuff.Mode.SRC_ATOP);
472c5c60ad3592f53549c9ffaa58e9a87b0480080e8Sunny Goyal                d.draw(canvas);
473c5c60ad3592f53549c9ffaa58e9a87b0480080e8Sunny Goyal                d.clearColorFilter();
474c5c60ad3592f53549c9ffaa58e9a87b0480080e8Sunny Goyal            }
475d4e53c882494f8cd7e4c0d44dbfc300d3610afcfWinson Chung            d.setBounds(mOldBounds);
476d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        }
477d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        canvas.restore();
478d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen    }
47976fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen
480f172b747c24f28e29baaaf58f08bab48847b7a40Adam Cohen    /**
481f172b747c24f28e29baaaf58f08bab48847b7a40Adam Cohen     * This object represents a FolderIcon preview background. It stores drawing / measurement
482f172b747c24f28e29baaaf58f08bab48847b7a40Adam Cohen     * information, handles drawing, and animation (accept state <--> rest state).
483f172b747c24f28e29baaaf58f08bab48847b7a40Adam Cohen     */
484efca0279eb927faebffc38c8382818df67fcd159Adam Cohen    public static class PreviewBackground {
485efca0279eb927faebffc38c8382818df67fcd159Adam Cohen        private float mScale = 1f;
486efca0279eb927faebffc38c8382818df67fcd159Adam Cohen        private float mColorMultiplier = 1f;
487efca0279eb927faebffc38c8382818df67fcd159Adam Cohen        private Path mClipPath = new Path();
488efca0279eb927faebffc38c8382818df67fcd159Adam Cohen        private int mStrokeWidth;
489f172b747c24f28e29baaaf58f08bab48847b7a40Adam Cohen        private View mInvalidateDelegate;
490efca0279eb927faebffc38c8382818df67fcd159Adam Cohen
491efca0279eb927faebffc38c8382818df67fcd159Adam Cohen        public int previewSize;
492efca0279eb927faebffc38c8382818df67fcd159Adam Cohen        private int basePreviewOffsetX;
493efca0279eb927faebffc38c8382818df67fcd159Adam Cohen        private int basePreviewOffsetY;
494efca0279eb927faebffc38c8382818df67fcd159Adam Cohen
495efca0279eb927faebffc38c8382818df67fcd159Adam Cohen        private CellLayout mDrawingDelegate;
496efca0279eb927faebffc38c8382818df67fcd159Adam Cohen        public int delegateCellX;
497efca0279eb927faebffc38c8382818df67fcd159Adam Cohen        public int delegateCellY;
498efca0279eb927faebffc38c8382818df67fcd159Adam Cohen
499f172b747c24f28e29baaaf58f08bab48847b7a40Adam Cohen        // When the PreviewBackground is drawn under an icon (for creating a folder) the border
500f172b747c24f28e29baaaf58f08bab48847b7a40Adam Cohen        // should not occlude the icon
501f172b747c24f28e29baaaf58f08bab48847b7a40Adam Cohen        public boolean isClipping = true;
502f172b747c24f28e29baaaf58f08bab48847b7a40Adam Cohen
503efca0279eb927faebffc38c8382818df67fcd159Adam Cohen        // Drawing / animation configurations
504efca0279eb927faebffc38c8382818df67fcd159Adam Cohen        private static final float ACCEPT_SCALE_FACTOR = 1.25f;
505efca0279eb927faebffc38c8382818df67fcd159Adam Cohen        private static final float ACCEPT_COLOR_MULTIPLIER = 1.5f;
506efca0279eb927faebffc38c8382818df67fcd159Adam Cohen
507efca0279eb927faebffc38c8382818df67fcd159Adam Cohen        // Expressed on a scale from 0 to 255.
508efca0279eb927faebffc38c8382818df67fcd159Adam Cohen        private static final int BG_OPACITY = 160;
509efca0279eb927faebffc38c8382818df67fcd159Adam Cohen        private static final int MAX_BG_OPACITY = 225;
510efca0279eb927faebffc38c8382818df67fcd159Adam Cohen        private static final int BG_INTENSITY = 245;
511efca0279eb927faebffc38c8382818df67fcd159Adam Cohen        private static final int SHADOW_OPACITY = 80;
512efca0279eb927faebffc38c8382818df67fcd159Adam Cohen
513efca0279eb927faebffc38c8382818df67fcd159Adam Cohen        ValueAnimator mScaleAnimator;
514efca0279eb927faebffc38c8382818df67fcd159Adam Cohen
515f172b747c24f28e29baaaf58f08bab48847b7a40Adam Cohen        public void setup(DisplayMetrics dm, DeviceProfile grid, View invalidateDelegate,
516efca0279eb927faebffc38c8382818df67fcd159Adam Cohen                   int availableSpace, int topPadding) {
517f172b747c24f28e29baaaf58f08bab48847b7a40Adam Cohen            mInvalidateDelegate = invalidateDelegate;
518efca0279eb927faebffc38c8382818df67fcd159Adam Cohen
519efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            final int previewSize = grid.folderIconSizePx;
520efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            final int previewPadding = grid.folderIconPreviewPadding;
521efca0279eb927faebffc38c8382818df67fcd159Adam Cohen
522efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            this.previewSize = (previewSize - 2 * previewPadding);
523efca0279eb927faebffc38c8382818df67fcd159Adam Cohen
524efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            basePreviewOffsetX = (availableSpace - this.previewSize) / 2;
525efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            basePreviewOffsetY = previewPadding + grid.folderBackgroundOffset + topPadding;
526efca0279eb927faebffc38c8382818df67fcd159Adam Cohen
527efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            mStrokeWidth = Utilities.pxFromDp(1, dm);
528efca0279eb927faebffc38c8382818df67fcd159Adam Cohen
529efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            invalidate();
530efca0279eb927faebffc38c8382818df67fcd159Adam Cohen        }
531efca0279eb927faebffc38c8382818df67fcd159Adam Cohen
532efca0279eb927faebffc38c8382818df67fcd159Adam Cohen        int getRadius() {
533efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            return previewSize / 2;
534efca0279eb927faebffc38c8382818df67fcd159Adam Cohen        }
535efca0279eb927faebffc38c8382818df67fcd159Adam Cohen
536efca0279eb927faebffc38c8382818df67fcd159Adam Cohen        int getScaledRadius() {
537efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            return (int) (mScale * getRadius());
538efca0279eb927faebffc38c8382818df67fcd159Adam Cohen        }
539efca0279eb927faebffc38c8382818df67fcd159Adam Cohen
540efca0279eb927faebffc38c8382818df67fcd159Adam Cohen        int getOffsetX() {
541efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            return basePreviewOffsetX - (getScaledRadius() - getRadius());
542efca0279eb927faebffc38c8382818df67fcd159Adam Cohen        }
543efca0279eb927faebffc38c8382818df67fcd159Adam Cohen
544efca0279eb927faebffc38c8382818df67fcd159Adam Cohen        int getOffsetY() {
545efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            return basePreviewOffsetY - (getScaledRadius() - getRadius());
546efca0279eb927faebffc38c8382818df67fcd159Adam Cohen        }
547efca0279eb927faebffc38c8382818df67fcd159Adam Cohen
548efca0279eb927faebffc38c8382818df67fcd159Adam Cohen        void invalidate() {
549efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            int radius = getScaledRadius();
550efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            mClipPath.reset();
551efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            mClipPath.addCircle(radius, radius, radius, Path.Direction.CW);
552efca0279eb927faebffc38c8382818df67fcd159Adam Cohen
553f172b747c24f28e29baaaf58f08bab48847b7a40Adam Cohen            if (mInvalidateDelegate != null) {
554f172b747c24f28e29baaaf58f08bab48847b7a40Adam Cohen                mInvalidateDelegate.invalidate();
555efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            }
556efca0279eb927faebffc38c8382818df67fcd159Adam Cohen
557efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            if (mDrawingDelegate != null) {
558efca0279eb927faebffc38c8382818df67fcd159Adam Cohen                mDrawingDelegate.invalidate();
559efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            }
560efca0279eb927faebffc38c8382818df67fcd159Adam Cohen        }
561efca0279eb927faebffc38c8382818df67fcd159Adam Cohen
562f172b747c24f28e29baaaf58f08bab48847b7a40Adam Cohen        void setInvalidateDelegate(View invalidateDelegate) {
563f172b747c24f28e29baaaf58f08bab48847b7a40Adam Cohen            mInvalidateDelegate = invalidateDelegate;
564efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            invalidate();
565efca0279eb927faebffc38c8382818df67fcd159Adam Cohen        }
566efca0279eb927faebffc38c8382818df67fcd159Adam Cohen
567efca0279eb927faebffc38c8382818df67fcd159Adam Cohen        public void drawBackground(Canvas canvas, Paint paint) {
568efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            canvas.save();
569efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            canvas.translate(getOffsetX(), getOffsetY());
570efca0279eb927faebffc38c8382818df67fcd159Adam Cohen
571efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            paint.reset();
572efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            paint.setStyle(Paint.Style.FILL);
573efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            paint.setXfermode(null);
574efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            paint.setAntiAlias(true);
575efca0279eb927faebffc38c8382818df67fcd159Adam Cohen
576efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            int alpha = (int) Math.min(MAX_BG_OPACITY, BG_OPACITY * mColorMultiplier);
577efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            paint.setColor(Color.argb(alpha, BG_INTENSITY, BG_INTENSITY, BG_INTENSITY));
578efca0279eb927faebffc38c8382818df67fcd159Adam Cohen
579efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            float radius = getScaledRadius();
580efca0279eb927faebffc38c8382818df67fcd159Adam Cohen
581efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            canvas.drawCircle(radius, radius, radius, paint);
582efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            canvas.clipPath(mClipPath, Region.Op.DIFFERENCE);
583efca0279eb927faebffc38c8382818df67fcd159Adam Cohen
584efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            paint.setStyle(Paint.Style.STROKE);
585efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            paint.setColor(Color.TRANSPARENT);
586efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            paint.setShadowLayer(mStrokeWidth, 0, mStrokeWidth, Color.argb(SHADOW_OPACITY, 0, 0, 0));
587efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            canvas.drawCircle(radius, radius, radius, paint);
588efca0279eb927faebffc38c8382818df67fcd159Adam Cohen
589efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            canvas.restore();
590efca0279eb927faebffc38c8382818df67fcd159Adam Cohen        }
591efca0279eb927faebffc38c8382818df67fcd159Adam Cohen
592efca0279eb927faebffc38c8382818df67fcd159Adam Cohen        public void drawBackgroundStroke(Canvas canvas, Paint paint) {
593efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            canvas.save();
594efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            canvas.translate(getOffsetX(), getOffsetY());
595efca0279eb927faebffc38c8382818df67fcd159Adam Cohen
596efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            paint.reset();
597efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            paint.setAntiAlias(true);
598efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            paint.setColor(Color.argb(255, BG_INTENSITY, BG_INTENSITY, BG_INTENSITY));
599efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            paint.setStyle(Paint.Style.STROKE);
600efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            paint.setStrokeWidth(mStrokeWidth);
601efca0279eb927faebffc38c8382818df67fcd159Adam Cohen
602efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            float radius = getScaledRadius();
603efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            canvas.drawCircle(radius, radius, radius - 1, paint);
604efca0279eb927faebffc38c8382818df67fcd159Adam Cohen
605efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            canvas.restore();
606efca0279eb927faebffc38c8382818df67fcd159Adam Cohen        }
607efca0279eb927faebffc38c8382818df67fcd159Adam Cohen
608efca0279eb927faebffc38c8382818df67fcd159Adam Cohen        public void drawLeaveBehind(Canvas canvas, Paint paint) {
609efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            float originalScale = mScale;
610efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            mScale = 0.5f;
611efca0279eb927faebffc38c8382818df67fcd159Adam Cohen
612efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            canvas.save();
613efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            canvas.translate(getOffsetX(), getOffsetY());
614efca0279eb927faebffc38c8382818df67fcd159Adam Cohen
615efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            paint.reset();
616efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            paint.setAntiAlias(true);
617efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            paint.setColor(Color.argb(160, 245, 245, 245));
618efca0279eb927faebffc38c8382818df67fcd159Adam Cohen
619efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            float radius = getScaledRadius();
620efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            canvas.drawCircle(radius, radius, radius, paint);
621efca0279eb927faebffc38c8382818df67fcd159Adam Cohen
622efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            canvas.restore();
623efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            mScale = originalScale;
624efca0279eb927faebffc38c8382818df67fcd159Adam Cohen        }
625efca0279eb927faebffc38c8382818df67fcd159Adam Cohen
626efca0279eb927faebffc38c8382818df67fcd159Adam Cohen        // It is the callers responsibility to save and restore the canvas.
627efca0279eb927faebffc38c8382818df67fcd159Adam Cohen        private void clipCanvas(Canvas canvas) {
628efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            canvas.translate(getOffsetX(), getOffsetY());
629efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            canvas.clipPath(mClipPath);
630efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            canvas.translate(-getOffsetX(), -getOffsetY());
631efca0279eb927faebffc38c8382818df67fcd159Adam Cohen        }
632efca0279eb927faebffc38c8382818df67fcd159Adam Cohen
633efca0279eb927faebffc38c8382818df67fcd159Adam Cohen        private void delegateDrawing(CellLayout delegate, int cellX, int cellY) {
634efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            if (mDrawingDelegate != delegate) {
635efca0279eb927faebffc38c8382818df67fcd159Adam Cohen                delegate.addFolderBackground(this);
636efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            }
637efca0279eb927faebffc38c8382818df67fcd159Adam Cohen
638efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            mDrawingDelegate = delegate;
639efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            delegateCellX = cellX;
640efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            delegateCellY = cellY;
641efca0279eb927faebffc38c8382818df67fcd159Adam Cohen
642efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            invalidate();
643efca0279eb927faebffc38c8382818df67fcd159Adam Cohen        }
644efca0279eb927faebffc38c8382818df67fcd159Adam Cohen
645efca0279eb927faebffc38c8382818df67fcd159Adam Cohen        private void clearDrawingDelegate() {
646efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            if (mDrawingDelegate != null) {
647efca0279eb927faebffc38c8382818df67fcd159Adam Cohen                mDrawingDelegate.removeFolderBackground(this);
648efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            }
649efca0279eb927faebffc38c8382818df67fcd159Adam Cohen
650efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            mDrawingDelegate = null;
651efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            invalidate();
652efca0279eb927faebffc38c8382818df67fcd159Adam Cohen        }
653efca0279eb927faebffc38c8382818df67fcd159Adam Cohen
654efca0279eb927faebffc38c8382818df67fcd159Adam Cohen        private boolean drawingDelegated() {
655efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            return mDrawingDelegate != null;
656efca0279eb927faebffc38c8382818df67fcd159Adam Cohen        }
657efca0279eb927faebffc38c8382818df67fcd159Adam Cohen
658efca0279eb927faebffc38c8382818df67fcd159Adam Cohen        private void animateScale(float finalScale, float finalMultiplier,
659efca0279eb927faebffc38c8382818df67fcd159Adam Cohen                final Runnable onStart, final Runnable onEnd) {
660efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            final float scale0 = mScale;
661efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            final float scale1 = finalScale;
662efca0279eb927faebffc38c8382818df67fcd159Adam Cohen
663efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            final float bgMultiplier0 = mColorMultiplier;
664efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            final float bgMultiplier1 = finalMultiplier;
665efca0279eb927faebffc38c8382818df67fcd159Adam Cohen
666efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            if (mScaleAnimator != null) {
667efca0279eb927faebffc38c8382818df67fcd159Adam Cohen                mScaleAnimator.cancel();
668efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            }
669efca0279eb927faebffc38c8382818df67fcd159Adam Cohen
670efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            mScaleAnimator = LauncherAnimUtils.ofFloat(null, 0f, 1.0f);
671efca0279eb927faebffc38c8382818df67fcd159Adam Cohen
672efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            mScaleAnimator.addUpdateListener(new AnimatorUpdateListener() {
673efca0279eb927faebffc38c8382818df67fcd159Adam Cohen                @Override
674efca0279eb927faebffc38c8382818df67fcd159Adam Cohen                public void onAnimationUpdate(ValueAnimator animation) {
675efca0279eb927faebffc38c8382818df67fcd159Adam Cohen                    float prog = animation.getAnimatedFraction();
676efca0279eb927faebffc38c8382818df67fcd159Adam Cohen                    mScale = prog * scale1 + (1 - prog) * scale0;
677efca0279eb927faebffc38c8382818df67fcd159Adam Cohen                    mColorMultiplier = prog * bgMultiplier1 + (1 - prog) * bgMultiplier0;
678efca0279eb927faebffc38c8382818df67fcd159Adam Cohen                    invalidate();
679efca0279eb927faebffc38c8382818df67fcd159Adam Cohen                }
680efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            });
681efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            mScaleAnimator.addListener(new AnimatorListenerAdapter() {
682efca0279eb927faebffc38c8382818df67fcd159Adam Cohen                @Override
683efca0279eb927faebffc38c8382818df67fcd159Adam Cohen                public void onAnimationStart(Animator animation) {
684efca0279eb927faebffc38c8382818df67fcd159Adam Cohen                    if (onStart != null) {
685efca0279eb927faebffc38c8382818df67fcd159Adam Cohen                        onStart.run();
686efca0279eb927faebffc38c8382818df67fcd159Adam Cohen                    }
687efca0279eb927faebffc38c8382818df67fcd159Adam Cohen                }
688efca0279eb927faebffc38c8382818df67fcd159Adam Cohen
689efca0279eb927faebffc38c8382818df67fcd159Adam Cohen                @Override
690efca0279eb927faebffc38c8382818df67fcd159Adam Cohen                public void onAnimationEnd(Animator animation) {
691efca0279eb927faebffc38c8382818df67fcd159Adam Cohen                    if (onEnd != null) {
692efca0279eb927faebffc38c8382818df67fcd159Adam Cohen                        onEnd.run();
693efca0279eb927faebffc38c8382818df67fcd159Adam Cohen                    }
694efca0279eb927faebffc38c8382818df67fcd159Adam Cohen                    mScaleAnimator = null;
695efca0279eb927faebffc38c8382818df67fcd159Adam Cohen                }
696efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            });
697efca0279eb927faebffc38c8382818df67fcd159Adam Cohen
698efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            mScaleAnimator.setDuration(CONSUMPTION_ANIMATION_DURATION);
699efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            mScaleAnimator.start();
700efca0279eb927faebffc38c8382818df67fcd159Adam Cohen        }
701efca0279eb927faebffc38c8382818df67fcd159Adam Cohen
702efca0279eb927faebffc38c8382818df67fcd159Adam Cohen        public void animateToAccept(final CellLayout cl, final int cellX, final int cellY) {
703efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            Runnable onStart = new Runnable() {
704efca0279eb927faebffc38c8382818df67fcd159Adam Cohen                @Override
705efca0279eb927faebffc38c8382818df67fcd159Adam Cohen                public void run() {
706efca0279eb927faebffc38c8382818df67fcd159Adam Cohen                    delegateDrawing(cl, cellX, cellY);
707efca0279eb927faebffc38c8382818df67fcd159Adam Cohen                }
708efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            };
709efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            animateScale(ACCEPT_SCALE_FACTOR, ACCEPT_COLOR_MULTIPLIER, onStart, null);
710efca0279eb927faebffc38c8382818df67fcd159Adam Cohen        }
711efca0279eb927faebffc38c8382818df67fcd159Adam Cohen
712efca0279eb927faebffc38c8382818df67fcd159Adam Cohen        public void animateToRest() {
713efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            // This can be called multiple times -- we need to make sure the drawing delegate
714efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            // is saved and restored at the beginning of the animation, since cancelling the
715efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            // existing animation can clear the delgate.
716efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            final CellLayout cl = mDrawingDelegate;
717efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            final int cellX = delegateCellX;
718efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            final int cellY = delegateCellY;
719efca0279eb927faebffc38c8382818df67fcd159Adam Cohen
720efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            Runnable onStart = new Runnable() {
721efca0279eb927faebffc38c8382818df67fcd159Adam Cohen                @Override
722efca0279eb927faebffc38c8382818df67fcd159Adam Cohen                public void run() {
723efca0279eb927faebffc38c8382818df67fcd159Adam Cohen                    delegateDrawing(cl, cellX, cellY);
724efca0279eb927faebffc38c8382818df67fcd159Adam Cohen                }
725efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            };
726efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            Runnable onEnd = new Runnable() {
727efca0279eb927faebffc38c8382818df67fcd159Adam Cohen                @Override
728efca0279eb927faebffc38c8382818df67fcd159Adam Cohen                public void run() {
729efca0279eb927faebffc38c8382818df67fcd159Adam Cohen                    clearDrawingDelegate();
730efca0279eb927faebffc38c8382818df67fcd159Adam Cohen                }
731efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            };
732efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            animateScale(1f, 1f, onStart, onEnd);
733efca0279eb927faebffc38c8382818df67fcd159Adam Cohen        }
734efca0279eb927faebffc38c8382818df67fcd159Adam Cohen    }
735efca0279eb927faebffc38c8382818df67fcd159Adam Cohen
736efca0279eb927faebffc38c8382818df67fcd159Adam Cohen    public void setFolderBackground(PreviewBackground bg) {
737efca0279eb927faebffc38c8382818df67fcd159Adam Cohen        mBackground = bg;
738f172b747c24f28e29baaaf58f08bab48847b7a40Adam Cohen        mBackground.setInvalidateDelegate(this);
739efca0279eb927faebffc38c8382818df67fcd159Adam Cohen    }
740efca0279eb927faebffc38c8382818df67fcd159Adam Cohen
741d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen    @Override
742d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen    protected void dispatchDraw(Canvas canvas) {
743d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        super.dispatchDraw(canvas);
744badf71e11fba2d6efa1d1bcca9542001f90a3777Adam Cohen
7454f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen        if (mReferenceDrawable != null) {
7464f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen            computePreviewDrawingParams(mReferenceDrawable);
747d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        }
748a9cf38f533d1e86269868f1e6a806ccffd4a78fcAdam Cohen
749efca0279eb927faebffc38c8382818df67fcd159Adam Cohen        if (!mBackground.drawingDelegated()) {
750efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            mBackground.drawBackground(canvas, mBgPaint);
751efca0279eb927faebffc38c8382818df67fcd159Adam Cohen        }
752efca0279eb927faebffc38c8382818df67fcd159Adam Cohen
753efca0279eb927faebffc38c8382818df67fcd159Adam Cohen        if (mFolder == null) return;
754efca0279eb927faebffc38c8382818df67fcd159Adam Cohen        if (mFolder.getItemCount() == 0 && !mAnimating) return;
755efca0279eb927faebffc38c8382818df67fcd159Adam Cohen
756119e8982ab6a0cf00e31e8744f27b72ba8bf7b20Adam Cohen        canvas.save();
757efca0279eb927faebffc38c8382818df67fcd159Adam Cohen
758efca0279eb927faebffc38c8382818df67fcd159Adam Cohen
759efca0279eb927faebffc38c8382818df67fcd159Adam Cohen        if (mPreviewLayoutRule.clipToBackground()) {
760efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            mBackground.clipCanvas(canvas);
761119e8982ab6a0cf00e31e8744f27b72ba8bf7b20Adam Cohen        }
762119e8982ab6a0cf00e31e8744f27b72ba8bf7b20Adam Cohen
763efca0279eb927faebffc38c8382818df67fcd159Adam Cohen        // The items are drawn in coordinates relative to the preview offset
764efca0279eb927faebffc38c8382818df67fcd159Adam Cohen        canvas.translate(mBackground.basePreviewOffsetX, mBackground.basePreviewOffsetY);
765efca0279eb927faebffc38c8382818df67fcd159Adam Cohen
7664f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen        // The first item should be drawn last (ie. on top of later items)
7674f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen        for (int i = mDrawingParams.size() - 1; i >= 0; i--) {
7684f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen            PreviewItemDrawingParams p = mDrawingParams.get(i);
7694f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen            if (!p.hidden) {
7704f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen                drawPreviewItem(canvas, p);
771a9cf38f533d1e86269868f1e6a806ccffd4a78fcAdam Cohen            }
772a9cf38f533d1e86269868f1e6a806ccffd4a78fcAdam Cohen        }
773119e8982ab6a0cf00e31e8744f27b72ba8bf7b20Adam Cohen        canvas.restore();
774efca0279eb927faebffc38c8382818df67fcd159Adam Cohen
775efca0279eb927faebffc38c8382818df67fcd159Adam Cohen        if (mPreviewLayoutRule.clipToBackground() && !mBackground.drawingDelegated()) {
776efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            mBackground.drawBackgroundStroke(canvas, mBgPaint);
777efca0279eb927faebffc38c8382818df67fcd159Adam Cohen        }
778d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen    }
779d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen
7803484638cad97e255a412b0489a63873fb3ca4218Sunny Goyal    private Drawable getTopDrawable(TextView v) {
7813484638cad97e255a412b0489a63873fb3ca4218Sunny Goyal        Drawable d = v.getCompoundDrawables()[1];
7823484638cad97e255a412b0489a63873fb3ca4218Sunny Goyal        return (d instanceof PreloadIconDrawable) ? ((PreloadIconDrawable) d).mIcon : d;
7833484638cad97e255a412b0489a63873fb3ca4218Sunny Goyal    }
7843484638cad97e255a412b0489a63873fb3ca4218Sunny Goyal
7854f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen    class FolderPreviewItemAnim {
7864f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen        ValueAnimator mValueAnimator;
7874f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen        float finalScale;
7884f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen        float finalTransX;
7894f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen        float finalTransY;
7904f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen
7914f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen        /**
7924f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen         *
7934f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen         * @param params layout params to animate
7944f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen         * @param index0 original index of the item to be animated
7954f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen         * @param nItems0 original number of items in the preview
7964f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen         * @param index1 new index of the item to be animated
7974f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen         * @param nItems1 new number of items in the preview
7984f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen         * @param duration duration in ms of the animation
7994f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen         * @param onCompleteRunnable runnable to execute upon animation completion
8004f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen         */
8014f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen        public FolderPreviewItemAnim(final PreviewItemDrawingParams params, int index0, int nItems0,
8024f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen                int index1, int nItems1, int duration, final Runnable onCompleteRunnable) {
8034f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen
8044f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen            computePreviewItemDrawingParams(index1, nItems1, mTmpParams);
8054f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen
8064f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen            finalScale = mTmpParams.scale;
8074f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen            finalTransX = mTmpParams.transX;
8084f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen            finalTransY = mTmpParams.transY;
8094f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen
8104f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen            computePreviewItemDrawingParams(index0, nItems0, mTmpParams);
8114f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen
8124f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen            final float scale0 = mTmpParams.scale;
8134f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen            final float transX0 = mTmpParams.transX;
8144f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen            final float transY0 = mTmpParams.transY;
8154f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen
8164f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen            mValueAnimator = LauncherAnimUtils.ofFloat(FolderIcon.this, 0f, 1.0f);
8174f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen            mValueAnimator.addUpdateListener(new AnimatorUpdateListener(){
8184f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen                public void onAnimationUpdate(ValueAnimator animation) {
8194f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen                    float progress = animation.getAnimatedFraction();
820119e8982ab6a0cf00e31e8744f27b72ba8bf7b20Adam Cohen
8214f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen                    params.transX = transX0 + progress * (finalTransX - transX0);
8224f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen                    params.transY = transY0 + progress * (finalTransY - transY0);
8234f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen                    params.scale = scale0 + progress * (finalScale - scale0);
8244f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen                    invalidate();
8254f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen                }
8264f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen            });
827d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen
8284f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen            mValueAnimator.addListener(new AnimatorListenerAdapter() {
8294f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen                @Override
8304f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen                public void onAnimationStart(Animator animation) {
831fb91f303f5e672f9b4c4f9f8a03486b224d60cd6Adam Cohen                }
832d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen
8334f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen                @Override
8344f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen                public void onAnimationEnd(Animator animation) {
8354f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen                    if (onCompleteRunnable != null) {
8364f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen                        onCompleteRunnable.run();
8374f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen                    }
8384f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen                    params.anim = null;
839fb91f303f5e672f9b4c4f9f8a03486b224d60cd6Adam Cohen                }
8404f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen            });
8414f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen            mValueAnimator.setDuration(duration);
8424f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen        }
8434f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen
8444f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen        public void start() {
8454f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen            mValueAnimator.start();
8464f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen        }
8474f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen
8484f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen        public void cancel() {
8494f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen            mValueAnimator.cancel();
8504f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen        }
8514f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen
8524f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen        public boolean hasEqualFinalState(FolderPreviewItemAnim anim) {
8534f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen            return finalTransY == anim.finalTransY && finalTransX == anim.finalTransX &&
8544f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen                    finalScale == anim.finalScale;
8554f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen
8564f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen        }
8574f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen    }
8584f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen
8594f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen    private void animateFirstItem(final Drawable d, int duration, final boolean reverse,
8604f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen            final Runnable onCompleteRunnable) {
8614f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen
8624f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen        FolderPreviewItemAnim anim;
8634f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen        if (!reverse) {
8644f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen            anim = new FolderPreviewItemAnim(mDrawingParams.get(0), -1, -1, 0, 2, duration,
8654f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen                    onCompleteRunnable);
8664f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen        } else {
8674f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen            anim = new FolderPreviewItemAnim(mDrawingParams.get(0), 0, 2, -1, -1, duration,
8684f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen                    onCompleteRunnable);
8694f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen        }
8704f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen        anim.start();
871a9cf38f533d1e86269868f1e6a806ccffd4a78fcAdam Cohen    }
872a9cf38f533d1e86269868f1e6a806ccffd4a78fcAdam Cohen
873099f60d51f6310e1290687e83958e665b3324504Adam Cohen    public void setTextVisible(boolean visible) {
874099f60d51f6310e1290687e83958e665b3324504Adam Cohen        if (visible) {
875099f60d51f6310e1290687e83958e665b3324504Adam Cohen            mFolderName.setVisibility(VISIBLE);
876099f60d51f6310e1290687e83958e665b3324504Adam Cohen        } else {
877099f60d51f6310e1290687e83958e665b3324504Adam Cohen            mFolderName.setVisibility(INVISIBLE);
878099f60d51f6310e1290687e83958e665b3324504Adam Cohen        }
879099f60d51f6310e1290687e83958e665b3324504Adam Cohen    }
880099f60d51f6310e1290687e83958e665b3324504Adam Cohen
881099f60d51f6310e1290687e83958e665b3324504Adam Cohen    public boolean getTextVisible() {
882099f60d51f6310e1290687e83958e665b3324504Adam Cohen        return mFolderName.getVisibility() == VISIBLE;
883099f60d51f6310e1290687e83958e665b3324504Adam Cohen    }
884099f60d51f6310e1290687e83958e665b3324504Adam Cohen
8854f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen    private void updateItemDrawingParams(boolean animate) {
8864f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen        ArrayList<View> items = mFolder.getItemsInReadingOrder();
8874f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen        int nItemsInPreview = Math.min(items.size(), mPreviewLayoutRule.numItems());
8884f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen
8894f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen        int prevNumItems = mDrawingParams.size();
8904f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen
8914f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen        // We adjust the size of the list to match the number of items in the preview
8924f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen        while (nItemsInPreview < mDrawingParams.size()) {
8934f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen            mDrawingParams.remove(mDrawingParams.size() - 1);
8944f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen        }
8954f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen        while (nItemsInPreview > mDrawingParams.size()) {
8964f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen            mDrawingParams.add(new PreviewItemDrawingParams(0, 0, 0, 0));
8974f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen        }
8984f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen
8994f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen        for (int i = 0; i < mDrawingParams.size(); i++) {
9004f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen            PreviewItemDrawingParams p = mDrawingParams.get(i);
9014f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen            p.drawable = getTopDrawable((TextView) items.get(i));
9024f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen
903efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            if (!animate || FeatureFlags.LAUNCHER3_LEGACY_FOLDER_ICON) {
9044f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen                computePreviewItemDrawingParams(i, nItemsInPreview, p);
9054f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen                if (mReferenceDrawable == null) {
9064f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen                    mReferenceDrawable = p.drawable;
9074f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen                }
9084f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen            } else {
9094f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen                FolderPreviewItemAnim anim = new FolderPreviewItemAnim(p, i, prevNumItems, i,
9104f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen                        nItemsInPreview, DROP_IN_ANIMATION_DURATION, null);
9114f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen
9124f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen                if (p.anim != null) {
9134f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen                    if (p.anim.hasEqualFinalState(anim)) {
9144f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen                        // do nothing, let the current animation finish
9154f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen                        continue;
9164f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen                    }
9174f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen                    p.anim.cancel();
9184f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen                }
9194f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen                p.anim = anim;
9204f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen                p.anim.start();
9214f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen            }
9224f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen        }
9234f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen    }
9244f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen
925c52ba710053e4c6927937dd1a26d1abe06b6fa99Sunny Goyal    @Override
926c52ba710053e4c6927937dd1a26d1abe06b6fa99Sunny Goyal    public void onItemsChanged(boolean animate) {
927c52ba710053e4c6927937dd1a26d1abe06b6fa99Sunny Goyal        updateItemDrawingParams(animate);
92876078c4ef35b6e95fb6d8129a32cf52a36625e28Adam Cohen        invalidate();
92976078c4ef35b6e95fb6d8129a32cf52a36625e28Adam Cohen        requestLayout();
93076078c4ef35b6e95fb6d8129a32cf52a36625e28Adam Cohen    }
93176078c4ef35b6e95fb6d8129a32cf52a36625e28Adam Cohen
932a9cf38f533d1e86269868f1e6a806ccffd4a78fcAdam Cohen    public void onAdd(ShortcutInfo item) {
933a9cf38f533d1e86269868f1e6a806ccffd4a78fcAdam Cohen        invalidate();
934a9cf38f533d1e86269868f1e6a806ccffd4a78fcAdam Cohen        requestLayout();
935a9cf38f533d1e86269868f1e6a806ccffd4a78fcAdam Cohen    }
936a9cf38f533d1e86269868f1e6a806ccffd4a78fcAdam Cohen
937a9cf38f533d1e86269868f1e6a806ccffd4a78fcAdam Cohen    public void onRemove(ShortcutInfo item) {
938a9cf38f533d1e86269868f1e6a806ccffd4a78fcAdam Cohen        invalidate();
939a9cf38f533d1e86269868f1e6a806ccffd4a78fcAdam Cohen        requestLayout();
940a9cf38f533d1e86269868f1e6a806ccffd4a78fcAdam Cohen    }
94176fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen
94276fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen    public void onTitleChanged(CharSequence title) {
94382b016cb56540fe26213e817dd0dd668099c8e20Winson Chung        mFolderName.setText(title);
944f4f89ef608245d39bbddda05f291361d2ae06667Sunny Goyal        setContentDescription(getContext().getString(R.string.folder_name_format, title));
94576fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen    }
94688f334571fe41df620ba903ced9b2c69b0170d5cWinson Chung
94788f334571fe41df620ba903ced9b2c69b0170d5cWinson Chung    @Override
94888f334571fe41df620ba903ced9b2c69b0170d5cWinson Chung    public boolean onTouchEvent(MotionEvent event) {
94988f334571fe41df620ba903ced9b2c69b0170d5cWinson Chung        // Call the superclass onTouchEvent first, because sometimes it changes the state to
95088f334571fe41df620ba903ced9b2c69b0170d5cWinson Chung        // isPressed() on an ACTION_UP
95188f334571fe41df620ba903ced9b2c69b0170d5cWinson Chung        boolean result = super.onTouchEvent(event);
95288f334571fe41df620ba903ced9b2c69b0170d5cWinson Chung
953ef044dd380ac3abf354027750efdc16d5d48ac70Mady Mellor        // Check for a stylus button press, if it occurs cancel any long press checks.
954bb83520a620919a8f19472ba4426585d007d1abaMady Mellor        if (mStylusEventHelper.onMotionEvent(event)) {
955ef044dd380ac3abf354027750efdc16d5d48ac70Mady Mellor            mLongPressHelper.cancelLongPress();
956ef044dd380ac3abf354027750efdc16d5d48ac70Mady Mellor            return true;
957ef044dd380ac3abf354027750efdc16d5d48ac70Mady Mellor        }
958ef044dd380ac3abf354027750efdc16d5d48ac70Mady Mellor
95988f334571fe41df620ba903ced9b2c69b0170d5cWinson Chung        switch (event.getAction()) {
96088f334571fe41df620ba903ced9b2c69b0170d5cWinson Chung            case MotionEvent.ACTION_DOWN:
96188f334571fe41df620ba903ced9b2c69b0170d5cWinson Chung                mLongPressHelper.postCheckForLongPress();
96288f334571fe41df620ba903ced9b2c69b0170d5cWinson Chung                break;
96388f334571fe41df620ba903ced9b2c69b0170d5cWinson Chung            case MotionEvent.ACTION_CANCEL:
96488f334571fe41df620ba903ced9b2c69b0170d5cWinson Chung            case MotionEvent.ACTION_UP:
96588f334571fe41df620ba903ced9b2c69b0170d5cWinson Chung                mLongPressHelper.cancelLongPress();
96688f334571fe41df620ba903ced9b2c69b0170d5cWinson Chung                break;
96702dd7aea3d8ac94126a8f8069e6762592ea60326Jason Monk            case MotionEvent.ACTION_MOVE:
96802dd7aea3d8ac94126a8f8069e6762592ea60326Jason Monk                if (!Utilities.pointInView(this, event.getX(), event.getY(), mSlop)) {
96902dd7aea3d8ac94126a8f8069e6762592ea60326Jason Monk                    mLongPressHelper.cancelLongPress();
97002dd7aea3d8ac94126a8f8069e6762592ea60326Jason Monk                }
97102dd7aea3d8ac94126a8f8069e6762592ea60326Jason Monk                break;
97288f334571fe41df620ba903ced9b2c69b0170d5cWinson Chung        }
97388f334571fe41df620ba903ced9b2c69b0170d5cWinson Chung        return result;
97488f334571fe41df620ba903ced9b2c69b0170d5cWinson Chung    }
97588f334571fe41df620ba903ced9b2c69b0170d5cWinson Chung
97688f334571fe41df620ba903ced9b2c69b0170d5cWinson Chung    @Override
97702dd7aea3d8ac94126a8f8069e6762592ea60326Jason Monk    protected void onAttachedToWindow() {
97802dd7aea3d8ac94126a8f8069e6762592ea60326Jason Monk        super.onAttachedToWindow();
97902dd7aea3d8ac94126a8f8069e6762592ea60326Jason Monk        mSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
98002dd7aea3d8ac94126a8f8069e6762592ea60326Jason Monk    }
98102dd7aea3d8ac94126a8f8069e6762592ea60326Jason Monk
98202dd7aea3d8ac94126a8f8069e6762592ea60326Jason Monk    @Override
98388f334571fe41df620ba903ced9b2c69b0170d5cWinson Chung    public void cancelLongPress() {
98488f334571fe41df620ba903ced9b2c69b0170d5cWinson Chung        super.cancelLongPress();
98588f334571fe41df620ba903ced9b2c69b0170d5cWinson Chung        mLongPressHelper.cancelLongPress();
98688f334571fe41df620ba903ced9b2c69b0170d5cWinson Chung    }
987f9c184a619e4e4b82cf9e0bf318ca6d8deaaaee7Adam Cohen
988aaf7d1d13bd88bdeac5c56a9ab1d293fdaea3c11Sunny Goyal    public void removeListeners() {
989aaf7d1d13bd88bdeac5c56a9ab1d293fdaea3c11Sunny Goyal        mInfo.removeListener(this);
990aaf7d1d13bd88bdeac5c56a9ab1d293fdaea3c11Sunny Goyal        mInfo.removeListener(mFolder);
991aaf7d1d13bd88bdeac5c56a9ab1d293fdaea3c11Sunny Goyal    }
992aaf7d1d13bd88bdeac5c56a9ab1d293fdaea3c11Sunny Goyal
993f9c184a619e4e4b82cf9e0bf318ca6d8deaaaee7Adam Cohen    public interface PreviewLayoutRule {
994119e8982ab6a0cf00e31e8744f27b72ba8bf7b20Adam Cohen        public PreviewItemDrawingParams computePreviewItemDrawingParams(int index, int curNumItems,
995f9c184a619e4e4b82cf9e0bf318ca6d8deaaaee7Adam Cohen            PreviewItemDrawingParams params);
996f9c184a619e4e4b82cf9e0bf318ca6d8deaaaee7Adam Cohen
997119e8982ab6a0cf00e31e8744f27b72ba8bf7b20Adam Cohen        public void init(int availableSpace, int intrinsicIconSize, boolean rtl);
998f9c184a619e4e4b82cf9e0bf318ca6d8deaaaee7Adam Cohen
999f9c184a619e4e4b82cf9e0bf318ca6d8deaaaee7Adam Cohen        public int numItems();
1000efca0279eb927faebffc38c8382818df67fcd159Adam Cohen        public boolean clipToBackground();
1001f9c184a619e4e4b82cf9e0bf318ca6d8deaaaee7Adam Cohen    }
100231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project}
1003