DragLayer.java revision 2d783ce2f4b2e507bead0d723f0edcdf902dbd46
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;
276788269814a678af976dfc7d6135993e172ce586Adam Cohenimport android.graphics.Rect;
28360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chungimport android.graphics.drawable.Drawable;
2931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.util.AttributeSet;
3026279c6d0917015eb4e6de0743b79edeea25f9bcDave Hawkeyimport android.view.KeyEvent;
3126279c6d0917015eb4e6de0743b79edeea25f9bcDave Hawkeyimport android.view.MotionEvent;
3226279c6d0917015eb4e6de0743b79edeea25f9bcDave Hawkeyimport android.view.View;
3326279c6d0917015eb4e6de0743b79edeea25f9bcDave Hawkeyimport android.view.ViewGroup;
343371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohenimport android.view.accessibility.AccessibilityEvent;
353371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohenimport android.view.accessibility.AccessibilityManager;
36716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohenimport android.view.animation.DecelerateInterpolator;
373e8f811f31a2275e778244427271f77f4116c08bAdam Cohenimport android.view.animation.Interpolator;
3831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.widget.FrameLayout;
39ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohenimport android.widget.TextView;
4031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
411d9af7d1e75bad13bb10ad37f5900ed59882622eAdam Cohenimport java.util.ArrayList;
426788269814a678af976dfc7d6135993e172ce586Adam Cohen
4331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project/**
440e26059548e429e5d1c973bebe4c561bead2926fMichael Jurka * A ViewGroup that coordinates dragging across its descendants
4531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project */
468b805b17158886035b38261eb611d8641701ae43Michael Jurkapublic class DragLayer extends FrameLayout implements ViewGroup.OnHierarchyChangeListener {
47120980bd00f5eecec5717f49a3d7db96571025a9Adam Cohen    private DragController mDragController;
48120980bd00f5eecec5717f49a3d7db96571025a9Adam Cohen    private int[] mTmpXY = new int[2];
4931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
50716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen    private int mXDown, mYDown;
51716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen    private Launcher mLauncher;
52716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen
536788269814a678af976dfc7d6135993e172ce586Adam Cohen    // Variables relating to resizing widgets
546788269814a678af976dfc7d6135993e172ce586Adam Cohen    private final ArrayList<AppWidgetResizeFrame> mResizeFrames =
556788269814a678af976dfc7d6135993e172ce586Adam Cohen            new ArrayList<AppWidgetResizeFrame>();
566788269814a678af976dfc7d6135993e172ce586Adam Cohen    private AppWidgetResizeFrame mCurrentResizeFrame;
57716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen
58716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen    // Variables relating to animation of views after drop
59716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen    private ValueAnimator mDropAnim = null;
608dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen    private ValueAnimator mFadeOutAnim = null;
618dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen    private TimeInterpolator mCubicEaseOutInterpolator = new DecelerateInterpolator(1.5f);
627bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung    private DragView mDropView = null;
636441de0ec2a71862798dd51180d0811b42edd514Adam Cohen    private int mAnchorViewInitialScrollX = 0;
646441de0ec2a71862798dd51180d0811b42edd514Adam Cohen    private View mAnchorView = null;
658dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen
663371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen    private boolean mHoverPointClosesFolder = false;
673371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen    private Rect mHitRect = new Rect();
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
76432609a246819f3cf887a80c2ae56b61fc5ca25aAdam Cohen    private View mOverlayView;
77432609a246819f3cf887a80c2ae56b61fc5ca25aAdam Cohen    private int mTopViewIndex;
782d783ce2f4b2e507bead0d723f0edcdf902dbd46Adam Cohen    private int mChildCountOnLastUpdate = -1;
7955bd9725d5c0373b89f7b9bbd9547550ea3bbc63Jorim Jaggi
8031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    /**
8131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * Used to create a new DragLayer from XML.
8231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     *
8331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param context The application's context.
840e26059548e429e5d1c973bebe4c561bead2926fMichael Jurka     * @param attrs The attributes set containing the Workspace's customization values.
8531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     */
8631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    public DragLayer(Context context, AttributeSet attrs) {
8731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        super(context, attrs);
88be62afa34d58edab0fc9ba7499f0dd543039c903Winson Chung
89be62afa34d58edab0fc9ba7499f0dd543039c903Winson Chung        // Disable multitouch across the workspace/all apps/customize tray
90be62afa34d58edab0fc9ba7499f0dd543039c903Winson Chung        setMotionEventSplittingEnabled(false);
9121b411074e39fd10cbc8dd0220bb159da4af2c76Adam Cohen        setChildrenDrawingOrderEnabled(true);
928b805b17158886035b38261eb611d8641701ae43Michael Jurka        setOnHierarchyChangeListener(this);
93360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung
94360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung        mLeftHoverDrawable = getResources().getDrawable(R.drawable.page_hover_left_holo);
95360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung        mRightHoverDrawable = getResources().getDrawable(R.drawable.page_hover_right_holo);
9631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
9731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
984c98d9235d164680186180974719f551cf935d08Winson Chung    public void setup(Launcher launcher, DragController controller) {
994c98d9235d164680186180974719f551cf935d08Winson Chung        mLauncher = launcher;
10000acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato        mDragController = controller;
10131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
10276fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen
10331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    @Override
10431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    public boolean dispatchKeyEvent(KeyEvent event) {
10500acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato        return mDragController.dispatchKeyEvent(event) || super.dispatchKeyEvent(event);
10631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
10731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
10877e1f47520958edd7ec04e203db65b932537bd1cJohn Spurlock    @Override
10977e1f47520958edd7ec04e203db65b932537bd1cJohn Spurlock    protected boolean fitSystemWindows(Rect insets) {
11077e1f47520958edd7ec04e203db65b932537bd1cJohn Spurlock        final int n = getChildCount();
11177e1f47520958edd7ec04e203db65b932537bd1cJohn Spurlock        for (int i = 0; i < n; i++) {
11277e1f47520958edd7ec04e203db65b932537bd1cJohn Spurlock            final View child = getChildAt(i);
11326279c6d0917015eb4e6de0743b79edeea25f9bcDave Hawkey            setInsets(child, insets, mInsets);
11477e1f47520958edd7ec04e203db65b932537bd1cJohn Spurlock        }
11577e1f47520958edd7ec04e203db65b932537bd1cJohn Spurlock        mInsets.set(insets);
11677e1f47520958edd7ec04e203db65b932537bd1cJohn Spurlock        return true; // I'll take it from here
11777e1f47520958edd7ec04e203db65b932537bd1cJohn Spurlock    }
11877e1f47520958edd7ec04e203db65b932537bd1cJohn Spurlock
11926279c6d0917015eb4e6de0743b79edeea25f9bcDave Hawkey    @Override
12026279c6d0917015eb4e6de0743b79edeea25f9bcDave Hawkey    public void addView(View child, int index, android.view.ViewGroup.LayoutParams params) {
12126279c6d0917015eb4e6de0743b79edeea25f9bcDave Hawkey        super.addView(child, index, params);
12226279c6d0917015eb4e6de0743b79edeea25f9bcDave Hawkey        setInsets(child, mInsets, new Rect());
12326279c6d0917015eb4e6de0743b79edeea25f9bcDave Hawkey    }
12426279c6d0917015eb4e6de0743b79edeea25f9bcDave Hawkey
125432609a246819f3cf887a80c2ae56b61fc5ca25aAdam Cohen    public void showOverlayView(View introScreen) {
126432609a246819f3cf887a80c2ae56b61fc5ca25aAdam Cohen        LayoutParams lp = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
127432609a246819f3cf887a80c2ae56b61fc5ca25aAdam Cohen        mOverlayView = introScreen;
128432609a246819f3cf887a80c2ae56b61fc5ca25aAdam Cohen        addView(introScreen, lp);
129432609a246819f3cf887a80c2ae56b61fc5ca25aAdam Cohen    }
130432609a246819f3cf887a80c2ae56b61fc5ca25aAdam Cohen
131432609a246819f3cf887a80c2ae56b61fc5ca25aAdam Cohen    public void dismissOverlayView() {
132432609a246819f3cf887a80c2ae56b61fc5ca25aAdam Cohen        removeView(mOverlayView);
133432609a246819f3cf887a80c2ae56b61fc5ca25aAdam Cohen    }
134432609a246819f3cf887a80c2ae56b61fc5ca25aAdam Cohen
13526279c6d0917015eb4e6de0743b79edeea25f9bcDave Hawkey    private void setInsets(View child, Rect newInsets, Rect oldInsets) {
13626279c6d0917015eb4e6de0743b79edeea25f9bcDave Hawkey        final FrameLayout.LayoutParams flp = (FrameLayout.LayoutParams) child.getLayoutParams();
13726279c6d0917015eb4e6de0743b79edeea25f9bcDave Hawkey        if (child instanceof Insettable) {
13826279c6d0917015eb4e6de0743b79edeea25f9bcDave Hawkey            ((Insettable) child).setInsets(newInsets);
13926279c6d0917015eb4e6de0743b79edeea25f9bcDave Hawkey        } else {
14026279c6d0917015eb4e6de0743b79edeea25f9bcDave Hawkey            flp.topMargin += (newInsets.top - oldInsets.top);
14126279c6d0917015eb4e6de0743b79edeea25f9bcDave Hawkey            flp.leftMargin += (newInsets.left - oldInsets.left);
14226279c6d0917015eb4e6de0743b79edeea25f9bcDave Hawkey            flp.rightMargin += (newInsets.right - oldInsets.right);
14326279c6d0917015eb4e6de0743b79edeea25f9bcDave Hawkey            flp.bottomMargin += (newInsets.bottom - oldInsets.bottom);
14426279c6d0917015eb4e6de0743b79edeea25f9bcDave Hawkey        }
14526279c6d0917015eb4e6de0743b79edeea25f9bcDave Hawkey        child.setLayoutParams(flp);
14626279c6d0917015eb4e6de0743b79edeea25f9bcDave Hawkey    }
14726279c6d0917015eb4e6de0743b79edeea25f9bcDave Hawkey
1483371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen    private boolean isEventOverFolderTextRegion(Folder folder, MotionEvent ev) {
1493371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen        getDescendantRectRelativeToSelf(folder.getEditTextRegion(), mHitRect);
1503371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen        if (mHitRect.contains((int) ev.getX(), (int) ev.getY())) {
1513371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen            return true;
1523371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen        }
1533371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen        return false;
1543371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen    }
1553371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen
1563371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen    private boolean isEventOverFolder(Folder folder, MotionEvent ev) {
1573371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen        getDescendantRectRelativeToSelf(folder, mHitRect);
1583371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen        if (mHitRect.contains((int) ev.getX(), (int) ev.getY())) {
1593371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen            return true;
1603371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen        }
1613371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen        return false;
1623371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen    }
1633371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen
16476fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen    private boolean handleTouchDown(MotionEvent ev, boolean intercept) {
1656788269814a678af976dfc7d6135993e172ce586Adam Cohen        Rect hitRect = new Rect();
1666788269814a678af976dfc7d6135993e172ce586Adam Cohen        int x = (int) ev.getX();
1676788269814a678af976dfc7d6135993e172ce586Adam Cohen        int y = (int) ev.getY();
1686788269814a678af976dfc7d6135993e172ce586Adam Cohen
1696788269814a678af976dfc7d6135993e172ce586Adam Cohen        for (AppWidgetResizeFrame child: mResizeFrames) {
1706788269814a678af976dfc7d6135993e172ce586Adam Cohen            child.getHitRect(hitRect);
1716788269814a678af976dfc7d6135993e172ce586Adam Cohen            if (hitRect.contains(x, y)) {
1726788269814a678af976dfc7d6135993e172ce586Adam Cohen                if (child.beginResizeIfPointInRegion(x - child.getLeft(), y - child.getTop())) {
1736788269814a678af976dfc7d6135993e172ce586Adam Cohen                    mCurrentResizeFrame = child;
1746788269814a678af976dfc7d6135993e172ce586Adam Cohen                    mXDown = x;
1756788269814a678af976dfc7d6135993e172ce586Adam Cohen                    mYDown = y;
1766788269814a678af976dfc7d6135993e172ce586Adam Cohen                    requestDisallowInterceptTouchEvent(true);
1776788269814a678af976dfc7d6135993e172ce586Adam Cohen                    return true;
1786788269814a678af976dfc7d6135993e172ce586Adam Cohen                }
1796788269814a678af976dfc7d6135993e172ce586Adam Cohen            }
1806788269814a678af976dfc7d6135993e172ce586Adam Cohen        }
18176fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen
1821d9af7d1e75bad13bb10ad37f5900ed59882622eAdam Cohen        Folder currentFolder = mLauncher.getWorkspace().getOpenFolder();
183a694524047fda0a51dede4eefb1201a598d2d3a7Winson Chung        if (currentFolder != null && !mLauncher.getLauncherClings().isFolderClingVisible() &&
184a694524047fda0a51dede4eefb1201a598d2d3a7Winson Chung                intercept) {
1851d9af7d1e75bad13bb10ad37f5900ed59882622eAdam Cohen            if (currentFolder.isEditingName()) {
1863371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                if (!isEventOverFolderTextRegion(currentFolder, ev)) {
1871d9af7d1e75bad13bb10ad37f5900ed59882622eAdam Cohen                    currentFolder.dismissEditingName();
18876fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen                    return true;
1892801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen                }
1902801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen            }
19176fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen
1921d9af7d1e75bad13bb10ad37f5900ed59882622eAdam Cohen            getDescendantRectRelativeToSelf(currentFolder, hitRect);
1933371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen            if (!isEventOverFolder(currentFolder, ev)) {
19476fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen                mLauncher.closeFolder();
19576fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen                return true;
19676fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen            }
1972801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen        }
1986788269814a678af976dfc7d6135993e172ce586Adam Cohen        return false;
1996788269814a678af976dfc7d6135993e172ce586Adam Cohen    }
2006788269814a678af976dfc7d6135993e172ce586Adam Cohen
20131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    @Override
20231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    public boolean onInterceptTouchEvent(MotionEvent ev) {
203b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen        int action = ev.getAction();
204b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen
205b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen        if (action == MotionEvent.ACTION_DOWN) {
20676fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen            if (handleTouchDown(ev, true)) {
2076788269814a678af976dfc7d6135993e172ce586Adam Cohen                return true;
208d1837cc69eb222371afdd30890f7215d117510f2Patrick Dubroy            }
209b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen        } else if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) {
210b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen            if (mTouchCompleteListener != null) {
211b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen                mTouchCompleteListener.onTouchComplete();
212b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen            }
213b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen            mTouchCompleteListener = null;
2141b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen        }
2156788269814a678af976dfc7d6135993e172ce586Adam Cohen        clearAllResizeFrames();
2164db52312c10e822162a21c60404f06f6e507f0d6Joe Onorato        return mDragController.onInterceptTouchEvent(ev);
21731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
21831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
21931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    @Override
2203371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen    public boolean onInterceptHoverEvent(MotionEvent ev) {
221023c71eb3b2bbe63272cb74baaf050c4188c89b0Michael Jurka        if (mLauncher == null || mLauncher.getWorkspace() == null) {
222023c71eb3b2bbe63272cb74baaf050c4188c89b0Michael Jurka            return false;
223023c71eb3b2bbe63272cb74baaf050c4188c89b0Michael Jurka        }
2243371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen        Folder currentFolder = mLauncher.getWorkspace().getOpenFolder();
2253371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen        if (currentFolder == null) {
2263371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen            return false;
2273371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen        } else {
2288b805b17158886035b38261eb611d8641701ae43Michael Jurka                AccessibilityManager accessibilityManager = (AccessibilityManager)
2298b805b17158886035b38261eb611d8641701ae43Michael Jurka                        getContext().getSystemService(Context.ACCESSIBILITY_SERVICE);
2308b805b17158886035b38261eb611d8641701ae43Michael Jurka            if (accessibilityManager.isTouchExplorationEnabled()) {
2313371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                final int action = ev.getAction();
2323371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                boolean isOverFolder;
2333371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                switch (action) {
2343371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                    case MotionEvent.ACTION_HOVER_ENTER:
2353371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                        isOverFolder = isEventOverFolder(currentFolder, ev);
2363371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                        if (!isOverFolder) {
2373371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                            sendTapOutsideFolderAccessibilityEvent(currentFolder.isEditingName());
2383371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                            mHoverPointClosesFolder = true;
2393371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                            return true;
2403371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                        }
241693fbc7f1737d89f11f9ab81558c109f0883ab0eMihail Dumitrescu                        mHoverPointClosesFolder = false;
242693fbc7f1737d89f11f9ab81558c109f0883ab0eMihail Dumitrescu                        break;
2433371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                    case MotionEvent.ACTION_HOVER_MOVE:
2443371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                        isOverFolder = isEventOverFolder(currentFolder, ev);
2453371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                        if (!isOverFolder && !mHoverPointClosesFolder) {
2463371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                            sendTapOutsideFolderAccessibilityEvent(currentFolder.isEditingName());
2473371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                            mHoverPointClosesFolder = true;
2483371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                            return true;
249693fbc7f1737d89f11f9ab81558c109f0883ab0eMihail Dumitrescu                        } else if (!isOverFolder) {
2503371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                            return true;
2513371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                        }
252693fbc7f1737d89f11f9ab81558c109f0883ab0eMihail Dumitrescu                        mHoverPointClosesFolder = false;
2533371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                }
2543371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen            }
2553371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen        }
2563371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen        return false;
2573371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen    }
2583371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen
2593371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen    private void sendTapOutsideFolderAccessibilityEvent(boolean isEditingName) {
2608b805b17158886035b38261eb611d8641701ae43Michael Jurka        AccessibilityManager accessibilityManager = (AccessibilityManager)
2618b805b17158886035b38261eb611d8641701ae43Michael Jurka                getContext().getSystemService(Context.ACCESSIBILITY_SERVICE);
2628b805b17158886035b38261eb611d8641701ae43Michael Jurka        if (accessibilityManager.isEnabled()) {
2633371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen            int stringId = isEditingName ? R.string.folder_tap_to_rename : R.string.folder_tap_to_close;
2643371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen            AccessibilityEvent event = AccessibilityEvent.obtain(
2653371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                    AccessibilityEvent.TYPE_VIEW_FOCUSED);
2663371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen            onInitializeAccessibilityEvent(event);
2678b805b17158886035b38261eb611d8641701ae43Michael Jurka            event.getText().add(getContext().getString(stringId));
2688b805b17158886035b38261eb611d8641701ae43Michael Jurka            accessibilityManager.sendAccessibilityEvent(event);
2693371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen        }
27083ca480941b3dd635b62347008fc8d7859d82002Winson Chung    }
27183ca480941b3dd635b62347008fc8d7859d82002Winson Chung
27283ca480941b3dd635b62347008fc8d7859d82002Winson Chung    @Override
27383ca480941b3dd635b62347008fc8d7859d82002Winson Chung    public boolean onRequestSendAccessibilityEvent(View child, AccessibilityEvent event) {
27483ca480941b3dd635b62347008fc8d7859d82002Winson Chung        Folder currentFolder = mLauncher.getWorkspace().getOpenFolder();
27583ca480941b3dd635b62347008fc8d7859d82002Winson Chung        if (currentFolder != null) {
27683ca480941b3dd635b62347008fc8d7859d82002Winson Chung            if (child == currentFolder) {
27783ca480941b3dd635b62347008fc8d7859d82002Winson Chung                return super.onRequestSendAccessibilityEvent(child, event);
27883ca480941b3dd635b62347008fc8d7859d82002Winson Chung            }
27983ca480941b3dd635b62347008fc8d7859d82002Winson Chung            // Skip propagating onRequestSendAccessibilityEvent all for other children
28083ca480941b3dd635b62347008fc8d7859d82002Winson Chung            // when a folder is open
28183ca480941b3dd635b62347008fc8d7859d82002Winson Chung            return false;
28283ca480941b3dd635b62347008fc8d7859d82002Winson Chung        }
28383ca480941b3dd635b62347008fc8d7859d82002Winson Chung        return super.onRequestSendAccessibilityEvent(child, event);
28483ca480941b3dd635b62347008fc8d7859d82002Winson Chung    }
28583ca480941b3dd635b62347008fc8d7859d82002Winson Chung
28683ca480941b3dd635b62347008fc8d7859d82002Winson Chung    @Override
28783ca480941b3dd635b62347008fc8d7859d82002Winson Chung    public void addChildrenForAccessibility(ArrayList<View> childrenForAccessibility) {
28883ca480941b3dd635b62347008fc8d7859d82002Winson Chung        Folder currentFolder = mLauncher.getWorkspace().getOpenFolder();
28983ca480941b3dd635b62347008fc8d7859d82002Winson Chung        if (currentFolder != null) {
29083ca480941b3dd635b62347008fc8d7859d82002Winson Chung            // Only add the folder as a child for accessibility when it is open
29183ca480941b3dd635b62347008fc8d7859d82002Winson Chung            childrenForAccessibility.add(currentFolder);
29283ca480941b3dd635b62347008fc8d7859d82002Winson Chung        } else {
29383ca480941b3dd635b62347008fc8d7859d82002Winson Chung            super.addChildrenForAccessibility(childrenForAccessibility);
29483ca480941b3dd635b62347008fc8d7859d82002Winson Chung        }
2953371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen    }
2963371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen
2973371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen    @Override
2983371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen    public boolean onHoverEvent(MotionEvent ev) {
2993371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen        // If we've received this, we've already done the necessary handling
3003371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen        // in onInterceptHoverEvent. Return true to consume the event.
3013371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen        return false;
3023371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen    }
3033371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen
3043371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen    @Override
30531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    public boolean onTouchEvent(MotionEvent ev) {
3066788269814a678af976dfc7d6135993e172ce586Adam Cohen        boolean handled = false;
3076788269814a678af976dfc7d6135993e172ce586Adam Cohen        int action = ev.getAction();
3086788269814a678af976dfc7d6135993e172ce586Adam Cohen
3096788269814a678af976dfc7d6135993e172ce586Adam Cohen        int x = (int) ev.getX();
3106788269814a678af976dfc7d6135993e172ce586Adam Cohen        int y = (int) ev.getY();
3116788269814a678af976dfc7d6135993e172ce586Adam Cohen
312b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen        if (action == MotionEvent.ACTION_DOWN) {
313b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen            if (handleTouchDown(ev, false)) {
314b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen                return true;
315b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen            }
316b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen        } else if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) {
317b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen            if (mTouchCompleteListener != null) {
318b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen                mTouchCompleteListener.onTouchComplete();
3196788269814a678af976dfc7d6135993e172ce586Adam Cohen            }
320b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen            mTouchCompleteListener = null;
3216788269814a678af976dfc7d6135993e172ce586Adam Cohen        }
3226788269814a678af976dfc7d6135993e172ce586Adam Cohen
3236788269814a678af976dfc7d6135993e172ce586Adam Cohen        if (mCurrentResizeFrame != null) {
3246788269814a678af976dfc7d6135993e172ce586Adam Cohen            handled = true;
3256788269814a678af976dfc7d6135993e172ce586Adam Cohen            switch (action) {
3266788269814a678af976dfc7d6135993e172ce586Adam Cohen                case MotionEvent.ACTION_MOVE:
3276788269814a678af976dfc7d6135993e172ce586Adam Cohen                    mCurrentResizeFrame.visualizeResizeForDelta(x - mXDown, y - mYDown);
3286788269814a678af976dfc7d6135993e172ce586Adam Cohen                    break;
3296788269814a678af976dfc7d6135993e172ce586Adam Cohen                case MotionEvent.ACTION_CANCEL:
3306788269814a678af976dfc7d6135993e172ce586Adam Cohen                case MotionEvent.ACTION_UP:
331bebf042666cffe52039b875a549a582abd78a431Adam Cohen                    mCurrentResizeFrame.visualizeResizeForDelta(x - mXDown, y - mYDown);
332bebf042666cffe52039b875a549a582abd78a431Adam Cohen                    mCurrentResizeFrame.onTouchUp();
3336788269814a678af976dfc7d6135993e172ce586Adam Cohen                    mCurrentResizeFrame = null;
3346788269814a678af976dfc7d6135993e172ce586Adam Cohen            }
3356788269814a678af976dfc7d6135993e172ce586Adam Cohen        }
3366788269814a678af976dfc7d6135993e172ce586Adam Cohen        if (handled) return true;
3374db52312c10e822162a21c60404f06f6e507f0d6Joe Onorato        return mDragController.onTouchEvent(ev);
33891a9c9636f10f1e12cd1f660b2e330634fbdc7dcRomain Guy    }
339ea3763c2672f77539538af8cdd395ad97058eaabRomain Guy
34035e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen    /**
34135e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen     * Determine the rect of the descendant in this DragLayer's coordinates
34235e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen     *
34335e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen     * @param descendant The descendant whose coordinates we want to find.
34435e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen     * @param r The rect into which to place the results.
34535e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen     * @return The factor by which this descendant is scaled relative to this DragLayer.
34635e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen     */
347ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen    public float getDescendantRectRelativeToSelf(View descendant, Rect r) {
348716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen        mTmpXY[0] = 0;
349716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen        mTmpXY[1] = 0;
350ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen        float scale = getDescendantCoordRelativeToSelf(descendant, mTmpXY);
3517d30a37007bac318db1c9af47a9af12d348042a5Adam Cohen
3528dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        r.set(mTmpXY[0], mTmpXY[1],
3537d30a37007bac318db1c9af47a9af12d348042a5Adam Cohen                (int) (mTmpXY[0] + scale * descendant.getMeasuredWidth()),
3547d30a37007bac318db1c9af47a9af12d348042a5Adam Cohen                (int) (mTmpXY[1] + scale * descendant.getMeasuredHeight()));
355ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen        return scale;
356716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen    }
35776fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen
358307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen    public float getLocationInDragLayer(View child, int[] loc) {
35935e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen        loc[0] = 0;
36035e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen        loc[1] = 0;
361307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen        return getDescendantCoordRelativeToSelf(child, loc);
36235e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen    }
36335e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen
3647d30a37007bac318db1c9af47a9af12d348042a5Adam Cohen    public float getDescendantCoordRelativeToSelf(View descendant, int[] coord) {
3657d30a37007bac318db1c9af47a9af12d348042a5Adam Cohen        return getDescendantCoordRelativeToSelf(descendant, coord, false);
3667d30a37007bac318db1c9af47a9af12d348042a5Adam Cohen    }
3677d30a37007bac318db1c9af47a9af12d348042a5Adam Cohen
36835e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen    /**
36935e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen     * Given a coordinate relative to the descendant, find the coordinate in this DragLayer's
37035e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen     * coordinates.
37135e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen     *
37235e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen     * @param descendant The descendant to which the passed coordinate is relative.
37335e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen     * @param coord The coordinate that we want mapped.
3747d30a37007bac318db1c9af47a9af12d348042a5Adam Cohen     * @param includeRootScroll Whether or not to account for the scroll of the root descendant:
3757d30a37007bac318db1c9af47a9af12d348042a5Adam Cohen     *          sometimes this is relevant as in a child's coordinates within the root descendant.
376307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen     * @return The factor by which this descendant is scaled relative to this DragLayer. Caution
377307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen     *         this scale factor is assumed to be equal in X and Y, and so if at any point this
378307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen     *         assumption fails, we will need to return a pair of scale factors.
37935e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen     */
3807d30a37007bac318db1c9af47a9af12d348042a5Adam Cohen    public float getDescendantCoordRelativeToSelf(View descendant, int[] coord,
3817d30a37007bac318db1c9af47a9af12d348042a5Adam Cohen            boolean includeRootScroll) {
382c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung        return Utilities.getDescendantCoordRelativeToParent(descendant, this,
383c9ca2980983ab21fc8631c7a65399d6d9c70f39cWinson Chung                coord, includeRootScroll);
384c9ca2980983ab21fc8631c7a65399d6d9c70f39cWinson Chung    }
385c9ca2980983ab21fc8631c7a65399d6d9c70f39cWinson Chung
3867d30a37007bac318db1c9af47a9af12d348042a5Adam Cohen    /**
3877d30a37007bac318db1c9af47a9af12d348042a5Adam Cohen     * Inverse of {@link #getDescendantCoordRelativeToSelf(View, int[])}.
3887d30a37007bac318db1c9af47a9af12d348042a5Adam Cohen     */
3897d30a37007bac318db1c9af47a9af12d348042a5Adam Cohen    public float mapCoordInSelfToDescendent(View descendant, int[] coord) {
390c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung        return Utilities.mapCoordInSelfToDescendent(descendant, this, coord);
39176fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen    }
39276fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen
3933e8f811f31a2275e778244427271f77f4116c08bAdam Cohen    public void getViewRectRelativeToSelf(View v, Rect r) {
3943e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        int[] loc = new int[2];
3958dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        getLocationInWindow(loc);
3963e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        int x = loc[0];
3973e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        int y = loc[1];
398716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen
3998dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        v.getLocationInWindow(loc);
4003e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        int vX = loc[0];
4013e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        int vY = loc[1];
402716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen
4033e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        int left = vX - x;
4043e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        int top = vY - y;
4053e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        r.set(left, top, left + v.getMeasuredWidth(), top + v.getMeasuredHeight());
406716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen    }
407716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen
408ea3763c2672f77539538af8cdd395ad97058eaabRomain Guy    @Override
409ea3763c2672f77539538af8cdd395ad97058eaabRomain Guy    public boolean dispatchUnhandledMove(View focused, int direction) {
410ea3763c2672f77539538af8cdd395ad97058eaabRomain Guy        return mDragController.dispatchUnhandledMove(focused, direction);
411ea3763c2672f77539538af8cdd395ad97058eaabRomain Guy    }
412120980bd00f5eecec5717f49a3d7db96571025a9Adam Cohen
4136788269814a678af976dfc7d6135993e172ce586Adam Cohen    public static class LayoutParams extends FrameLayout.LayoutParams {
4146788269814a678af976dfc7d6135993e172ce586Adam Cohen        public int x, y;
4156788269814a678af976dfc7d6135993e172ce586Adam Cohen        public boolean customPosition = false;
4166788269814a678af976dfc7d6135993e172ce586Adam Cohen
4176788269814a678af976dfc7d6135993e172ce586Adam Cohen        /**
4186788269814a678af976dfc7d6135993e172ce586Adam Cohen         * {@inheritDoc}
4196788269814a678af976dfc7d6135993e172ce586Adam Cohen         */
4206788269814a678af976dfc7d6135993e172ce586Adam Cohen        public LayoutParams(int width, int height) {
4216788269814a678af976dfc7d6135993e172ce586Adam Cohen            super(width, height);
4226788269814a678af976dfc7d6135993e172ce586Adam Cohen        }
4236788269814a678af976dfc7d6135993e172ce586Adam Cohen
4246788269814a678af976dfc7d6135993e172ce586Adam Cohen        public void setWidth(int width) {
4256788269814a678af976dfc7d6135993e172ce586Adam Cohen            this.width = width;
4266788269814a678af976dfc7d6135993e172ce586Adam Cohen        }
4276788269814a678af976dfc7d6135993e172ce586Adam Cohen
4286788269814a678af976dfc7d6135993e172ce586Adam Cohen        public int getWidth() {
4296788269814a678af976dfc7d6135993e172ce586Adam Cohen            return width;
4306788269814a678af976dfc7d6135993e172ce586Adam Cohen        }
4316788269814a678af976dfc7d6135993e172ce586Adam Cohen
4326788269814a678af976dfc7d6135993e172ce586Adam Cohen        public void setHeight(int height) {
4336788269814a678af976dfc7d6135993e172ce586Adam Cohen            this.height = height;
4346788269814a678af976dfc7d6135993e172ce586Adam Cohen        }
4356788269814a678af976dfc7d6135993e172ce586Adam Cohen
4366788269814a678af976dfc7d6135993e172ce586Adam Cohen        public int getHeight() {
4376788269814a678af976dfc7d6135993e172ce586Adam Cohen            return height;
4386788269814a678af976dfc7d6135993e172ce586Adam Cohen        }
4396788269814a678af976dfc7d6135993e172ce586Adam Cohen
4406788269814a678af976dfc7d6135993e172ce586Adam Cohen        public void setX(int x) {
4416788269814a678af976dfc7d6135993e172ce586Adam Cohen            this.x = x;
4426788269814a678af976dfc7d6135993e172ce586Adam Cohen        }
4436788269814a678af976dfc7d6135993e172ce586Adam Cohen
4446788269814a678af976dfc7d6135993e172ce586Adam Cohen        public int getX() {
4456788269814a678af976dfc7d6135993e172ce586Adam Cohen            return x;
4466788269814a678af976dfc7d6135993e172ce586Adam Cohen        }
4476788269814a678af976dfc7d6135993e172ce586Adam Cohen
4486788269814a678af976dfc7d6135993e172ce586Adam Cohen        public void setY(int y) {
4496788269814a678af976dfc7d6135993e172ce586Adam Cohen            this.y = y;
4506788269814a678af976dfc7d6135993e172ce586Adam Cohen        }
4516788269814a678af976dfc7d6135993e172ce586Adam Cohen
4526788269814a678af976dfc7d6135993e172ce586Adam Cohen        public int getY() {
4536788269814a678af976dfc7d6135993e172ce586Adam Cohen            return y;
4546788269814a678af976dfc7d6135993e172ce586Adam Cohen        }
4556788269814a678af976dfc7d6135993e172ce586Adam Cohen    }
4566788269814a678af976dfc7d6135993e172ce586Adam Cohen
4576788269814a678af976dfc7d6135993e172ce586Adam Cohen    protected void onLayout(boolean changed, int l, int t, int r, int b) {
4586788269814a678af976dfc7d6135993e172ce586Adam Cohen        super.onLayout(changed, l, t, r, b);
4596788269814a678af976dfc7d6135993e172ce586Adam Cohen        int count = getChildCount();
4606788269814a678af976dfc7d6135993e172ce586Adam Cohen        for (int i = 0; i < count; i++) {
4616788269814a678af976dfc7d6135993e172ce586Adam Cohen            View child = getChildAt(i);
4626788269814a678af976dfc7d6135993e172ce586Adam Cohen            final FrameLayout.LayoutParams flp = (FrameLayout.LayoutParams) child.getLayoutParams();
4636788269814a678af976dfc7d6135993e172ce586Adam Cohen            if (flp instanceof LayoutParams) {
4646788269814a678af976dfc7d6135993e172ce586Adam Cohen                final LayoutParams lp = (LayoutParams) flp;
4656788269814a678af976dfc7d6135993e172ce586Adam Cohen                if (lp.customPosition) {
4666788269814a678af976dfc7d6135993e172ce586Adam Cohen                    child.layout(lp.x, lp.y, lp.x + lp.width, lp.y + lp.height);
4676788269814a678af976dfc7d6135993e172ce586Adam Cohen                }
4686788269814a678af976dfc7d6135993e172ce586Adam Cohen            }
4696788269814a678af976dfc7d6135993e172ce586Adam Cohen        }
4706788269814a678af976dfc7d6135993e172ce586Adam Cohen    }
4716788269814a678af976dfc7d6135993e172ce586Adam Cohen
4726788269814a678af976dfc7d6135993e172ce586Adam Cohen    public void clearAllResizeFrames() {
4736788269814a678af976dfc7d6135993e172ce586Adam Cohen        if (mResizeFrames.size() > 0) {
4746788269814a678af976dfc7d6135993e172ce586Adam Cohen            for (AppWidgetResizeFrame frame: mResizeFrames) {
475bebf042666cffe52039b875a549a582abd78a431Adam Cohen                frame.commitResize();
4766788269814a678af976dfc7d6135993e172ce586Adam Cohen                removeView(frame);
4776788269814a678af976dfc7d6135993e172ce586Adam Cohen            }
4786788269814a678af976dfc7d6135993e172ce586Adam Cohen            mResizeFrames.clear();
4796788269814a678af976dfc7d6135993e172ce586Adam Cohen        }
4806788269814a678af976dfc7d6135993e172ce586Adam Cohen    }
4816788269814a678af976dfc7d6135993e172ce586Adam Cohen
4826788269814a678af976dfc7d6135993e172ce586Adam Cohen    public boolean hasResizeFrames() {
4836788269814a678af976dfc7d6135993e172ce586Adam Cohen        return mResizeFrames.size() > 0;
4846788269814a678af976dfc7d6135993e172ce586Adam Cohen    }
4856788269814a678af976dfc7d6135993e172ce586Adam Cohen
4866788269814a678af976dfc7d6135993e172ce586Adam Cohen    public boolean isWidgetBeingResized() {
4876788269814a678af976dfc7d6135993e172ce586Adam Cohen        return mCurrentResizeFrame != null;
4886788269814a678af976dfc7d6135993e172ce586Adam Cohen    }
4896788269814a678af976dfc7d6135993e172ce586Adam Cohen
4906788269814a678af976dfc7d6135993e172ce586Adam Cohen    public void addResizeFrame(ItemInfo itemInfo, LauncherAppWidgetHostView widget,
4916788269814a678af976dfc7d6135993e172ce586Adam Cohen            CellLayout cellLayout) {
4926788269814a678af976dfc7d6135993e172ce586Adam Cohen        AppWidgetResizeFrame resizeFrame = new AppWidgetResizeFrame(getContext(),
4933a9fcedbcd235372cd2ab64f825a0b5b3937f59eMichael Jurka                widget, cellLayout, this);
4946788269814a678af976dfc7d6135993e172ce586Adam Cohen
4956788269814a678af976dfc7d6135993e172ce586Adam Cohen        LayoutParams lp = new LayoutParams(-1, -1);
4966788269814a678af976dfc7d6135993e172ce586Adam Cohen        lp.customPosition = true;
4976788269814a678af976dfc7d6135993e172ce586Adam Cohen
4986788269814a678af976dfc7d6135993e172ce586Adam Cohen        addView(resizeFrame, lp);
4996788269814a678af976dfc7d6135993e172ce586Adam Cohen        mResizeFrames.add(resizeFrame);
5006788269814a678af976dfc7d6135993e172ce586Adam Cohen
5016788269814a678af976dfc7d6135993e172ce586Adam Cohen        resizeFrame.snapToWidget(false);
5026788269814a678af976dfc7d6135993e172ce586Adam Cohen    }
503716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen
504716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen    public void animateViewIntoPosition(DragView dragView, final View child) {
50528f852ab678d9750879b6d3549bf5da176cf1225Adam Cohen        animateViewIntoPosition(dragView, child, null, null);
506557d6ed50cc6560163440aa134870ef0bb11415bWinson Chung    }
507ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen
5087bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung    public void animateViewIntoPosition(DragView dragView, final int[] pos, float alpha,
5097bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung            float scaleX, float scaleY, int animationEndStyle, Runnable onFinishRunnable,
5107bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung            int duration) {
511b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen        Rect r = new Rect();
512b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen        getViewRectRelativeToSelf(dragView, r);
513b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen        final int fromX = r.left;
514b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen        final int fromY = r.top;
515b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen
5167bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung        animateViewIntoPosition(dragView, fromX, fromY, pos[0], pos[1], alpha, 1, 1, scaleX, scaleY,
517ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen                onFinishRunnable, animationEndStyle, duration, null);
518ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen    }
519ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen
520557d6ed50cc6560163440aa134870ef0bb11415bWinson Chung    public void animateViewIntoPosition(DragView dragView, final View child,
52128f852ab678d9750879b6d3549bf5da176cf1225Adam Cohen            final Runnable onFinishAnimationRunnable, View anchorView) {
52228f852ab678d9750879b6d3549bf5da176cf1225Adam Cohen        animateViewIntoPosition(dragView, child, -1, onFinishAnimationRunnable, anchorView);
523ed51cc9a12c50d12e7d30ed209a49f1a40858043Adam Cohen    }
524ed51cc9a12c50d12e7d30ed209a49f1a40858043Adam Cohen
525ed51cc9a12c50d12e7d30ed209a49f1a40858043Adam Cohen    public void animateViewIntoPosition(DragView dragView, final View child, int duration,
5266441de0ec2a71862798dd51180d0811b42edd514Adam Cohen            final Runnable onFinishAnimationRunnable, View anchorView) {
527a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        ShortcutAndWidgetContainer parentChildren = (ShortcutAndWidgetContainer) child.getParent();
528716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen        CellLayout.LayoutParams lp =  (CellLayout.LayoutParams) child.getLayoutParams();
529eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung        parentChildren.measureChild(child);
530716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen
5313e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        Rect r = new Rect();
5323e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        getViewRectRelativeToSelf(dragView, r);
533716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen
534716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen        int coord[] = new int[2];
535307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen        float childScale = child.getScaleX();
536307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen        coord[0] = lp.x + (int) (child.getMeasuredWidth() * (1 - childScale) / 2);
537307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen        coord[1] = lp.y + (int) (child.getMeasuredHeight() * (1 - childScale) / 2);
538eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung
5398dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        // Since the child hasn't necessarily been laid out, we force the lp to be updated with
540ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen        // the correct coordinates (above) and use these to determine the final location
541557d6ed50cc6560163440aa134870ef0bb11415bWinson Chung        float scale = getDescendantCoordRelativeToSelf((View) child.getParent(), coord);
542307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen        // We need to account for the scale of the child itself, as the above only accounts for
543307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen        // for the scale in parents.
544307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen        scale *= childScale;
545ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen        int toX = coord[0];
546ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen        int toY = coord[1];
547eeb5bbc9409978cc2ae52d48380399fcde3d9f85Winson Chung        float toScale = scale;
5484497ebf9a2726e2a7dbb7f3c49389308908f8454Andrew Flynn        if (child instanceof TextView) {
5494497ebf9a2726e2a7dbb7f3c49389308908f8454Andrew Flynn            TextView tv = (TextView) child;
550eeb5bbc9409978cc2ae52d48380399fcde3d9f85Winson Chung            // Account for the source scale of the icon (ie. from AllApps to Workspace, in which
551eeb5bbc9409978cc2ae52d48380399fcde3d9f85Winson Chung            // the workspace may have smaller icon bounds).
552eeb5bbc9409978cc2ae52d48380399fcde3d9f85Winson Chung            toScale = scale / dragView.getIntrinsicIconScaleFactor();
5534497ebf9a2726e2a7dbb7f3c49389308908f8454Andrew Flynn
5544497ebf9a2726e2a7dbb7f3c49389308908f8454Andrew Flynn            // The child may be scaled (always about the center of the view) so to account for it,
5554497ebf9a2726e2a7dbb7f3c49389308908f8454Andrew Flynn            // we have to offset the position by the scaled size.  Once we do that, we can center
5564497ebf9a2726e2a7dbb7f3c49389308908f8454Andrew Flynn            // the drag view about the scaled child view.
557eeb5bbc9409978cc2ae52d48380399fcde3d9f85Winson Chung            toY += Math.round(toScale * tv.getPaddingTop());
558eeb5bbc9409978cc2ae52d48380399fcde3d9f85Winson Chung            toY -= dragView.getMeasuredHeight() * (1 - toScale) / 2;
5594497ebf9a2726e2a7dbb7f3c49389308908f8454Andrew Flynn            toX -= (dragView.getMeasuredWidth() - Math.round(scale * child.getMeasuredWidth())) / 2;
5604497ebf9a2726e2a7dbb7f3c49389308908f8454Andrew Flynn        } else if (child instanceof FolderIcon) {
561ea359c6aee44c0fe3bb94f7002c3b49208b32b7fWinson Chung            // Account for holographic blur padding on the drag view
5625f8afe6280eae34620067696173e71943e1a30a3Winson Chung            toY += Math.round(scale * (child.getPaddingTop() - dragView.getDragRegionTop()));
563307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen            toY -= scale * Workspace.DRAG_BITMAP_PADDING / 2;
564307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen            toY -= (1 - scale) * dragView.getMeasuredHeight() / 2;
565ea359c6aee44c0fe3bb94f7002c3b49208b32b7fWinson Chung            // Center in the x coordinate about the target's drawable
566ea359c6aee44c0fe3bb94f7002c3b49208b32b7fWinson Chung            toX -= (dragView.getMeasuredWidth() - Math.round(scale * child.getMeasuredWidth())) / 2;
567ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen        } else {
568ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen            toY -= (Math.round(scale * (dragView.getHeight() - child.getMeasuredHeight()))) / 2;
569ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen            toX -= (Math.round(scale * (dragView.getMeasuredWidth()
570ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen                    - child.getMeasuredWidth()))) / 2;
571ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen        }
572716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen
573ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen        final int fromX = r.left;
574ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen        final int fromY = r.top;
575716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen        child.setVisibility(INVISIBLE);
5768dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        Runnable onCompleteRunnable = new Runnable() {
5778dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen            public void run() {
5788dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen                child.setVisibility(VISIBLE);
579d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                if (onFinishAnimationRunnable != null) {
580d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    onFinishAnimationRunnable.run();
581d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                }
5828dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen            }
5838dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        };
584eeb5bbc9409978cc2ae52d48380399fcde3d9f85Winson Chung        animateViewIntoPosition(dragView, fromX, fromY, toX, toY, 1, 1, 1, toScale, toScale,
585d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                onCompleteRunnable, ANIMATION_END_DISAPPEAR, duration, anchorView);
586557d6ed50cc6560163440aa134870ef0bb11415bWinson Chung    }
587557d6ed50cc6560163440aa134870ef0bb11415bWinson Chung
588d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen    public void animateViewIntoPosition(final DragView view, final int fromX, final int fromY,
589ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen            final int toX, final int toY, float finalAlpha, float initScaleX, float initScaleY,
590ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen            float finalScaleX, float finalScaleY, Runnable onCompleteRunnable,
591ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen            int animationEndStyle, int duration, View anchorView) {
5928dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        Rect from = new Rect(fromX, fromY, fromX +
5938dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen                view.getMeasuredWidth(), fromY + view.getMeasuredHeight());
5943e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        Rect to = new Rect(toX, toY, toX + view.getMeasuredWidth(), toY + view.getMeasuredHeight());
595ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen        animateView(view, from, to, finalAlpha, initScaleX, initScaleY, finalScaleX, finalScaleY, duration,
596ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen                null, null, onCompleteRunnable, animationEndStyle, anchorView);
5973e8f811f31a2275e778244427271f77f4116c08bAdam Cohen    }
5983e8f811f31a2275e778244427271f77f4116c08bAdam Cohen
599b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen    /**
600b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen     * This method animates a view at the end of a drag and drop animation.
601b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen     *
602b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen     * @param view The view to be animated. This view is drawn directly into DragLayer, and so
603b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen     *        doesn't need to be a child of DragLayer.
604b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen     * @param from The initial location of the view. Only the left and top parameters are used.
605b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen     * @param to The final location of the view. Only the left and top parameters are used. This
606b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen     *        location doesn't account for scaling, and so should be centered about the desired
607b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen     *        final location (including scaling).
608b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen     * @param finalAlpha The final alpha of the view, in case we want it to fade as it animates.
609b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen     * @param finalScale The final scale of the view. The view is scaled about its center.
610b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen     * @param duration The duration of the animation.
611b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen     * @param motionInterpolator The interpolator to use for the location of the view.
612b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen     * @param alphaInterpolator The interpolator to use for the alpha of the view.
613b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen     * @param onCompleteRunnable Optional runnable to run on animation completion.
614b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen     * @param fadeOut Whether or not to fade out the view once the animation completes. If true,
615b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen     *        the runnable will execute after the view is faded out.
6166441de0ec2a71862798dd51180d0811b42edd514Adam Cohen     * @param anchorView If not null, this represents the view which the animated view stays
6176441de0ec2a71862798dd51180d0811b42edd514Adam Cohen     *        anchored to in case scrolling is currently taking place. Note: currently this is
6186441de0ec2a71862798dd51180d0811b42edd514Adam Cohen     *        only used for the X dimension for the case of the workspace.
619b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen     */
6207bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung    public void animateView(final DragView view, final Rect from, final Rect to,
6217bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung            final float finalAlpha, final float initScaleX, final float initScaleY,
6227bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung            final float finalScaleX, final float finalScaleY, int duration,
6237bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung            final Interpolator motionInterpolator, final Interpolator alphaInterpolator,
6247bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung            final Runnable onCompleteRunnable, final int animationEndStyle, View anchorView) {
6257bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung
626716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen        // Calculate the duration of the animation based on the object's distance
6273e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        final float dist = (float) Math.sqrt(Math.pow(to.left - from.left, 2) +
6283e8f811f31a2275e778244427271f77f4116c08bAdam Cohen                Math.pow(to.top - from.top, 2));
629716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen        final Resources res = getResources();
630716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen        final float maxDist = (float) res.getInteger(R.integer.config_dropAnimMaxDist);
6313e8f811f31a2275e778244427271f77f4116c08bAdam Cohen
6323e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        // If duration < 0, this is a cue to compute the duration based on the distance
6333e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        if (duration < 0) {
6343e8f811f31a2275e778244427271f77f4116c08bAdam Cohen            duration = res.getInteger(R.integer.config_dropAnimMaxDuration);
6353e8f811f31a2275e778244427271f77f4116c08bAdam Cohen            if (dist < maxDist) {
6368dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen                duration *= mCubicEaseOutInterpolator.getInterpolation(dist / maxDist);
6373e8f811f31a2275e778244427271f77f4116c08bAdam Cohen            }
63861b0c69d3fe331d3de338322396d5de691d58613Winson Chung            duration = Math.max(duration, res.getInteger(R.integer.config_dropAnimMinDuration));
639716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen        }
640716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen
641043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        // Fall back to cubic ease out interpolator for the animation if none is specified
642043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        TimeInterpolator interpolator = null;
6433e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        if (alphaInterpolator == null || motionInterpolator == null) {
644043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung            interpolator = mCubicEaseOutInterpolator;
6453e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        }
646716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen
647043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        // Animate the view
6487bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung        final float initAlpha = view.getAlpha();
649043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        final float dropViewScale = view.getScaleX();
650043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        AnimatorUpdateListener updateCb = new AnimatorUpdateListener() {
651043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung            @Override
652716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen            public void onAnimationUpdate(ValueAnimator animation) {
653716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen                final float percent = (Float) animation.getAnimatedValue();
6547bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung                final int width = view.getMeasuredWidth();
6557bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung                final int height = view.getMeasuredHeight();
656716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen
6573e8f811f31a2275e778244427271f77f4116c08bAdam Cohen                float alphaPercent = alphaInterpolator == null ? percent :
6583e8f811f31a2275e778244427271f77f4116c08bAdam Cohen                        alphaInterpolator.getInterpolation(percent);
6593e8f811f31a2275e778244427271f77f4116c08bAdam Cohen                float motionPercent = motionInterpolator == null ? percent :
6603e8f811f31a2275e778244427271f77f4116c08bAdam Cohen                        motionInterpolator.getInterpolation(percent);
661a1cdab039292f3d809528c0e2e38580b37864d8dWinson Chung
6627bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung                float initialScaleX = initScaleX * dropViewScale;
6637bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung                float initialScaleY = initScaleY * dropViewScale;
6647bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung                float scaleX = finalScaleX * percent + initialScaleX * (1 - percent);
6657bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung                float scaleY = finalScaleY * percent + initialScaleY * (1 - percent);
6667bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung                float alpha = finalAlpha * alphaPercent + initAlpha * (1 - alphaPercent);
6677bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung
6687bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung                float fromLeft = from.left + (initialScaleX - 1f) * width / 2;
6697bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung                float fromTop = from.top + (initialScaleY - 1f) * height / 2;
6707bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung
6717bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung                int x = (int) (fromLeft + Math.round(((to.left - fromLeft) * motionPercent)));
6727bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung                int y = (int) (fromTop + Math.round(((to.top - fromTop) * motionPercent)));
6737bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung
67428f852ab678d9750879b6d3549bf5da176cf1225Adam Cohen                int anchorAdjust = mAnchorView == null ? 0 : (int) (mAnchorView.getScaleX() *
67528f852ab678d9750879b6d3549bf5da176cf1225Adam Cohen                    (mAnchorViewInitialScrollX - mAnchorView.getScrollX()));
67628f852ab678d9750879b6d3549bf5da176cf1225Adam Cohen
67728f852ab678d9750879b6d3549bf5da176cf1225Adam Cohen                int xPos = x - mDropView.getScrollX() + anchorAdjust;
6787bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung                int yPos = y - mDropView.getScrollY();
6797bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung
6807bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung                mDropView.setTranslationX(xPos);
6817bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung                mDropView.setTranslationY(yPos);
6827bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung                mDropView.setScaleX(scaleX);
6837bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung                mDropView.setScaleY(scaleY);
6847bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung                mDropView.setAlpha(alpha);
685716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen            }
686043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        };
687043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        animateView(view, updateCb, duration, interpolator, onCompleteRunnable, animationEndStyle,
688043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung                anchorView);
689043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung    }
690043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung
691043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung    public void animateView(final DragView view, AnimatorUpdateListener updateCb, int duration,
692043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung            TimeInterpolator interpolator, final Runnable onCompleteRunnable,
693043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung            final int animationEndStyle, View anchorView) {
694043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        // Clean up the previous animations
695043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        if (mDropAnim != null) mDropAnim.cancel();
696043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        if (mFadeOutAnim != null) mFadeOutAnim.cancel();
697043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung
698043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        // Show the drop view if it was previously hidden
699043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        mDropView = view;
700043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        mDropView.cancelAnimation();
701043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        mDropView.resetLayoutParams();
702043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung
703043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        // Set the anchor view if the page is scrolling
704043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        if (anchorView != null) {
705043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung            mAnchorViewInitialScrollX = anchorView.getScrollX();
706043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        }
707043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        mAnchorView = anchorView;
708043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung
709043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        // Create and start the animation
710043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        mDropAnim = new ValueAnimator();
711043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        mDropAnim.setInterpolator(interpolator);
712043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        mDropAnim.setDuration(duration);
713043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        mDropAnim.setFloatValues(0f, 1f);
714043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        mDropAnim.addUpdateListener(updateCb);
7153e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        mDropAnim.addListener(new AnimatorListenerAdapter() {
7163e8f811f31a2275e778244427271f77f4116c08bAdam Cohen            public void onAnimationEnd(Animator animation) {
7178dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen                if (onCompleteRunnable != null) {
7188dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen                    onCompleteRunnable.run();
7198dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen                }
720ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen                switch (animationEndStyle) {
721ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen                case ANIMATION_END_DISAPPEAR:
722ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen                    clearAnimatedView();
723ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen                    break;
724ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen                case ANIMATION_END_FADE_OUT:
7258dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen                    fadeOutDragView();
726ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen                    break;
727ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen                case ANIMATION_END_REMAIN_VISIBLE:
728ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen                    break;
7293e8f811f31a2275e778244427271f77f4116c08bAdam Cohen                }
7303e8f811f31a2275e778244427271f77f4116c08bAdam Cohen            }
7313e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        });
732716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen        mDropAnim.start();
733716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen    }
734716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen
735ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen    public void clearAnimatedView() {
7367bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung        if (mDropAnim != null) {
7377bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung            mDropAnim.cancel();
7387bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung        }
7397bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung        if (mDropView != null) {
7402d783ce2f4b2e507bead0d723f0edcdf902dbd46Adam Cohen            mDragController.onDeferredEndDrag(mDropView);
7417bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung        }
742ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen        mDropView = null;
743ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen        invalidate();
744ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen    }
745ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen
746ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen    public View getAnimatedView() {
747ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen        return mDropView;
748ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen    }
749ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen
7508dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen    private void fadeOutDragView() {
7518dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        mFadeOutAnim = new ValueAnimator();
7528dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        mFadeOutAnim.setDuration(150);
7538dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        mFadeOutAnim.setFloatValues(0f, 1f);
7548dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        mFadeOutAnim.removeAllUpdateListeners();
7558dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        mFadeOutAnim.addUpdateListener(new AnimatorUpdateListener() {
7568dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen            public void onAnimationUpdate(ValueAnimator animation) {
7578dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen                final float percent = (Float) animation.getAnimatedValue();
7587bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung
7597bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung                float alpha = 1 - percent;
7607bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung                mDropView.setAlpha(alpha);
7618dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen            }
7628dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        });
7638dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        mFadeOutAnim.addListener(new AnimatorListenerAdapter() {
7648dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen            public void onAnimationEnd(Animator animation) {
7657bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung                if (mDropView != null) {
766043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung                    mDragController.onDeferredEndDrag(mDropView);
7677bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung                }
7688dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen                mDropView = null;
769ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen                invalidate();
7708dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen            }
7718dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        });
7728dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        mFadeOutAnim.start();
7738dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen    }
7748dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen
775716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen    @Override
7768b805b17158886035b38261eb611d8641701ae43Michael Jurka    public void onChildViewAdded(View parent, View child) {
77721b411074e39fd10cbc8dd0220bb159da4af2c76Adam Cohen        updateChildIndices();
77821b411074e39fd10cbc8dd0220bb159da4af2c76Adam Cohen    }
77921b411074e39fd10cbc8dd0220bb159da4af2c76Adam Cohen
78021b411074e39fd10cbc8dd0220bb159da4af2c76Adam Cohen    @Override
7818b805b17158886035b38261eb611d8641701ae43Michael Jurka    public void onChildViewRemoved(View parent, View child) {
78221b411074e39fd10cbc8dd0220bb159da4af2c76Adam Cohen        updateChildIndices();
78321b411074e39fd10cbc8dd0220bb159da4af2c76Adam Cohen    }
78421b411074e39fd10cbc8dd0220bb159da4af2c76Adam Cohen
785432609a246819f3cf887a80c2ae56b61fc5ca25aAdam Cohen    @Override
786432609a246819f3cf887a80c2ae56b61fc5ca25aAdam Cohen    public void bringChildToFront(View child) {
787432609a246819f3cf887a80c2ae56b61fc5ca25aAdam Cohen        super.bringChildToFront(child);
788432609a246819f3cf887a80c2ae56b61fc5ca25aAdam Cohen        updateChildIndices();
789432609a246819f3cf887a80c2ae56b61fc5ca25aAdam Cohen    }
790432609a246819f3cf887a80c2ae56b61fc5ca25aAdam Cohen
79121b411074e39fd10cbc8dd0220bb159da4af2c76Adam Cohen    private void updateChildIndices() {
792432609a246819f3cf887a80c2ae56b61fc5ca25aAdam Cohen        mTopViewIndex = -1;
79355bd9725d5c0373b89f7b9bbd9547550ea3bbc63Jorim Jaggi        int childCount = getChildCount();
79455bd9725d5c0373b89f7b9bbd9547550ea3bbc63Jorim Jaggi        for (int i = 0; i < childCount; i++) {
795432609a246819f3cf887a80c2ae56b61fc5ca25aAdam Cohen            if (getChildAt(i) instanceof DragView ||
796432609a246819f3cf887a80c2ae56b61fc5ca25aAdam Cohen                    getChildAt(i) == mOverlayView) {
797432609a246819f3cf887a80c2ae56b61fc5ca25aAdam Cohen                mTopViewIndex = i;
79855bd9725d5c0373b89f7b9bbd9547550ea3bbc63Jorim Jaggi            }
79921b411074e39fd10cbc8dd0220bb159da4af2c76Adam Cohen        }
8002d783ce2f4b2e507bead0d723f0edcdf902dbd46Adam Cohen        mChildCountOnLastUpdate = childCount;
80121b411074e39fd10cbc8dd0220bb159da4af2c76Adam Cohen    }
80221b411074e39fd10cbc8dd0220bb159da4af2c76Adam Cohen
80321b411074e39fd10cbc8dd0220bb159da4af2c76Adam Cohen    @Override
80421b411074e39fd10cbc8dd0220bb159da4af2c76Adam Cohen    protected int getChildDrawingOrder(int childCount, int i) {
8052d783ce2f4b2e507bead0d723f0edcdf902dbd46Adam Cohen        if (mChildCountOnLastUpdate != childCount) {
8062d783ce2f4b2e507bead0d723f0edcdf902dbd46Adam Cohen            // between platform versions 17 and 18, behavior for onChildViewRemoved / Added changed.
8072d783ce2f4b2e507bead0d723f0edcdf902dbd46Adam Cohen            // Pre-18, the child was not added / removed by the time of those callbacks. We need to
8082d783ce2f4b2e507bead0d723f0edcdf902dbd46Adam Cohen            // force update our representation of things here to avoid crashing on pre-18 devices
8092d783ce2f4b2e507bead0d723f0edcdf902dbd46Adam Cohen            // in certain instances.
8102d783ce2f4b2e507bead0d723f0edcdf902dbd46Adam Cohen            updateChildIndices();
8112d783ce2f4b2e507bead0d723f0edcdf902dbd46Adam Cohen        }
8122d783ce2f4b2e507bead0d723f0edcdf902dbd46Adam Cohen
813432609a246819f3cf887a80c2ae56b61fc5ca25aAdam Cohen        // i represents the current draw iteration
814432609a246819f3cf887a80c2ae56b61fc5ca25aAdam Cohen        if (mTopViewIndex == -1) {
815432609a246819f3cf887a80c2ae56b61fc5ca25aAdam Cohen            // in general we do nothing
81621b411074e39fd10cbc8dd0220bb159da4af2c76Adam Cohen            return i;
817432609a246819f3cf887a80c2ae56b61fc5ca25aAdam Cohen        } else if (i == childCount - 1) {
818432609a246819f3cf887a80c2ae56b61fc5ca25aAdam Cohen            // if we have a top index, we return it when drawing last item (highest z-order)
819432609a246819f3cf887a80c2ae56b61fc5ca25aAdam Cohen            return mTopViewIndex;
820432609a246819f3cf887a80c2ae56b61fc5ca25aAdam Cohen        } else if (i < mTopViewIndex) {
82121b411074e39fd10cbc8dd0220bb159da4af2c76Adam Cohen            return i;
82255bd9725d5c0373b89f7b9bbd9547550ea3bbc63Jorim Jaggi        } else {
823432609a246819f3cf887a80c2ae56b61fc5ca25aAdam Cohen            // for indexes greater than the top index, we fetch one item above to shift for the
824432609a246819f3cf887a80c2ae56b61fc5ca25aAdam Cohen            // displacement of the top index
825432609a246819f3cf887a80c2ae56b61fc5ca25aAdam Cohen            return i + 1;
82621b411074e39fd10cbc8dd0220bb159da4af2c76Adam Cohen        }
82721b411074e39fd10cbc8dd0220bb159da4af2c76Adam Cohen    }
828360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung
829360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung    private boolean mInScrollArea;
830360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung    private Drawable mLeftHoverDrawable;
831360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung    private Drawable mRightHoverDrawable;
832360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung
833360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung    void onEnterScrollArea(int direction) {
834360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung        mInScrollArea = true;
835360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung        invalidate();
836360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung    }
837360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung
838360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung    void onExitScrollArea() {
839360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung        mInScrollArea = false;
840360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung        invalidate();
841360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung    }
842360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung
843fe1fe268b6d9ffd99218117795b3524a87e5110bWinson Chung    /**
844fe1fe268b6d9ffd99218117795b3524a87e5110bWinson Chung     * Note: this is a reimplementation of View.isLayoutRtl() since that is currently hidden api.
845fe1fe268b6d9ffd99218117795b3524a87e5110bWinson Chung     */
846fe1fe268b6d9ffd99218117795b3524a87e5110bWinson Chung    private boolean isLayoutRtl() {
847fe1fe268b6d9ffd99218117795b3524a87e5110bWinson Chung        return (getLayoutDirection() == LAYOUT_DIRECTION_RTL);
848fe1fe268b6d9ffd99218117795b3524a87e5110bWinson Chung    }
849fe1fe268b6d9ffd99218117795b3524a87e5110bWinson Chung
850360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung    @Override
851360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung    protected void dispatchDraw(Canvas canvas) {
852360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung        super.dispatchDraw(canvas);
853360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung
854e4f9891f01bdc10d8f96e4e2429e2f4d0558238bDaniel Sandler        if (mInScrollArea && !LauncherAppState.getInstance().isScreenLarge()) {
855360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung            Workspace workspace = mLauncher.getWorkspace();
85661a9a5c359e3e14cb1beaf43dbdb54e00911fe80Adam Cohen            int width = getMeasuredWidth();
857360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung            Rect childRect = new Rect();
858360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung            getDescendantRectRelativeToSelf(workspace.getChildAt(0), childRect);
859360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung
860360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung            int page = workspace.getNextPage();
861fe1fe268b6d9ffd99218117795b3524a87e5110bWinson Chung            final boolean isRtl = isLayoutRtl();
862fe1fe268b6d9ffd99218117795b3524a87e5110bWinson Chung            CellLayout leftPage = (CellLayout) workspace.getChildAt(isRtl ? page + 1 : page - 1);
863fe1fe268b6d9ffd99218117795b3524a87e5110bWinson Chung            CellLayout rightPage = (CellLayout) workspace.getChildAt(isRtl ? page - 1 : page + 1);
864360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung
865360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung            if (leftPage != null && leftPage.getIsDragOverlapping()) {
866360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung                mLeftHoverDrawable.setBounds(0, childRect.top,
867360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung                        mLeftHoverDrawable.getIntrinsicWidth(), childRect.bottom);
868360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung                mLeftHoverDrawable.draw(canvas);
869360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung            } else if (rightPage != null && rightPage.getIsDragOverlapping()) {
870360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung                mRightHoverDrawable.setBounds(width - mRightHoverDrawable.getIntrinsicWidth(),
871360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung                        childRect.top, width, childRect.bottom);
872360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung                mRightHoverDrawable.draw(canvas);
873360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung            }
874360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung        }
875360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung    }
876b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen
877b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen    public void setTouchCompleteListener(TouchCompleteListener listener) {
878b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen        mTouchCompleteListener = listener;
879b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen    }
880b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen
881b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen    public interface TouchCompleteListener {
882b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen        public void onTouchComplete();
883b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen    }
88431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project}
885