DragLayer.java revision 424418bb50ccf5d9270650b70cc51f423da51a65
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
806c5891a9fce95eee3d87823d11d21889743e9c68Adam Cohen    // Darkening scrim
816c5891a9fce95eee3d87823d11d21889743e9c68Adam Cohen    private Drawable mBackground;
826c5891a9fce95eee3d87823d11d21889743e9c68Adam Cohen    private float mBackgroundAlpha = 0;
836c5891a9fce95eee3d87823d11d21889743e9c68Adam Cohen
848cc05507150fea5282b7581e1a268967a702bcc9Adam Cohen    // Related to adjacent page hints
858cc05507150fea5282b7581e1a268967a702bcc9Adam Cohen    private boolean mInScrollArea;
868cc05507150fea5282b7581e1a268967a702bcc9Adam Cohen    private boolean mShowPageHints;
878cc05507150fea5282b7581e1a268967a702bcc9Adam Cohen    private Drawable mLeftHoverDrawable;
888cc05507150fea5282b7581e1a268967a702bcc9Adam Cohen    private Drawable mRightHoverDrawable;
898cc05507150fea5282b7581e1a268967a702bcc9Adam Cohen    private Drawable mLeftHoverDrawableActive;
908cc05507150fea5282b7581e1a268967a702bcc9Adam Cohen    private Drawable mRightHoverDrawableActive;
918cc05507150fea5282b7581e1a268967a702bcc9Adam Cohen
9231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    /**
9331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * Used to create a new DragLayer from XML.
9431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     *
9531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param context The application's context.
960e26059548e429e5d1c973bebe4c561bead2926fMichael Jurka     * @param attrs The attributes set containing the Workspace's customization values.
9731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     */
9831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    public DragLayer(Context context, AttributeSet attrs) {
9931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        super(context, attrs);
100be62afa34d58edab0fc9ba7499f0dd543039c903Winson Chung
101be62afa34d58edab0fc9ba7499f0dd543039c903Winson Chung        // Disable multitouch across the workspace/all apps/customize tray
102be62afa34d58edab0fc9ba7499f0dd543039c903Winson Chung        setMotionEventSplittingEnabled(false);
10321b411074e39fd10cbc8dd0220bb159da4af2c76Adam Cohen        setChildrenDrawingOrderEnabled(true);
1048b805b17158886035b38261eb611d8641701ae43Michael Jurka        setOnHierarchyChangeListener(this);
105360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung
1066c5891a9fce95eee3d87823d11d21889743e9c68Adam Cohen        final Resources res = getResources();
107c50438c802355dff714b04f42a32e518cb9e91d8Adam Cohen        mLeftHoverDrawable = res.getDrawable(R.drawable.page_hover_left);
108c50438c802355dff714b04f42a32e518cb9e91d8Adam Cohen        mRightHoverDrawable = res.getDrawable(R.drawable.page_hover_right);
109c50438c802355dff714b04f42a32e518cb9e91d8Adam Cohen        mLeftHoverDrawableActive = res.getDrawable(R.drawable.page_hover_left_active);
110c50438c802355dff714b04f42a32e518cb9e91d8Adam Cohen        mRightHoverDrawableActive = res.getDrawable(R.drawable.page_hover_right_active);
1116c5891a9fce95eee3d87823d11d21889743e9c68Adam Cohen        mBackground = res.getDrawable(R.drawable.apps_customize_bg);
11231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
11331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
1144c98d9235d164680186180974719f551cf935d08Winson Chung    public void setup(Launcher launcher, DragController controller) {
1154c98d9235d164680186180974719f551cf935d08Winson Chung        mLauncher = launcher;
11600acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato        mDragController = controller;
11731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
11876fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen
11931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    @Override
12031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    public boolean dispatchKeyEvent(KeyEvent event) {
12100acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato        return mDragController.dispatchKeyEvent(event) || super.dispatchKeyEvent(event);
12231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
12331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
12477e1f47520958edd7ec04e203db65b932537bd1cJohn Spurlock    @Override
12577e1f47520958edd7ec04e203db65b932537bd1cJohn Spurlock    protected boolean fitSystemWindows(Rect insets) {
12677e1f47520958edd7ec04e203db65b932537bd1cJohn Spurlock        final int n = getChildCount();
12777e1f47520958edd7ec04e203db65b932537bd1cJohn Spurlock        for (int i = 0; i < n; i++) {
12877e1f47520958edd7ec04e203db65b932537bd1cJohn Spurlock            final View child = getChildAt(i);
12926279c6d0917015eb4e6de0743b79edeea25f9bcDave Hawkey            setInsets(child, insets, mInsets);
13077e1f47520958edd7ec04e203db65b932537bd1cJohn Spurlock        }
13177e1f47520958edd7ec04e203db65b932537bd1cJohn Spurlock        mInsets.set(insets);
13277e1f47520958edd7ec04e203db65b932537bd1cJohn Spurlock        return true; // I'll take it from here
13377e1f47520958edd7ec04e203db65b932537bd1cJohn Spurlock    }
13477e1f47520958edd7ec04e203db65b932537bd1cJohn Spurlock
135424418bb50ccf5d9270650b70cc51f423da51a65Sunny Goyal    Rect getInsets() {
136424418bb50ccf5d9270650b70cc51f423da51a65Sunny Goyal        return mInsets;
137424418bb50ccf5d9270650b70cc51f423da51a65Sunny Goyal    }
138424418bb50ccf5d9270650b70cc51f423da51a65Sunny Goyal
13926279c6d0917015eb4e6de0743b79edeea25f9bcDave Hawkey    @Override
14026279c6d0917015eb4e6de0743b79edeea25f9bcDave Hawkey    public void addView(View child, int index, android.view.ViewGroup.LayoutParams params) {
14126279c6d0917015eb4e6de0743b79edeea25f9bcDave Hawkey        super.addView(child, index, params);
14226279c6d0917015eb4e6de0743b79edeea25f9bcDave Hawkey        setInsets(child, mInsets, new Rect());
14326279c6d0917015eb4e6de0743b79edeea25f9bcDave Hawkey    }
14426279c6d0917015eb4e6de0743b79edeea25f9bcDave Hawkey
145b670f195ffb7b4a0519fd0b337b68f7412159414Adam Cohen    public void showOverlayView(View overlayView) {
146432609a246819f3cf887a80c2ae56b61fc5ca25aAdam Cohen        LayoutParams lp = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
147b670f195ffb7b4a0519fd0b337b68f7412159414Adam Cohen        mOverlayView = overlayView;
148b670f195ffb7b4a0519fd0b337b68f7412159414Adam Cohen        addView(overlayView, lp);
149b670f195ffb7b4a0519fd0b337b68f7412159414Adam Cohen
150b670f195ffb7b4a0519fd0b337b68f7412159414Adam Cohen        // ensure that the overlay view stays on top. we can't use drawing order for this
151b670f195ffb7b4a0519fd0b337b68f7412159414Adam Cohen        // because in API level 16 touch dispatch doesn't respect drawing order.
152b670f195ffb7b4a0519fd0b337b68f7412159414Adam Cohen        mOverlayView.bringToFront();
153432609a246819f3cf887a80c2ae56b61fc5ca25aAdam Cohen    }
154432609a246819f3cf887a80c2ae56b61fc5ca25aAdam Cohen
155432609a246819f3cf887a80c2ae56b61fc5ca25aAdam Cohen    public void dismissOverlayView() {
156432609a246819f3cf887a80c2ae56b61fc5ca25aAdam Cohen        removeView(mOverlayView);
157432609a246819f3cf887a80c2ae56b61fc5ca25aAdam Cohen    }
158432609a246819f3cf887a80c2ae56b61fc5ca25aAdam Cohen
15926279c6d0917015eb4e6de0743b79edeea25f9bcDave Hawkey    private void setInsets(View child, Rect newInsets, Rect oldInsets) {
16026279c6d0917015eb4e6de0743b79edeea25f9bcDave Hawkey        final FrameLayout.LayoutParams flp = (FrameLayout.LayoutParams) child.getLayoutParams();
16126279c6d0917015eb4e6de0743b79edeea25f9bcDave Hawkey        if (child instanceof Insettable) {
16226279c6d0917015eb4e6de0743b79edeea25f9bcDave Hawkey            ((Insettable) child).setInsets(newInsets);
16326279c6d0917015eb4e6de0743b79edeea25f9bcDave Hawkey        } else {
16426279c6d0917015eb4e6de0743b79edeea25f9bcDave Hawkey            flp.topMargin += (newInsets.top - oldInsets.top);
16526279c6d0917015eb4e6de0743b79edeea25f9bcDave Hawkey            flp.leftMargin += (newInsets.left - oldInsets.left);
16626279c6d0917015eb4e6de0743b79edeea25f9bcDave Hawkey            flp.rightMargin += (newInsets.right - oldInsets.right);
16726279c6d0917015eb4e6de0743b79edeea25f9bcDave Hawkey            flp.bottomMargin += (newInsets.bottom - oldInsets.bottom);
16826279c6d0917015eb4e6de0743b79edeea25f9bcDave Hawkey        }
16926279c6d0917015eb4e6de0743b79edeea25f9bcDave Hawkey        child.setLayoutParams(flp);
17026279c6d0917015eb4e6de0743b79edeea25f9bcDave Hawkey    }
17126279c6d0917015eb4e6de0743b79edeea25f9bcDave Hawkey
1723371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen    private boolean isEventOverFolderTextRegion(Folder folder, MotionEvent ev) {
1733371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen        getDescendantRectRelativeToSelf(folder.getEditTextRegion(), mHitRect);
1743371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen        if (mHitRect.contains((int) ev.getX(), (int) ev.getY())) {
1753371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen            return true;
1763371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen        }
1773371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen        return false;
1783371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen    }
1793371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen
1803371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen    private boolean isEventOverFolder(Folder folder, MotionEvent ev) {
1813371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen        getDescendantRectRelativeToSelf(folder, mHitRect);
1823371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen        if (mHitRect.contains((int) ev.getX(), (int) ev.getY())) {
1833371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen            return true;
1843371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen        }
1853371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen        return false;
1863371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen    }
1873371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen
18876fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen    private boolean handleTouchDown(MotionEvent ev, boolean intercept) {
1896788269814a678af976dfc7d6135993e172ce586Adam Cohen        Rect hitRect = new Rect();
1906788269814a678af976dfc7d6135993e172ce586Adam Cohen        int x = (int) ev.getX();
1916788269814a678af976dfc7d6135993e172ce586Adam Cohen        int y = (int) ev.getY();
1926788269814a678af976dfc7d6135993e172ce586Adam Cohen
1936788269814a678af976dfc7d6135993e172ce586Adam Cohen        for (AppWidgetResizeFrame child: mResizeFrames) {
1946788269814a678af976dfc7d6135993e172ce586Adam Cohen            child.getHitRect(hitRect);
1956788269814a678af976dfc7d6135993e172ce586Adam Cohen            if (hitRect.contains(x, y)) {
1966788269814a678af976dfc7d6135993e172ce586Adam Cohen                if (child.beginResizeIfPointInRegion(x - child.getLeft(), y - child.getTop())) {
1976788269814a678af976dfc7d6135993e172ce586Adam Cohen                    mCurrentResizeFrame = child;
1986788269814a678af976dfc7d6135993e172ce586Adam Cohen                    mXDown = x;
1996788269814a678af976dfc7d6135993e172ce586Adam Cohen                    mYDown = y;
2006788269814a678af976dfc7d6135993e172ce586Adam Cohen                    requestDisallowInterceptTouchEvent(true);
2016788269814a678af976dfc7d6135993e172ce586Adam Cohen                    return true;
2026788269814a678af976dfc7d6135993e172ce586Adam Cohen                }
2036788269814a678af976dfc7d6135993e172ce586Adam Cohen            }
2046788269814a678af976dfc7d6135993e172ce586Adam Cohen        }
20576fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen
2061d9af7d1e75bad13bb10ad37f5900ed59882622eAdam Cohen        Folder currentFolder = mLauncher.getWorkspace().getOpenFolder();
207424418bb50ccf5d9270650b70cc51f423da51a65Sunny Goyal        if (currentFolder != null && intercept) {
2081d9af7d1e75bad13bb10ad37f5900ed59882622eAdam Cohen            if (currentFolder.isEditingName()) {
2093371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                if (!isEventOverFolderTextRegion(currentFolder, ev)) {
2101d9af7d1e75bad13bb10ad37f5900ed59882622eAdam Cohen                    currentFolder.dismissEditingName();
21176fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen                    return true;
2122801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen                }
2132801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen            }
21476fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen
2151d9af7d1e75bad13bb10ad37f5900ed59882622eAdam Cohen            getDescendantRectRelativeToSelf(currentFolder, hitRect);
2163371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen            if (!isEventOverFolder(currentFolder, ev)) {
21776fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen                mLauncher.closeFolder();
21876fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen                return true;
21976fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen            }
2202801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen        }
2216788269814a678af976dfc7d6135993e172ce586Adam Cohen        return false;
2226788269814a678af976dfc7d6135993e172ce586Adam Cohen    }
2236788269814a678af976dfc7d6135993e172ce586Adam Cohen
22431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    @Override
22531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    public boolean onInterceptTouchEvent(MotionEvent ev) {
226b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen        int action = ev.getAction();
227b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen
228b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen        if (action == MotionEvent.ACTION_DOWN) {
22976fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen            if (handleTouchDown(ev, true)) {
2306788269814a678af976dfc7d6135993e172ce586Adam Cohen                return true;
231d1837cc69eb222371afdd30890f7215d117510f2Patrick Dubroy            }
232b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen        } else if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) {
233b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen            if (mTouchCompleteListener != null) {
234b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen                mTouchCompleteListener.onTouchComplete();
235b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen            }
236b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen            mTouchCompleteListener = null;
2371b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen        }
2386788269814a678af976dfc7d6135993e172ce586Adam Cohen        clearAllResizeFrames();
2394db52312c10e822162a21c60404f06f6e507f0d6Joe Onorato        return mDragController.onInterceptTouchEvent(ev);
24031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
24131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
24231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    @Override
2433371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen    public boolean onInterceptHoverEvent(MotionEvent ev) {
244023c71eb3b2bbe63272cb74baaf050c4188c89b0Michael Jurka        if (mLauncher == null || mLauncher.getWorkspace() == null) {
245023c71eb3b2bbe63272cb74baaf050c4188c89b0Michael Jurka            return false;
246023c71eb3b2bbe63272cb74baaf050c4188c89b0Michael Jurka        }
2473371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen        Folder currentFolder = mLauncher.getWorkspace().getOpenFolder();
2483371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen        if (currentFolder == null) {
2493371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen            return false;
2503371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen        } else {
2518b805b17158886035b38261eb611d8641701ae43Michael Jurka                AccessibilityManager accessibilityManager = (AccessibilityManager)
2528b805b17158886035b38261eb611d8641701ae43Michael Jurka                        getContext().getSystemService(Context.ACCESSIBILITY_SERVICE);
2538b805b17158886035b38261eb611d8641701ae43Michael Jurka            if (accessibilityManager.isTouchExplorationEnabled()) {
2543371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                final int action = ev.getAction();
2553371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                boolean isOverFolder;
2563371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                switch (action) {
2573371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                    case MotionEvent.ACTION_HOVER_ENTER:
2583371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                        isOverFolder = isEventOverFolder(currentFolder, ev);
2593371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                        if (!isOverFolder) {
2603371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                            sendTapOutsideFolderAccessibilityEvent(currentFolder.isEditingName());
2613371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                            mHoverPointClosesFolder = true;
2623371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                            return true;
2633371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                        }
264693fbc7f1737d89f11f9ab81558c109f0883ab0eMihail Dumitrescu                        mHoverPointClosesFolder = false;
265693fbc7f1737d89f11f9ab81558c109f0883ab0eMihail Dumitrescu                        break;
2663371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                    case MotionEvent.ACTION_HOVER_MOVE:
2673371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                        isOverFolder = isEventOverFolder(currentFolder, ev);
2683371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                        if (!isOverFolder && !mHoverPointClosesFolder) {
2693371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                            sendTapOutsideFolderAccessibilityEvent(currentFolder.isEditingName());
2703371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                            mHoverPointClosesFolder = true;
2713371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                            return true;
272693fbc7f1737d89f11f9ab81558c109f0883ab0eMihail Dumitrescu                        } else if (!isOverFolder) {
2733371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                            return true;
2743371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                        }
275693fbc7f1737d89f11f9ab81558c109f0883ab0eMihail Dumitrescu                        mHoverPointClosesFolder = false;
2763371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                }
2773371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen            }
2783371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen        }
2793371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen        return false;
2803371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen    }
2813371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen
2823371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen    private void sendTapOutsideFolderAccessibilityEvent(boolean isEditingName) {
2838b805b17158886035b38261eb611d8641701ae43Michael Jurka        AccessibilityManager accessibilityManager = (AccessibilityManager)
2848b805b17158886035b38261eb611d8641701ae43Michael Jurka                getContext().getSystemService(Context.ACCESSIBILITY_SERVICE);
2858b805b17158886035b38261eb611d8641701ae43Michael Jurka        if (accessibilityManager.isEnabled()) {
2863371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen            int stringId = isEditingName ? R.string.folder_tap_to_rename : R.string.folder_tap_to_close;
2873371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen            AccessibilityEvent event = AccessibilityEvent.obtain(
2883371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                    AccessibilityEvent.TYPE_VIEW_FOCUSED);
2893371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen            onInitializeAccessibilityEvent(event);
2908b805b17158886035b38261eb611d8641701ae43Michael Jurka            event.getText().add(getContext().getString(stringId));
2918b805b17158886035b38261eb611d8641701ae43Michael Jurka            accessibilityManager.sendAccessibilityEvent(event);
2923371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen        }
29383ca480941b3dd635b62347008fc8d7859d82002Winson Chung    }
29483ca480941b3dd635b62347008fc8d7859d82002Winson Chung
29583ca480941b3dd635b62347008fc8d7859d82002Winson Chung    @Override
29683ca480941b3dd635b62347008fc8d7859d82002Winson Chung    public boolean onRequestSendAccessibilityEvent(View child, AccessibilityEvent event) {
29783ca480941b3dd635b62347008fc8d7859d82002Winson Chung        Folder currentFolder = mLauncher.getWorkspace().getOpenFolder();
29883ca480941b3dd635b62347008fc8d7859d82002Winson Chung        if (currentFolder != null) {
29983ca480941b3dd635b62347008fc8d7859d82002Winson Chung            if (child == currentFolder) {
30083ca480941b3dd635b62347008fc8d7859d82002Winson Chung                return super.onRequestSendAccessibilityEvent(child, event);
30183ca480941b3dd635b62347008fc8d7859d82002Winson Chung            }
30283ca480941b3dd635b62347008fc8d7859d82002Winson Chung            // Skip propagating onRequestSendAccessibilityEvent all for other children
30383ca480941b3dd635b62347008fc8d7859d82002Winson Chung            // when a folder is open
30483ca480941b3dd635b62347008fc8d7859d82002Winson Chung            return false;
30583ca480941b3dd635b62347008fc8d7859d82002Winson Chung        }
30683ca480941b3dd635b62347008fc8d7859d82002Winson Chung        return super.onRequestSendAccessibilityEvent(child, event);
30783ca480941b3dd635b62347008fc8d7859d82002Winson Chung    }
30883ca480941b3dd635b62347008fc8d7859d82002Winson Chung
30983ca480941b3dd635b62347008fc8d7859d82002Winson Chung    @Override
31083ca480941b3dd635b62347008fc8d7859d82002Winson Chung    public void addChildrenForAccessibility(ArrayList<View> childrenForAccessibility) {
31183ca480941b3dd635b62347008fc8d7859d82002Winson Chung        Folder currentFolder = mLauncher.getWorkspace().getOpenFolder();
31283ca480941b3dd635b62347008fc8d7859d82002Winson Chung        if (currentFolder != null) {
31383ca480941b3dd635b62347008fc8d7859d82002Winson Chung            // Only add the folder as a child for accessibility when it is open
31483ca480941b3dd635b62347008fc8d7859d82002Winson Chung            childrenForAccessibility.add(currentFolder);
31583ca480941b3dd635b62347008fc8d7859d82002Winson Chung        } else {
31683ca480941b3dd635b62347008fc8d7859d82002Winson Chung            super.addChildrenForAccessibility(childrenForAccessibility);
31783ca480941b3dd635b62347008fc8d7859d82002Winson Chung        }
3183371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen    }
3193371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen
3203371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen    @Override
3213371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen    public boolean onHoverEvent(MotionEvent ev) {
3223371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen        // If we've received this, we've already done the necessary handling
3233371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen        // in onInterceptHoverEvent. Return true to consume the event.
3243371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen        return false;
3253371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen    }
3263371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen
3273371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen    @Override
32831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    public boolean onTouchEvent(MotionEvent ev) {
3296788269814a678af976dfc7d6135993e172ce586Adam Cohen        boolean handled = false;
3306788269814a678af976dfc7d6135993e172ce586Adam Cohen        int action = ev.getAction();
3316788269814a678af976dfc7d6135993e172ce586Adam Cohen
3326788269814a678af976dfc7d6135993e172ce586Adam Cohen        int x = (int) ev.getX();
3336788269814a678af976dfc7d6135993e172ce586Adam Cohen        int y = (int) ev.getY();
3346788269814a678af976dfc7d6135993e172ce586Adam Cohen
335b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen        if (action == MotionEvent.ACTION_DOWN) {
336b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen            if (handleTouchDown(ev, false)) {
337b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen                return true;
338b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen            }
339b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen        } else if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) {
340b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen            if (mTouchCompleteListener != null) {
341b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen                mTouchCompleteListener.onTouchComplete();
3426788269814a678af976dfc7d6135993e172ce586Adam Cohen            }
343b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen            mTouchCompleteListener = null;
3446788269814a678af976dfc7d6135993e172ce586Adam Cohen        }
3456788269814a678af976dfc7d6135993e172ce586Adam Cohen
3466788269814a678af976dfc7d6135993e172ce586Adam Cohen        if (mCurrentResizeFrame != null) {
3476788269814a678af976dfc7d6135993e172ce586Adam Cohen            handled = true;
3486788269814a678af976dfc7d6135993e172ce586Adam Cohen            switch (action) {
3496788269814a678af976dfc7d6135993e172ce586Adam Cohen                case MotionEvent.ACTION_MOVE:
3506788269814a678af976dfc7d6135993e172ce586Adam Cohen                    mCurrentResizeFrame.visualizeResizeForDelta(x - mXDown, y - mYDown);
3516788269814a678af976dfc7d6135993e172ce586Adam Cohen                    break;
3526788269814a678af976dfc7d6135993e172ce586Adam Cohen                case MotionEvent.ACTION_CANCEL:
3536788269814a678af976dfc7d6135993e172ce586Adam Cohen                case MotionEvent.ACTION_UP:
354bebf042666cffe52039b875a549a582abd78a431Adam Cohen                    mCurrentResizeFrame.visualizeResizeForDelta(x - mXDown, y - mYDown);
355bebf042666cffe52039b875a549a582abd78a431Adam Cohen                    mCurrentResizeFrame.onTouchUp();
3566788269814a678af976dfc7d6135993e172ce586Adam Cohen                    mCurrentResizeFrame = null;
3576788269814a678af976dfc7d6135993e172ce586Adam Cohen            }
3586788269814a678af976dfc7d6135993e172ce586Adam Cohen        }
3596788269814a678af976dfc7d6135993e172ce586Adam Cohen        if (handled) return true;
3604db52312c10e822162a21c60404f06f6e507f0d6Joe Onorato        return mDragController.onTouchEvent(ev);
36191a9c9636f10f1e12cd1f660b2e330634fbdc7dcRomain Guy    }
362ea3763c2672f77539538af8cdd395ad97058eaabRomain Guy
36335e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen    /**
36435e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen     * Determine the rect of the descendant in this DragLayer's coordinates
36535e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen     *
36635e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen     * @param descendant The descendant whose coordinates we want to find.
36735e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen     * @param r The rect into which to place the results.
36835e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen     * @return The factor by which this descendant is scaled relative to this DragLayer.
36935e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen     */
370ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen    public float getDescendantRectRelativeToSelf(View descendant, Rect r) {
371716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen        mTmpXY[0] = 0;
372716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen        mTmpXY[1] = 0;
373ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen        float scale = getDescendantCoordRelativeToSelf(descendant, mTmpXY);
3747d30a37007bac318db1c9af47a9af12d348042a5Adam Cohen
3758dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        r.set(mTmpXY[0], mTmpXY[1],
3767d30a37007bac318db1c9af47a9af12d348042a5Adam Cohen                (int) (mTmpXY[0] + scale * descendant.getMeasuredWidth()),
3777d30a37007bac318db1c9af47a9af12d348042a5Adam Cohen                (int) (mTmpXY[1] + scale * descendant.getMeasuredHeight()));
378ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen        return scale;
379716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen    }
38076fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen
381307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen    public float getLocationInDragLayer(View child, int[] loc) {
38235e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen        loc[0] = 0;
38335e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen        loc[1] = 0;
384307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen        return getDescendantCoordRelativeToSelf(child, loc);
38535e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen    }
38635e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen
3877d30a37007bac318db1c9af47a9af12d348042a5Adam Cohen    public float getDescendantCoordRelativeToSelf(View descendant, int[] coord) {
3887d30a37007bac318db1c9af47a9af12d348042a5Adam Cohen        return getDescendantCoordRelativeToSelf(descendant, coord, false);
3897d30a37007bac318db1c9af47a9af12d348042a5Adam Cohen    }
3907d30a37007bac318db1c9af47a9af12d348042a5Adam Cohen
39135e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen    /**
39235e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen     * Given a coordinate relative to the descendant, find the coordinate in this DragLayer's
39335e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen     * coordinates.
39435e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen     *
39535e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen     * @param descendant The descendant to which the passed coordinate is relative.
39635e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen     * @param coord The coordinate that we want mapped.
3977d30a37007bac318db1c9af47a9af12d348042a5Adam Cohen     * @param includeRootScroll Whether or not to account for the scroll of the root descendant:
3987d30a37007bac318db1c9af47a9af12d348042a5Adam Cohen     *          sometimes this is relevant as in a child's coordinates within the root descendant.
399307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen     * @return The factor by which this descendant is scaled relative to this DragLayer. Caution
400307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen     *         this scale factor is assumed to be equal in X and Y, and so if at any point this
401307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen     *         assumption fails, we will need to return a pair of scale factors.
40235e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen     */
4037d30a37007bac318db1c9af47a9af12d348042a5Adam Cohen    public float getDescendantCoordRelativeToSelf(View descendant, int[] coord,
4047d30a37007bac318db1c9af47a9af12d348042a5Adam Cohen            boolean includeRootScroll) {
405c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung        return Utilities.getDescendantCoordRelativeToParent(descendant, this,
406c9ca2980983ab21fc8631c7a65399d6d9c70f39cWinson Chung                coord, includeRootScroll);
407c9ca2980983ab21fc8631c7a65399d6d9c70f39cWinson Chung    }
408c9ca2980983ab21fc8631c7a65399d6d9c70f39cWinson Chung
4097d30a37007bac318db1c9af47a9af12d348042a5Adam Cohen    /**
4107d30a37007bac318db1c9af47a9af12d348042a5Adam Cohen     * Inverse of {@link #getDescendantCoordRelativeToSelf(View, int[])}.
4117d30a37007bac318db1c9af47a9af12d348042a5Adam Cohen     */
4127d30a37007bac318db1c9af47a9af12d348042a5Adam Cohen    public float mapCoordInSelfToDescendent(View descendant, int[] coord) {
413c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung        return Utilities.mapCoordInSelfToDescendent(descendant, this, coord);
41476fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen    }
41576fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen
4163e8f811f31a2275e778244427271f77f4116c08bAdam Cohen    public void getViewRectRelativeToSelf(View v, Rect r) {
4173e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        int[] loc = new int[2];
4188dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        getLocationInWindow(loc);
4193e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        int x = loc[0];
4203e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        int y = loc[1];
421716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen
4228dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        v.getLocationInWindow(loc);
4233e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        int vX = loc[0];
4243e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        int vY = loc[1];
425716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen
4263e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        int left = vX - x;
4273e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        int top = vY - y;
4283e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        r.set(left, top, left + v.getMeasuredWidth(), top + v.getMeasuredHeight());
429716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen    }
430716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen
431ea3763c2672f77539538af8cdd395ad97058eaabRomain Guy    @Override
432ea3763c2672f77539538af8cdd395ad97058eaabRomain Guy    public boolean dispatchUnhandledMove(View focused, int direction) {
433ea3763c2672f77539538af8cdd395ad97058eaabRomain Guy        return mDragController.dispatchUnhandledMove(focused, direction);
434ea3763c2672f77539538af8cdd395ad97058eaabRomain Guy    }
435120980bd00f5eecec5717f49a3d7db96571025a9Adam Cohen
4366788269814a678af976dfc7d6135993e172ce586Adam Cohen    public static class LayoutParams extends FrameLayout.LayoutParams {
4376788269814a678af976dfc7d6135993e172ce586Adam Cohen        public int x, y;
4386788269814a678af976dfc7d6135993e172ce586Adam Cohen        public boolean customPosition = false;
4396788269814a678af976dfc7d6135993e172ce586Adam Cohen
4406788269814a678af976dfc7d6135993e172ce586Adam Cohen        /**
4416788269814a678af976dfc7d6135993e172ce586Adam Cohen         * {@inheritDoc}
4426788269814a678af976dfc7d6135993e172ce586Adam Cohen         */
4436788269814a678af976dfc7d6135993e172ce586Adam Cohen        public LayoutParams(int width, int height) {
4446788269814a678af976dfc7d6135993e172ce586Adam Cohen            super(width, height);
4456788269814a678af976dfc7d6135993e172ce586Adam Cohen        }
4466788269814a678af976dfc7d6135993e172ce586Adam Cohen
4476788269814a678af976dfc7d6135993e172ce586Adam Cohen        public void setWidth(int width) {
4486788269814a678af976dfc7d6135993e172ce586Adam Cohen            this.width = width;
4496788269814a678af976dfc7d6135993e172ce586Adam Cohen        }
4506788269814a678af976dfc7d6135993e172ce586Adam Cohen
4516788269814a678af976dfc7d6135993e172ce586Adam Cohen        public int getWidth() {
4526788269814a678af976dfc7d6135993e172ce586Adam Cohen            return width;
4536788269814a678af976dfc7d6135993e172ce586Adam Cohen        }
4546788269814a678af976dfc7d6135993e172ce586Adam Cohen
4556788269814a678af976dfc7d6135993e172ce586Adam Cohen        public void setHeight(int height) {
4566788269814a678af976dfc7d6135993e172ce586Adam Cohen            this.height = height;
4576788269814a678af976dfc7d6135993e172ce586Adam Cohen        }
4586788269814a678af976dfc7d6135993e172ce586Adam Cohen
4596788269814a678af976dfc7d6135993e172ce586Adam Cohen        public int getHeight() {
4606788269814a678af976dfc7d6135993e172ce586Adam Cohen            return height;
4616788269814a678af976dfc7d6135993e172ce586Adam Cohen        }
4626788269814a678af976dfc7d6135993e172ce586Adam Cohen
4636788269814a678af976dfc7d6135993e172ce586Adam Cohen        public void setX(int x) {
4646788269814a678af976dfc7d6135993e172ce586Adam Cohen            this.x = x;
4656788269814a678af976dfc7d6135993e172ce586Adam Cohen        }
4666788269814a678af976dfc7d6135993e172ce586Adam Cohen
4676788269814a678af976dfc7d6135993e172ce586Adam Cohen        public int getX() {
4686788269814a678af976dfc7d6135993e172ce586Adam Cohen            return x;
4696788269814a678af976dfc7d6135993e172ce586Adam Cohen        }
4706788269814a678af976dfc7d6135993e172ce586Adam Cohen
4716788269814a678af976dfc7d6135993e172ce586Adam Cohen        public void setY(int y) {
4726788269814a678af976dfc7d6135993e172ce586Adam Cohen            this.y = y;
4736788269814a678af976dfc7d6135993e172ce586Adam Cohen        }
4746788269814a678af976dfc7d6135993e172ce586Adam Cohen
4756788269814a678af976dfc7d6135993e172ce586Adam Cohen        public int getY() {
4766788269814a678af976dfc7d6135993e172ce586Adam Cohen            return y;
4776788269814a678af976dfc7d6135993e172ce586Adam Cohen        }
4786788269814a678af976dfc7d6135993e172ce586Adam Cohen    }
4796788269814a678af976dfc7d6135993e172ce586Adam Cohen
4806788269814a678af976dfc7d6135993e172ce586Adam Cohen    protected void onLayout(boolean changed, int l, int t, int r, int b) {
4816788269814a678af976dfc7d6135993e172ce586Adam Cohen        super.onLayout(changed, l, t, r, b);
4826788269814a678af976dfc7d6135993e172ce586Adam Cohen        int count = getChildCount();
4836788269814a678af976dfc7d6135993e172ce586Adam Cohen        for (int i = 0; i < count; i++) {
4846788269814a678af976dfc7d6135993e172ce586Adam Cohen            View child = getChildAt(i);
4856788269814a678af976dfc7d6135993e172ce586Adam Cohen            final FrameLayout.LayoutParams flp = (FrameLayout.LayoutParams) child.getLayoutParams();
4866788269814a678af976dfc7d6135993e172ce586Adam Cohen            if (flp instanceof LayoutParams) {
4876788269814a678af976dfc7d6135993e172ce586Adam Cohen                final LayoutParams lp = (LayoutParams) flp;
4886788269814a678af976dfc7d6135993e172ce586Adam Cohen                if (lp.customPosition) {
4896788269814a678af976dfc7d6135993e172ce586Adam Cohen                    child.layout(lp.x, lp.y, lp.x + lp.width, lp.y + lp.height);
4906788269814a678af976dfc7d6135993e172ce586Adam Cohen                }
4916788269814a678af976dfc7d6135993e172ce586Adam Cohen            }
4926788269814a678af976dfc7d6135993e172ce586Adam Cohen        }
4936788269814a678af976dfc7d6135993e172ce586Adam Cohen    }
4946788269814a678af976dfc7d6135993e172ce586Adam Cohen
4956788269814a678af976dfc7d6135993e172ce586Adam Cohen    public void clearAllResizeFrames() {
4966788269814a678af976dfc7d6135993e172ce586Adam Cohen        if (mResizeFrames.size() > 0) {
4976788269814a678af976dfc7d6135993e172ce586Adam Cohen            for (AppWidgetResizeFrame frame: mResizeFrames) {
498bebf042666cffe52039b875a549a582abd78a431Adam Cohen                frame.commitResize();
4996788269814a678af976dfc7d6135993e172ce586Adam Cohen                removeView(frame);
5006788269814a678af976dfc7d6135993e172ce586Adam Cohen            }
5016788269814a678af976dfc7d6135993e172ce586Adam Cohen            mResizeFrames.clear();
5026788269814a678af976dfc7d6135993e172ce586Adam Cohen        }
5036788269814a678af976dfc7d6135993e172ce586Adam Cohen    }
5046788269814a678af976dfc7d6135993e172ce586Adam Cohen
5056788269814a678af976dfc7d6135993e172ce586Adam Cohen    public boolean hasResizeFrames() {
5066788269814a678af976dfc7d6135993e172ce586Adam Cohen        return mResizeFrames.size() > 0;
5076788269814a678af976dfc7d6135993e172ce586Adam Cohen    }
5086788269814a678af976dfc7d6135993e172ce586Adam Cohen
5096788269814a678af976dfc7d6135993e172ce586Adam Cohen    public boolean isWidgetBeingResized() {
5106788269814a678af976dfc7d6135993e172ce586Adam Cohen        return mCurrentResizeFrame != null;
5116788269814a678af976dfc7d6135993e172ce586Adam Cohen    }
5126788269814a678af976dfc7d6135993e172ce586Adam Cohen
5136788269814a678af976dfc7d6135993e172ce586Adam Cohen    public void addResizeFrame(ItemInfo itemInfo, LauncherAppWidgetHostView widget,
5146788269814a678af976dfc7d6135993e172ce586Adam Cohen            CellLayout cellLayout) {
5156788269814a678af976dfc7d6135993e172ce586Adam Cohen        AppWidgetResizeFrame resizeFrame = new AppWidgetResizeFrame(getContext(),
5163a9fcedbcd235372cd2ab64f825a0b5b3937f59eMichael Jurka                widget, cellLayout, this);
5176788269814a678af976dfc7d6135993e172ce586Adam Cohen
5186788269814a678af976dfc7d6135993e172ce586Adam Cohen        LayoutParams lp = new LayoutParams(-1, -1);
5196788269814a678af976dfc7d6135993e172ce586Adam Cohen        lp.customPosition = true;
5206788269814a678af976dfc7d6135993e172ce586Adam Cohen
5216788269814a678af976dfc7d6135993e172ce586Adam Cohen        addView(resizeFrame, lp);
5226788269814a678af976dfc7d6135993e172ce586Adam Cohen        mResizeFrames.add(resizeFrame);
5236788269814a678af976dfc7d6135993e172ce586Adam Cohen
5246788269814a678af976dfc7d6135993e172ce586Adam Cohen        resizeFrame.snapToWidget(false);
5256788269814a678af976dfc7d6135993e172ce586Adam Cohen    }
526716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen
527716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen    public void animateViewIntoPosition(DragView dragView, final View child) {
52828f852ab678d9750879b6d3549bf5da176cf1225Adam Cohen        animateViewIntoPosition(dragView, child, null, null);
529557d6ed50cc6560163440aa134870ef0bb11415bWinson Chung    }
530ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen
5317bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung    public void animateViewIntoPosition(DragView dragView, final int[] pos, float alpha,
5327bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung            float scaleX, float scaleY, int animationEndStyle, Runnable onFinishRunnable,
5337bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung            int duration) {
534b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen        Rect r = new Rect();
535b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen        getViewRectRelativeToSelf(dragView, r);
536b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen        final int fromX = r.left;
537b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen        final int fromY = r.top;
538b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen
5397bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung        animateViewIntoPosition(dragView, fromX, fromY, pos[0], pos[1], alpha, 1, 1, scaleX, scaleY,
540ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen                onFinishRunnable, animationEndStyle, duration, null);
541ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen    }
542ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen
543557d6ed50cc6560163440aa134870ef0bb11415bWinson Chung    public void animateViewIntoPosition(DragView dragView, final View child,
54428f852ab678d9750879b6d3549bf5da176cf1225Adam Cohen            final Runnable onFinishAnimationRunnable, View anchorView) {
54528f852ab678d9750879b6d3549bf5da176cf1225Adam Cohen        animateViewIntoPosition(dragView, child, -1, onFinishAnimationRunnable, anchorView);
546ed51cc9a12c50d12e7d30ed209a49f1a40858043Adam Cohen    }
547ed51cc9a12c50d12e7d30ed209a49f1a40858043Adam Cohen
548ed51cc9a12c50d12e7d30ed209a49f1a40858043Adam Cohen    public void animateViewIntoPosition(DragView dragView, final View child, int duration,
5496441de0ec2a71862798dd51180d0811b42edd514Adam Cohen            final Runnable onFinishAnimationRunnable, View anchorView) {
550a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        ShortcutAndWidgetContainer parentChildren = (ShortcutAndWidgetContainer) child.getParent();
551716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen        CellLayout.LayoutParams lp =  (CellLayout.LayoutParams) child.getLayoutParams();
552eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung        parentChildren.measureChild(child);
553716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen
5543e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        Rect r = new Rect();
5553e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        getViewRectRelativeToSelf(dragView, r);
556716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen
557716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen        int coord[] = new int[2];
558307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen        float childScale = child.getScaleX();
559307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen        coord[0] = lp.x + (int) (child.getMeasuredWidth() * (1 - childScale) / 2);
560307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen        coord[1] = lp.y + (int) (child.getMeasuredHeight() * (1 - childScale) / 2);
561eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung
5628dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        // Since the child hasn't necessarily been laid out, we force the lp to be updated with
563ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen        // the correct coordinates (above) and use these to determine the final location
564557d6ed50cc6560163440aa134870ef0bb11415bWinson Chung        float scale = getDescendantCoordRelativeToSelf((View) child.getParent(), coord);
565307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen        // We need to account for the scale of the child itself, as the above only accounts for
566307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen        // for the scale in parents.
567307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen        scale *= childScale;
568ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen        int toX = coord[0];
569ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen        int toY = coord[1];
570eeb5bbc9409978cc2ae52d48380399fcde3d9f85Winson Chung        float toScale = scale;
5714497ebf9a2726e2a7dbb7f3c49389308908f8454Andrew Flynn        if (child instanceof TextView) {
5724497ebf9a2726e2a7dbb7f3c49389308908f8454Andrew Flynn            TextView tv = (TextView) child;
573eeb5bbc9409978cc2ae52d48380399fcde3d9f85Winson Chung            // Account for the source scale of the icon (ie. from AllApps to Workspace, in which
574eeb5bbc9409978cc2ae52d48380399fcde3d9f85Winson Chung            // the workspace may have smaller icon bounds).
575eeb5bbc9409978cc2ae52d48380399fcde3d9f85Winson Chung            toScale = scale / dragView.getIntrinsicIconScaleFactor();
5764497ebf9a2726e2a7dbb7f3c49389308908f8454Andrew Flynn
5774497ebf9a2726e2a7dbb7f3c49389308908f8454Andrew Flynn            // The child may be scaled (always about the center of the view) so to account for it,
5784497ebf9a2726e2a7dbb7f3c49389308908f8454Andrew Flynn            // we have to offset the position by the scaled size.  Once we do that, we can center
5794497ebf9a2726e2a7dbb7f3c49389308908f8454Andrew Flynn            // the drag view about the scaled child view.
580eeb5bbc9409978cc2ae52d48380399fcde3d9f85Winson Chung            toY += Math.round(toScale * tv.getPaddingTop());
581eeb5bbc9409978cc2ae52d48380399fcde3d9f85Winson Chung            toY -= dragView.getMeasuredHeight() * (1 - toScale) / 2;
58295abbb330ce9bbaf23594245f0f8a795c8118038Sunny Goyal            if (dragView.getDragVisualizeOffset() != null) {
58395abbb330ce9bbaf23594245f0f8a795c8118038Sunny Goyal                toY -=  Math.round(toScale * dragView.getDragVisualizeOffset().y);
58495abbb330ce9bbaf23594245f0f8a795c8118038Sunny Goyal            }
58595abbb330ce9bbaf23594245f0f8a795c8118038Sunny Goyal
5864497ebf9a2726e2a7dbb7f3c49389308908f8454Andrew Flynn            toX -= (dragView.getMeasuredWidth() - Math.round(scale * child.getMeasuredWidth())) / 2;
5874497ebf9a2726e2a7dbb7f3c49389308908f8454Andrew Flynn        } else if (child instanceof FolderIcon) {
588ea359c6aee44c0fe3bb94f7002c3b49208b32b7fWinson Chung            // Account for holographic blur padding on the drag view
5895f8afe6280eae34620067696173e71943e1a30a3Winson Chung            toY += Math.round(scale * (child.getPaddingTop() - dragView.getDragRegionTop()));
590307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen            toY -= scale * Workspace.DRAG_BITMAP_PADDING / 2;
591307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen            toY -= (1 - scale) * dragView.getMeasuredHeight() / 2;
592ea359c6aee44c0fe3bb94f7002c3b49208b32b7fWinson Chung            // Center in the x coordinate about the target's drawable
593ea359c6aee44c0fe3bb94f7002c3b49208b32b7fWinson Chung            toX -= (dragView.getMeasuredWidth() - Math.round(scale * child.getMeasuredWidth())) / 2;
594ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen        } else {
595ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen            toY -= (Math.round(scale * (dragView.getHeight() - child.getMeasuredHeight()))) / 2;
596ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen            toX -= (Math.round(scale * (dragView.getMeasuredWidth()
597ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen                    - child.getMeasuredWidth()))) / 2;
598ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen        }
599716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen
600ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen        final int fromX = r.left;
601ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen        final int fromY = r.top;
602716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen        child.setVisibility(INVISIBLE);
6038dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        Runnable onCompleteRunnable = new Runnable() {
6048dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen            public void run() {
6058dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen                child.setVisibility(VISIBLE);
606d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                if (onFinishAnimationRunnable != null) {
607d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    onFinishAnimationRunnable.run();
608d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                }
6098dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen            }
6108dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        };
611eeb5bbc9409978cc2ae52d48380399fcde3d9f85Winson Chung        animateViewIntoPosition(dragView, fromX, fromY, toX, toY, 1, 1, 1, toScale, toScale,
612d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                onCompleteRunnable, ANIMATION_END_DISAPPEAR, duration, anchorView);
613557d6ed50cc6560163440aa134870ef0bb11415bWinson Chung    }
614557d6ed50cc6560163440aa134870ef0bb11415bWinson Chung
615d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen    public void animateViewIntoPosition(final DragView view, final int fromX, final int fromY,
616ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen            final int toX, final int toY, float finalAlpha, float initScaleX, float initScaleY,
617ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen            float finalScaleX, float finalScaleY, Runnable onCompleteRunnable,
618ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen            int animationEndStyle, int duration, View anchorView) {
6198dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        Rect from = new Rect(fromX, fromY, fromX +
6208dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen                view.getMeasuredWidth(), fromY + view.getMeasuredHeight());
6213e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        Rect to = new Rect(toX, toY, toX + view.getMeasuredWidth(), toY + view.getMeasuredHeight());
622ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen        animateView(view, from, to, finalAlpha, initScaleX, initScaleY, finalScaleX, finalScaleY, duration,
623ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen                null, null, onCompleteRunnable, animationEndStyle, anchorView);
6243e8f811f31a2275e778244427271f77f4116c08bAdam Cohen    }
6253e8f811f31a2275e778244427271f77f4116c08bAdam Cohen
626b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen    /**
627b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen     * This method animates a view at the end of a drag and drop animation.
628b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen     *
629b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen     * @param view The view to be animated. This view is drawn directly into DragLayer, and so
630b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen     *        doesn't need to be a child of DragLayer.
631b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen     * @param from The initial location of the view. Only the left and top parameters are used.
632b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen     * @param to The final location of the view. Only the left and top parameters are used. This
633b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen     *        location doesn't account for scaling, and so should be centered about the desired
634b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen     *        final location (including scaling).
635b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen     * @param finalAlpha The final alpha of the view, in case we want it to fade as it animates.
636b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen     * @param finalScale The final scale of the view. The view is scaled about its center.
637b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen     * @param duration The duration of the animation.
638b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen     * @param motionInterpolator The interpolator to use for the location of the view.
639b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen     * @param alphaInterpolator The interpolator to use for the alpha of the view.
640b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen     * @param onCompleteRunnable Optional runnable to run on animation completion.
641b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen     * @param fadeOut Whether or not to fade out the view once the animation completes. If true,
642b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen     *        the runnable will execute after the view is faded out.
6436441de0ec2a71862798dd51180d0811b42edd514Adam Cohen     * @param anchorView If not null, this represents the view which the animated view stays
6446441de0ec2a71862798dd51180d0811b42edd514Adam Cohen     *        anchored to in case scrolling is currently taking place. Note: currently this is
6456441de0ec2a71862798dd51180d0811b42edd514Adam Cohen     *        only used for the X dimension for the case of the workspace.
646b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen     */
6477bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung    public void animateView(final DragView view, final Rect from, final Rect to,
6487bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung            final float finalAlpha, final float initScaleX, final float initScaleY,
6497bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung            final float finalScaleX, final float finalScaleY, int duration,
6507bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung            final Interpolator motionInterpolator, final Interpolator alphaInterpolator,
6517bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung            final Runnable onCompleteRunnable, final int animationEndStyle, View anchorView) {
6527bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung
653716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen        // Calculate the duration of the animation based on the object's distance
6543e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        final float dist = (float) Math.sqrt(Math.pow(to.left - from.left, 2) +
6553e8f811f31a2275e778244427271f77f4116c08bAdam Cohen                Math.pow(to.top - from.top, 2));
656716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen        final Resources res = getResources();
657716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen        final float maxDist = (float) res.getInteger(R.integer.config_dropAnimMaxDist);
6583e8f811f31a2275e778244427271f77f4116c08bAdam Cohen
6593e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        // If duration < 0, this is a cue to compute the duration based on the distance
6603e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        if (duration < 0) {
6613e8f811f31a2275e778244427271f77f4116c08bAdam Cohen            duration = res.getInteger(R.integer.config_dropAnimMaxDuration);
6623e8f811f31a2275e778244427271f77f4116c08bAdam Cohen            if (dist < maxDist) {
6638dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen                duration *= mCubicEaseOutInterpolator.getInterpolation(dist / maxDist);
6643e8f811f31a2275e778244427271f77f4116c08bAdam Cohen            }
66561b0c69d3fe331d3de338322396d5de691d58613Winson Chung            duration = Math.max(duration, res.getInteger(R.integer.config_dropAnimMinDuration));
666716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen        }
667716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen
668043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        // Fall back to cubic ease out interpolator for the animation if none is specified
669043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        TimeInterpolator interpolator = null;
6703e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        if (alphaInterpolator == null || motionInterpolator == null) {
671043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung            interpolator = mCubicEaseOutInterpolator;
6723e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        }
673716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen
674043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        // Animate the view
6757bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung        final float initAlpha = view.getAlpha();
676043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        final float dropViewScale = view.getScaleX();
677043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        AnimatorUpdateListener updateCb = new AnimatorUpdateListener() {
678043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung            @Override
679716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen            public void onAnimationUpdate(ValueAnimator animation) {
680716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen                final float percent = (Float) animation.getAnimatedValue();
6817bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung                final int width = view.getMeasuredWidth();
6827bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung                final int height = view.getMeasuredHeight();
683716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen
6843e8f811f31a2275e778244427271f77f4116c08bAdam Cohen                float alphaPercent = alphaInterpolator == null ? percent :
6853e8f811f31a2275e778244427271f77f4116c08bAdam Cohen                        alphaInterpolator.getInterpolation(percent);
6863e8f811f31a2275e778244427271f77f4116c08bAdam Cohen                float motionPercent = motionInterpolator == null ? percent :
6873e8f811f31a2275e778244427271f77f4116c08bAdam Cohen                        motionInterpolator.getInterpolation(percent);
688a1cdab039292f3d809528c0e2e38580b37864d8dWinson Chung
6897bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung                float initialScaleX = initScaleX * dropViewScale;
6907bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung                float initialScaleY = initScaleY * dropViewScale;
6917bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung                float scaleX = finalScaleX * percent + initialScaleX * (1 - percent);
6927bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung                float scaleY = finalScaleY * percent + initialScaleY * (1 - percent);
6937bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung                float alpha = finalAlpha * alphaPercent + initAlpha * (1 - alphaPercent);
6947bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung
6957bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung                float fromLeft = from.left + (initialScaleX - 1f) * width / 2;
6967bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung                float fromTop = from.top + (initialScaleY - 1f) * height / 2;
6977bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung
6987bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung                int x = (int) (fromLeft + Math.round(((to.left - fromLeft) * motionPercent)));
6997bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung                int y = (int) (fromTop + Math.round(((to.top - fromTop) * motionPercent)));
7007bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung
70128f852ab678d9750879b6d3549bf5da176cf1225Adam Cohen                int anchorAdjust = mAnchorView == null ? 0 : (int) (mAnchorView.getScaleX() *
70228f852ab678d9750879b6d3549bf5da176cf1225Adam Cohen                    (mAnchorViewInitialScrollX - mAnchorView.getScrollX()));
70328f852ab678d9750879b6d3549bf5da176cf1225Adam Cohen
70428f852ab678d9750879b6d3549bf5da176cf1225Adam Cohen                int xPos = x - mDropView.getScrollX() + anchorAdjust;
7057bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung                int yPos = y - mDropView.getScrollY();
7067bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung
7077bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung                mDropView.setTranslationX(xPos);
7087bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung                mDropView.setTranslationY(yPos);
7097bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung                mDropView.setScaleX(scaleX);
7107bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung                mDropView.setScaleY(scaleY);
7117bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung                mDropView.setAlpha(alpha);
712716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen            }
713043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        };
714043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        animateView(view, updateCb, duration, interpolator, onCompleteRunnable, animationEndStyle,
715043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung                anchorView);
716043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung    }
717043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung
718043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung    public void animateView(final DragView view, AnimatorUpdateListener updateCb, int duration,
719043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung            TimeInterpolator interpolator, final Runnable onCompleteRunnable,
720043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung            final int animationEndStyle, View anchorView) {
721043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        // Clean up the previous animations
722043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        if (mDropAnim != null) mDropAnim.cancel();
723043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        if (mFadeOutAnim != null) mFadeOutAnim.cancel();
724043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung
725043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        // Show the drop view if it was previously hidden
726043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        mDropView = view;
727043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        mDropView.cancelAnimation();
728043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        mDropView.resetLayoutParams();
729043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung
730043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        // Set the anchor view if the page is scrolling
731043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        if (anchorView != null) {
732043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung            mAnchorViewInitialScrollX = anchorView.getScrollX();
733043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        }
734043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        mAnchorView = anchorView;
735043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung
736043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        // Create and start the animation
737043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        mDropAnim = new ValueAnimator();
738043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        mDropAnim.setInterpolator(interpolator);
739043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        mDropAnim.setDuration(duration);
740043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        mDropAnim.setFloatValues(0f, 1f);
741043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        mDropAnim.addUpdateListener(updateCb);
7423e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        mDropAnim.addListener(new AnimatorListenerAdapter() {
7433e8f811f31a2275e778244427271f77f4116c08bAdam Cohen            public void onAnimationEnd(Animator animation) {
7448dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen                if (onCompleteRunnable != null) {
7458dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen                    onCompleteRunnable.run();
7468dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen                }
747ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen                switch (animationEndStyle) {
748ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen                case ANIMATION_END_DISAPPEAR:
749ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen                    clearAnimatedView();
750ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen                    break;
751ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen                case ANIMATION_END_FADE_OUT:
7528dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen                    fadeOutDragView();
753ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen                    break;
754ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen                case ANIMATION_END_REMAIN_VISIBLE:
755ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen                    break;
7563e8f811f31a2275e778244427271f77f4116c08bAdam Cohen                }
7573e8f811f31a2275e778244427271f77f4116c08bAdam Cohen            }
7583e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        });
759716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen        mDropAnim.start();
760716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen    }
761716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen
762ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen    public void clearAnimatedView() {
7637bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung        if (mDropAnim != null) {
7647bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung            mDropAnim.cancel();
7657bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung        }
7667bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung        if (mDropView != null) {
7672d783ce2f4b2e507bead0d723f0edcdf902dbd46Adam Cohen            mDragController.onDeferredEndDrag(mDropView);
7687bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung        }
769ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen        mDropView = null;
770ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen        invalidate();
771ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen    }
772ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen
773ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen    public View getAnimatedView() {
774ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen        return mDropView;
775ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen    }
776ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen
7778dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen    private void fadeOutDragView() {
7788dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        mFadeOutAnim = new ValueAnimator();
7798dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        mFadeOutAnim.setDuration(150);
7808dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        mFadeOutAnim.setFloatValues(0f, 1f);
7818dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        mFadeOutAnim.removeAllUpdateListeners();
7828dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        mFadeOutAnim.addUpdateListener(new AnimatorUpdateListener() {
7838dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen            public void onAnimationUpdate(ValueAnimator animation) {
7848dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen                final float percent = (Float) animation.getAnimatedValue();
7857bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung
7867bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung                float alpha = 1 - percent;
7877bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung                mDropView.setAlpha(alpha);
7888dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen            }
7898dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        });
7908dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        mFadeOutAnim.addListener(new AnimatorListenerAdapter() {
7918dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen            public void onAnimationEnd(Animator animation) {
7927bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung                if (mDropView != null) {
793043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung                    mDragController.onDeferredEndDrag(mDropView);
7947bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung                }
7958dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen                mDropView = null;
796ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen                invalidate();
7978dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen            }
7988dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        });
7998dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        mFadeOutAnim.start();
8008dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen    }
8018dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen
802716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen    @Override
8038b805b17158886035b38261eb611d8641701ae43Michael Jurka    public void onChildViewAdded(View parent, View child) {
804b670f195ffb7b4a0519fd0b337b68f7412159414Adam Cohen        if (mOverlayView != null) {
805b670f195ffb7b4a0519fd0b337b68f7412159414Adam Cohen            // ensure that the overlay view stays on top. we can't use drawing order for this
806b670f195ffb7b4a0519fd0b337b68f7412159414Adam Cohen            // because in API level 16 touch dispatch doesn't respect drawing order.
807b670f195ffb7b4a0519fd0b337b68f7412159414Adam Cohen            mOverlayView.bringToFront();
808b670f195ffb7b4a0519fd0b337b68f7412159414Adam Cohen        }
80921b411074e39fd10cbc8dd0220bb159da4af2c76Adam Cohen        updateChildIndices();
81021b411074e39fd10cbc8dd0220bb159da4af2c76Adam Cohen    }
81121b411074e39fd10cbc8dd0220bb159da4af2c76Adam Cohen
81221b411074e39fd10cbc8dd0220bb159da4af2c76Adam Cohen    @Override
8138b805b17158886035b38261eb611d8641701ae43Michael Jurka    public void onChildViewRemoved(View parent, View child) {
81421b411074e39fd10cbc8dd0220bb159da4af2c76Adam Cohen        updateChildIndices();
81521b411074e39fd10cbc8dd0220bb159da4af2c76Adam Cohen    }
81621b411074e39fd10cbc8dd0220bb159da4af2c76Adam Cohen
817432609a246819f3cf887a80c2ae56b61fc5ca25aAdam Cohen    @Override
818432609a246819f3cf887a80c2ae56b61fc5ca25aAdam Cohen    public void bringChildToFront(View child) {
819432609a246819f3cf887a80c2ae56b61fc5ca25aAdam Cohen        super.bringChildToFront(child);
820b670f195ffb7b4a0519fd0b337b68f7412159414Adam Cohen        if (child != mOverlayView && mOverlayView != null) {
821b670f195ffb7b4a0519fd0b337b68f7412159414Adam Cohen            // ensure that the overlay view stays on top. we can't use drawing order for this
822b670f195ffb7b4a0519fd0b337b68f7412159414Adam Cohen            // because in API level 16 touch dispatch doesn't respect drawing order.
823b670f195ffb7b4a0519fd0b337b68f7412159414Adam Cohen            mOverlayView.bringToFront();
824b670f195ffb7b4a0519fd0b337b68f7412159414Adam Cohen        }
825432609a246819f3cf887a80c2ae56b61fc5ca25aAdam Cohen        updateChildIndices();
826432609a246819f3cf887a80c2ae56b61fc5ca25aAdam Cohen    }
827432609a246819f3cf887a80c2ae56b61fc5ca25aAdam Cohen
82821b411074e39fd10cbc8dd0220bb159da4af2c76Adam Cohen    private void updateChildIndices() {
829432609a246819f3cf887a80c2ae56b61fc5ca25aAdam Cohen        mTopViewIndex = -1;
83055bd9725d5c0373b89f7b9bbd9547550ea3bbc63Jorim Jaggi        int childCount = getChildCount();
83155bd9725d5c0373b89f7b9bbd9547550ea3bbc63Jorim Jaggi        for (int i = 0; i < childCount; i++) {
832b670f195ffb7b4a0519fd0b337b68f7412159414Adam Cohen            if (getChildAt(i) instanceof DragView) {
833432609a246819f3cf887a80c2ae56b61fc5ca25aAdam Cohen                mTopViewIndex = i;
83455bd9725d5c0373b89f7b9bbd9547550ea3bbc63Jorim Jaggi            }
83521b411074e39fd10cbc8dd0220bb159da4af2c76Adam Cohen        }
8362d783ce2f4b2e507bead0d723f0edcdf902dbd46Adam Cohen        mChildCountOnLastUpdate = childCount;
83721b411074e39fd10cbc8dd0220bb159da4af2c76Adam Cohen    }
83821b411074e39fd10cbc8dd0220bb159da4af2c76Adam Cohen
83921b411074e39fd10cbc8dd0220bb159da4af2c76Adam Cohen    @Override
84021b411074e39fd10cbc8dd0220bb159da4af2c76Adam Cohen    protected int getChildDrawingOrder(int childCount, int i) {
8412d783ce2f4b2e507bead0d723f0edcdf902dbd46Adam Cohen        if (mChildCountOnLastUpdate != childCount) {
8422d783ce2f4b2e507bead0d723f0edcdf902dbd46Adam Cohen            // between platform versions 17 and 18, behavior for onChildViewRemoved / Added changed.
8432d783ce2f4b2e507bead0d723f0edcdf902dbd46Adam Cohen            // Pre-18, the child was not added / removed by the time of those callbacks. We need to
8442d783ce2f4b2e507bead0d723f0edcdf902dbd46Adam Cohen            // force update our representation of things here to avoid crashing on pre-18 devices
8452d783ce2f4b2e507bead0d723f0edcdf902dbd46Adam Cohen            // in certain instances.
8462d783ce2f4b2e507bead0d723f0edcdf902dbd46Adam Cohen            updateChildIndices();
8472d783ce2f4b2e507bead0d723f0edcdf902dbd46Adam Cohen        }
8482d783ce2f4b2e507bead0d723f0edcdf902dbd46Adam Cohen
849432609a246819f3cf887a80c2ae56b61fc5ca25aAdam Cohen        // i represents the current draw iteration
850432609a246819f3cf887a80c2ae56b61fc5ca25aAdam Cohen        if (mTopViewIndex == -1) {
851432609a246819f3cf887a80c2ae56b61fc5ca25aAdam Cohen            // in general we do nothing
85221b411074e39fd10cbc8dd0220bb159da4af2c76Adam Cohen            return i;
853432609a246819f3cf887a80c2ae56b61fc5ca25aAdam Cohen        } else if (i == childCount - 1) {
854432609a246819f3cf887a80c2ae56b61fc5ca25aAdam Cohen            // if we have a top index, we return it when drawing last item (highest z-order)
855432609a246819f3cf887a80c2ae56b61fc5ca25aAdam Cohen            return mTopViewIndex;
856432609a246819f3cf887a80c2ae56b61fc5ca25aAdam Cohen        } else if (i < mTopViewIndex) {
85721b411074e39fd10cbc8dd0220bb159da4af2c76Adam Cohen            return i;
85855bd9725d5c0373b89f7b9bbd9547550ea3bbc63Jorim Jaggi        } else {
859432609a246819f3cf887a80c2ae56b61fc5ca25aAdam Cohen            // for indexes greater than the top index, we fetch one item above to shift for the
860432609a246819f3cf887a80c2ae56b61fc5ca25aAdam Cohen            // displacement of the top index
861432609a246819f3cf887a80c2ae56b61fc5ca25aAdam Cohen            return i + 1;
86221b411074e39fd10cbc8dd0220bb159da4af2c76Adam Cohen        }
86321b411074e39fd10cbc8dd0220bb159da4af2c76Adam Cohen    }
864360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung
865360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung    void onEnterScrollArea(int direction) {
866360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung        mInScrollArea = true;
867360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung        invalidate();
868360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung    }
869360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung
870360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung    void onExitScrollArea() {
871360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung        mInScrollArea = false;
872360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung        invalidate();
873360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung    }
874360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung
875c50438c802355dff714b04f42a32e518cb9e91d8Adam Cohen    void showPageHints() {
876c50438c802355dff714b04f42a32e518cb9e91d8Adam Cohen        mShowPageHints = true;
877c50438c802355dff714b04f42a32e518cb9e91d8Adam Cohen        invalidate();
878c50438c802355dff714b04f42a32e518cb9e91d8Adam Cohen    }
879c50438c802355dff714b04f42a32e518cb9e91d8Adam Cohen
880c50438c802355dff714b04f42a32e518cb9e91d8Adam Cohen    void hidePageHints() {
881c50438c802355dff714b04f42a32e518cb9e91d8Adam Cohen        mShowPageHints = false;
882c50438c802355dff714b04f42a32e518cb9e91d8Adam Cohen        invalidate();
883c50438c802355dff714b04f42a32e518cb9e91d8Adam Cohen    }
884c50438c802355dff714b04f42a32e518cb9e91d8Adam Cohen
885fe1fe268b6d9ffd99218117795b3524a87e5110bWinson Chung    /**
886fe1fe268b6d9ffd99218117795b3524a87e5110bWinson Chung     * Note: this is a reimplementation of View.isLayoutRtl() since that is currently hidden api.
887fe1fe268b6d9ffd99218117795b3524a87e5110bWinson Chung     */
888fe1fe268b6d9ffd99218117795b3524a87e5110bWinson Chung    private boolean isLayoutRtl() {
889fe1fe268b6d9ffd99218117795b3524a87e5110bWinson Chung        return (getLayoutDirection() == LAYOUT_DIRECTION_RTL);
890fe1fe268b6d9ffd99218117795b3524a87e5110bWinson Chung    }
891fe1fe268b6d9ffd99218117795b3524a87e5110bWinson Chung
892360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung    @Override
893360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung    protected void dispatchDraw(Canvas canvas) {
8946c5891a9fce95eee3d87823d11d21889743e9c68Adam Cohen        // Draw the background gradient below children.
8956c5891a9fce95eee3d87823d11d21889743e9c68Adam Cohen        if (mBackground != null && mBackgroundAlpha > 0.0f) {
8966c5891a9fce95eee3d87823d11d21889743e9c68Adam Cohen            int alpha = (int) (mBackgroundAlpha * 255);
8976c5891a9fce95eee3d87823d11d21889743e9c68Adam Cohen            mBackground.setAlpha(alpha);
8986c5891a9fce95eee3d87823d11d21889743e9c68Adam Cohen            mBackground.setBounds(0, 0, getMeasuredWidth(), getMeasuredHeight());
8996c5891a9fce95eee3d87823d11d21889743e9c68Adam Cohen            mBackground.draw(canvas);
9006c5891a9fce95eee3d87823d11d21889743e9c68Adam Cohen        }
9016c5891a9fce95eee3d87823d11d21889743e9c68Adam Cohen
902360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung        super.dispatchDraw(canvas);
9038cc05507150fea5282b7581e1a268967a702bcc9Adam Cohen    }
904360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung
9058cc05507150fea5282b7581e1a268967a702bcc9Adam Cohen    private void drawPageHints(Canvas canvas) {
906c50438c802355dff714b04f42a32e518cb9e91d8Adam Cohen        if (mShowPageHints) {
907360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung            Workspace workspace = mLauncher.getWorkspace();
90861a9a5c359e3e14cb1beaf43dbdb54e00911fe80Adam Cohen            int width = getMeasuredWidth();
909360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung            Rect childRect = new Rect();
910c50438c802355dff714b04f42a32e518cb9e91d8Adam Cohen            getDescendantRectRelativeToSelf(workspace.getChildAt(workspace.getChildCount() - 1),
911c50438c802355dff714b04f42a32e518cb9e91d8Adam Cohen                    childRect);
912360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung
913360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung            int page = workspace.getNextPage();
914fe1fe268b6d9ffd99218117795b3524a87e5110bWinson Chung            final boolean isRtl = isLayoutRtl();
915fe1fe268b6d9ffd99218117795b3524a87e5110bWinson Chung            CellLayout leftPage = (CellLayout) workspace.getChildAt(isRtl ? page + 1 : page - 1);
916fe1fe268b6d9ffd99218117795b3524a87e5110bWinson Chung            CellLayout rightPage = (CellLayout) workspace.getChildAt(isRtl ? page - 1 : page + 1);
917360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung
918c50438c802355dff714b04f42a32e518cb9e91d8Adam Cohen            if (leftPage != null && leftPage.isDragTarget()) {
919c50438c802355dff714b04f42a32e518cb9e91d8Adam Cohen                Drawable left = mInScrollArea && leftPage.getIsDragOverlapping() ?
920c50438c802355dff714b04f42a32e518cb9e91d8Adam Cohen                        mLeftHoverDrawableActive : mLeftHoverDrawable;
921c50438c802355dff714b04f42a32e518cb9e91d8Adam Cohen                left.setBounds(0, childRect.top,
922c50438c802355dff714b04f42a32e518cb9e91d8Adam Cohen                        left.getIntrinsicWidth(), childRect.bottom);
923c50438c802355dff714b04f42a32e518cb9e91d8Adam Cohen                left.draw(canvas);
924c50438c802355dff714b04f42a32e518cb9e91d8Adam Cohen            }
925c50438c802355dff714b04f42a32e518cb9e91d8Adam Cohen            if (rightPage != null && rightPage.isDragTarget()) {
926c50438c802355dff714b04f42a32e518cb9e91d8Adam Cohen                Drawable right = mInScrollArea && rightPage.getIsDragOverlapping() ?
927c50438c802355dff714b04f42a32e518cb9e91d8Adam Cohen                        mRightHoverDrawableActive : mRightHoverDrawable;
928c50438c802355dff714b04f42a32e518cb9e91d8Adam Cohen                right.setBounds(width - right.getIntrinsicWidth(),
929360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung                        childRect.top, width, childRect.bottom);
930c50438c802355dff714b04f42a32e518cb9e91d8Adam Cohen                right.draw(canvas);
931360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung            }
932360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung        }
933360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung    }
934b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen
9358cc05507150fea5282b7581e1a268967a702bcc9Adam Cohen    protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
9368cc05507150fea5282b7581e1a268967a702bcc9Adam Cohen        boolean ret = super.drawChild(canvas, child, drawingTime);
9378cc05507150fea5282b7581e1a268967a702bcc9Adam Cohen
9388cc05507150fea5282b7581e1a268967a702bcc9Adam Cohen        // We want to draw the page hints above the workspace, but below the drag view.
9398cc05507150fea5282b7581e1a268967a702bcc9Adam Cohen        if (child instanceof Workspace) {
9408cc05507150fea5282b7581e1a268967a702bcc9Adam Cohen            drawPageHints(canvas);
9418cc05507150fea5282b7581e1a268967a702bcc9Adam Cohen        }
9428cc05507150fea5282b7581e1a268967a702bcc9Adam Cohen        return ret;
9438cc05507150fea5282b7581e1a268967a702bcc9Adam Cohen    }
9448cc05507150fea5282b7581e1a268967a702bcc9Adam Cohen
9456c5891a9fce95eee3d87823d11d21889743e9c68Adam Cohen    public void setBackgroundAlpha(float alpha) {
9466c5891a9fce95eee3d87823d11d21889743e9c68Adam Cohen        if (alpha != mBackgroundAlpha) {
9476c5891a9fce95eee3d87823d11d21889743e9c68Adam Cohen            mBackgroundAlpha = alpha;
9486c5891a9fce95eee3d87823d11d21889743e9c68Adam Cohen            invalidate();
9496c5891a9fce95eee3d87823d11d21889743e9c68Adam Cohen        }
9506c5891a9fce95eee3d87823d11d21889743e9c68Adam Cohen    }
9516c5891a9fce95eee3d87823d11d21889743e9c68Adam Cohen
9526c5891a9fce95eee3d87823d11d21889743e9c68Adam Cohen    public float getBackgroundAlpha() {
9536c5891a9fce95eee3d87823d11d21889743e9c68Adam Cohen        return mBackgroundAlpha;
9546c5891a9fce95eee3d87823d11d21889743e9c68Adam Cohen    }
9556c5891a9fce95eee3d87823d11d21889743e9c68Adam Cohen
956b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen    public void setTouchCompleteListener(TouchCompleteListener listener) {
957b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen        mTouchCompleteListener = listener;
958b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen    }
959b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen
960b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen    public interface TouchCompleteListener {
961b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen        public void onTouchComplete();
962b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen    }
96331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project}
964