FolderIcon.java revision f172b747c24f28e29baaaf58f08bab48847b7a40
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();
128f9c184a619e4e4b82cf9e0bf318ca6d8deaaaee7Adam Cohen    @Thunk
129f9c184a619e4e4b82cf9e0bf318ca6d8deaaaee7Adam Cohen    ItemInfo mDragInfo;
13055bd9725d5c0373b89f7b9bbd9547550ea3bbc63Jorim Jaggi
13131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    public FolderIcon(Context context, AttributeSet attrs) {
13231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        super(context, attrs);
13388f334571fe41df620ba903ced9b2c69b0170d5cWinson Chung        init();
13431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
13531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
13631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    public FolderIcon(Context context) {
13731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        super(context);
13888f334571fe41df620ba903ced9b2c69b0170d5cWinson Chung        init();
13988f334571fe41df620ba903ced9b2c69b0170d5cWinson Chung    }
14088f334571fe41df620ba903ced9b2c69b0170d5cWinson Chung
14188f334571fe41df620ba903ced9b2c69b0170d5cWinson Chung    private void init() {
14288f334571fe41df620ba903ced9b2c69b0170d5cWinson Chung        mLongPressHelper = new CheckLongPressHelper(this);
143bb83520a620919a8f19472ba4426585d007d1abaMady Mellor        mStylusEventHelper = new StylusEventHelper(new SimpleOnStylusPressListener(this), this);
144efca0279eb927faebffc38c8382818df67fcd159Adam Cohen        mPreviewLayoutRule = FeatureFlags.LAUNCHER3_LEGACY_FOLDER_ICON ?
145efca0279eb927faebffc38c8382818df67fcd159Adam Cohen                new StackFolderIconLayoutRule() :
146efca0279eb927faebffc38c8382818df67fcd159Adam Cohen                new ClippedFolderIconLayoutRule();
14731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
148efca0279eb927faebffc38c8382818df67fcd159Adam Cohen        setAccessibilityDelegate(LauncherAppState.getInstance().getAccessibilityDelegate());
1490280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    }
1500280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka
151f9c184a619e4e4b82cf9e0bf318ca6d8deaaaee7Adam Cohen    public static FolderIcon fromXml(int resId, Launcher launcher, ViewGroup group,
152df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen            FolderInfo folderInfo, IconCache iconCache) {
1533a9fcedbcd235372cd2ab64f825a0b5b3937f59eMichael Jurka        @SuppressWarnings("all") // suppress dead code warning
1543a9fcedbcd235372cd2ab64f825a0b5b3937f59eMichael Jurka        final boolean error = INITIAL_ITEM_ANIMATION_DURATION >= DROP_IN_ANIMATION_DURATION;
1553a9fcedbcd235372cd2ab64f825a0b5b3937f59eMichael Jurka        if (error) {
156d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen            throw new IllegalStateException("DROP_IN_ANIMATION_DURATION must be greater than " +
157d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen                    "INITIAL_ITEM_ANIMATION_DURATION, as sequencing of adding first two items " +
158d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen                    "is dependent on this");
159d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        }
1602e6da1539bc7286336b3c24d96ab76434939ce4dAdam Cohen
1612e6da1539bc7286336b3c24d96ab76434939ce4dAdam Cohen        DeviceProfile grid = launcher.getDeviceProfile();
16231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        FolderIcon icon = (FolderIcon) LayoutInflater.from(launcher).inflate(resId, group, false);
163efca0279eb927faebffc38c8382818df67fcd159Adam Cohen
164efca0279eb927faebffc38c8382818df67fcd159Adam Cohen        // For performance and compatibility reasons we render the preview using a software layer.
165efca0279eb927faebffc38c8382818df67fcd159Adam Cohen        // In particular, hardware path clipping has spotty ecosystem support and bad performance.
166efca0279eb927faebffc38c8382818df67fcd159Adam Cohen        // Software rendering also allows us to use shadow layers.
167efca0279eb927faebffc38c8382818df67fcd159Adam Cohen        icon.setLayerType(LAYER_TYPE_SOFTWARE, new Paint(Paint.FILTER_BITMAP_FLAG));
168efca0279eb927faebffc38c8382818df67fcd159Adam Cohen
1695f8afe6280eae34620067696173e71943e1a30a3Winson Chung        icon.setClipToPadding(false);
170d2eca6b66e654e71fb46ae718910af3ec6c2cf9cAdam Cohen        icon.mFolderName = (BubbleTextView) icon.findViewById(R.id.folder_icon_name);
17176fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen        icon.mFolderName.setText(folderInfo.title);
1726e1c0d34bb31cacc24c57c89ab01deaa8985814fWinson Chung        icon.mFolderName.setCompoundDrawablePadding(0);
1736e1c0d34bb31cacc24c57c89ab01deaa8985814fWinson Chung        FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) icon.mFolderName.getLayoutParams();
1746e1c0d34bb31cacc24c57c89ab01deaa8985814fWinson Chung        lp.topMargin = grid.iconSizePx + grid.iconDrawablePaddingPx;
1756e1c0d34bb31cacc24c57c89ab01deaa8985814fWinson Chung
17631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        icon.setTag(folderInfo);
17731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        icon.setOnClickListener(launcher);
17831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        icon.mInfo = folderInfo;
17931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        icon.mLauncher = launcher;
180f4f89ef608245d39bbddda05f291361d2ae06667Sunny Goyal        icon.setContentDescription(launcher.getString(R.string.folder_name_format, folderInfo.title));
181a9cf38f533d1e86269868f1e6a806ccffd4a78fcAdam Cohen        Folder folder = Folder.fromXml(launcher);
182a9cf38f533d1e86269868f1e6a806ccffd4a78fcAdam Cohen        folder.setDragController(launcher.getDragController());
1832801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen        folder.setFolderIcon(icon);
184a9cf38f533d1e86269868f1e6a806ccffd4a78fcAdam Cohen        folder.bind(folderInfo);
1854f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen        icon.setFolder(folder);
186099f60d51f6310e1290687e83958e665b3324504Adam Cohen
187099f60d51f6310e1290687e83958e665b3324504Adam Cohen        folderInfo.addListener(icon);
188099f60d51f6310e1290687e83958e665b3324504Adam Cohen
189dcbcc86353e9ed52daac87f292aece667cd0ac71Sunny Goyal        icon.setOnFocusChangeListener(launcher.mFocusHandler);
19019072da7441e07d5e90026d9e9e1b38f11245e44Adam Cohen        return icon;
19119072da7441e07d5e90026d9e9e1b38f11245e44Adam Cohen    }
19219072da7441e07d5e90026d9e9e1b38f11245e44Adam Cohen
193099f60d51f6310e1290687e83958e665b3324504Adam Cohen    @Override
194099f60d51f6310e1290687e83958e665b3324504Adam Cohen    protected Parcelable onSaveInstanceState() {
195099f60d51f6310e1290687e83958e665b3324504Adam Cohen        sStaticValuesDirty = true;
196099f60d51f6310e1290687e83958e665b3324504Adam Cohen        return super.onSaveInstanceState();
197099f60d51f6310e1290687e83958e665b3324504Adam Cohen    }
198099f60d51f6310e1290687e83958e665b3324504Adam Cohen
19969ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen
20031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
201f05545fcc2df05518731f8d7ff048d797fe776d5Anjali Koppal    public Folder getFolder() {
202fb91f303f5e672f9b4c4f9f8a03486b224d60cd6Adam Cohen        return mFolder;
203fb91f303f5e672f9b4c4f9f8a03486b224d60cd6Adam Cohen    }
204fb91f303f5e672f9b4c4f9f8a03486b224d60cd6Adam Cohen
2054f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen    private void setFolder(Folder folder) {
2064f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen        mFolder = folder;
2074f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen        updateItemDrawingParams(false);
2084f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen    }
2094f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen
210f9c184a619e4e4b82cf9e0bf318ca6d8deaaaee7Adam Cohen    public FolderInfo getFolderInfo() {
211fb91f303f5e672f9b4c4f9f8a03486b224d60cd6Adam Cohen        return mInfo;
212fb91f303f5e672f9b4c4f9f8a03486b224d60cd6Adam Cohen    }
213fb91f303f5e672f9b4c4f9f8a03486b224d60cd6Adam Cohen
214073a46ff635d089cbcb15d939d1de42dd2b86c97Adam Cohen    private boolean willAcceptItem(ItemInfo item) {
21531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        final int itemType = item.itemType;
2162801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen        return ((itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION ||
2172801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen                itemType == LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT) &&
218c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen                !mFolder.isFull() && item != mInfo && !mInfo.opened);
219073a46ff635d089cbcb15d939d1de42dd2b86c97Adam Cohen    }
220073a46ff635d089cbcb15d939d1de42dd2b86c97Adam Cohen
221aa8ef119f18864f4ab41c12f9c2ad6d7f643a0a9Sunny Goyal    public boolean acceptDrop(ItemInfo dragInfo) {
222aa8ef119f18864f4ab41c12f9c2ad6d7f643a0a9Sunny Goyal        final ItemInfo item = dragInfo;
223fb91f303f5e672f9b4c4f9f8a03486b224d60cd6Adam Cohen        return !mFolder.isDestroyed() && willAcceptItem(item);
22431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
22531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
226df0353815c629fc678824b07a234b89a1ff94208Adam Cohen    public void addItem(ShortcutInfo item) {
227df0353815c629fc678824b07a234b89a1ff94208Adam Cohen        mInfo.add(item);
228df0353815c629fc678824b07a234b89a1ff94208Adam Cohen    }
229df0353815c629fc678824b07a234b89a1ff94208Adam Cohen
230aa8ef119f18864f4ab41c12f9c2ad6d7f643a0a9Sunny Goyal    public void onDragEnter(ItemInfo dragInfo) {
231aa8ef119f18864f4ab41c12f9c2ad6d7f643a0a9Sunny Goyal        if (mFolder.isDestroyed() || !willAcceptItem(dragInfo)) return;
23269ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen        CellLayout.LayoutParams lp = (CellLayout.LayoutParams) getLayoutParams();
233efca0279eb927faebffc38c8382818df67fcd159Adam Cohen        CellLayout cl = (CellLayout) getParent().getParent();
234efca0279eb927faebffc38c8382818df67fcd159Adam Cohen
235efca0279eb927faebffc38c8382818df67fcd159Adam Cohen        mBackground.animateToAccept(cl, lp.cellX, lp.cellY);
23655bd9725d5c0373b89f7b9bbd9547550ea3bbc63Jorim Jaggi        mOpenAlarm.setOnAlarmListener(mOnOpenListener);
237dedfca2aef7573624bdb421b1805ef5e04bee502Adam Cohen        if (SPRING_LOADING_ENABLED &&
238dedfca2aef7573624bdb421b1805ef5e04bee502Adam Cohen                ((dragInfo instanceof AppInfo) || (dragInfo instanceof ShortcutInfo))) {
239dedfca2aef7573624bdb421b1805ef5e04bee502Adam Cohen            // TODO: we currently don't support spring-loading for PendingAddShortcutInfos even
240dedfca2aef7573624bdb421b1805ef5e04bee502Adam Cohen            // though widget-style shortcuts can be added to folders. The issue is that we need
241dedfca2aef7573624bdb421b1805ef5e04bee502Adam Cohen            // to deal with configuration activities which are currently handled in
242dedfca2aef7573624bdb421b1805ef5e04bee502Adam Cohen            // Workspace#onDropExternal.
24355bd9725d5c0373b89f7b9bbd9547550ea3bbc63Jorim Jaggi            mOpenAlarm.setAlarm(ON_OPEN_DELAY);
24455bd9725d5c0373b89f7b9bbd9547550ea3bbc63Jorim Jaggi        }
245aa8ef119f18864f4ab41c12f9c2ad6d7f643a0a9Sunny Goyal        mDragInfo = dragInfo;
246073a46ff635d089cbcb15d939d1de42dd2b86c97Adam Cohen    }
247073a46ff635d089cbcb15d939d1de42dd2b86c97Adam Cohen
24855bd9725d5c0373b89f7b9bbd9547550ea3bbc63Jorim Jaggi    OnAlarmListener mOnOpenListener = new OnAlarmListener() {
24955bd9725d5c0373b89f7b9bbd9547550ea3bbc63Jorim Jaggi        public void onAlarm(Alarm alarm) {
25055bd9725d5c0373b89f7b9bbd9547550ea3bbc63Jorim Jaggi            ShortcutInfo item;
25155bd9725d5c0373b89f7b9bbd9547550ea3bbc63Jorim Jaggi            if (mDragInfo instanceof AppInfo) {
25255bd9725d5c0373b89f7b9bbd9547550ea3bbc63Jorim Jaggi                // Came from all apps -- make a copy.
25355bd9725d5c0373b89f7b9bbd9547550ea3bbc63Jorim Jaggi                item = ((AppInfo) mDragInfo).makeShortcut();
25455bd9725d5c0373b89f7b9bbd9547550ea3bbc63Jorim Jaggi                item.spanX = 1;
25555bd9725d5c0373b89f7b9bbd9547550ea3bbc63Jorim Jaggi                item.spanY = 1;
25655bd9725d5c0373b89f7b9bbd9547550ea3bbc63Jorim Jaggi            } else {
257dedfca2aef7573624bdb421b1805ef5e04bee502Adam Cohen                // ShortcutInfo
25855bd9725d5c0373b89f7b9bbd9547550ea3bbc63Jorim Jaggi                item = (ShortcutInfo) mDragInfo;
25955bd9725d5c0373b89f7b9bbd9547550ea3bbc63Jorim Jaggi            }
26055bd9725d5c0373b89f7b9bbd9547550ea3bbc63Jorim Jaggi            mFolder.beginExternalDrag(item);
26108442b84a25a22f3f21aad89ed5a6adccaa2166dSunny Goyal            mLauncher.openFolder(FolderIcon.this, true);
26255bd9725d5c0373b89f7b9bbd9547550ea3bbc63Jorim Jaggi        }
26355bd9725d5c0373b89f7b9bbd9547550ea3bbc63Jorim Jaggi    };
26455bd9725d5c0373b89f7b9bbd9547550ea3bbc63Jorim Jaggi
265d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen    public void performCreateAnimation(final ShortcutInfo destInfo, final View destView,
2667bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung            final ShortcutInfo srcInfo, final DragView srcView, Rect dstRect,
267ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen            float scaleRelativeToDragLayer, Runnable postAnimationRunnable) {
268d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen
269fb91f303f5e672f9b4c4f9f8a03486b224d60cd6Adam Cohen        // These correspond two the drawable and view that the icon was dropped _onto_
27095abbb330ce9bbaf23594245f0f8a795c8118038Sunny Goyal        Drawable animateDrawable = getTopDrawable((TextView) destView);
271fb91f303f5e672f9b4c4f9f8a03486b224d60cd6Adam Cohen        computePreviewDrawingParams(animateDrawable.getIntrinsicWidth(),
272fb91f303f5e672f9b4c4f9f8a03486b224d60cd6Adam Cohen                destView.getMeasuredWidth());
273fb91f303f5e672f9b4c4f9f8a03486b224d60cd6Adam Cohen
2744f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen        mReferenceDrawable = animateDrawable;
2754f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen
2764f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen        addItem(destInfo);
277fb91f303f5e672f9b4c4f9f8a03486b224d60cd6Adam Cohen        // This will animate the first item from it's position as an icon into its
278fb91f303f5e672f9b4c4f9f8a03486b224d60cd6Adam Cohen        // position as the first item in the preview
279fb91f303f5e672f9b4c4f9f8a03486b224d60cd6Adam Cohen        animateFirstItem(animateDrawable, INITIAL_ITEM_ANIMATION_DURATION, false, null);
280ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen
281d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        // This will animate the dragView (srcView) into the new folder
2827bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung        onDrop(srcInfo, srcView, dstRect, scaleRelativeToDragLayer, 1, postAnimationRunnable, null);
283fb91f303f5e672f9b4c4f9f8a03486b224d60cd6Adam Cohen    }
284fb91f303f5e672f9b4c4f9f8a03486b224d60cd6Adam Cohen
285fb91f303f5e672f9b4c4f9f8a03486b224d60cd6Adam Cohen    public void performDestroyAnimation(final View finalView, Runnable onCompleteRunnable) {
28695abbb330ce9bbaf23594245f0f8a795c8118038Sunny Goyal        Drawable animateDrawable = getTopDrawable((TextView) finalView);
28702dd7aea3d8ac94126a8f8069e6762592ea60326Jason Monk        computePreviewDrawingParams(animateDrawable.getIntrinsicWidth(),
288fb91f303f5e672f9b4c4f9f8a03486b224d60cd6Adam Cohen                finalView.getMeasuredWidth());
289d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen
290d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        // This will animate the first item from it's position as an icon into its
291d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        // position as the first item in the preview
292fb91f303f5e672f9b4c4f9f8a03486b224d60cd6Adam Cohen        animateFirstItem(animateDrawable, FINAL_ITEM_ANIMATION_DURATION, true,
293fb91f303f5e672f9b4c4f9f8a03486b224d60cd6Adam Cohen                onCompleteRunnable);
294d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen    }
295d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen
296c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen    public void onDragExit(Object dragInfo) {
297c6cc61d45836e4081920883cc4d448ccb0bb8417Adam Cohen        onDragExit();
298c6cc61d45836e4081920883cc4d448ccb0bb8417Adam Cohen    }
299c6cc61d45836e4081920883cc4d448ccb0bb8417Adam Cohen
300c6cc61d45836e4081920883cc4d448ccb0bb8417Adam Cohen    public void onDragExit() {
301efca0279eb927faebffc38c8382818df67fcd159Adam Cohen        mBackground.animateToRest();
30255bd9725d5c0373b89f7b9bbd9547550ea3bbc63Jorim Jaggi        mOpenAlarm.cancelAlarm();
303073a46ff635d089cbcb15d939d1de42dd2b86c97Adam Cohen    }
304073a46ff635d089cbcb15d939d1de42dd2b86c97Adam Cohen
3057bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung    private void onDrop(final ShortcutInfo item, DragView animateView, Rect finalRect,
3067bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung            float scaleRelativeToDragLayer, int index, Runnable postAnimationRunnable,
3077bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung            DragObject d) {
308d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        item.cellX = -1;
309d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        item.cellY = -1;
310d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen
311558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen        // Typically, the animateView corresponds to the DragView; however, if this is being done
312558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen        // after a configuration activity (ie. for a Shortcut being dragged from AllApps) we
313558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen        // will not have a view to animate
314558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen        if (animateView != null) {
315558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen            DragLayer dragLayer = mLauncher.getDragLayer();
316558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen            Rect from = new Rect();
317558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen            dragLayer.getViewRectRelativeToSelf(animateView, from);
318558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen            Rect to = finalRect;
319558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen            if (to == null) {
320558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen                to = new Rect();
321558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen                Workspace workspace = mLauncher.getWorkspace();
322558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen                // Set cellLayout and this to it's final state to compute final animation locations
323558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen                workspace.setFinalTransitionTransform((CellLayout) getParent().getParent());
324558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen                float scaleX = getScaleX();
325558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen                float scaleY = getScaleY();
326558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen                setScaleX(1.0f);
327558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen                setScaleY(1.0f);
328558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen                scaleRelativeToDragLayer = dragLayer.getDescendantRectRelativeToSelf(this, to);
329558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen                // Finished computing final animation locations, restore current state
330558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen                setScaleX(scaleX);
331558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen                setScaleY(scaleY);
332558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen                workspace.resetTransitionTransform((CellLayout) getParent().getParent());
333558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen            }
334ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen
335558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen            int[] center = new int[2];
336119e8982ab6a0cf00e31e8744f27b72ba8bf7b20Adam Cohen            float scale = getLocalCenterForIndex(index, index + 1, center);
337558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen            center[0] = (int) Math.round(scaleRelativeToDragLayer * center[0]);
338558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen            center[1] = (int) Math.round(scaleRelativeToDragLayer * center[1]);
339d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen
340558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen            to.offset(center[0] - animateView.getMeasuredWidth() / 2,
3415f8afe6280eae34620067696173e71943e1a30a3Winson Chung                      center[1] - animateView.getMeasuredHeight() / 2);
342d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen
343f9c184a619e4e4b82cf9e0bf318ca6d8deaaaee7Adam Cohen            float finalAlpha = index < mPreviewLayoutRule.numItems() ? 0.5f : 0f;
344558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen
345ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen            float finalScale = scale * scaleRelativeToDragLayer;
346558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen            dragLayer.animateView(animateView, from, to, finalAlpha,
347ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen                    1, 1, finalScale, finalScale, DROP_IN_ANIMATION_DURATION,
348558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen                    new DecelerateInterpolator(2), new AccelerateInterpolator(2),
349ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen                    postAnimationRunnable, DragLayer.ANIMATION_END_DISAPPEAR, null);
350fb91f303f5e672f9b4c4f9f8a03486b224d60cd6Adam Cohen            addItem(item);
3517a8b82b5926e6a520df28e7f591b9a94ec605581Adam Cohen            mFolder.hideItem(item);
3524f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen
3534f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen            final PreviewItemDrawingParams params = index < mDrawingParams.size() ?
3544f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen                    mDrawingParams.get(index) : null;
3554f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen            if (params != null) params.hidden = true;
356558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen            postDelayed(new Runnable() {
357558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen                public void run() {
3584f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen                    if (params != null) params.hidden = false;
3597a8b82b5926e6a520df28e7f591b9a94ec605581Adam Cohen                    mFolder.showItem(item);
360fb91f303f5e672f9b4c4f9f8a03486b224d60cd6Adam Cohen                    invalidate();
361558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen                }
362558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen            }, DROP_IN_ANIMATION_DURATION);
363558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen        } else {
364558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen            addItem(item);
365558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen        }
366d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen    }
367d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen
3683e8f811f31a2275e778244427271f77f4116c08bAdam Cohen    public void onDrop(DragObject d) {
369c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen        ShortcutInfo item;
370eadbfc564d84aaf1d800da3d0d6edf6312f89648Michael Jurka        if (d.dragInfo instanceof AppInfo) {
371c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen            // Came from all apps -- make a copy
372eadbfc564d84aaf1d800da3d0d6edf6312f89648Michael Jurka            item = ((AppInfo) d.dragInfo).makeShortcut();
373c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen        } else {
3743e8f811f31a2275e778244427271f77f4116c08bAdam Cohen            item = (ShortcutInfo) d.dragInfo;
375c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen        }
37667bd9ccf856840856944815a382e4bbb0e71e949Adam Cohen        mFolder.notifyDrop();
3777bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung        onDrop(item, d.dragView, null, 1.0f, mInfo.contents.size(), d.postAnimationRunnable, d);
378c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen    }
379c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen
380d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen    private void computePreviewDrawingParams(int drawableSize, int totalSize) {
381aa2542a461072a57058ce45946ff6f5552ecce8aAdam Cohen        if (mIntrinsicIconSize != drawableSize || mTotalWidth != totalSize ||
382aa2542a461072a57058ce45946ff6f5552ecce8aAdam Cohen                mPrevTopPadding != getPaddingTop()) {
3832e6da1539bc7286336b3c24d96ab76434939ce4dAdam Cohen            DeviceProfile grid = mLauncher.getDeviceProfile();
3845f8afe6280eae34620067696173e71943e1a30a3Winson Chung
385d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen            mIntrinsicIconSize = drawableSize;
386d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen            mTotalWidth = totalSize;
387aa2542a461072a57058ce45946ff6f5552ecce8aAdam Cohen            mPrevTopPadding = getPaddingTop();
38876fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen
389efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            mBackground.setup(getResources().getDisplayMetrics(), grid, this, mTotalWidth,
390efca0279eb927faebffc38c8382818df67fcd159Adam Cohen                    getPaddingTop());
391efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            mPreviewLayoutRule.init(mBackground.previewSize, mIntrinsicIconSize,
392119e8982ab6a0cf00e31e8744f27b72ba8bf7b20Adam Cohen                    Utilities.isRtl(getResources()));
393efca0279eb927faebffc38c8382818df67fcd159Adam Cohen
3944f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen            updateItemDrawingParams(false);
395073a46ff635d089cbcb15d939d1de42dd2b86c97Adam Cohen        }
396d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen    }
39776fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen
398d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen    private void computePreviewDrawingParams(Drawable d) {
399d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        computePreviewDrawingParams(d.getIntrinsicWidth(), getMeasuredWidth());
400d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen    }
401073a46ff635d089cbcb15d939d1de42dd2b86c97Adam Cohen
402261194387beebaa7927ec4e310274218b651494dSunny Goyal    static class PreviewItemDrawingParams {
403261194387beebaa7927ec4e310274218b651494dSunny Goyal        PreviewItemDrawingParams(float transX, float transY, float scale, float overlayAlpha) {
404d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen            this.transX = transX;
405d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen            this.transY = transY;
406d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen            this.scale = scale;
407d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen            this.overlayAlpha = overlayAlpha;
408d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        }
4094f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen
4104f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen        public void update(float transX, float transY, float scale) {
4114f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen            // We ensure the update will not interfere with an animation on the layout params
4124f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen            // If the final values differ, we cancel the animation.
4134f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen            if (anim != null) {
4144f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen                if (anim.finalTransX == transX || anim.finalTransY == transY
4154f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen                        || anim.finalScale == scale) {
4164f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen                    return;
4174f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen                }
4184f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen                anim.cancel();
4194f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen            }
4204f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen
4214f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen            this.transX = transX;
4224f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen            this.transY = transY;
4234f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen            this.scale = scale;
4244f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen        }
4254f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen
426261194387beebaa7927ec4e310274218b651494dSunny Goyal        float transX;
427261194387beebaa7927ec4e310274218b651494dSunny Goyal        float transY;
428261194387beebaa7927ec4e310274218b651494dSunny Goyal        float scale;
4294f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen        public float overlayAlpha;
4304f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen        boolean hidden;
4314f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen        FolderPreviewItemAnim anim;
432261194387beebaa7927ec4e310274218b651494dSunny Goyal        Drawable drawable;
433d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen    }
434badf71e11fba2d6efa1d1bcca9542001f90a3777Adam Cohen
435119e8982ab6a0cf00e31e8744f27b72ba8bf7b20Adam Cohen    private float getLocalCenterForIndex(int index, int curNumItems, int[] center) {
4364f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen        mTmpParams = computePreviewItemDrawingParams(Math.min(mPreviewLayoutRule.numItems(), index),
4374f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen                curNumItems, mTmpParams);
438a9cf38f533d1e86269868f1e6a806ccffd4a78fcAdam Cohen
439efca0279eb927faebffc38c8382818df67fcd159Adam Cohen        mTmpParams.transX += mBackground.basePreviewOffsetX;
440efca0279eb927faebffc38c8382818df67fcd159Adam Cohen        mTmpParams.transY += mBackground.basePreviewOffsetY;
4414f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen        float offsetX = mTmpParams.transX + (mTmpParams.scale * mIntrinsicIconSize) / 2;
4424f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen        float offsetY = mTmpParams.transY + (mTmpParams.scale * mIntrinsicIconSize) / 2;
443badf71e11fba2d6efa1d1bcca9542001f90a3777Adam Cohen
444ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen        center[0] = (int) Math.round(offsetX);
445ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen        center[1] = (int) Math.round(offsetY);
4464f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen        return mTmpParams.scale;
447d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen    }
448badf71e11fba2d6efa1d1bcca9542001f90a3777Adam Cohen
449119e8982ab6a0cf00e31e8744f27b72ba8bf7b20Adam Cohen    private PreviewItemDrawingParams computePreviewItemDrawingParams(int index, int curNumItems,
450d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen            PreviewItemDrawingParams params) {
4514f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen        // We use an index of -1 to represent an icon on the workspace for the destroy and
4524f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen        // create animations
4534f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen        if (index == -1) {
4544f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen            return getFinalIconParams(params);
4554f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen        }
456119e8982ab6a0cf00e31e8744f27b72ba8bf7b20Adam Cohen        return mPreviewLayoutRule.computePreviewItemDrawingParams(index, curNumItems, params);
457d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen    }
458badf71e11fba2d6efa1d1bcca9542001f90a3777Adam Cohen
4594f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen    private PreviewItemDrawingParams getFinalIconParams(PreviewItemDrawingParams params) {
4604f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen        float iconSize = mLauncher.getDeviceProfile().iconSizePx;
4614f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen
4624f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen        final float scale = iconSize / mReferenceDrawable.getIntrinsicWidth();
463efca0279eb927faebffc38c8382818df67fcd159Adam Cohen        final float trans = (mBackground.previewSize - iconSize) / 2;
4644f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen
4654f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen        params.update(trans, trans, scale);
4664f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen        return params;
4674f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen    }
4684f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen
469d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen    private void drawPreviewItem(Canvas canvas, PreviewItemDrawingParams params) {
470d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        canvas.save();
471119e8982ab6a0cf00e31e8744f27b72ba8bf7b20Adam Cohen        canvas.translate(params.transX, params.transY);
472d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        canvas.scale(params.scale, params.scale);
473d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        Drawable d = params.drawable;
474d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen
475d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        if (d != null) {
476d4e53c882494f8cd7e4c0d44dbfc300d3610afcfWinson Chung            mOldBounds.set(d.getBounds());
477d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen            d.setBounds(0, 0, mIntrinsicIconSize, mIntrinsicIconSize);
478c5c60ad3592f53549c9ffaa58e9a87b0480080e8Sunny Goyal            if (d instanceof FastBitmapDrawable) {
479c5c60ad3592f53549c9ffaa58e9a87b0480080e8Sunny Goyal                FastBitmapDrawable fd = (FastBitmapDrawable) d;
480c088049113c261331b5685e64050d14a31cd72dfWinson                float oldBrightness = fd.getBrightness();
481508da15509224b46fcccabbe78f3e92fe69a67d8Sunny Goyal                fd.setBrightness(params.overlayAlpha);
482c5c60ad3592f53549c9ffaa58e9a87b0480080e8Sunny Goyal                d.draw(canvas);
483508da15509224b46fcccabbe78f3e92fe69a67d8Sunny Goyal                fd.setBrightness(oldBrightness);
484c5c60ad3592f53549c9ffaa58e9a87b0480080e8Sunny Goyal            } else {
485c088049113c261331b5685e64050d14a31cd72dfWinson                d.setColorFilter(Color.argb((int) (params.overlayAlpha * 255), 255, 255, 255),
486c5c60ad3592f53549c9ffaa58e9a87b0480080e8Sunny Goyal                        PorterDuff.Mode.SRC_ATOP);
487c5c60ad3592f53549c9ffaa58e9a87b0480080e8Sunny Goyal                d.draw(canvas);
488c5c60ad3592f53549c9ffaa58e9a87b0480080e8Sunny Goyal                d.clearColorFilter();
489c5c60ad3592f53549c9ffaa58e9a87b0480080e8Sunny Goyal            }
490d4e53c882494f8cd7e4c0d44dbfc300d3610afcfWinson Chung            d.setBounds(mOldBounds);
491d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        }
492d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        canvas.restore();
493d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen    }
49476fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen
495f172b747c24f28e29baaaf58f08bab48847b7a40Adam Cohen    /**
496f172b747c24f28e29baaaf58f08bab48847b7a40Adam Cohen     * This object represents a FolderIcon preview background. It stores drawing / measurement
497f172b747c24f28e29baaaf58f08bab48847b7a40Adam Cohen     * information, handles drawing, and animation (accept state <--> rest state).
498f172b747c24f28e29baaaf58f08bab48847b7a40Adam Cohen     */
499efca0279eb927faebffc38c8382818df67fcd159Adam Cohen    public static class PreviewBackground {
500efca0279eb927faebffc38c8382818df67fcd159Adam Cohen        private float mScale = 1f;
501efca0279eb927faebffc38c8382818df67fcd159Adam Cohen        private float mColorMultiplier = 1f;
502efca0279eb927faebffc38c8382818df67fcd159Adam Cohen        private Path mClipPath = new Path();
503efca0279eb927faebffc38c8382818df67fcd159Adam Cohen        private int mStrokeWidth;
504f172b747c24f28e29baaaf58f08bab48847b7a40Adam Cohen        private View mInvalidateDelegate;
505efca0279eb927faebffc38c8382818df67fcd159Adam Cohen
506efca0279eb927faebffc38c8382818df67fcd159Adam Cohen        public int previewSize;
507efca0279eb927faebffc38c8382818df67fcd159Adam Cohen        private int basePreviewOffsetX;
508efca0279eb927faebffc38c8382818df67fcd159Adam Cohen        private int basePreviewOffsetY;
509efca0279eb927faebffc38c8382818df67fcd159Adam Cohen
510efca0279eb927faebffc38c8382818df67fcd159Adam Cohen        private CellLayout mDrawingDelegate;
511efca0279eb927faebffc38c8382818df67fcd159Adam Cohen        public int delegateCellX;
512efca0279eb927faebffc38c8382818df67fcd159Adam Cohen        public int delegateCellY;
513efca0279eb927faebffc38c8382818df67fcd159Adam Cohen
514f172b747c24f28e29baaaf58f08bab48847b7a40Adam Cohen        // When the PreviewBackground is drawn under an icon (for creating a folder) the border
515f172b747c24f28e29baaaf58f08bab48847b7a40Adam Cohen        // should not occlude the icon
516f172b747c24f28e29baaaf58f08bab48847b7a40Adam Cohen        public boolean isClipping = true;
517f172b747c24f28e29baaaf58f08bab48847b7a40Adam Cohen
518efca0279eb927faebffc38c8382818df67fcd159Adam Cohen        // Drawing / animation configurations
519efca0279eb927faebffc38c8382818df67fcd159Adam Cohen        private static final float ACCEPT_SCALE_FACTOR = 1.25f;
520efca0279eb927faebffc38c8382818df67fcd159Adam Cohen        private static final float ACCEPT_COLOR_MULTIPLIER = 1.5f;
521efca0279eb927faebffc38c8382818df67fcd159Adam Cohen
522efca0279eb927faebffc38c8382818df67fcd159Adam Cohen        // Expressed on a scale from 0 to 255.
523efca0279eb927faebffc38c8382818df67fcd159Adam Cohen        private static final int BG_OPACITY = 160;
524efca0279eb927faebffc38c8382818df67fcd159Adam Cohen        private static final int MAX_BG_OPACITY = 225;
525efca0279eb927faebffc38c8382818df67fcd159Adam Cohen        private static final int BG_INTENSITY = 245;
526efca0279eb927faebffc38c8382818df67fcd159Adam Cohen        private static final int SHADOW_OPACITY = 80;
527efca0279eb927faebffc38c8382818df67fcd159Adam Cohen
528efca0279eb927faebffc38c8382818df67fcd159Adam Cohen        ValueAnimator mScaleAnimator;
529efca0279eb927faebffc38c8382818df67fcd159Adam Cohen
530f172b747c24f28e29baaaf58f08bab48847b7a40Adam Cohen        public void setup(DisplayMetrics dm, DeviceProfile grid, View invalidateDelegate,
531efca0279eb927faebffc38c8382818df67fcd159Adam Cohen                   int availableSpace, int topPadding) {
532f172b747c24f28e29baaaf58f08bab48847b7a40Adam Cohen            mInvalidateDelegate = invalidateDelegate;
533efca0279eb927faebffc38c8382818df67fcd159Adam Cohen
534efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            final int previewSize = grid.folderIconSizePx;
535efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            final int previewPadding = grid.folderIconPreviewPadding;
536efca0279eb927faebffc38c8382818df67fcd159Adam Cohen
537efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            this.previewSize = (previewSize - 2 * previewPadding);
538efca0279eb927faebffc38c8382818df67fcd159Adam Cohen
539efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            basePreviewOffsetX = (availableSpace - this.previewSize) / 2;
540efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            basePreviewOffsetY = previewPadding + grid.folderBackgroundOffset + topPadding;
541efca0279eb927faebffc38c8382818df67fcd159Adam Cohen
542efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            mStrokeWidth = Utilities.pxFromDp(1, dm);
543efca0279eb927faebffc38c8382818df67fcd159Adam Cohen
544efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            invalidate();
545efca0279eb927faebffc38c8382818df67fcd159Adam Cohen        }
546efca0279eb927faebffc38c8382818df67fcd159Adam Cohen
547efca0279eb927faebffc38c8382818df67fcd159Adam Cohen        int getRadius() {
548efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            return previewSize / 2;
549efca0279eb927faebffc38c8382818df67fcd159Adam Cohen        }
550efca0279eb927faebffc38c8382818df67fcd159Adam Cohen
551efca0279eb927faebffc38c8382818df67fcd159Adam Cohen        int getScaledRadius() {
552efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            return (int) (mScale * getRadius());
553efca0279eb927faebffc38c8382818df67fcd159Adam Cohen        }
554efca0279eb927faebffc38c8382818df67fcd159Adam Cohen
555efca0279eb927faebffc38c8382818df67fcd159Adam Cohen        int getOffsetX() {
556efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            return basePreviewOffsetX - (getScaledRadius() - getRadius());
557efca0279eb927faebffc38c8382818df67fcd159Adam Cohen        }
558efca0279eb927faebffc38c8382818df67fcd159Adam Cohen
559efca0279eb927faebffc38c8382818df67fcd159Adam Cohen        int getOffsetY() {
560efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            return basePreviewOffsetY - (getScaledRadius() - getRadius());
561efca0279eb927faebffc38c8382818df67fcd159Adam Cohen        }
562efca0279eb927faebffc38c8382818df67fcd159Adam Cohen
563efca0279eb927faebffc38c8382818df67fcd159Adam Cohen        void invalidate() {
564efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            int radius = getScaledRadius();
565efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            mClipPath.reset();
566efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            mClipPath.addCircle(radius, radius, radius, Path.Direction.CW);
567efca0279eb927faebffc38c8382818df67fcd159Adam Cohen
568f172b747c24f28e29baaaf58f08bab48847b7a40Adam Cohen            if (mInvalidateDelegate != null) {
569f172b747c24f28e29baaaf58f08bab48847b7a40Adam Cohen                mInvalidateDelegate.invalidate();
570efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            }
571efca0279eb927faebffc38c8382818df67fcd159Adam Cohen
572efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            if (mDrawingDelegate != null) {
573efca0279eb927faebffc38c8382818df67fcd159Adam Cohen                mDrawingDelegate.invalidate();
574efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            }
575efca0279eb927faebffc38c8382818df67fcd159Adam Cohen        }
576efca0279eb927faebffc38c8382818df67fcd159Adam Cohen
577f172b747c24f28e29baaaf58f08bab48847b7a40Adam Cohen        void setInvalidateDelegate(View invalidateDelegate) {
578f172b747c24f28e29baaaf58f08bab48847b7a40Adam Cohen            mInvalidateDelegate = invalidateDelegate;
579efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            invalidate();
580efca0279eb927faebffc38c8382818df67fcd159Adam Cohen        }
581efca0279eb927faebffc38c8382818df67fcd159Adam Cohen
582efca0279eb927faebffc38c8382818df67fcd159Adam Cohen        public void drawBackground(Canvas canvas, Paint paint) {
583efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            canvas.save();
584efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            canvas.translate(getOffsetX(), getOffsetY());
585efca0279eb927faebffc38c8382818df67fcd159Adam Cohen
586efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            paint.reset();
587efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            paint.setStyle(Paint.Style.FILL);
588efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            paint.setXfermode(null);
589efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            paint.setAntiAlias(true);
590efca0279eb927faebffc38c8382818df67fcd159Adam Cohen
591efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            int alpha = (int) Math.min(MAX_BG_OPACITY, BG_OPACITY * mColorMultiplier);
592efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            paint.setColor(Color.argb(alpha, BG_INTENSITY, BG_INTENSITY, BG_INTENSITY));
593efca0279eb927faebffc38c8382818df67fcd159Adam Cohen
594efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            float radius = getScaledRadius();
595efca0279eb927faebffc38c8382818df67fcd159Adam Cohen
596efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            canvas.drawCircle(radius, radius, radius, paint);
597efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            canvas.clipPath(mClipPath, Region.Op.DIFFERENCE);
598efca0279eb927faebffc38c8382818df67fcd159Adam Cohen
599efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            paint.setStyle(Paint.Style.STROKE);
600efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            paint.setColor(Color.TRANSPARENT);
601efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            paint.setShadowLayer(mStrokeWidth, 0, mStrokeWidth, Color.argb(SHADOW_OPACITY, 0, 0, 0));
602efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            canvas.drawCircle(radius, radius, radius, paint);
603efca0279eb927faebffc38c8382818df67fcd159Adam Cohen
604efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            canvas.restore();
605efca0279eb927faebffc38c8382818df67fcd159Adam Cohen        }
606efca0279eb927faebffc38c8382818df67fcd159Adam Cohen
607efca0279eb927faebffc38c8382818df67fcd159Adam Cohen        public void drawBackgroundStroke(Canvas canvas, Paint paint) {
608efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            canvas.save();
609efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            canvas.translate(getOffsetX(), getOffsetY());
610efca0279eb927faebffc38c8382818df67fcd159Adam Cohen
611efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            paint.reset();
612efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            paint.setAntiAlias(true);
613efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            paint.setColor(Color.argb(255, BG_INTENSITY, BG_INTENSITY, BG_INTENSITY));
614efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            paint.setStyle(Paint.Style.STROKE);
615efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            paint.setStrokeWidth(mStrokeWidth);
616efca0279eb927faebffc38c8382818df67fcd159Adam Cohen
617efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            float radius = getScaledRadius();
618efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            canvas.drawCircle(radius, radius, radius - 1, paint);
619efca0279eb927faebffc38c8382818df67fcd159Adam Cohen
620efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            canvas.restore();
621efca0279eb927faebffc38c8382818df67fcd159Adam Cohen        }
622efca0279eb927faebffc38c8382818df67fcd159Adam Cohen
623efca0279eb927faebffc38c8382818df67fcd159Adam Cohen        public void drawLeaveBehind(Canvas canvas, Paint paint) {
624efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            float originalScale = mScale;
625efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            mScale = 0.5f;
626efca0279eb927faebffc38c8382818df67fcd159Adam Cohen
627efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            canvas.save();
628efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            canvas.translate(getOffsetX(), getOffsetY());
629efca0279eb927faebffc38c8382818df67fcd159Adam Cohen
630efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            paint.reset();
631efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            paint.setAntiAlias(true);
632efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            paint.setColor(Color.argb(160, 245, 245, 245));
633efca0279eb927faebffc38c8382818df67fcd159Adam Cohen
634efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            float radius = getScaledRadius();
635efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            canvas.drawCircle(radius, radius, radius, paint);
636efca0279eb927faebffc38c8382818df67fcd159Adam Cohen
637efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            canvas.restore();
638efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            mScale = originalScale;
639efca0279eb927faebffc38c8382818df67fcd159Adam Cohen        }
640efca0279eb927faebffc38c8382818df67fcd159Adam Cohen
641efca0279eb927faebffc38c8382818df67fcd159Adam Cohen        // It is the callers responsibility to save and restore the canvas.
642efca0279eb927faebffc38c8382818df67fcd159Adam Cohen        private void clipCanvas(Canvas canvas) {
643efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            canvas.translate(getOffsetX(), getOffsetY());
644efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            canvas.clipPath(mClipPath);
645efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            canvas.translate(-getOffsetX(), -getOffsetY());
646efca0279eb927faebffc38c8382818df67fcd159Adam Cohen        }
647efca0279eb927faebffc38c8382818df67fcd159Adam Cohen
648efca0279eb927faebffc38c8382818df67fcd159Adam Cohen        private void delegateDrawing(CellLayout delegate, int cellX, int cellY) {
649efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            if (mDrawingDelegate != delegate) {
650efca0279eb927faebffc38c8382818df67fcd159Adam Cohen                delegate.addFolderBackground(this);
651efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            }
652efca0279eb927faebffc38c8382818df67fcd159Adam Cohen
653efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            mDrawingDelegate = delegate;
654efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            delegateCellX = cellX;
655efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            delegateCellY = cellY;
656efca0279eb927faebffc38c8382818df67fcd159Adam Cohen
657efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            invalidate();
658efca0279eb927faebffc38c8382818df67fcd159Adam Cohen        }
659efca0279eb927faebffc38c8382818df67fcd159Adam Cohen
660efca0279eb927faebffc38c8382818df67fcd159Adam Cohen        private void clearDrawingDelegate() {
661efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            if (mDrawingDelegate != null) {
662efca0279eb927faebffc38c8382818df67fcd159Adam Cohen                mDrawingDelegate.removeFolderBackground(this);
663efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            }
664efca0279eb927faebffc38c8382818df67fcd159Adam Cohen
665efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            mDrawingDelegate = null;
666efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            invalidate();
667efca0279eb927faebffc38c8382818df67fcd159Adam Cohen        }
668efca0279eb927faebffc38c8382818df67fcd159Adam Cohen
669efca0279eb927faebffc38c8382818df67fcd159Adam Cohen        private boolean drawingDelegated() {
670efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            return mDrawingDelegate != null;
671efca0279eb927faebffc38c8382818df67fcd159Adam Cohen        }
672efca0279eb927faebffc38c8382818df67fcd159Adam Cohen
673efca0279eb927faebffc38c8382818df67fcd159Adam Cohen        private void animateScale(float finalScale, float finalMultiplier,
674efca0279eb927faebffc38c8382818df67fcd159Adam Cohen                final Runnable onStart, final Runnable onEnd) {
675efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            final float scale0 = mScale;
676efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            final float scale1 = finalScale;
677efca0279eb927faebffc38c8382818df67fcd159Adam Cohen
678efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            final float bgMultiplier0 = mColorMultiplier;
679efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            final float bgMultiplier1 = finalMultiplier;
680efca0279eb927faebffc38c8382818df67fcd159Adam Cohen
681efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            if (mScaleAnimator != null) {
682efca0279eb927faebffc38c8382818df67fcd159Adam Cohen                mScaleAnimator.cancel();
683efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            }
684efca0279eb927faebffc38c8382818df67fcd159Adam Cohen
685efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            mScaleAnimator = LauncherAnimUtils.ofFloat(null, 0f, 1.0f);
686efca0279eb927faebffc38c8382818df67fcd159Adam Cohen
687efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            mScaleAnimator.addUpdateListener(new AnimatorUpdateListener() {
688efca0279eb927faebffc38c8382818df67fcd159Adam Cohen                @Override
689efca0279eb927faebffc38c8382818df67fcd159Adam Cohen                public void onAnimationUpdate(ValueAnimator animation) {
690efca0279eb927faebffc38c8382818df67fcd159Adam Cohen                    float prog = animation.getAnimatedFraction();
691efca0279eb927faebffc38c8382818df67fcd159Adam Cohen                    mScale = prog * scale1 + (1 - prog) * scale0;
692efca0279eb927faebffc38c8382818df67fcd159Adam Cohen                    mColorMultiplier = prog * bgMultiplier1 + (1 - prog) * bgMultiplier0;
693efca0279eb927faebffc38c8382818df67fcd159Adam Cohen                    invalidate();
694efca0279eb927faebffc38c8382818df67fcd159Adam Cohen                }
695efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            });
696efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            mScaleAnimator.addListener(new AnimatorListenerAdapter() {
697efca0279eb927faebffc38c8382818df67fcd159Adam Cohen                @Override
698efca0279eb927faebffc38c8382818df67fcd159Adam Cohen                public void onAnimationStart(Animator animation) {
699efca0279eb927faebffc38c8382818df67fcd159Adam Cohen                    if (onStart != null) {
700efca0279eb927faebffc38c8382818df67fcd159Adam Cohen                        onStart.run();
701efca0279eb927faebffc38c8382818df67fcd159Adam Cohen                    }
702efca0279eb927faebffc38c8382818df67fcd159Adam Cohen                }
703efca0279eb927faebffc38c8382818df67fcd159Adam Cohen
704efca0279eb927faebffc38c8382818df67fcd159Adam Cohen                @Override
705efca0279eb927faebffc38c8382818df67fcd159Adam Cohen                public void onAnimationEnd(Animator animation) {
706efca0279eb927faebffc38c8382818df67fcd159Adam Cohen                    if (onEnd != null) {
707efca0279eb927faebffc38c8382818df67fcd159Adam Cohen                        onEnd.run();
708efca0279eb927faebffc38c8382818df67fcd159Adam Cohen                    }
709efca0279eb927faebffc38c8382818df67fcd159Adam Cohen                    mScaleAnimator = null;
710efca0279eb927faebffc38c8382818df67fcd159Adam Cohen                }
711efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            });
712efca0279eb927faebffc38c8382818df67fcd159Adam Cohen
713efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            mScaleAnimator.setDuration(CONSUMPTION_ANIMATION_DURATION);
714efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            mScaleAnimator.start();
715efca0279eb927faebffc38c8382818df67fcd159Adam Cohen        }
716efca0279eb927faebffc38c8382818df67fcd159Adam Cohen
717efca0279eb927faebffc38c8382818df67fcd159Adam Cohen        public void animateToAccept(final CellLayout cl, final int cellX, final int cellY) {
718efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            Runnable onStart = new Runnable() {
719efca0279eb927faebffc38c8382818df67fcd159Adam Cohen                @Override
720efca0279eb927faebffc38c8382818df67fcd159Adam Cohen                public void run() {
721efca0279eb927faebffc38c8382818df67fcd159Adam Cohen                    delegateDrawing(cl, cellX, cellY);
722efca0279eb927faebffc38c8382818df67fcd159Adam Cohen                }
723efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            };
724efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            animateScale(ACCEPT_SCALE_FACTOR, ACCEPT_COLOR_MULTIPLIER, onStart, null);
725efca0279eb927faebffc38c8382818df67fcd159Adam Cohen        }
726efca0279eb927faebffc38c8382818df67fcd159Adam Cohen
727efca0279eb927faebffc38c8382818df67fcd159Adam Cohen        public void animateToRest() {
728efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            // This can be called multiple times -- we need to make sure the drawing delegate
729efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            // is saved and restored at the beginning of the animation, since cancelling the
730efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            // existing animation can clear the delgate.
731efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            final CellLayout cl = mDrawingDelegate;
732efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            final int cellX = delegateCellX;
733efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            final int cellY = delegateCellY;
734efca0279eb927faebffc38c8382818df67fcd159Adam Cohen
735efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            Runnable onStart = new Runnable() {
736efca0279eb927faebffc38c8382818df67fcd159Adam Cohen                @Override
737efca0279eb927faebffc38c8382818df67fcd159Adam Cohen                public void run() {
738efca0279eb927faebffc38c8382818df67fcd159Adam Cohen                    delegateDrawing(cl, cellX, cellY);
739efca0279eb927faebffc38c8382818df67fcd159Adam Cohen                }
740efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            };
741efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            Runnable onEnd = new Runnable() {
742efca0279eb927faebffc38c8382818df67fcd159Adam Cohen                @Override
743efca0279eb927faebffc38c8382818df67fcd159Adam Cohen                public void run() {
744efca0279eb927faebffc38c8382818df67fcd159Adam Cohen                    clearDrawingDelegate();
745efca0279eb927faebffc38c8382818df67fcd159Adam Cohen                }
746efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            };
747efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            animateScale(1f, 1f, onStart, onEnd);
748efca0279eb927faebffc38c8382818df67fcd159Adam Cohen        }
749efca0279eb927faebffc38c8382818df67fcd159Adam Cohen    }
750efca0279eb927faebffc38c8382818df67fcd159Adam Cohen
751efca0279eb927faebffc38c8382818df67fcd159Adam Cohen    public void setFolderBackground(PreviewBackground bg) {
752efca0279eb927faebffc38c8382818df67fcd159Adam Cohen        mBackground = bg;
753f172b747c24f28e29baaaf58f08bab48847b7a40Adam Cohen        mBackground.setInvalidateDelegate(this);
754efca0279eb927faebffc38c8382818df67fcd159Adam Cohen    }
755efca0279eb927faebffc38c8382818df67fcd159Adam Cohen
756d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen    @Override
757d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen    protected void dispatchDraw(Canvas canvas) {
758d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        super.dispatchDraw(canvas);
759badf71e11fba2d6efa1d1bcca9542001f90a3777Adam Cohen
7604f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen        if (mReferenceDrawable != null) {
7614f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen            computePreviewDrawingParams(mReferenceDrawable);
762d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        }
763a9cf38f533d1e86269868f1e6a806ccffd4a78fcAdam Cohen
764efca0279eb927faebffc38c8382818df67fcd159Adam Cohen        if (!mBackground.drawingDelegated()) {
765efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            mBackground.drawBackground(canvas, mBgPaint);
766efca0279eb927faebffc38c8382818df67fcd159Adam Cohen        }
767efca0279eb927faebffc38c8382818df67fcd159Adam Cohen
768efca0279eb927faebffc38c8382818df67fcd159Adam Cohen        if (mFolder == null) return;
769efca0279eb927faebffc38c8382818df67fcd159Adam Cohen        if (mFolder.getItemCount() == 0 && !mAnimating) return;
770efca0279eb927faebffc38c8382818df67fcd159Adam Cohen
771119e8982ab6a0cf00e31e8744f27b72ba8bf7b20Adam Cohen        canvas.save();
772efca0279eb927faebffc38c8382818df67fcd159Adam Cohen
773efca0279eb927faebffc38c8382818df67fcd159Adam Cohen
774efca0279eb927faebffc38c8382818df67fcd159Adam Cohen        if (mPreviewLayoutRule.clipToBackground()) {
775efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            mBackground.clipCanvas(canvas);
776119e8982ab6a0cf00e31e8744f27b72ba8bf7b20Adam Cohen        }
777119e8982ab6a0cf00e31e8744f27b72ba8bf7b20Adam Cohen
778efca0279eb927faebffc38c8382818df67fcd159Adam Cohen        // The items are drawn in coordinates relative to the preview offset
779efca0279eb927faebffc38c8382818df67fcd159Adam Cohen        canvas.translate(mBackground.basePreviewOffsetX, mBackground.basePreviewOffsetY);
780efca0279eb927faebffc38c8382818df67fcd159Adam Cohen
7814f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen        // The first item should be drawn last (ie. on top of later items)
7824f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen        for (int i = mDrawingParams.size() - 1; i >= 0; i--) {
7834f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen            PreviewItemDrawingParams p = mDrawingParams.get(i);
7844f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen            if (!p.hidden) {
7854f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen                drawPreviewItem(canvas, p);
786a9cf38f533d1e86269868f1e6a806ccffd4a78fcAdam Cohen            }
787a9cf38f533d1e86269868f1e6a806ccffd4a78fcAdam Cohen        }
788119e8982ab6a0cf00e31e8744f27b72ba8bf7b20Adam Cohen        canvas.restore();
789efca0279eb927faebffc38c8382818df67fcd159Adam Cohen
790efca0279eb927faebffc38c8382818df67fcd159Adam Cohen        if (mPreviewLayoutRule.clipToBackground() && !mBackground.drawingDelegated()) {
791efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            mBackground.drawBackgroundStroke(canvas, mBgPaint);
792efca0279eb927faebffc38c8382818df67fcd159Adam Cohen        }
793d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen    }
794d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen
7953484638cad97e255a412b0489a63873fb3ca4218Sunny Goyal    private Drawable getTopDrawable(TextView v) {
7963484638cad97e255a412b0489a63873fb3ca4218Sunny Goyal        Drawable d = v.getCompoundDrawables()[1];
7973484638cad97e255a412b0489a63873fb3ca4218Sunny Goyal        return (d instanceof PreloadIconDrawable) ? ((PreloadIconDrawable) d).mIcon : d;
7983484638cad97e255a412b0489a63873fb3ca4218Sunny Goyal    }
7993484638cad97e255a412b0489a63873fb3ca4218Sunny Goyal
8004f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen    class FolderPreviewItemAnim {
8014f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen        ValueAnimator mValueAnimator;
8024f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen        float finalScale;
8034f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen        float finalTransX;
8044f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen        float finalTransY;
8054f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen
8064f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen        /**
8074f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen         *
8084f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen         * @param params layout params to animate
8094f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen         * @param index0 original index of the item to be animated
8104f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen         * @param nItems0 original number of items in the preview
8114f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen         * @param index1 new index of the item to be animated
8124f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen         * @param nItems1 new number of items in the preview
8134f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen         * @param duration duration in ms of the animation
8144f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen         * @param onCompleteRunnable runnable to execute upon animation completion
8154f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen         */
8164f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen        public FolderPreviewItemAnim(final PreviewItemDrawingParams params, int index0, int nItems0,
8174f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen                int index1, int nItems1, int duration, final Runnable onCompleteRunnable) {
8184f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen
8194f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen            computePreviewItemDrawingParams(index1, nItems1, mTmpParams);
8204f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen
8214f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen            finalScale = mTmpParams.scale;
8224f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen            finalTransX = mTmpParams.transX;
8234f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen            finalTransY = mTmpParams.transY;
8244f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen
8254f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen            computePreviewItemDrawingParams(index0, nItems0, mTmpParams);
8264f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen
8274f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen            final float scale0 = mTmpParams.scale;
8284f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen            final float transX0 = mTmpParams.transX;
8294f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen            final float transY0 = mTmpParams.transY;
8304f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen
8314f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen            mValueAnimator = LauncherAnimUtils.ofFloat(FolderIcon.this, 0f, 1.0f);
8324f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen            mValueAnimator.addUpdateListener(new AnimatorUpdateListener(){
8334f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen                public void onAnimationUpdate(ValueAnimator animation) {
8344f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen                    float progress = animation.getAnimatedFraction();
835119e8982ab6a0cf00e31e8744f27b72ba8bf7b20Adam Cohen
8364f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen                    params.transX = transX0 + progress * (finalTransX - transX0);
8374f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen                    params.transY = transY0 + progress * (finalTransY - transY0);
8384f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen                    params.scale = scale0 + progress * (finalScale - scale0);
8394f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen                    invalidate();
8404f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen                }
8414f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen            });
842d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen
8434f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen            mValueAnimator.addListener(new AnimatorListenerAdapter() {
8444f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen                @Override
8454f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen                public void onAnimationStart(Animator animation) {
846fb91f303f5e672f9b4c4f9f8a03486b224d60cd6Adam Cohen                }
847d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen
8484f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen                @Override
8494f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen                public void onAnimationEnd(Animator animation) {
8504f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen                    if (onCompleteRunnable != null) {
8514f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen                        onCompleteRunnable.run();
8524f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen                    }
8534f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen                    params.anim = null;
854fb91f303f5e672f9b4c4f9f8a03486b224d60cd6Adam Cohen                }
8554f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen            });
8564f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen            mValueAnimator.setDuration(duration);
8574f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen        }
8584f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen
8594f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen        public void start() {
8604f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen            mValueAnimator.start();
8614f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen        }
8624f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen
8634f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen        public void cancel() {
8644f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen            mValueAnimator.cancel();
8654f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen        }
8664f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen
8674f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen        public boolean hasEqualFinalState(FolderPreviewItemAnim anim) {
8684f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen            return finalTransY == anim.finalTransY && finalTransX == anim.finalTransX &&
8694f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen                    finalScale == anim.finalScale;
8704f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen
8714f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen        }
8724f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen    }
8734f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen
8744f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen    private void animateFirstItem(final Drawable d, int duration, final boolean reverse,
8754f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen            final Runnable onCompleteRunnable) {
8764f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen
8774f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen        FolderPreviewItemAnim anim;
8784f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen        if (!reverse) {
8794f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen            anim = new FolderPreviewItemAnim(mDrawingParams.get(0), -1, -1, 0, 2, duration,
8804f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen                    onCompleteRunnable);
8814f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen        } else {
8824f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen            anim = new FolderPreviewItemAnim(mDrawingParams.get(0), 0, 2, -1, -1, duration,
8834f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen                    onCompleteRunnable);
8844f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen        }
8854f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen        anim.start();
886a9cf38f533d1e86269868f1e6a806ccffd4a78fcAdam Cohen    }
887a9cf38f533d1e86269868f1e6a806ccffd4a78fcAdam Cohen
888099f60d51f6310e1290687e83958e665b3324504Adam Cohen    public void setTextVisible(boolean visible) {
889099f60d51f6310e1290687e83958e665b3324504Adam Cohen        if (visible) {
890099f60d51f6310e1290687e83958e665b3324504Adam Cohen            mFolderName.setVisibility(VISIBLE);
891099f60d51f6310e1290687e83958e665b3324504Adam Cohen        } else {
892099f60d51f6310e1290687e83958e665b3324504Adam Cohen            mFolderName.setVisibility(INVISIBLE);
893099f60d51f6310e1290687e83958e665b3324504Adam Cohen        }
894099f60d51f6310e1290687e83958e665b3324504Adam Cohen    }
895099f60d51f6310e1290687e83958e665b3324504Adam Cohen
896099f60d51f6310e1290687e83958e665b3324504Adam Cohen    public boolean getTextVisible() {
897099f60d51f6310e1290687e83958e665b3324504Adam Cohen        return mFolderName.getVisibility() == VISIBLE;
898099f60d51f6310e1290687e83958e665b3324504Adam Cohen    }
899099f60d51f6310e1290687e83958e665b3324504Adam Cohen
9004f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen    private void updateItemDrawingParams(boolean animate) {
9014f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen        ArrayList<View> items = mFolder.getItemsInReadingOrder();
9024f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen        int nItemsInPreview = Math.min(items.size(), mPreviewLayoutRule.numItems());
9034f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen
9044f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen        int prevNumItems = mDrawingParams.size();
9054f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen
9064f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen        // We adjust the size of the list to match the number of items in the preview
9074f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen        while (nItemsInPreview < mDrawingParams.size()) {
9084f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen            mDrawingParams.remove(mDrawingParams.size() - 1);
9094f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen        }
9104f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen        while (nItemsInPreview > mDrawingParams.size()) {
9114f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen            mDrawingParams.add(new PreviewItemDrawingParams(0, 0, 0, 0));
9124f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen        }
9134f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen
9144f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen        for (int i = 0; i < mDrawingParams.size(); i++) {
9154f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen            PreviewItemDrawingParams p = mDrawingParams.get(i);
9164f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen            p.drawable = getTopDrawable((TextView) items.get(i));
9174f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen
918efca0279eb927faebffc38c8382818df67fcd159Adam Cohen            if (!animate || FeatureFlags.LAUNCHER3_LEGACY_FOLDER_ICON) {
9194f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen                computePreviewItemDrawingParams(i, nItemsInPreview, p);
9204f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen                if (mReferenceDrawable == null) {
9214f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen                    mReferenceDrawable = p.drawable;
9224f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen                }
9234f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen            } else {
9244f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen                FolderPreviewItemAnim anim = new FolderPreviewItemAnim(p, i, prevNumItems, i,
9254f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen                        nItemsInPreview, DROP_IN_ANIMATION_DURATION, null);
9264f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen
9274f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen                if (p.anim != null) {
9284f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen                    if (p.anim.hasEqualFinalState(anim)) {
9294f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen                        // do nothing, let the current animation finish
9304f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen                        continue;
9314f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen                    }
9324f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen                    p.anim.cancel();
9334f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen                }
9344f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen                p.anim = anim;
9354f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen                p.anim.start();
9364f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen            }
9374f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen        }
9384f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen    }
9394f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen
94076078c4ef35b6e95fb6d8129a32cf52a36625e28Adam Cohen    public void onItemsChanged() {
9414f8071b759fd54bc6d271ea450af00fe0730baeaAdam Cohen        updateItemDrawingParams(true);
94276078c4ef35b6e95fb6d8129a32cf52a36625e28Adam Cohen        invalidate();
94376078c4ef35b6e95fb6d8129a32cf52a36625e28Adam Cohen        requestLayout();
94476078c4ef35b6e95fb6d8129a32cf52a36625e28Adam Cohen    }
94576078c4ef35b6e95fb6d8129a32cf52a36625e28Adam Cohen
946a9cf38f533d1e86269868f1e6a806ccffd4a78fcAdam Cohen    public void onAdd(ShortcutInfo item) {
947a9cf38f533d1e86269868f1e6a806ccffd4a78fcAdam Cohen        invalidate();
948a9cf38f533d1e86269868f1e6a806ccffd4a78fcAdam Cohen        requestLayout();
949a9cf38f533d1e86269868f1e6a806ccffd4a78fcAdam Cohen    }
950a9cf38f533d1e86269868f1e6a806ccffd4a78fcAdam Cohen
951a9cf38f533d1e86269868f1e6a806ccffd4a78fcAdam Cohen    public void onRemove(ShortcutInfo item) {
952a9cf38f533d1e86269868f1e6a806ccffd4a78fcAdam Cohen        invalidate();
953a9cf38f533d1e86269868f1e6a806ccffd4a78fcAdam Cohen        requestLayout();
954a9cf38f533d1e86269868f1e6a806ccffd4a78fcAdam Cohen    }
95576fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen
95676fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen    public void onTitleChanged(CharSequence title) {
95782b016cb56540fe26213e817dd0dd668099c8e20Winson Chung        mFolderName.setText(title);
958f4f89ef608245d39bbddda05f291361d2ae06667Sunny Goyal        setContentDescription(getContext().getString(R.string.folder_name_format, title));
95976fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen    }
96088f334571fe41df620ba903ced9b2c69b0170d5cWinson Chung
96188f334571fe41df620ba903ced9b2c69b0170d5cWinson Chung    @Override
96288f334571fe41df620ba903ced9b2c69b0170d5cWinson Chung    public boolean onTouchEvent(MotionEvent event) {
96388f334571fe41df620ba903ced9b2c69b0170d5cWinson Chung        // Call the superclass onTouchEvent first, because sometimes it changes the state to
96488f334571fe41df620ba903ced9b2c69b0170d5cWinson Chung        // isPressed() on an ACTION_UP
96588f334571fe41df620ba903ced9b2c69b0170d5cWinson Chung        boolean result = super.onTouchEvent(event);
96688f334571fe41df620ba903ced9b2c69b0170d5cWinson Chung
967ef044dd380ac3abf354027750efdc16d5d48ac70Mady Mellor        // Check for a stylus button press, if it occurs cancel any long press checks.
968bb83520a620919a8f19472ba4426585d007d1abaMady Mellor        if (mStylusEventHelper.onMotionEvent(event)) {
969ef044dd380ac3abf354027750efdc16d5d48ac70Mady Mellor            mLongPressHelper.cancelLongPress();
970ef044dd380ac3abf354027750efdc16d5d48ac70Mady Mellor            return true;
971ef044dd380ac3abf354027750efdc16d5d48ac70Mady Mellor        }
972ef044dd380ac3abf354027750efdc16d5d48ac70Mady Mellor
97388f334571fe41df620ba903ced9b2c69b0170d5cWinson Chung        switch (event.getAction()) {
97488f334571fe41df620ba903ced9b2c69b0170d5cWinson Chung            case MotionEvent.ACTION_DOWN:
97588f334571fe41df620ba903ced9b2c69b0170d5cWinson Chung                mLongPressHelper.postCheckForLongPress();
97688f334571fe41df620ba903ced9b2c69b0170d5cWinson Chung                break;
97788f334571fe41df620ba903ced9b2c69b0170d5cWinson Chung            case MotionEvent.ACTION_CANCEL:
97888f334571fe41df620ba903ced9b2c69b0170d5cWinson Chung            case MotionEvent.ACTION_UP:
97988f334571fe41df620ba903ced9b2c69b0170d5cWinson Chung                mLongPressHelper.cancelLongPress();
98088f334571fe41df620ba903ced9b2c69b0170d5cWinson Chung                break;
98102dd7aea3d8ac94126a8f8069e6762592ea60326Jason Monk            case MotionEvent.ACTION_MOVE:
98202dd7aea3d8ac94126a8f8069e6762592ea60326Jason Monk                if (!Utilities.pointInView(this, event.getX(), event.getY(), mSlop)) {
98302dd7aea3d8ac94126a8f8069e6762592ea60326Jason Monk                    mLongPressHelper.cancelLongPress();
98402dd7aea3d8ac94126a8f8069e6762592ea60326Jason Monk                }
98502dd7aea3d8ac94126a8f8069e6762592ea60326Jason Monk                break;
98688f334571fe41df620ba903ced9b2c69b0170d5cWinson Chung        }
98788f334571fe41df620ba903ced9b2c69b0170d5cWinson Chung        return result;
98888f334571fe41df620ba903ced9b2c69b0170d5cWinson Chung    }
98988f334571fe41df620ba903ced9b2c69b0170d5cWinson Chung
99088f334571fe41df620ba903ced9b2c69b0170d5cWinson Chung    @Override
99102dd7aea3d8ac94126a8f8069e6762592ea60326Jason Monk    protected void onAttachedToWindow() {
99202dd7aea3d8ac94126a8f8069e6762592ea60326Jason Monk        super.onAttachedToWindow();
99302dd7aea3d8ac94126a8f8069e6762592ea60326Jason Monk        mSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
99402dd7aea3d8ac94126a8f8069e6762592ea60326Jason Monk    }
99502dd7aea3d8ac94126a8f8069e6762592ea60326Jason Monk
99602dd7aea3d8ac94126a8f8069e6762592ea60326Jason Monk    @Override
99788f334571fe41df620ba903ced9b2c69b0170d5cWinson Chung    public void cancelLongPress() {
99888f334571fe41df620ba903ced9b2c69b0170d5cWinson Chung        super.cancelLongPress();
99988f334571fe41df620ba903ced9b2c69b0170d5cWinson Chung        mLongPressHelper.cancelLongPress();
100088f334571fe41df620ba903ced9b2c69b0170d5cWinson Chung    }
1001f9c184a619e4e4b82cf9e0bf318ca6d8deaaaee7Adam Cohen
1002f9c184a619e4e4b82cf9e0bf318ca6d8deaaaee7Adam Cohen    public interface PreviewLayoutRule {
1003119e8982ab6a0cf00e31e8744f27b72ba8bf7b20Adam Cohen        public PreviewItemDrawingParams computePreviewItemDrawingParams(int index, int curNumItems,
1004f9c184a619e4e4b82cf9e0bf318ca6d8deaaaee7Adam Cohen            PreviewItemDrawingParams params);
1005f9c184a619e4e4b82cf9e0bf318ca6d8deaaaee7Adam Cohen
1006119e8982ab6a0cf00e31e8744f27b72ba8bf7b20Adam Cohen        public void init(int availableSpace, int intrinsicIconSize, boolean rtl);
1007f9c184a619e4e4b82cf9e0bf318ca6d8deaaaee7Adam Cohen
1008f9c184a619e4e4b82cf9e0bf318ca6d8deaaaee7Adam Cohen        public int numItems();
1009efca0279eb927faebffc38c8382818df67fcd159Adam Cohen        public boolean clipToBackground();
1010f9c184a619e4e4b82cf9e0bf318ca6d8deaaaee7Adam Cohen    }
101131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project}
1012