131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project/*
231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * Copyright (C) 2008 The Android Open Source Project
331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project *
431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * you may not use this file except in compliance with the License.
631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * You may obtain a copy of the License at
731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project *
831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project *
1031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
1131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
1231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * See the License for the specific language governing permissions and
1431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * limitations under the License.
1531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project */
1631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
17325dc23624160689e59fbac708cf6f222b20d025Daniel Sandlerpackage com.android.launcher3;
1831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
19716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohenimport android.animation.Animator;
20716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohenimport android.animation.AnimatorListenerAdapter;
21716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohenimport android.animation.TimeInterpolator;
22716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohenimport android.animation.ValueAnimator;
23716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohenimport android.animation.ValueAnimator.AnimatorUpdateListener;
2431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.content.Context;
25716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohenimport android.content.res.Resources;
26360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chungimport android.graphics.Canvas;
277d30a37007bac318db1c9af47a9af12d348042a5Adam Cohenimport android.graphics.Matrix;
286788269814a678af976dfc7d6135993e172ce586Adam Cohenimport android.graphics.Rect;
29360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chungimport android.graphics.drawable.Drawable;
3031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.util.AttributeSet;
315f8afe6280eae34620067696173e71943e1a30a3Winson Chungimport android.view.*;
323371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohenimport android.view.accessibility.AccessibilityEvent;
333371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohenimport android.view.accessibility.AccessibilityManager;
34716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohenimport android.view.animation.DecelerateInterpolator;
353e8f811f31a2275e778244427271f77f4116c08bAdam Cohenimport android.view.animation.Interpolator;
3631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.widget.FrameLayout;
37ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohenimport android.widget.TextView;
3831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
391d9af7d1e75bad13bb10ad37f5900ed59882622eAdam Cohenimport java.util.ArrayList;
406788269814a678af976dfc7d6135993e172ce586Adam Cohen
4131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project/**
420e26059548e429e5d1c973bebe4c561bead2926fMichael Jurka * A ViewGroup that coordinates dragging across its descendants
4331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project */
448b805b17158886035b38261eb611d8641701ae43Michael Jurkapublic class DragLayer extends FrameLayout implements ViewGroup.OnHierarchyChangeListener {
45120980bd00f5eecec5717f49a3d7db96571025a9Adam Cohen    private DragController mDragController;
46120980bd00f5eecec5717f49a3d7db96571025a9Adam Cohen    private int[] mTmpXY = new int[2];
4731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
48716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen    private int mXDown, mYDown;
49716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen    private Launcher mLauncher;
50716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen
516788269814a678af976dfc7d6135993e172ce586Adam Cohen    // Variables relating to resizing widgets
526788269814a678af976dfc7d6135993e172ce586Adam Cohen    private final ArrayList<AppWidgetResizeFrame> mResizeFrames =
536788269814a678af976dfc7d6135993e172ce586Adam Cohen            new ArrayList<AppWidgetResizeFrame>();
546788269814a678af976dfc7d6135993e172ce586Adam Cohen    private AppWidgetResizeFrame mCurrentResizeFrame;
55716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen
56716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen    // Variables relating to animation of views after drop
57716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen    private ValueAnimator mDropAnim = null;
588dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen    private ValueAnimator mFadeOutAnim = null;
598dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen    private TimeInterpolator mCubicEaseOutInterpolator = new DecelerateInterpolator(1.5f);
607bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung    private DragView mDropView = null;
616441de0ec2a71862798dd51180d0811b42edd514Adam Cohen    private int mAnchorViewInitialScrollX = 0;
626441de0ec2a71862798dd51180d0811b42edd514Adam Cohen    private View mAnchorView = null;
638dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen
643371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen    private boolean mHoverPointClosesFolder = false;
653371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen    private Rect mHitRect = new Rect();
6621b411074e39fd10cbc8dd0220bb159da4af2c76Adam Cohen    private int mWorkspaceIndex = -1;
67ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen    private int mQsbIndex = -1;
68ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen    public static final int ANIMATION_END_DISAPPEAR = 0;
69ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen    public static final int ANIMATION_END_FADE_OUT = 1;
70ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen    public static final int ANIMATION_END_REMAIN_VISIBLE = 2;
716788269814a678af976dfc7d6135993e172ce586Adam Cohen
72b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen    private TouchCompleteListener mTouchCompleteListener;
73b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen
7477e1f47520958edd7ec04e203db65b932537bd1cJohn Spurlock    private final Rect mInsets = new Rect();
7577e1f47520958edd7ec04e203db65b932537bd1cJohn Spurlock
7631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    /**
7731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * Used to create a new DragLayer from XML.
7831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     *
7931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param context The application's context.
800e26059548e429e5d1c973bebe4c561bead2926fMichael Jurka     * @param attrs The attributes set containing the Workspace's customization values.
8131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     */
8231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    public DragLayer(Context context, AttributeSet attrs) {
8331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        super(context, attrs);
84be62afa34d58edab0fc9ba7499f0dd543039c903Winson Chung
85be62afa34d58edab0fc9ba7499f0dd543039c903Winson Chung        // Disable multitouch across the workspace/all apps/customize tray
86be62afa34d58edab0fc9ba7499f0dd543039c903Winson Chung        setMotionEventSplittingEnabled(false);
8721b411074e39fd10cbc8dd0220bb159da4af2c76Adam Cohen        setChildrenDrawingOrderEnabled(true);
888b805b17158886035b38261eb611d8641701ae43Michael Jurka        setOnHierarchyChangeListener(this);
89360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung
90360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung        mLeftHoverDrawable = getResources().getDrawable(R.drawable.page_hover_left_holo);
91360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung        mRightHoverDrawable = getResources().getDrawable(R.drawable.page_hover_right_holo);
9231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
9331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
944c98d9235d164680186180974719f551cf935d08Winson Chung    public void setup(Launcher launcher, DragController controller) {
954c98d9235d164680186180974719f551cf935d08Winson Chung        mLauncher = launcher;
9600acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato        mDragController = controller;
9731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
9876fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen
9931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    @Override
10031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    public boolean dispatchKeyEvent(KeyEvent event) {
10100acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato        return mDragController.dispatchKeyEvent(event) || super.dispatchKeyEvent(event);
10231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
10331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
10477e1f47520958edd7ec04e203db65b932537bd1cJohn Spurlock    @Override
10577e1f47520958edd7ec04e203db65b932537bd1cJohn Spurlock    protected boolean fitSystemWindows(Rect insets) {
10677e1f47520958edd7ec04e203db65b932537bd1cJohn Spurlock        final int n = getChildCount();
10777e1f47520958edd7ec04e203db65b932537bd1cJohn Spurlock        for (int i = 0; i < n; i++) {
10877e1f47520958edd7ec04e203db65b932537bd1cJohn Spurlock            final View child = getChildAt(i);
10977e1f47520958edd7ec04e203db65b932537bd1cJohn Spurlock            final FrameLayout.LayoutParams flp = (FrameLayout.LayoutParams) child.getLayoutParams();
11077e1f47520958edd7ec04e203db65b932537bd1cJohn Spurlock            if (child instanceof Insettable) {
11177e1f47520958edd7ec04e203db65b932537bd1cJohn Spurlock                ((Insettable)child).setInsets(insets);
1126da63f81f8f2adaa539622c09d300d89123e0e6cWinson Chung            } else {
11377e1f47520958edd7ec04e203db65b932537bd1cJohn Spurlock                flp.topMargin += (insets.top - mInsets.top);
11477e1f47520958edd7ec04e203db65b932537bd1cJohn Spurlock                flp.leftMargin += (insets.left - mInsets.left);
11577e1f47520958edd7ec04e203db65b932537bd1cJohn Spurlock                flp.rightMargin += (insets.right - mInsets.right);
11677e1f47520958edd7ec04e203db65b932537bd1cJohn Spurlock                flp.bottomMargin += (insets.bottom - mInsets.bottom);
11777e1f47520958edd7ec04e203db65b932537bd1cJohn Spurlock            }
11877e1f47520958edd7ec04e203db65b932537bd1cJohn Spurlock            child.setLayoutParams(flp);
11977e1f47520958edd7ec04e203db65b932537bd1cJohn Spurlock        }
12077e1f47520958edd7ec04e203db65b932537bd1cJohn Spurlock        mInsets.set(insets);
12177e1f47520958edd7ec04e203db65b932537bd1cJohn Spurlock        return true; // I'll take it from here
12277e1f47520958edd7ec04e203db65b932537bd1cJohn Spurlock    }
12377e1f47520958edd7ec04e203db65b932537bd1cJohn Spurlock
1243371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen    private boolean isEventOverFolderTextRegion(Folder folder, MotionEvent ev) {
1253371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen        getDescendantRectRelativeToSelf(folder.getEditTextRegion(), mHitRect);
1263371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen        if (mHitRect.contains((int) ev.getX(), (int) ev.getY())) {
1273371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen            return true;
1283371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen        }
1293371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen        return false;
1303371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen    }
1313371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen
1323371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen    private boolean isEventOverFolder(Folder folder, MotionEvent ev) {
1333371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen        getDescendantRectRelativeToSelf(folder, mHitRect);
1343371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen        if (mHitRect.contains((int) ev.getX(), (int) ev.getY())) {
1353371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen            return true;
1363371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen        }
1373371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen        return false;
1383371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen    }
1393371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen
14076fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen    private boolean handleTouchDown(MotionEvent ev, boolean intercept) {
1416788269814a678af976dfc7d6135993e172ce586Adam Cohen        Rect hitRect = new Rect();
1426788269814a678af976dfc7d6135993e172ce586Adam Cohen        int x = (int) ev.getX();
1436788269814a678af976dfc7d6135993e172ce586Adam Cohen        int y = (int) ev.getY();
1446788269814a678af976dfc7d6135993e172ce586Adam Cohen
1456788269814a678af976dfc7d6135993e172ce586Adam Cohen        for (AppWidgetResizeFrame child: mResizeFrames) {
1466788269814a678af976dfc7d6135993e172ce586Adam Cohen            child.getHitRect(hitRect);
1476788269814a678af976dfc7d6135993e172ce586Adam Cohen            if (hitRect.contains(x, y)) {
1486788269814a678af976dfc7d6135993e172ce586Adam Cohen                if (child.beginResizeIfPointInRegion(x - child.getLeft(), y - child.getTop())) {
1496788269814a678af976dfc7d6135993e172ce586Adam Cohen                    mCurrentResizeFrame = child;
1506788269814a678af976dfc7d6135993e172ce586Adam Cohen                    mXDown = x;
1516788269814a678af976dfc7d6135993e172ce586Adam Cohen                    mYDown = y;
1526788269814a678af976dfc7d6135993e172ce586Adam Cohen                    requestDisallowInterceptTouchEvent(true);
1536788269814a678af976dfc7d6135993e172ce586Adam Cohen                    return true;
1546788269814a678af976dfc7d6135993e172ce586Adam Cohen                }
1556788269814a678af976dfc7d6135993e172ce586Adam Cohen            }
1566788269814a678af976dfc7d6135993e172ce586Adam Cohen        }
15776fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen
1581d9af7d1e75bad13bb10ad37f5900ed59882622eAdam Cohen        Folder currentFolder = mLauncher.getWorkspace().getOpenFolder();
1597d7541e7b48fdc114c24b3b0aa75e70d7228041eWinson Chung        if (currentFolder != null && !mLauncher.isFolderClingVisible() && intercept) {
1601d9af7d1e75bad13bb10ad37f5900ed59882622eAdam Cohen            if (currentFolder.isEditingName()) {
1613371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                if (!isEventOverFolderTextRegion(currentFolder, ev)) {
1621d9af7d1e75bad13bb10ad37f5900ed59882622eAdam Cohen                    currentFolder.dismissEditingName();
16376fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen                    return true;
1642801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen                }
1652801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen            }
16676fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen
1671d9af7d1e75bad13bb10ad37f5900ed59882622eAdam Cohen            getDescendantRectRelativeToSelf(currentFolder, hitRect);
1683371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen            if (!isEventOverFolder(currentFolder, ev)) {
16976fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen                mLauncher.closeFolder();
17076fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen                return true;
17176fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen            }
1722801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen        }
1736788269814a678af976dfc7d6135993e172ce586Adam Cohen        return false;
1746788269814a678af976dfc7d6135993e172ce586Adam Cohen    }
1756788269814a678af976dfc7d6135993e172ce586Adam Cohen
17631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    @Override
17731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    public boolean onInterceptTouchEvent(MotionEvent ev) {
178b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen        int action = ev.getAction();
179b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen
180b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen        if (action == MotionEvent.ACTION_DOWN) {
18176fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen            if (handleTouchDown(ev, true)) {
1826788269814a678af976dfc7d6135993e172ce586Adam Cohen                return true;
183d1837cc69eb222371afdd30890f7215d117510f2Patrick Dubroy            }
184b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen        } else if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) {
185b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen            if (mTouchCompleteListener != null) {
186b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen                mTouchCompleteListener.onTouchComplete();
187b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen            }
188b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen            mTouchCompleteListener = null;
1891b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen        }
1906788269814a678af976dfc7d6135993e172ce586Adam Cohen        clearAllResizeFrames();
1914db52312c10e822162a21c60404f06f6e507f0d6Joe Onorato        return mDragController.onInterceptTouchEvent(ev);
19231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
19331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
19431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    @Override
1953371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen    public boolean onInterceptHoverEvent(MotionEvent ev) {
196023c71eb3b2bbe63272cb74baaf050c4188c89b0Michael Jurka        if (mLauncher == null || mLauncher.getWorkspace() == null) {
197023c71eb3b2bbe63272cb74baaf050c4188c89b0Michael Jurka            return false;
198023c71eb3b2bbe63272cb74baaf050c4188c89b0Michael Jurka        }
1993371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen        Folder currentFolder = mLauncher.getWorkspace().getOpenFolder();
2003371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen        if (currentFolder == null) {
2013371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen            return false;
2023371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen        } else {
2038b805b17158886035b38261eb611d8641701ae43Michael Jurka                AccessibilityManager accessibilityManager = (AccessibilityManager)
2048b805b17158886035b38261eb611d8641701ae43Michael Jurka                        getContext().getSystemService(Context.ACCESSIBILITY_SERVICE);
2058b805b17158886035b38261eb611d8641701ae43Michael Jurka            if (accessibilityManager.isTouchExplorationEnabled()) {
2063371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                final int action = ev.getAction();
2073371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                boolean isOverFolder;
2083371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                switch (action) {
2093371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                    case MotionEvent.ACTION_HOVER_ENTER:
2103371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                        isOverFolder = isEventOverFolder(currentFolder, ev);
2113371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                        if (!isOverFolder) {
2123371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                            sendTapOutsideFolderAccessibilityEvent(currentFolder.isEditingName());
2133371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                            mHoverPointClosesFolder = true;
2143371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                            return true;
2153371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                        } else if (isOverFolder) {
2163371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                            mHoverPointClosesFolder = false;
2173371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                        } else {
2183371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                            return true;
2193371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                        }
2203371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                    case MotionEvent.ACTION_HOVER_MOVE:
2213371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                        isOverFolder = isEventOverFolder(currentFolder, ev);
2223371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                        if (!isOverFolder && !mHoverPointClosesFolder) {
2233371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                            sendTapOutsideFolderAccessibilityEvent(currentFolder.isEditingName());
2243371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                            mHoverPointClosesFolder = true;
2253371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                            return true;
2263371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                        } else if (isOverFolder) {
2273371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                            mHoverPointClosesFolder = false;
2283371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                        } else {
2293371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                            return true;
2303371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                        }
2313371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                }
2323371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen            }
2333371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen        }
2343371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen        return false;
2353371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen    }
2363371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen
2373371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen    private void sendTapOutsideFolderAccessibilityEvent(boolean isEditingName) {
2388b805b17158886035b38261eb611d8641701ae43Michael Jurka        AccessibilityManager accessibilityManager = (AccessibilityManager)
2398b805b17158886035b38261eb611d8641701ae43Michael Jurka                getContext().getSystemService(Context.ACCESSIBILITY_SERVICE);
2408b805b17158886035b38261eb611d8641701ae43Michael Jurka        if (accessibilityManager.isEnabled()) {
2413371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen            int stringId = isEditingName ? R.string.folder_tap_to_rename : R.string.folder_tap_to_close;
2423371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen            AccessibilityEvent event = AccessibilityEvent.obtain(
2433371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                    AccessibilityEvent.TYPE_VIEW_FOCUSED);
2443371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen            onInitializeAccessibilityEvent(event);
2458b805b17158886035b38261eb611d8641701ae43Michael Jurka            event.getText().add(getContext().getString(stringId));
2468b805b17158886035b38261eb611d8641701ae43Michael Jurka            accessibilityManager.sendAccessibilityEvent(event);
2473371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen        }
24883ca480941b3dd635b62347008fc8d7859d82002Winson Chung    }
24983ca480941b3dd635b62347008fc8d7859d82002Winson Chung
25083ca480941b3dd635b62347008fc8d7859d82002Winson Chung    @Override
25183ca480941b3dd635b62347008fc8d7859d82002Winson Chung    public boolean onRequestSendAccessibilityEvent(View child, AccessibilityEvent event) {
25283ca480941b3dd635b62347008fc8d7859d82002Winson Chung        Folder currentFolder = mLauncher.getWorkspace().getOpenFolder();
25383ca480941b3dd635b62347008fc8d7859d82002Winson Chung        if (currentFolder != null) {
25483ca480941b3dd635b62347008fc8d7859d82002Winson Chung            if (child == currentFolder) {
25583ca480941b3dd635b62347008fc8d7859d82002Winson Chung                return super.onRequestSendAccessibilityEvent(child, event);
25683ca480941b3dd635b62347008fc8d7859d82002Winson Chung            }
25783ca480941b3dd635b62347008fc8d7859d82002Winson Chung            // Skip propagating onRequestSendAccessibilityEvent all for other children
25883ca480941b3dd635b62347008fc8d7859d82002Winson Chung            // when a folder is open
25983ca480941b3dd635b62347008fc8d7859d82002Winson Chung            return false;
26083ca480941b3dd635b62347008fc8d7859d82002Winson Chung        }
26183ca480941b3dd635b62347008fc8d7859d82002Winson Chung        return super.onRequestSendAccessibilityEvent(child, event);
26283ca480941b3dd635b62347008fc8d7859d82002Winson Chung    }
26383ca480941b3dd635b62347008fc8d7859d82002Winson Chung
26483ca480941b3dd635b62347008fc8d7859d82002Winson Chung    @Override
26583ca480941b3dd635b62347008fc8d7859d82002Winson Chung    public void addChildrenForAccessibility(ArrayList<View> childrenForAccessibility) {
26683ca480941b3dd635b62347008fc8d7859d82002Winson Chung        Folder currentFolder = mLauncher.getWorkspace().getOpenFolder();
26783ca480941b3dd635b62347008fc8d7859d82002Winson Chung        if (currentFolder != null) {
26883ca480941b3dd635b62347008fc8d7859d82002Winson Chung            // Only add the folder as a child for accessibility when it is open
26983ca480941b3dd635b62347008fc8d7859d82002Winson Chung            childrenForAccessibility.add(currentFolder);
27083ca480941b3dd635b62347008fc8d7859d82002Winson Chung        } else {
27183ca480941b3dd635b62347008fc8d7859d82002Winson Chung            super.addChildrenForAccessibility(childrenForAccessibility);
27283ca480941b3dd635b62347008fc8d7859d82002Winson Chung        }
2733371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen    }
2743371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen
2753371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen    @Override
2763371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen    public boolean onHoverEvent(MotionEvent ev) {
2773371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen        // If we've received this, we've already done the necessary handling
2783371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen        // in onInterceptHoverEvent. Return true to consume the event.
2793371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen        return false;
2803371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen    }
2813371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen
2823371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen    @Override
28331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    public boolean onTouchEvent(MotionEvent ev) {
2846788269814a678af976dfc7d6135993e172ce586Adam Cohen        boolean handled = false;
2856788269814a678af976dfc7d6135993e172ce586Adam Cohen        int action = ev.getAction();
2866788269814a678af976dfc7d6135993e172ce586Adam Cohen
2876788269814a678af976dfc7d6135993e172ce586Adam Cohen        int x = (int) ev.getX();
2886788269814a678af976dfc7d6135993e172ce586Adam Cohen        int y = (int) ev.getY();
2896788269814a678af976dfc7d6135993e172ce586Adam Cohen
290b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen        if (action == MotionEvent.ACTION_DOWN) {
291b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen            if (handleTouchDown(ev, false)) {
292b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen                return true;
293b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen            }
294b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen        } else if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) {
295b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen            if (mTouchCompleteListener != null) {
296b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen                mTouchCompleteListener.onTouchComplete();
2976788269814a678af976dfc7d6135993e172ce586Adam Cohen            }
298b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen            mTouchCompleteListener = null;
2996788269814a678af976dfc7d6135993e172ce586Adam Cohen        }
3006788269814a678af976dfc7d6135993e172ce586Adam Cohen
3016788269814a678af976dfc7d6135993e172ce586Adam Cohen        if (mCurrentResizeFrame != null) {
3026788269814a678af976dfc7d6135993e172ce586Adam Cohen            handled = true;
3036788269814a678af976dfc7d6135993e172ce586Adam Cohen            switch (action) {
3046788269814a678af976dfc7d6135993e172ce586Adam Cohen                case MotionEvent.ACTION_MOVE:
3056788269814a678af976dfc7d6135993e172ce586Adam Cohen                    mCurrentResizeFrame.visualizeResizeForDelta(x - mXDown, y - mYDown);
3066788269814a678af976dfc7d6135993e172ce586Adam Cohen                    break;
3076788269814a678af976dfc7d6135993e172ce586Adam Cohen                case MotionEvent.ACTION_CANCEL:
3086788269814a678af976dfc7d6135993e172ce586Adam Cohen                case MotionEvent.ACTION_UP:
309bebf042666cffe52039b875a549a582abd78a431Adam Cohen                    mCurrentResizeFrame.visualizeResizeForDelta(x - mXDown, y - mYDown);
310bebf042666cffe52039b875a549a582abd78a431Adam Cohen                    mCurrentResizeFrame.onTouchUp();
3116788269814a678af976dfc7d6135993e172ce586Adam Cohen                    mCurrentResizeFrame = null;
3126788269814a678af976dfc7d6135993e172ce586Adam Cohen            }
3136788269814a678af976dfc7d6135993e172ce586Adam Cohen        }
3146788269814a678af976dfc7d6135993e172ce586Adam Cohen        if (handled) return true;
3154db52312c10e822162a21c60404f06f6e507f0d6Joe Onorato        return mDragController.onTouchEvent(ev);
31691a9c9636f10f1e12cd1f660b2e330634fbdc7dcRomain Guy    }
317ea3763c2672f77539538af8cdd395ad97058eaabRomain Guy
31835e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen    /**
31935e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen     * Determine the rect of the descendant in this DragLayer's coordinates
32035e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen     *
32135e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen     * @param descendant The descendant whose coordinates we want to find.
32235e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen     * @param r The rect into which to place the results.
32335e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen     * @return The factor by which this descendant is scaled relative to this DragLayer.
32435e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen     */
325ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen    public float getDescendantRectRelativeToSelf(View descendant, Rect r) {
326716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen        mTmpXY[0] = 0;
327716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen        mTmpXY[1] = 0;
328ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen        float scale = getDescendantCoordRelativeToSelf(descendant, mTmpXY);
3297d30a37007bac318db1c9af47a9af12d348042a5Adam Cohen
3308dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        r.set(mTmpXY[0], mTmpXY[1],
3317d30a37007bac318db1c9af47a9af12d348042a5Adam Cohen                (int) (mTmpXY[0] + scale * descendant.getMeasuredWidth()),
3327d30a37007bac318db1c9af47a9af12d348042a5Adam Cohen                (int) (mTmpXY[1] + scale * descendant.getMeasuredHeight()));
333ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen        return scale;
334716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen    }
33576fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen
336307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen    public float getLocationInDragLayer(View child, int[] loc) {
33735e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen        loc[0] = 0;
33835e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen        loc[1] = 0;
339307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen        return getDescendantCoordRelativeToSelf(child, loc);
34035e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen    }
34135e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen
3427d30a37007bac318db1c9af47a9af12d348042a5Adam Cohen    public float getDescendantCoordRelativeToSelf(View descendant, int[] coord) {
3437d30a37007bac318db1c9af47a9af12d348042a5Adam Cohen        return getDescendantCoordRelativeToSelf(descendant, coord, false);
3447d30a37007bac318db1c9af47a9af12d348042a5Adam Cohen    }
3457d30a37007bac318db1c9af47a9af12d348042a5Adam Cohen
34635e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen    /**
34735e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen     * Given a coordinate relative to the descendant, find the coordinate in this DragLayer's
34835e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen     * coordinates.
34935e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen     *
35035e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen     * @param descendant The descendant to which the passed coordinate is relative.
35135e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen     * @param coord The coordinate that we want mapped.
3527d30a37007bac318db1c9af47a9af12d348042a5Adam Cohen     * @param includeRootScroll Whether or not to account for the scroll of the root descendant:
3537d30a37007bac318db1c9af47a9af12d348042a5Adam Cohen     *          sometimes this is relevant as in a child's coordinates within the root descendant.
354307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen     * @return The factor by which this descendant is scaled relative to this DragLayer. Caution
355307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen     *         this scale factor is assumed to be equal in X and Y, and so if at any point this
356307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen     *         assumption fails, we will need to return a pair of scale factors.
35735e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen     */
3587d30a37007bac318db1c9af47a9af12d348042a5Adam Cohen    public float getDescendantCoordRelativeToSelf(View descendant, int[] coord,
3597d30a37007bac318db1c9af47a9af12d348042a5Adam Cohen            boolean includeRootScroll) {
360c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung        return Utilities.getDescendantCoordRelativeToParent(descendant, this,
361c9ca2980983ab21fc8631c7a65399d6d9c70f39cWinson Chung                coord, includeRootScroll);
362c9ca2980983ab21fc8631c7a65399d6d9c70f39cWinson Chung    }
363c9ca2980983ab21fc8631c7a65399d6d9c70f39cWinson Chung
3647d30a37007bac318db1c9af47a9af12d348042a5Adam Cohen    /**
3657d30a37007bac318db1c9af47a9af12d348042a5Adam Cohen     * Inverse of {@link #getDescendantCoordRelativeToSelf(View, int[])}.
3667d30a37007bac318db1c9af47a9af12d348042a5Adam Cohen     */
3677d30a37007bac318db1c9af47a9af12d348042a5Adam Cohen    public float mapCoordInSelfToDescendent(View descendant, int[] coord) {
368c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung        return Utilities.mapCoordInSelfToDescendent(descendant, this, coord);
36976fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen    }
37076fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen
3713e8f811f31a2275e778244427271f77f4116c08bAdam Cohen    public void getViewRectRelativeToSelf(View v, Rect r) {
3723e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        int[] loc = new int[2];
3738dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        getLocationInWindow(loc);
3743e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        int x = loc[0];
3753e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        int y = loc[1];
376716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen
3778dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        v.getLocationInWindow(loc);
3783e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        int vX = loc[0];
3793e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        int vY = loc[1];
380716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen
3813e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        int left = vX - x;
3823e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        int top = vY - y;
3833e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        r.set(left, top, left + v.getMeasuredWidth(), top + v.getMeasuredHeight());
384716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen    }
385716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen
386ea3763c2672f77539538af8cdd395ad97058eaabRomain Guy    @Override
387ea3763c2672f77539538af8cdd395ad97058eaabRomain Guy    public boolean dispatchUnhandledMove(View focused, int direction) {
388ea3763c2672f77539538af8cdd395ad97058eaabRomain Guy        return mDragController.dispatchUnhandledMove(focused, direction);
389ea3763c2672f77539538af8cdd395ad97058eaabRomain Guy    }
390120980bd00f5eecec5717f49a3d7db96571025a9Adam Cohen
3916788269814a678af976dfc7d6135993e172ce586Adam Cohen    public static class LayoutParams extends FrameLayout.LayoutParams {
3926788269814a678af976dfc7d6135993e172ce586Adam Cohen        public int x, y;
3936788269814a678af976dfc7d6135993e172ce586Adam Cohen        public boolean customPosition = false;
3946788269814a678af976dfc7d6135993e172ce586Adam Cohen
3956788269814a678af976dfc7d6135993e172ce586Adam Cohen        /**
3966788269814a678af976dfc7d6135993e172ce586Adam Cohen         * {@inheritDoc}
3976788269814a678af976dfc7d6135993e172ce586Adam Cohen         */
3986788269814a678af976dfc7d6135993e172ce586Adam Cohen        public LayoutParams(int width, int height) {
3996788269814a678af976dfc7d6135993e172ce586Adam Cohen            super(width, height);
4006788269814a678af976dfc7d6135993e172ce586Adam Cohen        }
4016788269814a678af976dfc7d6135993e172ce586Adam Cohen
4026788269814a678af976dfc7d6135993e172ce586Adam Cohen        public void setWidth(int width) {
4036788269814a678af976dfc7d6135993e172ce586Adam Cohen            this.width = width;
4046788269814a678af976dfc7d6135993e172ce586Adam Cohen        }
4056788269814a678af976dfc7d6135993e172ce586Adam Cohen
4066788269814a678af976dfc7d6135993e172ce586Adam Cohen        public int getWidth() {
4076788269814a678af976dfc7d6135993e172ce586Adam Cohen            return width;
4086788269814a678af976dfc7d6135993e172ce586Adam Cohen        }
4096788269814a678af976dfc7d6135993e172ce586Adam Cohen
4106788269814a678af976dfc7d6135993e172ce586Adam Cohen        public void setHeight(int height) {
4116788269814a678af976dfc7d6135993e172ce586Adam Cohen            this.height = height;
4126788269814a678af976dfc7d6135993e172ce586Adam Cohen        }
4136788269814a678af976dfc7d6135993e172ce586Adam Cohen
4146788269814a678af976dfc7d6135993e172ce586Adam Cohen        public int getHeight() {
4156788269814a678af976dfc7d6135993e172ce586Adam Cohen            return height;
4166788269814a678af976dfc7d6135993e172ce586Adam Cohen        }
4176788269814a678af976dfc7d6135993e172ce586Adam Cohen
4186788269814a678af976dfc7d6135993e172ce586Adam Cohen        public void setX(int x) {
4196788269814a678af976dfc7d6135993e172ce586Adam Cohen            this.x = x;
4206788269814a678af976dfc7d6135993e172ce586Adam Cohen        }
4216788269814a678af976dfc7d6135993e172ce586Adam Cohen
4226788269814a678af976dfc7d6135993e172ce586Adam Cohen        public int getX() {
4236788269814a678af976dfc7d6135993e172ce586Adam Cohen            return x;
4246788269814a678af976dfc7d6135993e172ce586Adam Cohen        }
4256788269814a678af976dfc7d6135993e172ce586Adam Cohen
4266788269814a678af976dfc7d6135993e172ce586Adam Cohen        public void setY(int y) {
4276788269814a678af976dfc7d6135993e172ce586Adam Cohen            this.y = y;
4286788269814a678af976dfc7d6135993e172ce586Adam Cohen        }
4296788269814a678af976dfc7d6135993e172ce586Adam Cohen
4306788269814a678af976dfc7d6135993e172ce586Adam Cohen        public int getY() {
4316788269814a678af976dfc7d6135993e172ce586Adam Cohen            return y;
4326788269814a678af976dfc7d6135993e172ce586Adam Cohen        }
4336788269814a678af976dfc7d6135993e172ce586Adam Cohen    }
4346788269814a678af976dfc7d6135993e172ce586Adam Cohen
4356788269814a678af976dfc7d6135993e172ce586Adam Cohen    protected void onLayout(boolean changed, int l, int t, int r, int b) {
4366788269814a678af976dfc7d6135993e172ce586Adam Cohen        super.onLayout(changed, l, t, r, b);
4376788269814a678af976dfc7d6135993e172ce586Adam Cohen        int count = getChildCount();
4386788269814a678af976dfc7d6135993e172ce586Adam Cohen        for (int i = 0; i < count; i++) {
4396788269814a678af976dfc7d6135993e172ce586Adam Cohen            View child = getChildAt(i);
4406788269814a678af976dfc7d6135993e172ce586Adam Cohen            final FrameLayout.LayoutParams flp = (FrameLayout.LayoutParams) child.getLayoutParams();
4416788269814a678af976dfc7d6135993e172ce586Adam Cohen            if (flp instanceof LayoutParams) {
4426788269814a678af976dfc7d6135993e172ce586Adam Cohen                final LayoutParams lp = (LayoutParams) flp;
4436788269814a678af976dfc7d6135993e172ce586Adam Cohen                if (lp.customPosition) {
4446788269814a678af976dfc7d6135993e172ce586Adam Cohen                    child.layout(lp.x, lp.y, lp.x + lp.width, lp.y + lp.height);
4456788269814a678af976dfc7d6135993e172ce586Adam Cohen                }
4466788269814a678af976dfc7d6135993e172ce586Adam Cohen            }
4476788269814a678af976dfc7d6135993e172ce586Adam Cohen        }
4486788269814a678af976dfc7d6135993e172ce586Adam Cohen    }
4496788269814a678af976dfc7d6135993e172ce586Adam Cohen
4506788269814a678af976dfc7d6135993e172ce586Adam Cohen    public void clearAllResizeFrames() {
4516788269814a678af976dfc7d6135993e172ce586Adam Cohen        if (mResizeFrames.size() > 0) {
4526788269814a678af976dfc7d6135993e172ce586Adam Cohen            for (AppWidgetResizeFrame frame: mResizeFrames) {
453bebf042666cffe52039b875a549a582abd78a431Adam Cohen                frame.commitResize();
4546788269814a678af976dfc7d6135993e172ce586Adam Cohen                removeView(frame);
4556788269814a678af976dfc7d6135993e172ce586Adam Cohen            }
4566788269814a678af976dfc7d6135993e172ce586Adam Cohen            mResizeFrames.clear();
4576788269814a678af976dfc7d6135993e172ce586Adam Cohen        }
4586788269814a678af976dfc7d6135993e172ce586Adam Cohen    }
4596788269814a678af976dfc7d6135993e172ce586Adam Cohen
4606788269814a678af976dfc7d6135993e172ce586Adam Cohen    public boolean hasResizeFrames() {
4616788269814a678af976dfc7d6135993e172ce586Adam Cohen        return mResizeFrames.size() > 0;
4626788269814a678af976dfc7d6135993e172ce586Adam Cohen    }
4636788269814a678af976dfc7d6135993e172ce586Adam Cohen
4646788269814a678af976dfc7d6135993e172ce586Adam Cohen    public boolean isWidgetBeingResized() {
4656788269814a678af976dfc7d6135993e172ce586Adam Cohen        return mCurrentResizeFrame != null;
4666788269814a678af976dfc7d6135993e172ce586Adam Cohen    }
4676788269814a678af976dfc7d6135993e172ce586Adam Cohen
4686788269814a678af976dfc7d6135993e172ce586Adam Cohen    public void addResizeFrame(ItemInfo itemInfo, LauncherAppWidgetHostView widget,
4696788269814a678af976dfc7d6135993e172ce586Adam Cohen            CellLayout cellLayout) {
4706788269814a678af976dfc7d6135993e172ce586Adam Cohen        AppWidgetResizeFrame resizeFrame = new AppWidgetResizeFrame(getContext(),
4713a9fcedbcd235372cd2ab64f825a0b5b3937f59eMichael Jurka                widget, cellLayout, this);
4726788269814a678af976dfc7d6135993e172ce586Adam Cohen
4736788269814a678af976dfc7d6135993e172ce586Adam Cohen        LayoutParams lp = new LayoutParams(-1, -1);
4746788269814a678af976dfc7d6135993e172ce586Adam Cohen        lp.customPosition = true;
4756788269814a678af976dfc7d6135993e172ce586Adam Cohen
4766788269814a678af976dfc7d6135993e172ce586Adam Cohen        addView(resizeFrame, lp);
4776788269814a678af976dfc7d6135993e172ce586Adam Cohen        mResizeFrames.add(resizeFrame);
4786788269814a678af976dfc7d6135993e172ce586Adam Cohen
4796788269814a678af976dfc7d6135993e172ce586Adam Cohen        resizeFrame.snapToWidget(false);
4806788269814a678af976dfc7d6135993e172ce586Adam Cohen    }
481716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen
482716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen    public void animateViewIntoPosition(DragView dragView, final View child) {
483557d6ed50cc6560163440aa134870ef0bb11415bWinson Chung        animateViewIntoPosition(dragView, child, null);
484557d6ed50cc6560163440aa134870ef0bb11415bWinson Chung    }
485ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen
4867bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung    public void animateViewIntoPosition(DragView dragView, final int[] pos, float alpha,
4877bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung            float scaleX, float scaleY, int animationEndStyle, Runnable onFinishRunnable,
4887bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung            int duration) {
489b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen        Rect r = new Rect();
490b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen        getViewRectRelativeToSelf(dragView, r);
491b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen        final int fromX = r.left;
492b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen        final int fromY = r.top;
493b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen
4947bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung        animateViewIntoPosition(dragView, fromX, fromY, pos[0], pos[1], alpha, 1, 1, scaleX, scaleY,
495ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen                onFinishRunnable, animationEndStyle, duration, null);
496ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen    }
497ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen
498557d6ed50cc6560163440aa134870ef0bb11415bWinson Chung    public void animateViewIntoPosition(DragView dragView, final View child,
499557d6ed50cc6560163440aa134870ef0bb11415bWinson Chung            final Runnable onFinishAnimationRunnable) {
5006441de0ec2a71862798dd51180d0811b42edd514Adam Cohen        animateViewIntoPosition(dragView, child, -1, onFinishAnimationRunnable, null);
501ed51cc9a12c50d12e7d30ed209a49f1a40858043Adam Cohen    }
502ed51cc9a12c50d12e7d30ed209a49f1a40858043Adam Cohen
503ed51cc9a12c50d12e7d30ed209a49f1a40858043Adam Cohen    public void animateViewIntoPosition(DragView dragView, final View child, int duration,
5046441de0ec2a71862798dd51180d0811b42edd514Adam Cohen            final Runnable onFinishAnimationRunnable, View anchorView) {
505a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        ShortcutAndWidgetContainer parentChildren = (ShortcutAndWidgetContainer) child.getParent();
506716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen        CellLayout.LayoutParams lp =  (CellLayout.LayoutParams) child.getLayoutParams();
507eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung        parentChildren.measureChild(child);
508716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen
5093e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        Rect r = new Rect();
5103e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        getViewRectRelativeToSelf(dragView, r);
511716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen
512716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen        int coord[] = new int[2];
513307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen        float childScale = child.getScaleX();
514307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen        coord[0] = lp.x + (int) (child.getMeasuredWidth() * (1 - childScale) / 2);
515307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen        coord[1] = lp.y + (int) (child.getMeasuredHeight() * (1 - childScale) / 2);
516eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung
5178dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        // Since the child hasn't necessarily been laid out, we force the lp to be updated with
518ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen        // the correct coordinates (above) and use these to determine the final location
519557d6ed50cc6560163440aa134870ef0bb11415bWinson Chung        float scale = getDescendantCoordRelativeToSelf((View) child.getParent(), coord);
520307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen        // We need to account for the scale of the child itself, as the above only accounts for
521307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen        // for the scale in parents.
522307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen        scale *= childScale;
523ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen        int toX = coord[0];
524ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen        int toY = coord[1];
5254497ebf9a2726e2a7dbb7f3c49389308908f8454Andrew Flynn        if (child instanceof TextView) {
5264497ebf9a2726e2a7dbb7f3c49389308908f8454Andrew Flynn            TextView tv = (TextView) child;
5274497ebf9a2726e2a7dbb7f3c49389308908f8454Andrew Flynn
5284497ebf9a2726e2a7dbb7f3c49389308908f8454Andrew Flynn            // The child may be scaled (always about the center of the view) so to account for it,
5294497ebf9a2726e2a7dbb7f3c49389308908f8454Andrew Flynn            // we have to offset the position by the scaled size.  Once we do that, we can center
5304497ebf9a2726e2a7dbb7f3c49389308908f8454Andrew Flynn            // the drag view about the scaled child view.
5314497ebf9a2726e2a7dbb7f3c49389308908f8454Andrew Flynn            toY += Math.round(scale * tv.getPaddingTop());
5324497ebf9a2726e2a7dbb7f3c49389308908f8454Andrew Flynn            toY -= dragView.getMeasuredHeight() * (1 - scale) / 2;
5334497ebf9a2726e2a7dbb7f3c49389308908f8454Andrew Flynn            toX -= (dragView.getMeasuredWidth() - Math.round(scale * child.getMeasuredWidth())) / 2;
5344497ebf9a2726e2a7dbb7f3c49389308908f8454Andrew Flynn        } else if (child instanceof FolderIcon) {
535ea359c6aee44c0fe3bb94f7002c3b49208b32b7fWinson Chung            // Account for holographic blur padding on the drag view
5365f8afe6280eae34620067696173e71943e1a30a3Winson Chung            toY += Math.round(scale * (child.getPaddingTop() - dragView.getDragRegionTop()));
537307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen            toY -= scale * Workspace.DRAG_BITMAP_PADDING / 2;
538307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen            toY -= (1 - scale) * dragView.getMeasuredHeight() / 2;
539ea359c6aee44c0fe3bb94f7002c3b49208b32b7fWinson Chung            // Center in the x coordinate about the target's drawable
540ea359c6aee44c0fe3bb94f7002c3b49208b32b7fWinson Chung            toX -= (dragView.getMeasuredWidth() - Math.round(scale * child.getMeasuredWidth())) / 2;
541ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen        } else {
542ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen            toY -= (Math.round(scale * (dragView.getHeight() - child.getMeasuredHeight()))) / 2;
543ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen            toX -= (Math.round(scale * (dragView.getMeasuredWidth()
544ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen                    - child.getMeasuredWidth()))) / 2;
545ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen        }
546716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen
547ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen        final int fromX = r.left;
548ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen        final int fromY = r.top;
549716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen        child.setVisibility(INVISIBLE);
5508dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        Runnable onCompleteRunnable = new Runnable() {
5518dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen            public void run() {
5528dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen                child.setVisibility(VISIBLE);
553d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                if (onFinishAnimationRunnable != null) {
554d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    onFinishAnimationRunnable.run();
555d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                }
5568dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen            }
5578dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        };
558ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen        animateViewIntoPosition(dragView, fromX, fromY, toX, toY, 1, 1, 1, scale, scale,
559d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                onCompleteRunnable, ANIMATION_END_DISAPPEAR, duration, anchorView);
560557d6ed50cc6560163440aa134870ef0bb11415bWinson Chung    }
561557d6ed50cc6560163440aa134870ef0bb11415bWinson Chung
562d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen    public void animateViewIntoPosition(final DragView view, final int fromX, final int fromY,
563ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen            final int toX, final int toY, float finalAlpha, float initScaleX, float initScaleY,
564ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen            float finalScaleX, float finalScaleY, Runnable onCompleteRunnable,
565ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen            int animationEndStyle, int duration, View anchorView) {
5668dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        Rect from = new Rect(fromX, fromY, fromX +
5678dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen                view.getMeasuredWidth(), fromY + view.getMeasuredHeight());
5683e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        Rect to = new Rect(toX, toY, toX + view.getMeasuredWidth(), toY + view.getMeasuredHeight());
569ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen        animateView(view, from, to, finalAlpha, initScaleX, initScaleY, finalScaleX, finalScaleY, duration,
570ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen                null, null, onCompleteRunnable, animationEndStyle, anchorView);
5713e8f811f31a2275e778244427271f77f4116c08bAdam Cohen    }
5723e8f811f31a2275e778244427271f77f4116c08bAdam Cohen
573b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen    /**
574b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen     * This method animates a view at the end of a drag and drop animation.
575b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen     *
576b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen     * @param view The view to be animated. This view is drawn directly into DragLayer, and so
577b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen     *        doesn't need to be a child of DragLayer.
578b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen     * @param from The initial location of the view. Only the left and top parameters are used.
579b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen     * @param to The final location of the view. Only the left and top parameters are used. This
580b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen     *        location doesn't account for scaling, and so should be centered about the desired
581b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen     *        final location (including scaling).
582b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen     * @param finalAlpha The final alpha of the view, in case we want it to fade as it animates.
583b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen     * @param finalScale The final scale of the view. The view is scaled about its center.
584b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen     * @param duration The duration of the animation.
585b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen     * @param motionInterpolator The interpolator to use for the location of the view.
586b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen     * @param alphaInterpolator The interpolator to use for the alpha of the view.
587b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen     * @param onCompleteRunnable Optional runnable to run on animation completion.
588b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen     * @param fadeOut Whether or not to fade out the view once the animation completes. If true,
589b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen     *        the runnable will execute after the view is faded out.
5906441de0ec2a71862798dd51180d0811b42edd514Adam Cohen     * @param anchorView If not null, this represents the view which the animated view stays
5916441de0ec2a71862798dd51180d0811b42edd514Adam Cohen     *        anchored to in case scrolling is currently taking place. Note: currently this is
5926441de0ec2a71862798dd51180d0811b42edd514Adam Cohen     *        only used for the X dimension for the case of the workspace.
593b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen     */
5947bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung    public void animateView(final DragView view, final Rect from, final Rect to,
5957bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung            final float finalAlpha, final float initScaleX, final float initScaleY,
5967bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung            final float finalScaleX, final float finalScaleY, int duration,
5977bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung            final Interpolator motionInterpolator, final Interpolator alphaInterpolator,
5987bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung            final Runnable onCompleteRunnable, final int animationEndStyle, View anchorView) {
5997bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung
600716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen        // Calculate the duration of the animation based on the object's distance
6013e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        final float dist = (float) Math.sqrt(Math.pow(to.left - from.left, 2) +
6023e8f811f31a2275e778244427271f77f4116c08bAdam Cohen                Math.pow(to.top - from.top, 2));
603716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen        final Resources res = getResources();
604716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen        final float maxDist = (float) res.getInteger(R.integer.config_dropAnimMaxDist);
6053e8f811f31a2275e778244427271f77f4116c08bAdam Cohen
6063e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        // If duration < 0, this is a cue to compute the duration based on the distance
6073e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        if (duration < 0) {
6083e8f811f31a2275e778244427271f77f4116c08bAdam Cohen            duration = res.getInteger(R.integer.config_dropAnimMaxDuration);
6093e8f811f31a2275e778244427271f77f4116c08bAdam Cohen            if (dist < maxDist) {
6108dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen                duration *= mCubicEaseOutInterpolator.getInterpolation(dist / maxDist);
6113e8f811f31a2275e778244427271f77f4116c08bAdam Cohen            }
61261b0c69d3fe331d3de338322396d5de691d58613Winson Chung            duration = Math.max(duration, res.getInteger(R.integer.config_dropAnimMinDuration));
613716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen        }
614716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen
615043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        // Fall back to cubic ease out interpolator for the animation if none is specified
616043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        TimeInterpolator interpolator = null;
6173e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        if (alphaInterpolator == null || motionInterpolator == null) {
618043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung            interpolator = mCubicEaseOutInterpolator;
6193e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        }
620716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen
621043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        // Animate the view
6227bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung        final float initAlpha = view.getAlpha();
623043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        final float dropViewScale = view.getScaleX();
624043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        AnimatorUpdateListener updateCb = new AnimatorUpdateListener() {
625043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung            @Override
626716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen            public void onAnimationUpdate(ValueAnimator animation) {
627716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen                final float percent = (Float) animation.getAnimatedValue();
6287bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung                final int width = view.getMeasuredWidth();
6297bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung                final int height = view.getMeasuredHeight();
630716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen
6313e8f811f31a2275e778244427271f77f4116c08bAdam Cohen                float alphaPercent = alphaInterpolator == null ? percent :
6323e8f811f31a2275e778244427271f77f4116c08bAdam Cohen                        alphaInterpolator.getInterpolation(percent);
6333e8f811f31a2275e778244427271f77f4116c08bAdam Cohen                float motionPercent = motionInterpolator == null ? percent :
6343e8f811f31a2275e778244427271f77f4116c08bAdam Cohen                        motionInterpolator.getInterpolation(percent);
635a1cdab039292f3d809528c0e2e38580b37864d8dWinson Chung
6367bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung                float initialScaleX = initScaleX * dropViewScale;
6377bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung                float initialScaleY = initScaleY * dropViewScale;
6387bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung                float scaleX = finalScaleX * percent + initialScaleX * (1 - percent);
6397bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung                float scaleY = finalScaleY * percent + initialScaleY * (1 - percent);
6407bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung                float alpha = finalAlpha * alphaPercent + initAlpha * (1 - alphaPercent);
6417bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung
6427bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung                float fromLeft = from.left + (initialScaleX - 1f) * width / 2;
6437bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung                float fromTop = from.top + (initialScaleY - 1f) * height / 2;
6447bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung
6457bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung                int x = (int) (fromLeft + Math.round(((to.left - fromLeft) * motionPercent)));
6467bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung                int y = (int) (fromTop + Math.round(((to.top - fromTop) * motionPercent)));
6477bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung
6487bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung                int xPos = x - mDropView.getScrollX() + (mAnchorView != null
6497bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung                        ? (mAnchorViewInitialScrollX - mAnchorView.getScrollX()) : 0);
6507bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung                int yPos = y - mDropView.getScrollY();
6517bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung
6527bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung                mDropView.setTranslationX(xPos);
6537bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung                mDropView.setTranslationY(yPos);
6547bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung                mDropView.setScaleX(scaleX);
6557bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung                mDropView.setScaleY(scaleY);
6567bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung                mDropView.setAlpha(alpha);
657716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen            }
658043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        };
659043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        animateView(view, updateCb, duration, interpolator, onCompleteRunnable, animationEndStyle,
660043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung                anchorView);
661043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung    }
662043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung
663043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung    public void animateView(final DragView view, AnimatorUpdateListener updateCb, int duration,
664043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung            TimeInterpolator interpolator, final Runnable onCompleteRunnable,
665043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung            final int animationEndStyle, View anchorView) {
666043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        // Clean up the previous animations
667043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        if (mDropAnim != null) mDropAnim.cancel();
668043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        if (mFadeOutAnim != null) mFadeOutAnim.cancel();
669043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung
670043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        // Show the drop view if it was previously hidden
671043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        mDropView = view;
672043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        mDropView.cancelAnimation();
673043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        mDropView.resetLayoutParams();
674043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung
675043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        // Set the anchor view if the page is scrolling
676043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        if (anchorView != null) {
677043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung            mAnchorViewInitialScrollX = anchorView.getScrollX();
678043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        }
679043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        mAnchorView = anchorView;
680043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung
681043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        // Create and start the animation
682043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        mDropAnim = new ValueAnimator();
683043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        mDropAnim.setInterpolator(interpolator);
684043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        mDropAnim.setDuration(duration);
685043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        mDropAnim.setFloatValues(0f, 1f);
686043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        mDropAnim.addUpdateListener(updateCb);
6873e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        mDropAnim.addListener(new AnimatorListenerAdapter() {
6883e8f811f31a2275e778244427271f77f4116c08bAdam Cohen            public void onAnimationEnd(Animator animation) {
6898dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen                if (onCompleteRunnable != null) {
6908dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen                    onCompleteRunnable.run();
6918dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen                }
692ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen                switch (animationEndStyle) {
693ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen                case ANIMATION_END_DISAPPEAR:
694ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen                    clearAnimatedView();
695ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen                    break;
696ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen                case ANIMATION_END_FADE_OUT:
6978dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen                    fadeOutDragView();
698ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen                    break;
699ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen                case ANIMATION_END_REMAIN_VISIBLE:
700ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen                    break;
7013e8f811f31a2275e778244427271f77f4116c08bAdam Cohen                }
7023e8f811f31a2275e778244427271f77f4116c08bAdam Cohen            }
7033e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        });
704716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen        mDropAnim.start();
705716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen    }
706716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen
707ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen    public void clearAnimatedView() {
7087bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung        if (mDropAnim != null) {
7097bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung            mDropAnim.cancel();
7107bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung        }
7117bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung        if (mDropView != null) {
712043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung            mDragController.onDeferredEndDrag(mDropView);
7137bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung        }
714ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen        mDropView = null;
715ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen        invalidate();
716ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen    }
717ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen
718ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen    public View getAnimatedView() {
719ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen        return mDropView;
720ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen    }
721ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen
7228dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen    private void fadeOutDragView() {
7238dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        mFadeOutAnim = new ValueAnimator();
7248dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        mFadeOutAnim.setDuration(150);
7258dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        mFadeOutAnim.setFloatValues(0f, 1f);
7268dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        mFadeOutAnim.removeAllUpdateListeners();
7278dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        mFadeOutAnim.addUpdateListener(new AnimatorUpdateListener() {
7288dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen            public void onAnimationUpdate(ValueAnimator animation) {
7298dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen                final float percent = (Float) animation.getAnimatedValue();
7307bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung
7317bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung                float alpha = 1 - percent;
7327bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung                mDropView.setAlpha(alpha);
7338dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen            }
7348dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        });
7358dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        mFadeOutAnim.addListener(new AnimatorListenerAdapter() {
7368dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen            public void onAnimationEnd(Animator animation) {
7377bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung                if (mDropView != null) {
738043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung                    mDragController.onDeferredEndDrag(mDropView);
7397bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung                }
7408dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen                mDropView = null;
741ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen                invalidate();
7428dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen            }
7438dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        });
7448dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        mFadeOutAnim.start();
7458dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen    }
7468dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen
747716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen    @Override
7488b805b17158886035b38261eb611d8641701ae43Michael Jurka    public void onChildViewAdded(View parent, View child) {
74921b411074e39fd10cbc8dd0220bb159da4af2c76Adam Cohen        updateChildIndices();
75021b411074e39fd10cbc8dd0220bb159da4af2c76Adam Cohen    }
75121b411074e39fd10cbc8dd0220bb159da4af2c76Adam Cohen
75221b411074e39fd10cbc8dd0220bb159da4af2c76Adam Cohen    @Override
7538b805b17158886035b38261eb611d8641701ae43Michael Jurka    public void onChildViewRemoved(View parent, View child) {
75421b411074e39fd10cbc8dd0220bb159da4af2c76Adam Cohen        updateChildIndices();
75521b411074e39fd10cbc8dd0220bb159da4af2c76Adam Cohen    }
75621b411074e39fd10cbc8dd0220bb159da4af2c76Adam Cohen
75721b411074e39fd10cbc8dd0220bb159da4af2c76Adam Cohen    private void updateChildIndices() {
75821b411074e39fd10cbc8dd0220bb159da4af2c76Adam Cohen        if (mLauncher != null) {
75921b411074e39fd10cbc8dd0220bb159da4af2c76Adam Cohen            mWorkspaceIndex = indexOfChild(mLauncher.getWorkspace());
760ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen            mQsbIndex = indexOfChild(mLauncher.getSearchBar());
76121b411074e39fd10cbc8dd0220bb159da4af2c76Adam Cohen        }
76221b411074e39fd10cbc8dd0220bb159da4af2c76Adam Cohen    }
76321b411074e39fd10cbc8dd0220bb159da4af2c76Adam Cohen
76421b411074e39fd10cbc8dd0220bb159da4af2c76Adam Cohen    @Override
76521b411074e39fd10cbc8dd0220bb159da4af2c76Adam Cohen    protected int getChildDrawingOrder(int childCount, int i) {
766e29c55ac322f3386327fa5b61e79b00ba3e5d428Adam Cohen        // TODO: We have turned off this custom drawing order because it now effects touch
767e29c55ac322f3386327fa5b61e79b00ba3e5d428Adam Cohen        // dispatch order. We need to sort that issue out and then decide how to go about this.
768cc8befac3550c81d04ea206c170adae36c9a6c93Daniel Sandler        if (true || LauncherAppState.isScreenLandscape(getContext()) ||
769e29c55ac322f3386327fa5b61e79b00ba3e5d428Adam Cohen                mWorkspaceIndex == -1 || mQsbIndex == -1 ||
77021b411074e39fd10cbc8dd0220bb159da4af2c76Adam Cohen                mLauncher.getWorkspace().isDrawingBackgroundGradient()) {
77121b411074e39fd10cbc8dd0220bb159da4af2c76Adam Cohen            return i;
77221b411074e39fd10cbc8dd0220bb159da4af2c76Adam Cohen        }
77321b411074e39fd10cbc8dd0220bb159da4af2c76Adam Cohen
77421b411074e39fd10cbc8dd0220bb159da4af2c76Adam Cohen        // This ensures that the workspace is drawn above the hotseat and qsb,
77521b411074e39fd10cbc8dd0220bb159da4af2c76Adam Cohen        // except when the workspace is drawing a background gradient, in which
77621b411074e39fd10cbc8dd0220bb159da4af2c76Adam Cohen        // case we want the workspace to stay behind these elements.
777ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen        if (i == mQsbIndex) {
77821b411074e39fd10cbc8dd0220bb159da4af2c76Adam Cohen            return mWorkspaceIndex;
77921b411074e39fd10cbc8dd0220bb159da4af2c76Adam Cohen        } else if (i == mWorkspaceIndex) {
780ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen            return mQsbIndex;
78121b411074e39fd10cbc8dd0220bb159da4af2c76Adam Cohen        } else {
78221b411074e39fd10cbc8dd0220bb159da4af2c76Adam Cohen            return i;
78321b411074e39fd10cbc8dd0220bb159da4af2c76Adam Cohen        }
78421b411074e39fd10cbc8dd0220bb159da4af2c76Adam Cohen    }
785360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung
786360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung    private boolean mInScrollArea;
787360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung    private Drawable mLeftHoverDrawable;
788360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung    private Drawable mRightHoverDrawable;
789360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung
790360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung    void onEnterScrollArea(int direction) {
791360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung        mInScrollArea = true;
792360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung        invalidate();
793360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung    }
794360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung
795360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung    void onExitScrollArea() {
796360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung        mInScrollArea = false;
797360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung        invalidate();
798360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung    }
799360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung
800fe1fe268b6d9ffd99218117795b3524a87e5110bWinson Chung    /**
801fe1fe268b6d9ffd99218117795b3524a87e5110bWinson Chung     * Note: this is a reimplementation of View.isLayoutRtl() since that is currently hidden api.
802fe1fe268b6d9ffd99218117795b3524a87e5110bWinson Chung     */
803fe1fe268b6d9ffd99218117795b3524a87e5110bWinson Chung    private boolean isLayoutRtl() {
804fe1fe268b6d9ffd99218117795b3524a87e5110bWinson Chung        return (getLayoutDirection() == LAYOUT_DIRECTION_RTL);
805fe1fe268b6d9ffd99218117795b3524a87e5110bWinson Chung    }
806fe1fe268b6d9ffd99218117795b3524a87e5110bWinson Chung
807360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung    @Override
808360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung    protected void dispatchDraw(Canvas canvas) {
809360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung        super.dispatchDraw(canvas);
810360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung
811e4f9891f01bdc10d8f96e4e2429e2f4d0558238bDaniel Sandler        if (mInScrollArea && !LauncherAppState.getInstance().isScreenLarge()) {
812360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung            Workspace workspace = mLauncher.getWorkspace();
81361a9a5c359e3e14cb1beaf43dbdb54e00911fe80Adam Cohen            int width = getMeasuredWidth();
814360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung            Rect childRect = new Rect();
815360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung            getDescendantRectRelativeToSelf(workspace.getChildAt(0), childRect);
816360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung
817360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung            int page = workspace.getNextPage();
818fe1fe268b6d9ffd99218117795b3524a87e5110bWinson Chung            final boolean isRtl = isLayoutRtl();
819fe1fe268b6d9ffd99218117795b3524a87e5110bWinson Chung            CellLayout leftPage = (CellLayout) workspace.getChildAt(isRtl ? page + 1 : page - 1);
820fe1fe268b6d9ffd99218117795b3524a87e5110bWinson Chung            CellLayout rightPage = (CellLayout) workspace.getChildAt(isRtl ? page - 1 : page + 1);
821360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung
822360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung            if (leftPage != null && leftPage.getIsDragOverlapping()) {
823360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung                mLeftHoverDrawable.setBounds(0, childRect.top,
824360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung                        mLeftHoverDrawable.getIntrinsicWidth(), childRect.bottom);
825360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung                mLeftHoverDrawable.draw(canvas);
826360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung            } else if (rightPage != null && rightPage.getIsDragOverlapping()) {
827360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung                mRightHoverDrawable.setBounds(width - mRightHoverDrawable.getIntrinsicWidth(),
828360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung                        childRect.top, width, childRect.bottom);
829360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung                mRightHoverDrawable.draw(canvas);
830360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung            }
831360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung        }
832360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung    }
833b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen
834b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen    public void setTouchCompleteListener(TouchCompleteListener listener) {
835b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen        mTouchCompleteListener = listener;
836b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen    }
837b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen
838b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen    public interface TouchCompleteListener {
839b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen        public void onTouchComplete();
840b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen    }
84131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project}
842