DragLayer.java revision 3371da0159cc54ff8ae1b1b26effb96445f208d5
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;
353371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohenimport android.view.accessibility.AccessibilityEvent;
363371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohenimport android.view.accessibility.AccessibilityManager;
37716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohenimport android.view.animation.DecelerateInterpolator;
383e8f811f31a2275e778244427271f77f4116c08bAdam Cohenimport android.view.animation.Interpolator;
3931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.widget.FrameLayout;
40ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohenimport android.widget.TextView;
4131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
42716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohenimport com.android.launcher.R;
43716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen
441d9af7d1e75bad13bb10ad37f5900ed59882622eAdam Cohenimport java.util.ArrayList;
456788269814a678af976dfc7d6135993e172ce586Adam Cohen
4631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project/**
470e26059548e429e5d1c973bebe4c561bead2926fMichael Jurka * A ViewGroup that coordinates dragging across its descendants
4831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project */
4900acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onoratopublic class DragLayer extends FrameLayout {
50120980bd00f5eecec5717f49a3d7db96571025a9Adam Cohen    private DragController mDragController;
51120980bd00f5eecec5717f49a3d7db96571025a9Adam Cohen    private int[] mTmpXY = new int[2];
5231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
53716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen    private int mXDown, mYDown;
54716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen    private Launcher mLauncher;
55716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen
566788269814a678af976dfc7d6135993e172ce586Adam Cohen    // Variables relating to resizing widgets
576788269814a678af976dfc7d6135993e172ce586Adam Cohen    private final ArrayList<AppWidgetResizeFrame> mResizeFrames =
586788269814a678af976dfc7d6135993e172ce586Adam Cohen            new ArrayList<AppWidgetResizeFrame>();
596788269814a678af976dfc7d6135993e172ce586Adam Cohen    private AppWidgetResizeFrame mCurrentResizeFrame;
60716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen
61716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen    // Variables relating to animation of views after drop
62716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen    private ValueAnimator mDropAnim = null;
638dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen    private ValueAnimator mFadeOutAnim = null;
648dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen    private TimeInterpolator mCubicEaseOutInterpolator = new DecelerateInterpolator(1.5f);
65716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen    private View mDropView = null;
668dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen
673e8f811f31a2275e778244427271f77f4116c08bAdam Cohen    private int[] mDropViewPos = new int[2];
683e8f811f31a2275e778244427271f77f4116c08bAdam Cohen    private float mDropViewScale;
693e8f811f31a2275e778244427271f77f4116c08bAdam Cohen    private float mDropViewAlpha;
703371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen    private boolean mHoverPointClosesFolder = false;
713371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen    private Rect mHitRect = new Rect();
726788269814a678af976dfc7d6135993e172ce586Adam Cohen
7331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    /**
7431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * Used to create a new DragLayer from XML.
7531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     *
7631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param context The application's context.
770e26059548e429e5d1c973bebe4c561bead2926fMichael Jurka     * @param attrs The attributes set containing the Workspace's customization values.
7831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     */
7931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    public DragLayer(Context context, AttributeSet attrs) {
8031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        super(context, attrs);
81be62afa34d58edab0fc9ba7499f0dd543039c903Winson Chung
82be62afa34d58edab0fc9ba7499f0dd543039c903Winson Chung        // Disable multitouch across the workspace/all apps/customize tray
83be62afa34d58edab0fc9ba7499f0dd543039c903Winson Chung        setMotionEventSplittingEnabled(false);
8431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
8531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
864c98d9235d164680186180974719f551cf935d08Winson Chung    public void setup(Launcher launcher, DragController controller) {
874c98d9235d164680186180974719f551cf935d08Winson Chung        mLauncher = launcher;
8800acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato        mDragController = controller;
8931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
9076fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen
9131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    @Override
9231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    public boolean dispatchKeyEvent(KeyEvent event) {
9300acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato        return mDragController.dispatchKeyEvent(event) || super.dispatchKeyEvent(event);
9431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
9531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
963371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen    private boolean isEventOverFolderTextRegion(Folder folder, MotionEvent ev) {
973371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen        getDescendantRectRelativeToSelf(folder.getEditTextRegion(), mHitRect);
983371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen        if (mHitRect.contains((int) ev.getX(), (int) ev.getY())) {
993371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen            return true;
1003371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen        }
1013371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen        return false;
1023371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen    }
1033371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen
1043371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen    private boolean isEventOverFolder(Folder folder, MotionEvent ev) {
1053371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen        getDescendantRectRelativeToSelf(folder, mHitRect);
1063371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen        if (mHitRect.contains((int) ev.getX(), (int) ev.getY())) {
1073371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen            return true;
1083371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen        }
1093371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen        return false;
1103371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen    }
1113371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen
11276fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen    private boolean handleTouchDown(MotionEvent ev, boolean intercept) {
1136788269814a678af976dfc7d6135993e172ce586Adam Cohen        Rect hitRect = new Rect();
1146788269814a678af976dfc7d6135993e172ce586Adam Cohen        int x = (int) ev.getX();
1156788269814a678af976dfc7d6135993e172ce586Adam Cohen        int y = (int) ev.getY();
1166788269814a678af976dfc7d6135993e172ce586Adam Cohen
1176788269814a678af976dfc7d6135993e172ce586Adam Cohen        for (AppWidgetResizeFrame child: mResizeFrames) {
1186788269814a678af976dfc7d6135993e172ce586Adam Cohen            child.getHitRect(hitRect);
1196788269814a678af976dfc7d6135993e172ce586Adam Cohen            if (hitRect.contains(x, y)) {
1206788269814a678af976dfc7d6135993e172ce586Adam Cohen                if (child.beginResizeIfPointInRegion(x - child.getLeft(), y - child.getTop())) {
1216788269814a678af976dfc7d6135993e172ce586Adam Cohen                    mCurrentResizeFrame = child;
1226788269814a678af976dfc7d6135993e172ce586Adam Cohen                    mXDown = x;
1236788269814a678af976dfc7d6135993e172ce586Adam Cohen                    mYDown = y;
1246788269814a678af976dfc7d6135993e172ce586Adam Cohen                    requestDisallowInterceptTouchEvent(true);
1256788269814a678af976dfc7d6135993e172ce586Adam Cohen                    return true;
1266788269814a678af976dfc7d6135993e172ce586Adam Cohen                }
1276788269814a678af976dfc7d6135993e172ce586Adam Cohen            }
1286788269814a678af976dfc7d6135993e172ce586Adam Cohen        }
12976fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen
1301d9af7d1e75bad13bb10ad37f5900ed59882622eAdam Cohen        Folder currentFolder = mLauncher.getWorkspace().getOpenFolder();
1317d7541e7b48fdc114c24b3b0aa75e70d7228041eWinson Chung        if (currentFolder != null && !mLauncher.isFolderClingVisible() && intercept) {
1321d9af7d1e75bad13bb10ad37f5900ed59882622eAdam Cohen            if (currentFolder.isEditingName()) {
1333371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                if (!isEventOverFolderTextRegion(currentFolder, ev)) {
1341d9af7d1e75bad13bb10ad37f5900ed59882622eAdam Cohen                    currentFolder.dismissEditingName();
13576fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen                    return true;
1362801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen                }
1372801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen            }
13876fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen
1391d9af7d1e75bad13bb10ad37f5900ed59882622eAdam Cohen            getDescendantRectRelativeToSelf(currentFolder, hitRect);
1403371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen            if (!isEventOverFolder(currentFolder, ev)) {
14176fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen                mLauncher.closeFolder();
14276fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen                return true;
14376fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen            }
1442801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen        }
1456788269814a678af976dfc7d6135993e172ce586Adam Cohen        return false;
1466788269814a678af976dfc7d6135993e172ce586Adam Cohen    }
1476788269814a678af976dfc7d6135993e172ce586Adam Cohen
14831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    @Override
14931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    public boolean onInterceptTouchEvent(MotionEvent ev) {
1506788269814a678af976dfc7d6135993e172ce586Adam Cohen        if (ev.getAction() == MotionEvent.ACTION_DOWN) {
15176fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen            if (handleTouchDown(ev, true)) {
1526788269814a678af976dfc7d6135993e172ce586Adam Cohen                return true;
153d1837cc69eb222371afdd30890f7215d117510f2Patrick Dubroy            }
1541b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen        }
1556788269814a678af976dfc7d6135993e172ce586Adam Cohen        clearAllResizeFrames();
1564db52312c10e822162a21c60404f06f6e507f0d6Joe Onorato        return mDragController.onInterceptTouchEvent(ev);
15731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
15831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
15931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    @Override
1603371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen    public boolean onInterceptHoverEvent(MotionEvent ev) {
1613371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen        Folder currentFolder = mLauncher.getWorkspace().getOpenFolder();
1623371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen        if (currentFolder == null) {
1633371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen            return false;
1643371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen        } else {
1653371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen            if (AccessibilityManager.getInstance(mContext).isTouchExplorationEnabled()) {
1663371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                final int action = ev.getAction();
1673371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                boolean isOverFolder;
1683371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                switch (action) {
1693371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                    case MotionEvent.ACTION_HOVER_ENTER:
1703371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                        isOverFolder = isEventOverFolder(currentFolder, ev);
1713371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                        if (!isOverFolder) {
1723371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                            sendTapOutsideFolderAccessibilityEvent(currentFolder.isEditingName());
1733371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                            mHoverPointClosesFolder = true;
1743371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                            return true;
1753371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                        } else if (isOverFolder) {
1763371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                            mHoverPointClosesFolder = false;
1773371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                        } else {
1783371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                            return true;
1793371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                        }
1803371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                    case MotionEvent.ACTION_HOVER_MOVE:
1813371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                        isOverFolder = isEventOverFolder(currentFolder, ev);
1823371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                        if (!isOverFolder && !mHoverPointClosesFolder) {
1833371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                            sendTapOutsideFolderAccessibilityEvent(currentFolder.isEditingName());
1843371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                            mHoverPointClosesFolder = true;
1853371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                            return true;
1863371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                        } else if (isOverFolder) {
1873371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                            mHoverPointClosesFolder = false;
1883371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                        } else {
1893371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                            return true;
1903371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                        }
1913371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                }
1923371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen            }
1933371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen        }
1943371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen        return false;
1953371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen    }
1963371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen
1973371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen    private void sendTapOutsideFolderAccessibilityEvent(boolean isEditingName) {
1983371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen        if (AccessibilityManager.getInstance(mContext).isEnabled()) {
1993371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen            Folder currentFolder = mLauncher.getWorkspace().getOpenFolder();
2003371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen            int stringId = isEditingName ? R.string.folder_tap_to_rename : R.string.folder_tap_to_close;
2013371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen            AccessibilityEvent event = AccessibilityEvent.obtain(
2023371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                    AccessibilityEvent.TYPE_VIEW_FOCUSED);
2033371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen            onInitializeAccessibilityEvent(event);
2043371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen            event.getText().add(mContext.getString(stringId));
2053371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen            AccessibilityManager.getInstance(mContext).sendAccessibilityEvent(event);
2063371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen        }
2073371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen    }
2083371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen
2093371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen    @Override
2103371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen    public boolean onHoverEvent(MotionEvent ev) {
2113371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen        // If we've received this, we've already done the necessary handling
2123371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen        // in onInterceptHoverEvent. Return true to consume the event.
2133371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen        return false;
2143371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen    }
2153371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen
2163371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen    @Override
21731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    public boolean onTouchEvent(MotionEvent ev) {
2186788269814a678af976dfc7d6135993e172ce586Adam Cohen        boolean handled = false;
2196788269814a678af976dfc7d6135993e172ce586Adam Cohen        int action = ev.getAction();
2206788269814a678af976dfc7d6135993e172ce586Adam Cohen
2216788269814a678af976dfc7d6135993e172ce586Adam Cohen        int x = (int) ev.getX();
2226788269814a678af976dfc7d6135993e172ce586Adam Cohen        int y = (int) ev.getY();
2236788269814a678af976dfc7d6135993e172ce586Adam Cohen
2246788269814a678af976dfc7d6135993e172ce586Adam Cohen        if (ev.getAction() == MotionEvent.ACTION_DOWN) {
2256788269814a678af976dfc7d6135993e172ce586Adam Cohen            if (ev.getAction() == MotionEvent.ACTION_DOWN) {
22676fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen                if (handleTouchDown(ev, false)) {
2276788269814a678af976dfc7d6135993e172ce586Adam Cohen                    return true;
2286788269814a678af976dfc7d6135993e172ce586Adam Cohen                }
2296788269814a678af976dfc7d6135993e172ce586Adam Cohen            }
2306788269814a678af976dfc7d6135993e172ce586Adam Cohen        }
2316788269814a678af976dfc7d6135993e172ce586Adam Cohen
2326788269814a678af976dfc7d6135993e172ce586Adam Cohen        if (mCurrentResizeFrame != null) {
2336788269814a678af976dfc7d6135993e172ce586Adam Cohen            handled = true;
2346788269814a678af976dfc7d6135993e172ce586Adam Cohen            switch (action) {
2356788269814a678af976dfc7d6135993e172ce586Adam Cohen                case MotionEvent.ACTION_MOVE:
2366788269814a678af976dfc7d6135993e172ce586Adam Cohen                    mCurrentResizeFrame.visualizeResizeForDelta(x - mXDown, y - mYDown);
2376788269814a678af976dfc7d6135993e172ce586Adam Cohen                    break;
2386788269814a678af976dfc7d6135993e172ce586Adam Cohen                case MotionEvent.ACTION_CANCEL:
2396788269814a678af976dfc7d6135993e172ce586Adam Cohen                case MotionEvent.ACTION_UP:
2406788269814a678af976dfc7d6135993e172ce586Adam Cohen                    mCurrentResizeFrame.commitResizeForDelta(x - mXDown, y - mYDown);
2416788269814a678af976dfc7d6135993e172ce586Adam Cohen                    mCurrentResizeFrame = null;
2426788269814a678af976dfc7d6135993e172ce586Adam Cohen            }
2436788269814a678af976dfc7d6135993e172ce586Adam Cohen        }
2446788269814a678af976dfc7d6135993e172ce586Adam Cohen        if (handled) return true;
2454db52312c10e822162a21c60404f06f6e507f0d6Joe Onorato        return mDragController.onTouchEvent(ev);
24691a9c9636f10f1e12cd1f660b2e330634fbdc7dcRomain Guy    }
247ea3763c2672f77539538af8cdd395ad97058eaabRomain Guy
24835e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen    /**
24935e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen     * Determine the rect of the descendant in this DragLayer's coordinates
25035e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen     *
25135e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen     * @param descendant The descendant whose coordinates we want to find.
25235e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen     * @param r The rect into which to place the results.
25335e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen     * @return The factor by which this descendant is scaled relative to this DragLayer.
25435e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen     */
255ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen    public float getDescendantRectRelativeToSelf(View descendant, Rect r) {
256716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen        mTmpXY[0] = 0;
257716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen        mTmpXY[1] = 0;
258ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen        float scale = getDescendantCoordRelativeToSelf(descendant, mTmpXY);
2598dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        r.set(mTmpXY[0], mTmpXY[1],
2608dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen                mTmpXY[0] + descendant.getWidth(), mTmpXY[1] + descendant.getHeight());
261ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen        return scale;
262716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen    }
26376fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen
26435e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen    public void getLocationInDragLayer(View child, int[] loc) {
26535e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen        loc[0] = 0;
26635e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen        loc[1] = 0;
26735e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen        getDescendantCoordRelativeToSelf(child, loc);
26835e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen    }
26935e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen
27035e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen    /**
27135e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen     * Given a coordinate relative to the descendant, find the coordinate in this DragLayer's
27235e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen     * coordinates.
27335e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen     *
27435e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen     * @param descendant The descendant to which the passed coordinate is relative.
27535e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen     * @param coord The coordinate that we want mapped.
27635e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen     * @return The factor by which this descendant is scaled relative to this DragLayer.
27735e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen     */
278b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen    public float getDescendantCoordRelativeToSelf(View descendant, int[] coord) {
279557d6ed50cc6560163440aa134870ef0bb11415bWinson Chung        float scale = 1.0f;
280557d6ed50cc6560163440aa134870ef0bb11415bWinson Chung        float[] pt = {coord[0], coord[1]};
281557d6ed50cc6560163440aa134870ef0bb11415bWinson Chung        descendant.getMatrix().mapPoints(pt);
282557d6ed50cc6560163440aa134870ef0bb11415bWinson Chung        scale *= descendant.getScaleX();
283557d6ed50cc6560163440aa134870ef0bb11415bWinson Chung        pt[0] += descendant.getLeft();
284557d6ed50cc6560163440aa134870ef0bb11415bWinson Chung        pt[1] += descendant.getTop();
28576fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen        ViewParent viewParent = descendant.getParent();
28676fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen        while (viewParent instanceof View && viewParent != this) {
28776fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen            final View view = (View)viewParent;
288557d6ed50cc6560163440aa134870ef0bb11415bWinson Chung            view.getMatrix().mapPoints(pt);
289557d6ed50cc6560163440aa134870ef0bb11415bWinson Chung            scale *= view.getScaleX();
290557d6ed50cc6560163440aa134870ef0bb11415bWinson Chung            pt[0] += view.getLeft() - view.getScrollX();
291557d6ed50cc6560163440aa134870ef0bb11415bWinson Chung            pt[1] += view.getTop() - view.getScrollY();
29276fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen            viewParent = view.getParent();
29376fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen        }
294fc53cd22c9a78708c78c85946443f23ec8c59502Adam Cohen        coord[0] = (int) Math.round(pt[0]);
295fc53cd22c9a78708c78c85946443f23ec8c59502Adam Cohen        coord[1] = (int) Math.round(pt[1]);
296557d6ed50cc6560163440aa134870ef0bb11415bWinson Chung        return scale;
29776fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen    }
29876fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen
2993e8f811f31a2275e778244427271f77f4116c08bAdam Cohen    public void getViewRectRelativeToSelf(View v, Rect r) {
3003e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        int[] loc = new int[2];
3018dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        getLocationInWindow(loc);
3023e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        int x = loc[0];
3033e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        int y = loc[1];
304716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen
3058dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        v.getLocationInWindow(loc);
3063e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        int vX = loc[0];
3073e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        int vY = loc[1];
308716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen
3093e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        int left = vX - x;
3103e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        int top = vY - y;
3113e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        r.set(left, top, left + v.getMeasuredWidth(), top + v.getMeasuredHeight());
312716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen    }
313716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen
314ea3763c2672f77539538af8cdd395ad97058eaabRomain Guy    @Override
315ea3763c2672f77539538af8cdd395ad97058eaabRomain Guy    public boolean dispatchUnhandledMove(View focused, int direction) {
316ea3763c2672f77539538af8cdd395ad97058eaabRomain Guy        return mDragController.dispatchUnhandledMove(focused, direction);
317ea3763c2672f77539538af8cdd395ad97058eaabRomain Guy    }
318120980bd00f5eecec5717f49a3d7db96571025a9Adam Cohen
3196788269814a678af976dfc7d6135993e172ce586Adam Cohen    public static class LayoutParams extends FrameLayout.LayoutParams {
3206788269814a678af976dfc7d6135993e172ce586Adam Cohen        public int x, y;
3216788269814a678af976dfc7d6135993e172ce586Adam Cohen        public boolean customPosition = false;
3226788269814a678af976dfc7d6135993e172ce586Adam Cohen
3236788269814a678af976dfc7d6135993e172ce586Adam Cohen        /**
3246788269814a678af976dfc7d6135993e172ce586Adam Cohen         * {@inheritDoc}
3256788269814a678af976dfc7d6135993e172ce586Adam Cohen         */
3266788269814a678af976dfc7d6135993e172ce586Adam Cohen        public LayoutParams(int width, int height) {
3276788269814a678af976dfc7d6135993e172ce586Adam Cohen            super(width, height);
3286788269814a678af976dfc7d6135993e172ce586Adam Cohen        }
3296788269814a678af976dfc7d6135993e172ce586Adam Cohen
3306788269814a678af976dfc7d6135993e172ce586Adam Cohen        public void setWidth(int width) {
3316788269814a678af976dfc7d6135993e172ce586Adam Cohen            this.width = width;
3326788269814a678af976dfc7d6135993e172ce586Adam Cohen        }
3336788269814a678af976dfc7d6135993e172ce586Adam Cohen
3346788269814a678af976dfc7d6135993e172ce586Adam Cohen        public int getWidth() {
3356788269814a678af976dfc7d6135993e172ce586Adam Cohen            return width;
3366788269814a678af976dfc7d6135993e172ce586Adam Cohen        }
3376788269814a678af976dfc7d6135993e172ce586Adam Cohen
3386788269814a678af976dfc7d6135993e172ce586Adam Cohen        public void setHeight(int height) {
3396788269814a678af976dfc7d6135993e172ce586Adam Cohen            this.height = height;
3406788269814a678af976dfc7d6135993e172ce586Adam Cohen        }
3416788269814a678af976dfc7d6135993e172ce586Adam Cohen
3426788269814a678af976dfc7d6135993e172ce586Adam Cohen        public int getHeight() {
3436788269814a678af976dfc7d6135993e172ce586Adam Cohen            return height;
3446788269814a678af976dfc7d6135993e172ce586Adam Cohen        }
3456788269814a678af976dfc7d6135993e172ce586Adam Cohen
3466788269814a678af976dfc7d6135993e172ce586Adam Cohen        public void setX(int x) {
3476788269814a678af976dfc7d6135993e172ce586Adam Cohen            this.x = x;
3486788269814a678af976dfc7d6135993e172ce586Adam Cohen        }
3496788269814a678af976dfc7d6135993e172ce586Adam Cohen
3506788269814a678af976dfc7d6135993e172ce586Adam Cohen        public int getX() {
3516788269814a678af976dfc7d6135993e172ce586Adam Cohen            return x;
3526788269814a678af976dfc7d6135993e172ce586Adam Cohen        }
3536788269814a678af976dfc7d6135993e172ce586Adam Cohen
3546788269814a678af976dfc7d6135993e172ce586Adam Cohen        public void setY(int y) {
3556788269814a678af976dfc7d6135993e172ce586Adam Cohen            this.y = y;
3566788269814a678af976dfc7d6135993e172ce586Adam Cohen        }
3576788269814a678af976dfc7d6135993e172ce586Adam Cohen
3586788269814a678af976dfc7d6135993e172ce586Adam Cohen        public int getY() {
3596788269814a678af976dfc7d6135993e172ce586Adam Cohen            return y;
3606788269814a678af976dfc7d6135993e172ce586Adam Cohen        }
3616788269814a678af976dfc7d6135993e172ce586Adam Cohen    }
3626788269814a678af976dfc7d6135993e172ce586Adam Cohen
3636788269814a678af976dfc7d6135993e172ce586Adam Cohen    protected void onLayout(boolean changed, int l, int t, int r, int b) {
3646788269814a678af976dfc7d6135993e172ce586Adam Cohen        super.onLayout(changed, l, t, r, b);
3656788269814a678af976dfc7d6135993e172ce586Adam Cohen        int count = getChildCount();
3666788269814a678af976dfc7d6135993e172ce586Adam Cohen        for (int i = 0; i < count; i++) {
3676788269814a678af976dfc7d6135993e172ce586Adam Cohen            View child = getChildAt(i);
3686788269814a678af976dfc7d6135993e172ce586Adam Cohen            final FrameLayout.LayoutParams flp = (FrameLayout.LayoutParams) child.getLayoutParams();
3696788269814a678af976dfc7d6135993e172ce586Adam Cohen            if (flp instanceof LayoutParams) {
3706788269814a678af976dfc7d6135993e172ce586Adam Cohen                final LayoutParams lp = (LayoutParams) flp;
3716788269814a678af976dfc7d6135993e172ce586Adam Cohen                if (lp.customPosition) {
3726788269814a678af976dfc7d6135993e172ce586Adam Cohen                    child.layout(lp.x, lp.y, lp.x + lp.width, lp.y + lp.height);
3736788269814a678af976dfc7d6135993e172ce586Adam Cohen                }
3746788269814a678af976dfc7d6135993e172ce586Adam Cohen            }
3756788269814a678af976dfc7d6135993e172ce586Adam Cohen        }
3766788269814a678af976dfc7d6135993e172ce586Adam Cohen    }
3776788269814a678af976dfc7d6135993e172ce586Adam Cohen
3786788269814a678af976dfc7d6135993e172ce586Adam Cohen    public void clearAllResizeFrames() {
3796788269814a678af976dfc7d6135993e172ce586Adam Cohen        if (mResizeFrames.size() > 0) {
3806788269814a678af976dfc7d6135993e172ce586Adam Cohen            for (AppWidgetResizeFrame frame: mResizeFrames) {
3816788269814a678af976dfc7d6135993e172ce586Adam Cohen                removeView(frame);
3826788269814a678af976dfc7d6135993e172ce586Adam Cohen            }
3836788269814a678af976dfc7d6135993e172ce586Adam Cohen            mResizeFrames.clear();
3846788269814a678af976dfc7d6135993e172ce586Adam Cohen        }
3856788269814a678af976dfc7d6135993e172ce586Adam Cohen    }
3866788269814a678af976dfc7d6135993e172ce586Adam Cohen
3876788269814a678af976dfc7d6135993e172ce586Adam Cohen    public boolean hasResizeFrames() {
3886788269814a678af976dfc7d6135993e172ce586Adam Cohen        return mResizeFrames.size() > 0;
3896788269814a678af976dfc7d6135993e172ce586Adam Cohen    }
3906788269814a678af976dfc7d6135993e172ce586Adam Cohen
3916788269814a678af976dfc7d6135993e172ce586Adam Cohen    public boolean isWidgetBeingResized() {
3926788269814a678af976dfc7d6135993e172ce586Adam Cohen        return mCurrentResizeFrame != null;
3936788269814a678af976dfc7d6135993e172ce586Adam Cohen    }
3946788269814a678af976dfc7d6135993e172ce586Adam Cohen
3956788269814a678af976dfc7d6135993e172ce586Adam Cohen    public void addResizeFrame(ItemInfo itemInfo, LauncherAppWidgetHostView widget,
3966788269814a678af976dfc7d6135993e172ce586Adam Cohen            CellLayout cellLayout) {
3976788269814a678af976dfc7d6135993e172ce586Adam Cohen        AppWidgetResizeFrame resizeFrame = new AppWidgetResizeFrame(getContext(),
3986788269814a678af976dfc7d6135993e172ce586Adam Cohen                itemInfo, widget, cellLayout, this);
3996788269814a678af976dfc7d6135993e172ce586Adam Cohen
4006788269814a678af976dfc7d6135993e172ce586Adam Cohen        LayoutParams lp = new LayoutParams(-1, -1);
4016788269814a678af976dfc7d6135993e172ce586Adam Cohen        lp.customPosition = true;
4026788269814a678af976dfc7d6135993e172ce586Adam Cohen
4036788269814a678af976dfc7d6135993e172ce586Adam Cohen        addView(resizeFrame, lp);
4046788269814a678af976dfc7d6135993e172ce586Adam Cohen        mResizeFrames.add(resizeFrame);
4056788269814a678af976dfc7d6135993e172ce586Adam Cohen
4066788269814a678af976dfc7d6135993e172ce586Adam Cohen        resizeFrame.snapToWidget(false);
4076788269814a678af976dfc7d6135993e172ce586Adam Cohen    }
408716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen
409716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen    public void animateViewIntoPosition(DragView dragView, final View child) {
410557d6ed50cc6560163440aa134870ef0bb11415bWinson Chung        animateViewIntoPosition(dragView, child, null);
411557d6ed50cc6560163440aa134870ef0bb11415bWinson Chung    }
412ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen
413b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen    public void animateViewIntoPosition(DragView dragView, final int[] pos, float scale,
414b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen            Runnable onFinishRunnable) {
415b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen        Rect r = new Rect();
416b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen        getViewRectRelativeToSelf(dragView, r);
417b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen        final int fromX = r.left;
418b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen        final int fromY = r.top;
419b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen
420b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen        animateViewIntoPosition(dragView, fromX, fromY, pos[0], pos[1], scale,
421ed51cc9a12c50d12e7d30ed209a49f1a40858043Adam Cohen                onFinishRunnable, true, -1);
422b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen    }
423b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen
424557d6ed50cc6560163440aa134870ef0bb11415bWinson Chung    public void animateViewIntoPosition(DragView dragView, final View child,
425557d6ed50cc6560163440aa134870ef0bb11415bWinson Chung            final Runnable onFinishAnimationRunnable) {
426ed51cc9a12c50d12e7d30ed209a49f1a40858043Adam Cohen        animateViewIntoPosition(dragView, child, -1, onFinishAnimationRunnable);
427ed51cc9a12c50d12e7d30ed209a49f1a40858043Adam Cohen    }
428ed51cc9a12c50d12e7d30ed209a49f1a40858043Adam Cohen
429ed51cc9a12c50d12e7d30ed209a49f1a40858043Adam Cohen    public void animateViewIntoPosition(DragView dragView, final View child, int duration,
430ed51cc9a12c50d12e7d30ed209a49f1a40858043Adam Cohen            final Runnable onFinishAnimationRunnable) {
431716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen        ((CellLayoutChildren) child.getParent()).measureChild(child);
432716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen        CellLayout.LayoutParams lp =  (CellLayout.LayoutParams) child.getLayoutParams();
433716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen
4343e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        Rect r = new Rect();
4353e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        getViewRectRelativeToSelf(dragView, r);
436716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen
437716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen        int coord[] = new int[2];
438ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen        coord[0] = lp.x;
439ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen        coord[1] = lp.y;
4408dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        // Since the child hasn't necessarily been laid out, we force the lp to be updated with
441ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen        // the correct coordinates (above) and use these to determine the final location
442557d6ed50cc6560163440aa134870ef0bb11415bWinson Chung        float scale = getDescendantCoordRelativeToSelf((View) child.getParent(), coord);
443ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen        int toX = coord[0];
444ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen        int toY = coord[1];
445ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen        if (child instanceof TextView) {
446ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen            TextView tv = (TextView) child;
447ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen            Drawable d = tv.getCompoundDrawables()[1];
448ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen
449ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen            // Center in the y coordinate about the target's drawable
450ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen            toY += Math.round(scale * tv.getPaddingTop());
451ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen            toY -= (dragView.getHeight() - (int) Math.round(scale * d.getIntrinsicHeight())) / 2;
452ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen            // Center in the x coordinate about the target's drawable
453ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen            toX -= (dragView.getMeasuredWidth() - Math.round(scale * child.getMeasuredWidth())) / 2;
454ea359c6aee44c0fe3bb94f7002c3b49208b32b7fWinson Chung        } else if (child instanceof FolderIcon) {
455ea359c6aee44c0fe3bb94f7002c3b49208b32b7fWinson Chung            // Account for holographic blur padding on the drag view
456ea359c6aee44c0fe3bb94f7002c3b49208b32b7fWinson Chung            toY -= HolographicOutlineHelper.MAX_OUTER_BLUR_RADIUS / 2;
457ea359c6aee44c0fe3bb94f7002c3b49208b32b7fWinson Chung            // Center in the x coordinate about the target's drawable
458ea359c6aee44c0fe3bb94f7002c3b49208b32b7fWinson Chung            toX -= (dragView.getMeasuredWidth() - Math.round(scale * child.getMeasuredWidth())) / 2;
459ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen        } else {
460ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen            toY -= (Math.round(scale * (dragView.getHeight() - child.getMeasuredHeight()))) / 2;
461ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen            toX -= (Math.round(scale * (dragView.getMeasuredWidth()
462ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen                    - child.getMeasuredWidth()))) / 2;
463ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen        }
464716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen
465ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen        final int fromX = r.left;
466ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen        final int fromY = r.top;
467716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen        child.setVisibility(INVISIBLE);
4688dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        child.setAlpha(0);
4698dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        Runnable onCompleteRunnable = new Runnable() {
4708dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen            public void run() {
4718dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen                child.setVisibility(VISIBLE);
4728dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen                ObjectAnimator oa = ObjectAnimator.ofFloat(child, "alpha", 0f, 1f);
4738dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen                oa.setDuration(60);
474557d6ed50cc6560163440aa134870ef0bb11415bWinson Chung                oa.addListener(new AnimatorListenerAdapter() {
475557d6ed50cc6560163440aa134870ef0bb11415bWinson Chung                    @Override
476557d6ed50cc6560163440aa134870ef0bb11415bWinson Chung                    public void onAnimationEnd(android.animation.Animator animation) {
477557d6ed50cc6560163440aa134870ef0bb11415bWinson Chung                        if (onFinishAnimationRunnable != null) {
478557d6ed50cc6560163440aa134870ef0bb11415bWinson Chung                            onFinishAnimationRunnable.run();
479557d6ed50cc6560163440aa134870ef0bb11415bWinson Chung                        }
480557d6ed50cc6560163440aa134870ef0bb11415bWinson Chung                    }
481557d6ed50cc6560163440aa134870ef0bb11415bWinson Chung                });
4828dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen                oa.start();
4838dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen            }
4848dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        };
485ed51cc9a12c50d12e7d30ed209a49f1a40858043Adam Cohen        animateViewIntoPosition(dragView, fromX, fromY, toX, toY, scale,
486ed51cc9a12c50d12e7d30ed209a49f1a40858043Adam Cohen                onCompleteRunnable, true, duration);
487557d6ed50cc6560163440aa134870ef0bb11415bWinson Chung    }
488557d6ed50cc6560163440aa134870ef0bb11415bWinson Chung
489716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen    private void animateViewIntoPosition(final View view, final int fromX, final int fromY,
490557d6ed50cc6560163440aa134870ef0bb11415bWinson Chung            final int toX, final int toY, float finalScale, Runnable onCompleteRunnable,
491ed51cc9a12c50d12e7d30ed209a49f1a40858043Adam Cohen            boolean fadeOut, int duration) {
4928dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        Rect from = new Rect(fromX, fromY, fromX +
4938dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen                view.getMeasuredWidth(), fromY + view.getMeasuredHeight());
4943e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        Rect to = new Rect(toX, toY, toX + view.getMeasuredWidth(), toY + view.getMeasuredHeight());
495ed51cc9a12c50d12e7d30ed209a49f1a40858043Adam Cohen        animateView(view, from, to, 1f, finalScale, duration, null, null, onCompleteRunnable, true);
4963e8f811f31a2275e778244427271f77f4116c08bAdam Cohen    }
4973e8f811f31a2275e778244427271f77f4116c08bAdam Cohen
498b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen    /**
499b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen     * This method animates a view at the end of a drag and drop animation.
500b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen     *
501b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen     * @param view The view to be animated. This view is drawn directly into DragLayer, and so
502b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen     *        doesn't need to be a child of DragLayer.
503b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen     * @param from The initial location of the view. Only the left and top parameters are used.
504b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen     * @param to The final location of the view. Only the left and top parameters are used. This
505b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen     *        location doesn't account for scaling, and so should be centered about the desired
506b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen     *        final location (including scaling).
507b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen     * @param finalAlpha The final alpha of the view, in case we want it to fade as it animates.
508b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen     * @param finalScale The final scale of the view. The view is scaled about its center.
509b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen     * @param duration The duration of the animation.
510b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen     * @param motionInterpolator The interpolator to use for the location of the view.
511b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen     * @param alphaInterpolator The interpolator to use for the alpha of the view.
512b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen     * @param onCompleteRunnable Optional runnable to run on animation completion.
513b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen     * @param fadeOut Whether or not to fade out the view once the animation completes. If true,
514b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen     *        the runnable will execute after the view is faded out.
515b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen     */
5163e8f811f31a2275e778244427271f77f4116c08bAdam Cohen    public void animateView(final View view, final Rect from, final Rect to, final float finalAlpha,
5173e8f811f31a2275e778244427271f77f4116c08bAdam Cohen            final float finalScale, int duration, final Interpolator motionInterpolator,
5188dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen            final Interpolator alphaInterpolator, final Runnable onCompleteRunnable,
5198dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen            final boolean fadeOut) {
520716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen        // Calculate the duration of the animation based on the object's distance
5213e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        final float dist = (float) Math.sqrt(Math.pow(to.left - from.left, 2) +
5223e8f811f31a2275e778244427271f77f4116c08bAdam Cohen                Math.pow(to.top - from.top, 2));
523716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen        final Resources res = getResources();
524716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen        final float maxDist = (float) res.getInteger(R.integer.config_dropAnimMaxDist);
5253e8f811f31a2275e778244427271f77f4116c08bAdam Cohen
5263e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        // If duration < 0, this is a cue to compute the duration based on the distance
5273e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        if (duration < 0) {
5283e8f811f31a2275e778244427271f77f4116c08bAdam Cohen            duration = res.getInteger(R.integer.config_dropAnimMaxDuration);
5293e8f811f31a2275e778244427271f77f4116c08bAdam Cohen            if (dist < maxDist) {
5308dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen                duration *= mCubicEaseOutInterpolator.getInterpolation(dist / maxDist);
5313e8f811f31a2275e778244427271f77f4116c08bAdam Cohen            }
532716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen        }
533716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen
534716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen        if (mDropAnim != null) {
5358dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen            mDropAnim.cancel();
536716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen        }
537716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen
538ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen        if (mFadeOutAnim != null) {
539ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen            mFadeOutAnim.cancel();
540ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen        }
541ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen
5423e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        mDropView = view;
5433e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        final float initialAlpha = view.getAlpha();
5443e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        mDropAnim = new ValueAnimator();
5453e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        if (alphaInterpolator == null || motionInterpolator == null) {
5468dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen            mDropAnim.setInterpolator(mCubicEaseOutInterpolator);
5473e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        }
548716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen
549716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen        mDropAnim.setDuration(duration);
550716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen        mDropAnim.setFloatValues(0.0f, 1.0f);
551716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen        mDropAnim.removeAllUpdateListeners();
552716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen        mDropAnim.addUpdateListener(new AnimatorUpdateListener() {
553716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen            public void onAnimationUpdate(ValueAnimator animation) {
554716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen                final float percent = (Float) animation.getAnimatedValue();
555716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen                // Invalidate the old position
556716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen                int width = view.getMeasuredWidth();
557716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen                int height = view.getMeasuredHeight();
558716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen                invalidate(mDropViewPos[0], mDropViewPos[1],
559716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen                        mDropViewPos[0] + width, mDropViewPos[1] + height);
560716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen
5613e8f811f31a2275e778244427271f77f4116c08bAdam Cohen                float alphaPercent = alphaInterpolator == null ? percent :
5623e8f811f31a2275e778244427271f77f4116c08bAdam Cohen                        alphaInterpolator.getInterpolation(percent);
5633e8f811f31a2275e778244427271f77f4116c08bAdam Cohen                float motionPercent = motionInterpolator == null ? percent :
5643e8f811f31a2275e778244427271f77f4116c08bAdam Cohen                        motionInterpolator.getInterpolation(percent);
5653e8f811f31a2275e778244427271f77f4116c08bAdam Cohen
566ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen                mDropViewPos[0] = from.left + (int) Math.round(((to.left - from.left) * motionPercent));
567ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen                mDropViewPos[1] = from.top + (int) Math.round(((to.top - from.top) * motionPercent));
5683e8f811f31a2275e778244427271f77f4116c08bAdam Cohen                mDropViewScale = percent * finalScale + (1 - percent);
5693e8f811f31a2275e778244427271f77f4116c08bAdam Cohen                mDropViewAlpha = alphaPercent * finalAlpha + (1 - alphaPercent) * initialAlpha;
570716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen                invalidate(mDropViewPos[0], mDropViewPos[1],
571716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen                        mDropViewPos[0] + width, mDropViewPos[1] + height);
572716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen            }
573716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen        });
5743e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        mDropAnim.addListener(new AnimatorListenerAdapter() {
5753e8f811f31a2275e778244427271f77f4116c08bAdam Cohen            public void onAnimationEnd(Animator animation) {
5768dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen                if (onCompleteRunnable != null) {
5778dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen                    onCompleteRunnable.run();
5788dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen                }
5798dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen                if (fadeOut) {
5808dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen                    fadeOutDragView();
5818dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen                } else {
5823e8f811f31a2275e778244427271f77f4116c08bAdam Cohen                    mDropView = null;
5833e8f811f31a2275e778244427271f77f4116c08bAdam Cohen                }
5843e8f811f31a2275e778244427271f77f4116c08bAdam Cohen            }
5853e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        });
586716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen        mDropAnim.start();
587716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen    }
588716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen
5898dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen    private void fadeOutDragView() {
5908dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        mFadeOutAnim = new ValueAnimator();
5918dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        mFadeOutAnim.setDuration(150);
5928dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        mFadeOutAnim.setFloatValues(0f, 1f);
5938dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        mFadeOutAnim.removeAllUpdateListeners();
5948dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        mFadeOutAnim.addUpdateListener(new AnimatorUpdateListener() {
5958dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen            public void onAnimationUpdate(ValueAnimator animation) {
5968dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen                final float percent = (Float) animation.getAnimatedValue();
5978dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen                mDropViewAlpha = 1 - percent;
5988dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen                int width = mDropView.getMeasuredWidth();
5998dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen                int height = mDropView.getMeasuredHeight();
6008dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen                invalidate(mDropViewPos[0], mDropViewPos[1],
6018dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen                        mDropViewPos[0] + width, mDropViewPos[1] + height);
6028dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen            }
6038dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        });
6048dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        mFadeOutAnim.addListener(new AnimatorListenerAdapter() {
6058dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen            public void onAnimationEnd(Animator animation) {
6068dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen                mDropView = null;
6078dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen            }
6088dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        });
6098dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        mFadeOutAnim.start();
6108dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen    }
6118dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen
612716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen    @Override
613716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen    protected void dispatchDraw(Canvas canvas) {
614716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen        super.dispatchDraw(canvas);
615716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen        if (mDropView != null) {
616716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen            // We are animating an item that was just dropped on the home screen.
617716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen            // Render its View in the current animation position.
618716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen            canvas.save(Canvas.MATRIX_SAVE_FLAG);
619716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen            final int xPos = mDropViewPos[0] - mDropView.getScrollX();
620716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen            final int yPos = mDropViewPos[1] - mDropView.getScrollY();
6213e8f811f31a2275e778244427271f77f4116c08bAdam Cohen            int width = mDropView.getMeasuredWidth();
6223e8f811f31a2275e778244427271f77f4116c08bAdam Cohen            int height = mDropView.getMeasuredHeight();
623716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen            canvas.translate(xPos, yPos);
6243e8f811f31a2275e778244427271f77f4116c08bAdam Cohen            canvas.translate((1 - mDropViewScale) * width / 2, (1 - mDropViewScale) * height / 2);
6253e8f811f31a2275e778244427271f77f4116c08bAdam Cohen            canvas.scale(mDropViewScale, mDropViewScale);
6263e8f811f31a2275e778244427271f77f4116c08bAdam Cohen            mDropView.setAlpha(mDropViewAlpha);
627716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen            mDropView.draw(canvas);
628716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen            canvas.restore();
629716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen        }
630716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen    }
63131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project}
632