DragLayer.java revision ea359c6aee44c0fe3bb94f7002c3b49208b32b7f
131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project/*
231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * Copyright (C) 2008 The Android Open Source Project
331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project *
431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * you may not use this file except in compliance with the License.
631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * You may obtain a copy of the License at
731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project *
831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project *
1031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
1131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
1231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * See the License for the specific language governing permissions and
1431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * limitations under the License.
1531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project */
1631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
17a5902524d4403885eb4c50360bf3465c6be796efJoe Onoratopackage com.android.launcher2;
1831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
19716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohenimport android.animation.Animator;
20716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohenimport android.animation.AnimatorListenerAdapter;
218dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohenimport android.animation.ObjectAnimator;
22716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohenimport android.animation.TimeInterpolator;
23716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohenimport android.animation.ValueAnimator;
24716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohenimport android.animation.ValueAnimator.AnimatorUpdateListener;
2531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.content.Context;
26716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohenimport android.content.res.Resources;
27716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohenimport android.graphics.Canvas;
286788269814a678af976dfc7d6135993e172ce586Adam Cohenimport android.graphics.Rect;
29ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohenimport android.graphics.drawable.Drawable;
3031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.util.AttributeSet;
3131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.view.KeyEvent;
320e26059548e429e5d1c973bebe4c561bead2926fMichael Jurkaimport android.view.MotionEvent;
33ea3763c2672f77539538af8cdd395ad97058eaabRomain Guyimport android.view.View;
3476fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohenimport android.view.ViewParent;
35716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohenimport android.view.animation.DecelerateInterpolator;
363e8f811f31a2275e778244427271f77f4116c08bAdam Cohenimport android.view.animation.Interpolator;
3731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.widget.FrameLayout;
38ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohenimport android.widget.TextView;
3931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
40716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohenimport com.android.launcher.R;
41716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen
421d9af7d1e75bad13bb10ad37f5900ed59882622eAdam Cohenimport java.util.ArrayList;
436788269814a678af976dfc7d6135993e172ce586Adam Cohen
4431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project/**
450e26059548e429e5d1c973bebe4c561bead2926fMichael Jurka * A ViewGroup that coordinates dragging across its descendants
4631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project */
4700acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onoratopublic class DragLayer extends FrameLayout {
48120980bd00f5eecec5717f49a3d7db96571025a9Adam Cohen    private DragController mDragController;
49120980bd00f5eecec5717f49a3d7db96571025a9Adam Cohen    private int[] mTmpXY = new int[2];
5031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
51716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen    private int mXDown, mYDown;
52716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen    private Launcher mLauncher;
53716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen
546788269814a678af976dfc7d6135993e172ce586Adam Cohen    // Variables relating to resizing widgets
556788269814a678af976dfc7d6135993e172ce586Adam Cohen    private final ArrayList<AppWidgetResizeFrame> mResizeFrames =
566788269814a678af976dfc7d6135993e172ce586Adam Cohen            new ArrayList<AppWidgetResizeFrame>();
576788269814a678af976dfc7d6135993e172ce586Adam Cohen    private AppWidgetResizeFrame mCurrentResizeFrame;
58716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen
59716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen    // Variables relating to animation of views after drop
60716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen    private ValueAnimator mDropAnim = null;
618dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen    private ValueAnimator mFadeOutAnim = null;
628dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen    private TimeInterpolator mCubicEaseOutInterpolator = new DecelerateInterpolator(1.5f);
63716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen    private View mDropView = null;
648dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen
653e8f811f31a2275e778244427271f77f4116c08bAdam Cohen    private int[] mDropViewPos = new int[2];
663e8f811f31a2275e778244427271f77f4116c08bAdam Cohen    private float mDropViewScale;
673e8f811f31a2275e778244427271f77f4116c08bAdam Cohen    private float mDropViewAlpha;
686788269814a678af976dfc7d6135993e172ce586Adam Cohen
6931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    /**
7031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * Used to create a new DragLayer from XML.
7131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     *
7231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param context The application's context.
730e26059548e429e5d1c973bebe4c561bead2926fMichael Jurka     * @param attrs The attributes set containing the Workspace's customization values.
7431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     */
7531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    public DragLayer(Context context, AttributeSet attrs) {
7631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        super(context, attrs);
77be62afa34d58edab0fc9ba7499f0dd543039c903Winson Chung
78be62afa34d58edab0fc9ba7499f0dd543039c903Winson Chung        // Disable multitouch across the workspace/all apps/customize tray
79be62afa34d58edab0fc9ba7499f0dd543039c903Winson Chung        setMotionEventSplittingEnabled(false);
8031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
8131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
824c98d9235d164680186180974719f551cf935d08Winson Chung    public void setup(Launcher launcher, DragController controller) {
834c98d9235d164680186180974719f551cf935d08Winson Chung        mLauncher = launcher;
8400acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato        mDragController = controller;
8531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
8676fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen
8731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    @Override
8831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    public boolean dispatchKeyEvent(KeyEvent event) {
8900acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato        return mDragController.dispatchKeyEvent(event) || super.dispatchKeyEvent(event);
9031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
9131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
9276fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen    private boolean handleTouchDown(MotionEvent ev, boolean intercept) {
936788269814a678af976dfc7d6135993e172ce586Adam Cohen        Rect hitRect = new Rect();
946788269814a678af976dfc7d6135993e172ce586Adam Cohen        int x = (int) ev.getX();
956788269814a678af976dfc7d6135993e172ce586Adam Cohen        int y = (int) ev.getY();
966788269814a678af976dfc7d6135993e172ce586Adam Cohen
976788269814a678af976dfc7d6135993e172ce586Adam Cohen        for (AppWidgetResizeFrame child: mResizeFrames) {
986788269814a678af976dfc7d6135993e172ce586Adam Cohen            child.getHitRect(hitRect);
996788269814a678af976dfc7d6135993e172ce586Adam Cohen            if (hitRect.contains(x, y)) {
1006788269814a678af976dfc7d6135993e172ce586Adam Cohen                if (child.beginResizeIfPointInRegion(x - child.getLeft(), y - child.getTop())) {
1016788269814a678af976dfc7d6135993e172ce586Adam Cohen                    mCurrentResizeFrame = child;
1026788269814a678af976dfc7d6135993e172ce586Adam Cohen                    mXDown = x;
1036788269814a678af976dfc7d6135993e172ce586Adam Cohen                    mYDown = y;
1046788269814a678af976dfc7d6135993e172ce586Adam Cohen                    requestDisallowInterceptTouchEvent(true);
1056788269814a678af976dfc7d6135993e172ce586Adam Cohen                    return true;
1066788269814a678af976dfc7d6135993e172ce586Adam Cohen                }
1076788269814a678af976dfc7d6135993e172ce586Adam Cohen            }
1086788269814a678af976dfc7d6135993e172ce586Adam Cohen        }
10976fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen
1101d9af7d1e75bad13bb10ad37f5900ed59882622eAdam Cohen        Folder currentFolder = mLauncher.getWorkspace().getOpenFolder();
1111d9af7d1e75bad13bb10ad37f5900ed59882622eAdam Cohen        if (currentFolder != null && intercept) {
1121d9af7d1e75bad13bb10ad37f5900ed59882622eAdam Cohen            if (currentFolder.isEditingName()) {
1131d9af7d1e75bad13bb10ad37f5900ed59882622eAdam Cohen                getDescendantRectRelativeToSelf(currentFolder.getEditTextRegion(), hitRect);
1142801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen                if (!hitRect.contains(x, y)) {
1151d9af7d1e75bad13bb10ad37f5900ed59882622eAdam Cohen                    currentFolder.dismissEditingName();
11676fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen                    return true;
1172801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen                }
1182801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen            }
11976fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen
1201d9af7d1e75bad13bb10ad37f5900ed59882622eAdam Cohen            getDescendantRectRelativeToSelf(currentFolder, hitRect);
12176fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen            if (!hitRect.contains(x, y)) {
12276fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen                mLauncher.closeFolder();
12376fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen                return true;
12476fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen            }
1252801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen        }
1266788269814a678af976dfc7d6135993e172ce586Adam Cohen        return false;
1276788269814a678af976dfc7d6135993e172ce586Adam Cohen    }
1286788269814a678af976dfc7d6135993e172ce586Adam Cohen
12931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    @Override
13031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    public boolean onInterceptTouchEvent(MotionEvent ev) {
1316788269814a678af976dfc7d6135993e172ce586Adam Cohen        if (ev.getAction() == MotionEvent.ACTION_DOWN) {
13276fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen            if (handleTouchDown(ev, true)) {
1336788269814a678af976dfc7d6135993e172ce586Adam Cohen                return true;
134d1837cc69eb222371afdd30890f7215d117510f2Patrick Dubroy            }
1351b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen        }
1366788269814a678af976dfc7d6135993e172ce586Adam Cohen        clearAllResizeFrames();
1374db52312c10e822162a21c60404f06f6e507f0d6Joe Onorato        return mDragController.onInterceptTouchEvent(ev);
13831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
13931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
14031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    @Override
14131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    public boolean onTouchEvent(MotionEvent ev) {
1426788269814a678af976dfc7d6135993e172ce586Adam Cohen        boolean handled = false;
1436788269814a678af976dfc7d6135993e172ce586Adam Cohen        int action = ev.getAction();
1446788269814a678af976dfc7d6135993e172ce586Adam Cohen
1456788269814a678af976dfc7d6135993e172ce586Adam Cohen        int x = (int) ev.getX();
1466788269814a678af976dfc7d6135993e172ce586Adam Cohen        int y = (int) ev.getY();
1476788269814a678af976dfc7d6135993e172ce586Adam Cohen
1486788269814a678af976dfc7d6135993e172ce586Adam Cohen        if (ev.getAction() == MotionEvent.ACTION_DOWN) {
1496788269814a678af976dfc7d6135993e172ce586Adam Cohen            if (ev.getAction() == MotionEvent.ACTION_DOWN) {
15076fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen                if (handleTouchDown(ev, false)) {
1516788269814a678af976dfc7d6135993e172ce586Adam Cohen                    return true;
1526788269814a678af976dfc7d6135993e172ce586Adam Cohen                }
1536788269814a678af976dfc7d6135993e172ce586Adam Cohen            }
1546788269814a678af976dfc7d6135993e172ce586Adam Cohen        }
1556788269814a678af976dfc7d6135993e172ce586Adam Cohen
1566788269814a678af976dfc7d6135993e172ce586Adam Cohen        if (mCurrentResizeFrame != null) {
1576788269814a678af976dfc7d6135993e172ce586Adam Cohen            handled = true;
1586788269814a678af976dfc7d6135993e172ce586Adam Cohen            switch (action) {
1596788269814a678af976dfc7d6135993e172ce586Adam Cohen                case MotionEvent.ACTION_MOVE:
1606788269814a678af976dfc7d6135993e172ce586Adam Cohen                    mCurrentResizeFrame.visualizeResizeForDelta(x - mXDown, y - mYDown);
1616788269814a678af976dfc7d6135993e172ce586Adam Cohen                    break;
1626788269814a678af976dfc7d6135993e172ce586Adam Cohen                case MotionEvent.ACTION_CANCEL:
1636788269814a678af976dfc7d6135993e172ce586Adam Cohen                case MotionEvent.ACTION_UP:
1646788269814a678af976dfc7d6135993e172ce586Adam Cohen                    mCurrentResizeFrame.commitResizeForDelta(x - mXDown, y - mYDown);
1656788269814a678af976dfc7d6135993e172ce586Adam Cohen                    mCurrentResizeFrame = null;
1666788269814a678af976dfc7d6135993e172ce586Adam Cohen            }
1676788269814a678af976dfc7d6135993e172ce586Adam Cohen        }
1686788269814a678af976dfc7d6135993e172ce586Adam Cohen        if (handled) return true;
1694db52312c10e822162a21c60404f06f6e507f0d6Joe Onorato        return mDragController.onTouchEvent(ev);
17091a9c9636f10f1e12cd1f660b2e330634fbdc7dcRomain Guy    }
171ea3763c2672f77539538af8cdd395ad97058eaabRomain Guy
17235e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen    /**
17335e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen     * Determine the rect of the descendant in this DragLayer's coordinates
17435e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen     *
17535e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen     * @param descendant The descendant whose coordinates we want to find.
17635e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen     * @param r The rect into which to place the results.
17735e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen     * @return The factor by which this descendant is scaled relative to this DragLayer.
17835e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen     */
179ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen    public float getDescendantRectRelativeToSelf(View descendant, Rect r) {
180716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen        mTmpXY[0] = 0;
181716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen        mTmpXY[1] = 0;
182ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen        float scale = getDescendantCoordRelativeToSelf(descendant, mTmpXY);
1838dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        r.set(mTmpXY[0], mTmpXY[1],
1848dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen                mTmpXY[0] + descendant.getWidth(), mTmpXY[1] + descendant.getHeight());
185ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen        return scale;
186716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen    }
18776fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen
18835e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen    public void getLocationInDragLayer(View child, int[] loc) {
18935e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen        loc[0] = 0;
19035e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen        loc[1] = 0;
19135e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen        getDescendantCoordRelativeToSelf(child, loc);
19235e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen    }
19335e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen
19435e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen    /**
19535e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen     * Given a coordinate relative to the descendant, find the coordinate in this DragLayer's
19635e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen     * coordinates.
19735e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen     *
19835e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen     * @param descendant The descendant to which the passed coordinate is relative.
19935e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen     * @param coord The coordinate that we want mapped.
20035e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen     * @return The factor by which this descendant is scaled relative to this DragLayer.
20135e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen     */
202b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen    public float getDescendantCoordRelativeToSelf(View descendant, int[] coord) {
203557d6ed50cc6560163440aa134870ef0bb11415bWinson Chung        float scale = 1.0f;
204557d6ed50cc6560163440aa134870ef0bb11415bWinson Chung        float[] pt = {coord[0], coord[1]};
205557d6ed50cc6560163440aa134870ef0bb11415bWinson Chung        descendant.getMatrix().mapPoints(pt);
206557d6ed50cc6560163440aa134870ef0bb11415bWinson Chung        scale *= descendant.getScaleX();
207557d6ed50cc6560163440aa134870ef0bb11415bWinson Chung        pt[0] += descendant.getLeft();
208557d6ed50cc6560163440aa134870ef0bb11415bWinson Chung        pt[1] += descendant.getTop();
20976fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen        ViewParent viewParent = descendant.getParent();
21076fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen        while (viewParent instanceof View && viewParent != this) {
21176fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen            final View view = (View)viewParent;
212557d6ed50cc6560163440aa134870ef0bb11415bWinson Chung            view.getMatrix().mapPoints(pt);
213557d6ed50cc6560163440aa134870ef0bb11415bWinson Chung            scale *= view.getScaleX();
214557d6ed50cc6560163440aa134870ef0bb11415bWinson Chung            pt[0] += view.getLeft() - view.getScrollX();
215557d6ed50cc6560163440aa134870ef0bb11415bWinson Chung            pt[1] += view.getTop() - view.getScrollY();
21676fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen            viewParent = view.getParent();
21776fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen        }
218fc53cd22c9a78708c78c85946443f23ec8c59502Adam Cohen        coord[0] = (int) Math.round(pt[0]);
219fc53cd22c9a78708c78c85946443f23ec8c59502Adam Cohen        coord[1] = (int) Math.round(pt[1]);
220557d6ed50cc6560163440aa134870ef0bb11415bWinson Chung        return scale;
22176fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen    }
22276fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen
2233e8f811f31a2275e778244427271f77f4116c08bAdam Cohen    public void getViewRectRelativeToSelf(View v, Rect r) {
2243e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        int[] loc = new int[2];
2258dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        getLocationInWindow(loc);
2263e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        int x = loc[0];
2273e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        int y = loc[1];
228716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen
2298dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        v.getLocationInWindow(loc);
2303e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        int vX = loc[0];
2313e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        int vY = loc[1];
232716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen
2333e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        int left = vX - x;
2343e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        int top = vY - y;
2353e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        r.set(left, top, left + v.getMeasuredWidth(), top + v.getMeasuredHeight());
236716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen    }
237716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen
238ea3763c2672f77539538af8cdd395ad97058eaabRomain Guy    @Override
239ea3763c2672f77539538af8cdd395ad97058eaabRomain Guy    public boolean dispatchUnhandledMove(View focused, int direction) {
240ea3763c2672f77539538af8cdd395ad97058eaabRomain Guy        return mDragController.dispatchUnhandledMove(focused, direction);
241ea3763c2672f77539538af8cdd395ad97058eaabRomain Guy    }
242120980bd00f5eecec5717f49a3d7db96571025a9Adam Cohen
2436788269814a678af976dfc7d6135993e172ce586Adam Cohen    public static class LayoutParams extends FrameLayout.LayoutParams {
2446788269814a678af976dfc7d6135993e172ce586Adam Cohen        public int x, y;
2456788269814a678af976dfc7d6135993e172ce586Adam Cohen        public boolean customPosition = false;
2466788269814a678af976dfc7d6135993e172ce586Adam Cohen
2476788269814a678af976dfc7d6135993e172ce586Adam Cohen        /**
2486788269814a678af976dfc7d6135993e172ce586Adam Cohen         * {@inheritDoc}
2496788269814a678af976dfc7d6135993e172ce586Adam Cohen         */
2506788269814a678af976dfc7d6135993e172ce586Adam Cohen        public LayoutParams(int width, int height) {
2516788269814a678af976dfc7d6135993e172ce586Adam Cohen            super(width, height);
2526788269814a678af976dfc7d6135993e172ce586Adam Cohen        }
2536788269814a678af976dfc7d6135993e172ce586Adam Cohen
2546788269814a678af976dfc7d6135993e172ce586Adam Cohen        public void setWidth(int width) {
2556788269814a678af976dfc7d6135993e172ce586Adam Cohen            this.width = width;
2566788269814a678af976dfc7d6135993e172ce586Adam Cohen        }
2576788269814a678af976dfc7d6135993e172ce586Adam Cohen
2586788269814a678af976dfc7d6135993e172ce586Adam Cohen        public int getWidth() {
2596788269814a678af976dfc7d6135993e172ce586Adam Cohen            return width;
2606788269814a678af976dfc7d6135993e172ce586Adam Cohen        }
2616788269814a678af976dfc7d6135993e172ce586Adam Cohen
2626788269814a678af976dfc7d6135993e172ce586Adam Cohen        public void setHeight(int height) {
2636788269814a678af976dfc7d6135993e172ce586Adam Cohen            this.height = height;
2646788269814a678af976dfc7d6135993e172ce586Adam Cohen        }
2656788269814a678af976dfc7d6135993e172ce586Adam Cohen
2666788269814a678af976dfc7d6135993e172ce586Adam Cohen        public int getHeight() {
2676788269814a678af976dfc7d6135993e172ce586Adam Cohen            return height;
2686788269814a678af976dfc7d6135993e172ce586Adam Cohen        }
2696788269814a678af976dfc7d6135993e172ce586Adam Cohen
2706788269814a678af976dfc7d6135993e172ce586Adam Cohen        public void setX(int x) {
2716788269814a678af976dfc7d6135993e172ce586Adam Cohen            this.x = x;
2726788269814a678af976dfc7d6135993e172ce586Adam Cohen        }
2736788269814a678af976dfc7d6135993e172ce586Adam Cohen
2746788269814a678af976dfc7d6135993e172ce586Adam Cohen        public int getX() {
2756788269814a678af976dfc7d6135993e172ce586Adam Cohen            return x;
2766788269814a678af976dfc7d6135993e172ce586Adam Cohen        }
2776788269814a678af976dfc7d6135993e172ce586Adam Cohen
2786788269814a678af976dfc7d6135993e172ce586Adam Cohen        public void setY(int y) {
2796788269814a678af976dfc7d6135993e172ce586Adam Cohen            this.y = y;
2806788269814a678af976dfc7d6135993e172ce586Adam Cohen        }
2816788269814a678af976dfc7d6135993e172ce586Adam Cohen
2826788269814a678af976dfc7d6135993e172ce586Adam Cohen        public int getY() {
2836788269814a678af976dfc7d6135993e172ce586Adam Cohen            return y;
2846788269814a678af976dfc7d6135993e172ce586Adam Cohen        }
2856788269814a678af976dfc7d6135993e172ce586Adam Cohen    }
2866788269814a678af976dfc7d6135993e172ce586Adam Cohen
2876788269814a678af976dfc7d6135993e172ce586Adam Cohen    protected void onLayout(boolean changed, int l, int t, int r, int b) {
2886788269814a678af976dfc7d6135993e172ce586Adam Cohen        super.onLayout(changed, l, t, r, b);
2896788269814a678af976dfc7d6135993e172ce586Adam Cohen        int count = getChildCount();
2906788269814a678af976dfc7d6135993e172ce586Adam Cohen        for (int i = 0; i < count; i++) {
2916788269814a678af976dfc7d6135993e172ce586Adam Cohen            View child = getChildAt(i);
2926788269814a678af976dfc7d6135993e172ce586Adam Cohen            final FrameLayout.LayoutParams flp = (FrameLayout.LayoutParams) child.getLayoutParams();
2936788269814a678af976dfc7d6135993e172ce586Adam Cohen            if (flp instanceof LayoutParams) {
2946788269814a678af976dfc7d6135993e172ce586Adam Cohen                final LayoutParams lp = (LayoutParams) flp;
2956788269814a678af976dfc7d6135993e172ce586Adam Cohen                if (lp.customPosition) {
2966788269814a678af976dfc7d6135993e172ce586Adam Cohen                    child.layout(lp.x, lp.y, lp.x + lp.width, lp.y + lp.height);
2976788269814a678af976dfc7d6135993e172ce586Adam Cohen                }
2986788269814a678af976dfc7d6135993e172ce586Adam Cohen            }
2996788269814a678af976dfc7d6135993e172ce586Adam Cohen        }
3006788269814a678af976dfc7d6135993e172ce586Adam Cohen    }
3016788269814a678af976dfc7d6135993e172ce586Adam Cohen
3026788269814a678af976dfc7d6135993e172ce586Adam Cohen    public void clearAllResizeFrames() {
3036788269814a678af976dfc7d6135993e172ce586Adam Cohen        if (mResizeFrames.size() > 0) {
3046788269814a678af976dfc7d6135993e172ce586Adam Cohen            for (AppWidgetResizeFrame frame: mResizeFrames) {
3056788269814a678af976dfc7d6135993e172ce586Adam Cohen                removeView(frame);
3066788269814a678af976dfc7d6135993e172ce586Adam Cohen            }
3076788269814a678af976dfc7d6135993e172ce586Adam Cohen            mResizeFrames.clear();
3086788269814a678af976dfc7d6135993e172ce586Adam Cohen        }
3096788269814a678af976dfc7d6135993e172ce586Adam Cohen    }
3106788269814a678af976dfc7d6135993e172ce586Adam Cohen
3116788269814a678af976dfc7d6135993e172ce586Adam Cohen    public boolean hasResizeFrames() {
3126788269814a678af976dfc7d6135993e172ce586Adam Cohen        return mResizeFrames.size() > 0;
3136788269814a678af976dfc7d6135993e172ce586Adam Cohen    }
3146788269814a678af976dfc7d6135993e172ce586Adam Cohen
3156788269814a678af976dfc7d6135993e172ce586Adam Cohen    public boolean isWidgetBeingResized() {
3166788269814a678af976dfc7d6135993e172ce586Adam Cohen        return mCurrentResizeFrame != null;
3176788269814a678af976dfc7d6135993e172ce586Adam Cohen    }
3186788269814a678af976dfc7d6135993e172ce586Adam Cohen
3196788269814a678af976dfc7d6135993e172ce586Adam Cohen    public void addResizeFrame(ItemInfo itemInfo, LauncherAppWidgetHostView widget,
3206788269814a678af976dfc7d6135993e172ce586Adam Cohen            CellLayout cellLayout) {
3216788269814a678af976dfc7d6135993e172ce586Adam Cohen        AppWidgetResizeFrame resizeFrame = new AppWidgetResizeFrame(getContext(),
3226788269814a678af976dfc7d6135993e172ce586Adam Cohen                itemInfo, widget, cellLayout, this);
3236788269814a678af976dfc7d6135993e172ce586Adam Cohen
3246788269814a678af976dfc7d6135993e172ce586Adam Cohen        LayoutParams lp = new LayoutParams(-1, -1);
3256788269814a678af976dfc7d6135993e172ce586Adam Cohen        lp.customPosition = true;
3266788269814a678af976dfc7d6135993e172ce586Adam Cohen
3276788269814a678af976dfc7d6135993e172ce586Adam Cohen        addView(resizeFrame, lp);
3286788269814a678af976dfc7d6135993e172ce586Adam Cohen        mResizeFrames.add(resizeFrame);
3296788269814a678af976dfc7d6135993e172ce586Adam Cohen
3306788269814a678af976dfc7d6135993e172ce586Adam Cohen        resizeFrame.snapToWidget(false);
3316788269814a678af976dfc7d6135993e172ce586Adam Cohen    }
332716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen
333716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen    public void animateViewIntoPosition(DragView dragView, final View child) {
334557d6ed50cc6560163440aa134870ef0bb11415bWinson Chung        animateViewIntoPosition(dragView, child, null);
335557d6ed50cc6560163440aa134870ef0bb11415bWinson Chung    }
336ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen
337b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen    public void animateViewIntoPosition(DragView dragView, final int[] pos, float scale,
338b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen            Runnable onFinishRunnable) {
339b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen        Rect r = new Rect();
340b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen        getViewRectRelativeToSelf(dragView, r);
341b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen        final int fromX = r.left;
342b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen        final int fromY = r.top;
343b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen
344b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen        animateViewIntoPosition(dragView, fromX, fromY, pos[0], pos[1], scale,
345ed51cc9a12c50d12e7d30ed209a49f1a40858043Adam Cohen                onFinishRunnable, true, -1);
346b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen    }
347b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen
348557d6ed50cc6560163440aa134870ef0bb11415bWinson Chung    public void animateViewIntoPosition(DragView dragView, final View child,
349557d6ed50cc6560163440aa134870ef0bb11415bWinson Chung            final Runnable onFinishAnimationRunnable) {
350ed51cc9a12c50d12e7d30ed209a49f1a40858043Adam Cohen        animateViewIntoPosition(dragView, child, -1, onFinishAnimationRunnable);
351ed51cc9a12c50d12e7d30ed209a49f1a40858043Adam Cohen    }
352ed51cc9a12c50d12e7d30ed209a49f1a40858043Adam Cohen
353ed51cc9a12c50d12e7d30ed209a49f1a40858043Adam Cohen    public void animateViewIntoPosition(DragView dragView, final View child, int duration,
354ed51cc9a12c50d12e7d30ed209a49f1a40858043Adam Cohen            final Runnable onFinishAnimationRunnable) {
355716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen        ((CellLayoutChildren) child.getParent()).measureChild(child);
356716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen        CellLayout.LayoutParams lp =  (CellLayout.LayoutParams) child.getLayoutParams();
357716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen
3583e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        Rect r = new Rect();
3593e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        getViewRectRelativeToSelf(dragView, r);
360716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen
361716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen        int coord[] = new int[2];
362ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen        coord[0] = lp.x;
363ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen        coord[1] = lp.y;
3648dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        // Since the child hasn't necessarily been laid out, we force the lp to be updated with
365ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen        // the correct coordinates (above) and use these to determine the final location
366557d6ed50cc6560163440aa134870ef0bb11415bWinson Chung        float scale = getDescendantCoordRelativeToSelf((View) child.getParent(), coord);
367ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen        int toX = coord[0];
368ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen        int toY = coord[1];
369ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen        if (child instanceof TextView) {
370ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen            TextView tv = (TextView) child;
371ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen            Drawable d = tv.getCompoundDrawables()[1];
372ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen
373ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen            // Center in the y coordinate about the target's drawable
374ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen            toY += Math.round(scale * tv.getPaddingTop());
375ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen            toY -= (dragView.getHeight() - (int) Math.round(scale * d.getIntrinsicHeight())) / 2;
376ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen            // Center in the x coordinate about the target's drawable
377ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen            toX -= (dragView.getMeasuredWidth() - Math.round(scale * child.getMeasuredWidth())) / 2;
378ea359c6aee44c0fe3bb94f7002c3b49208b32b7fWinson Chung        } else if (child instanceof FolderIcon) {
379ea359c6aee44c0fe3bb94f7002c3b49208b32b7fWinson Chung            // Account for holographic blur padding on the drag view
380ea359c6aee44c0fe3bb94f7002c3b49208b32b7fWinson Chung            toY -= HolographicOutlineHelper.MAX_OUTER_BLUR_RADIUS / 2;
381ea359c6aee44c0fe3bb94f7002c3b49208b32b7fWinson Chung            // Center in the x coordinate about the target's drawable
382ea359c6aee44c0fe3bb94f7002c3b49208b32b7fWinson Chung            toX -= (dragView.getMeasuredWidth() - Math.round(scale * child.getMeasuredWidth())) / 2;
383ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen        } else {
384ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen            toY -= (Math.round(scale * (dragView.getHeight() - child.getMeasuredHeight()))) / 2;
385ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen            toX -= (Math.round(scale * (dragView.getMeasuredWidth()
386ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen                    - child.getMeasuredWidth()))) / 2;
387ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen        }
388716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen
389ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen        final int fromX = r.left;
390ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen        final int fromY = r.top;
391716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen        child.setVisibility(INVISIBLE);
3928dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        child.setAlpha(0);
3938dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        Runnable onCompleteRunnable = new Runnable() {
3948dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen            public void run() {
3958dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen                child.setVisibility(VISIBLE);
3968dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen                ObjectAnimator oa = ObjectAnimator.ofFloat(child, "alpha", 0f, 1f);
3978dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen                oa.setDuration(60);
398557d6ed50cc6560163440aa134870ef0bb11415bWinson Chung                oa.addListener(new AnimatorListenerAdapter() {
399557d6ed50cc6560163440aa134870ef0bb11415bWinson Chung                    @Override
400557d6ed50cc6560163440aa134870ef0bb11415bWinson Chung                    public void onAnimationEnd(android.animation.Animator animation) {
401557d6ed50cc6560163440aa134870ef0bb11415bWinson Chung                        if (onFinishAnimationRunnable != null) {
402557d6ed50cc6560163440aa134870ef0bb11415bWinson Chung                            onFinishAnimationRunnable.run();
403557d6ed50cc6560163440aa134870ef0bb11415bWinson Chung                        }
404557d6ed50cc6560163440aa134870ef0bb11415bWinson Chung                    }
405557d6ed50cc6560163440aa134870ef0bb11415bWinson Chung                });
4068dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen                oa.start();
4078dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen            }
4088dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        };
409ed51cc9a12c50d12e7d30ed209a49f1a40858043Adam Cohen        animateViewIntoPosition(dragView, fromX, fromY, toX, toY, scale,
410ed51cc9a12c50d12e7d30ed209a49f1a40858043Adam Cohen                onCompleteRunnable, true, duration);
411557d6ed50cc6560163440aa134870ef0bb11415bWinson Chung    }
412557d6ed50cc6560163440aa134870ef0bb11415bWinson Chung
413716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen    private void animateViewIntoPosition(final View view, final int fromX, final int fromY,
414557d6ed50cc6560163440aa134870ef0bb11415bWinson Chung            final int toX, final int toY, float finalScale, Runnable onCompleteRunnable,
415ed51cc9a12c50d12e7d30ed209a49f1a40858043Adam Cohen            boolean fadeOut, int duration) {
4168dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        Rect from = new Rect(fromX, fromY, fromX +
4178dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen                view.getMeasuredWidth(), fromY + view.getMeasuredHeight());
4183e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        Rect to = new Rect(toX, toY, toX + view.getMeasuredWidth(), toY + view.getMeasuredHeight());
419ed51cc9a12c50d12e7d30ed209a49f1a40858043Adam Cohen        animateView(view, from, to, 1f, finalScale, duration, null, null, onCompleteRunnable, true);
4203e8f811f31a2275e778244427271f77f4116c08bAdam Cohen    }
4213e8f811f31a2275e778244427271f77f4116c08bAdam Cohen
422b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen    /**
423b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen     * This method animates a view at the end of a drag and drop animation.
424b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen     *
425b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen     * @param view The view to be animated. This view is drawn directly into DragLayer, and so
426b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen     *        doesn't need to be a child of DragLayer.
427b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen     * @param from The initial location of the view. Only the left and top parameters are used.
428b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen     * @param to The final location of the view. Only the left and top parameters are used. This
429b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen     *        location doesn't account for scaling, and so should be centered about the desired
430b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen     *        final location (including scaling).
431b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen     * @param finalAlpha The final alpha of the view, in case we want it to fade as it animates.
432b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen     * @param finalScale The final scale of the view. The view is scaled about its center.
433b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen     * @param duration The duration of the animation.
434b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen     * @param motionInterpolator The interpolator to use for the location of the view.
435b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen     * @param alphaInterpolator The interpolator to use for the alpha of the view.
436b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen     * @param onCompleteRunnable Optional runnable to run on animation completion.
437b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen     * @param fadeOut Whether or not to fade out the view once the animation completes. If true,
438b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen     *        the runnable will execute after the view is faded out.
439b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen     */
4403e8f811f31a2275e778244427271f77f4116c08bAdam Cohen    public void animateView(final View view, final Rect from, final Rect to, final float finalAlpha,
4413e8f811f31a2275e778244427271f77f4116c08bAdam Cohen            final float finalScale, int duration, final Interpolator motionInterpolator,
4428dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen            final Interpolator alphaInterpolator, final Runnable onCompleteRunnable,
4438dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen            final boolean fadeOut) {
444716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen        // Calculate the duration of the animation based on the object's distance
4453e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        final float dist = (float) Math.sqrt(Math.pow(to.left - from.left, 2) +
4463e8f811f31a2275e778244427271f77f4116c08bAdam Cohen                Math.pow(to.top - from.top, 2));
447716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen        final Resources res = getResources();
448716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen        final float maxDist = (float) res.getInteger(R.integer.config_dropAnimMaxDist);
4493e8f811f31a2275e778244427271f77f4116c08bAdam Cohen
4503e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        // If duration < 0, this is a cue to compute the duration based on the distance
4513e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        if (duration < 0) {
4523e8f811f31a2275e778244427271f77f4116c08bAdam Cohen            duration = res.getInteger(R.integer.config_dropAnimMaxDuration);
4533e8f811f31a2275e778244427271f77f4116c08bAdam Cohen            if (dist < maxDist) {
4548dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen                duration *= mCubicEaseOutInterpolator.getInterpolation(dist / maxDist);
4553e8f811f31a2275e778244427271f77f4116c08bAdam Cohen            }
456716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen        }
457716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen
458716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen        if (mDropAnim != null) {
4598dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen            mDropAnim.cancel();
460716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen        }
461716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen
462ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen        if (mFadeOutAnim != null) {
463ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen            mFadeOutAnim.cancel();
464ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen        }
465ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen
4663e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        mDropView = view;
4673e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        final float initialAlpha = view.getAlpha();
4683e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        mDropAnim = new ValueAnimator();
4693e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        if (alphaInterpolator == null || motionInterpolator == null) {
4708dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen            mDropAnim.setInterpolator(mCubicEaseOutInterpolator);
4713e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        }
472716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen
473716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen        mDropAnim.setDuration(duration);
474716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen        mDropAnim.setFloatValues(0.0f, 1.0f);
475716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen        mDropAnim.removeAllUpdateListeners();
476716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen        mDropAnim.addUpdateListener(new AnimatorUpdateListener() {
477716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen            public void onAnimationUpdate(ValueAnimator animation) {
478716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen                final float percent = (Float) animation.getAnimatedValue();
479716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen                // Invalidate the old position
480716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen                int width = view.getMeasuredWidth();
481716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen                int height = view.getMeasuredHeight();
482716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen                invalidate(mDropViewPos[0], mDropViewPos[1],
483716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen                        mDropViewPos[0] + width, mDropViewPos[1] + height);
484716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen
4853e8f811f31a2275e778244427271f77f4116c08bAdam Cohen                float alphaPercent = alphaInterpolator == null ? percent :
4863e8f811f31a2275e778244427271f77f4116c08bAdam Cohen                        alphaInterpolator.getInterpolation(percent);
4873e8f811f31a2275e778244427271f77f4116c08bAdam Cohen                float motionPercent = motionInterpolator == null ? percent :
4883e8f811f31a2275e778244427271f77f4116c08bAdam Cohen                        motionInterpolator.getInterpolation(percent);
4893e8f811f31a2275e778244427271f77f4116c08bAdam Cohen
490ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen                mDropViewPos[0] = from.left + (int) Math.round(((to.left - from.left) * motionPercent));
491ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen                mDropViewPos[1] = from.top + (int) Math.round(((to.top - from.top) * motionPercent));
4923e8f811f31a2275e778244427271f77f4116c08bAdam Cohen                mDropViewScale = percent * finalScale + (1 - percent);
4933e8f811f31a2275e778244427271f77f4116c08bAdam Cohen                mDropViewAlpha = alphaPercent * finalAlpha + (1 - alphaPercent) * initialAlpha;
494716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen                invalidate(mDropViewPos[0], mDropViewPos[1],
495716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen                        mDropViewPos[0] + width, mDropViewPos[1] + height);
496716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen            }
497716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen        });
4983e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        mDropAnim.addListener(new AnimatorListenerAdapter() {
4993e8f811f31a2275e778244427271f77f4116c08bAdam Cohen            public void onAnimationEnd(Animator animation) {
5008dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen                if (onCompleteRunnable != null) {
5018dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen                    onCompleteRunnable.run();
5028dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen                }
5038dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen                if (fadeOut) {
5048dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen                    fadeOutDragView();
5058dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen                } else {
5063e8f811f31a2275e778244427271f77f4116c08bAdam Cohen                    mDropView = null;
5073e8f811f31a2275e778244427271f77f4116c08bAdam Cohen                }
5083e8f811f31a2275e778244427271f77f4116c08bAdam Cohen            }
5093e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        });
510716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen        mDropAnim.start();
511716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen    }
512716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen
5138dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen    private void fadeOutDragView() {
5148dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        mFadeOutAnim = new ValueAnimator();
5158dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        mFadeOutAnim.setDuration(150);
5168dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        mFadeOutAnim.setFloatValues(0f, 1f);
5178dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        mFadeOutAnim.removeAllUpdateListeners();
5188dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        mFadeOutAnim.addUpdateListener(new AnimatorUpdateListener() {
5198dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen            public void onAnimationUpdate(ValueAnimator animation) {
5208dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen                final float percent = (Float) animation.getAnimatedValue();
5218dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen                mDropViewAlpha = 1 - percent;
5228dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen                int width = mDropView.getMeasuredWidth();
5238dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen                int height = mDropView.getMeasuredHeight();
5248dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen                invalidate(mDropViewPos[0], mDropViewPos[1],
5258dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen                        mDropViewPos[0] + width, mDropViewPos[1] + height);
5268dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen            }
5278dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        });
5288dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        mFadeOutAnim.addListener(new AnimatorListenerAdapter() {
5298dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen            public void onAnimationEnd(Animator animation) {
5308dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen                mDropView = null;
5318dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen            }
5328dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        });
5338dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        mFadeOutAnim.start();
5348dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen    }
5358dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen
536716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen    @Override
537716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen    protected void dispatchDraw(Canvas canvas) {
538716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen        super.dispatchDraw(canvas);
539716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen        if (mDropView != null) {
540716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen            // We are animating an item that was just dropped on the home screen.
541716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen            // Render its View in the current animation position.
542716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen            canvas.save(Canvas.MATRIX_SAVE_FLAG);
543716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen            final int xPos = mDropViewPos[0] - mDropView.getScrollX();
544716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen            final int yPos = mDropViewPos[1] - mDropView.getScrollY();
5453e8f811f31a2275e778244427271f77f4116c08bAdam Cohen            int width = mDropView.getMeasuredWidth();
5463e8f811f31a2275e778244427271f77f4116c08bAdam Cohen            int height = mDropView.getMeasuredHeight();
547716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen            canvas.translate(xPos, yPos);
5483e8f811f31a2275e778244427271f77f4116c08bAdam Cohen            canvas.translate((1 - mDropViewScale) * width / 2, (1 - mDropViewScale) * height / 2);
5493e8f811f31a2275e778244427271f77f4116c08bAdam Cohen            canvas.scale(mDropViewScale, mDropViewScale);
5503e8f811f31a2275e778244427271f77f4116c08bAdam Cohen            mDropView.setAlpha(mDropViewAlpha);
551716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen            mDropView.draw(canvas);
552716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen            canvas.restore();
553716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen        }
554716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen    }
55531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project}
556