DragLayer.java revision f7a29e83f06909b378dba39c83a522375682710a
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
41bc927f9c24001e250622ca9a2547ee5b65baef58Adam Cohenimport com.android.launcher3.InsettableFrameLayout.LayoutParams;
42091440a9cb9d4f42406631004aa484cbb79214caAdam Cohenimport com.android.launcher3.util.Thunk;
43bc927f9c24001e250622ca9a2547ee5b65baef58Adam Cohen
441d9af7d1e75bad13bb10ad37f5900ed59882622eAdam Cohenimport java.util.ArrayList;
456788269814a678af976dfc7d6135993e172ce586Adam Cohen
4631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project/**
470e26059548e429e5d1c973bebe4c561bead2926fMichael Jurka * A ViewGroup that coordinates dragging across its descendants
4831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project */
49a6d0492e5f0dd4e1b43d4034a770241dc65f8f8cAdam Cohenpublic class DragLayer extends InsettableFrameLayout {
50091440a9cb9d4f42406631004aa484cbb79214caAdam Cohen    @Thunk DragController mDragController;
51120980bd00f5eecec5717f49a3d7db96571025a9Adam Cohen    private int[] mTmpXY = new int[2];
5231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
53716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen    private int mXDown, mYDown;
54716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen    private Launcher mLauncher;
55716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen
566788269814a678af976dfc7d6135993e172ce586Adam Cohen    // Variables relating to resizing widgets
576788269814a678af976dfc7d6135993e172ce586Adam Cohen    private final ArrayList<AppWidgetResizeFrame> mResizeFrames =
586788269814a678af976dfc7d6135993e172ce586Adam Cohen            new ArrayList<AppWidgetResizeFrame>();
596788269814a678af976dfc7d6135993e172ce586Adam Cohen    private AppWidgetResizeFrame mCurrentResizeFrame;
60716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen
61716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen    // Variables relating to animation of views after drop
62716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen    private ValueAnimator mDropAnim = null;
638dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen    private ValueAnimator mFadeOutAnim = null;
648dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen    private TimeInterpolator mCubicEaseOutInterpolator = new DecelerateInterpolator(1.5f);
65091440a9cb9d4f42406631004aa484cbb79214caAdam Cohen    @Thunk DragView mDropView = null;
66091440a9cb9d4f42406631004aa484cbb79214caAdam Cohen    @Thunk int mAnchorViewInitialScrollX = 0;
67091440a9cb9d4f42406631004aa484cbb79214caAdam Cohen    @Thunk View mAnchorView = null;
688dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen
693371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen    private boolean mHoverPointClosesFolder = false;
703371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen    private Rect mHitRect = new Rect();
71ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen    public static final int ANIMATION_END_DISAPPEAR = 0;
72ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen    public static final int ANIMATION_END_FADE_OUT = 1;
73ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen    public static final int ANIMATION_END_REMAIN_VISIBLE = 2;
746788269814a678af976dfc7d6135993e172ce586Adam Cohen
75b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen    private TouchCompleteListener mTouchCompleteListener;
76b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen
77432609a246819f3cf887a80c2ae56b61fc5ca25aAdam Cohen    private View mOverlayView;
78432609a246819f3cf887a80c2ae56b61fc5ca25aAdam Cohen    private int mTopViewIndex;
792d783ce2f4b2e507bead0d723f0edcdf902dbd46Adam Cohen    private int mChildCountOnLastUpdate = -1;
8055bd9725d5c0373b89f7b9bbd9547550ea3bbc63Jorim Jaggi
816c5891a9fce95eee3d87823d11d21889743e9c68Adam Cohen    // Darkening scrim
826c5891a9fce95eee3d87823d11d21889743e9c68Adam Cohen    private Drawable mBackground;
836c5891a9fce95eee3d87823d11d21889743e9c68Adam Cohen    private float mBackgroundAlpha = 0;
846c5891a9fce95eee3d87823d11d21889743e9c68Adam Cohen
858cc05507150fea5282b7581e1a268967a702bcc9Adam Cohen    // Related to adjacent page hints
868cc05507150fea5282b7581e1a268967a702bcc9Adam Cohen    private boolean mInScrollArea;
878cc05507150fea5282b7581e1a268967a702bcc9Adam Cohen    private boolean mShowPageHints;
888cc05507150fea5282b7581e1a268967a702bcc9Adam Cohen    private Drawable mLeftHoverDrawable;
898cc05507150fea5282b7581e1a268967a702bcc9Adam Cohen    private Drawable mRightHoverDrawable;
908cc05507150fea5282b7581e1a268967a702bcc9Adam Cohen    private Drawable mLeftHoverDrawableActive;
918cc05507150fea5282b7581e1a268967a702bcc9Adam Cohen    private Drawable mRightHoverDrawableActive;
928cc05507150fea5282b7581e1a268967a702bcc9Adam Cohen
93c2d6e897dbcb96b7b629e42002966368fbda2f95Adam Cohen    private boolean mBlockTouches = false;
94c2d6e897dbcb96b7b629e42002966368fbda2f95Adam Cohen
9531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    /**
9631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * Used to create a new DragLayer from XML.
9731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     *
9831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param context The application's context.
990e26059548e429e5d1c973bebe4c561bead2926fMichael Jurka     * @param attrs The attributes set containing the Workspace's customization values.
10031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     */
10131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    public DragLayer(Context context, AttributeSet attrs) {
10231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        super(context, attrs);
103be62afa34d58edab0fc9ba7499f0dd543039c903Winson Chung
104be62afa34d58edab0fc9ba7499f0dd543039c903Winson Chung        // Disable multitouch across the workspace/all apps/customize tray
105be62afa34d58edab0fc9ba7499f0dd543039c903Winson Chung        setMotionEventSplittingEnabled(false);
10621b411074e39fd10cbc8dd0220bb159da4af2c76Adam Cohen        setChildrenDrawingOrderEnabled(true);
107360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung
1086c5891a9fce95eee3d87823d11d21889743e9c68Adam Cohen        final Resources res = getResources();
109c50438c802355dff714b04f42a32e518cb9e91d8Adam Cohen        mLeftHoverDrawable = res.getDrawable(R.drawable.page_hover_left);
110c50438c802355dff714b04f42a32e518cb9e91d8Adam Cohen        mRightHoverDrawable = res.getDrawable(R.drawable.page_hover_right);
111c50438c802355dff714b04f42a32e518cb9e91d8Adam Cohen        mLeftHoverDrawableActive = res.getDrawable(R.drawable.page_hover_left_active);
112c50438c802355dff714b04f42a32e518cb9e91d8Adam Cohen        mRightHoverDrawableActive = res.getDrawable(R.drawable.page_hover_right_active);
1136c5891a9fce95eee3d87823d11d21889743e9c68Adam Cohen        mBackground = res.getDrawable(R.drawable.apps_customize_bg);
11431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
11531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
1164c98d9235d164680186180974719f551cf935d08Winson Chung    public void setup(Launcher launcher, DragController controller) {
1174c98d9235d164680186180974719f551cf935d08Winson Chung        mLauncher = launcher;
11800acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato        mDragController = controller;
11931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
12076fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen
12131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    @Override
12231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    public boolean dispatchKeyEvent(KeyEvent event) {
12300acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato        return mDragController.dispatchKeyEvent(event) || super.dispatchKeyEvent(event);
12431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
12531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
126b670f195ffb7b4a0519fd0b337b68f7412159414Adam Cohen    public void showOverlayView(View overlayView) {
127432609a246819f3cf887a80c2ae56b61fc5ca25aAdam Cohen        LayoutParams lp = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
128b670f195ffb7b4a0519fd0b337b68f7412159414Adam Cohen        mOverlayView = overlayView;
129b670f195ffb7b4a0519fd0b337b68f7412159414Adam Cohen        addView(overlayView, lp);
130b670f195ffb7b4a0519fd0b337b68f7412159414Adam Cohen
131b670f195ffb7b4a0519fd0b337b68f7412159414Adam Cohen        // ensure that the overlay view stays on top. we can't use drawing order for this
132b670f195ffb7b4a0519fd0b337b68f7412159414Adam Cohen        // because in API level 16 touch dispatch doesn't respect drawing order.
133b670f195ffb7b4a0519fd0b337b68f7412159414Adam Cohen        mOverlayView.bringToFront();
134432609a246819f3cf887a80c2ae56b61fc5ca25aAdam Cohen    }
135432609a246819f3cf887a80c2ae56b61fc5ca25aAdam Cohen
136432609a246819f3cf887a80c2ae56b61fc5ca25aAdam Cohen    public void dismissOverlayView() {
137432609a246819f3cf887a80c2ae56b61fc5ca25aAdam Cohen        removeView(mOverlayView);
138432609a246819f3cf887a80c2ae56b61fc5ca25aAdam Cohen    }
139432609a246819f3cf887a80c2ae56b61fc5ca25aAdam Cohen
1403371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen    private boolean isEventOverFolderTextRegion(Folder folder, MotionEvent ev) {
1413371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen        getDescendantRectRelativeToSelf(folder.getEditTextRegion(), mHitRect);
1423371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen        if (mHitRect.contains((int) ev.getX(), (int) ev.getY())) {
1433371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen            return true;
1443371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen        }
1453371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen        return false;
1463371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen    }
1473371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen
1483371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen    private boolean isEventOverFolder(Folder folder, MotionEvent ev) {
1493371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen        getDescendantRectRelativeToSelf(folder, 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
156c2d6e897dbcb96b7b629e42002966368fbda2f95Adam Cohen    public void setBlockTouch(boolean block) {
157c2d6e897dbcb96b7b629e42002966368fbda2f95Adam Cohen        mBlockTouches = block;
158c2d6e897dbcb96b7b629e42002966368fbda2f95Adam Cohen    }
159c2d6e897dbcb96b7b629e42002966368fbda2f95Adam Cohen
16076fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen    private boolean handleTouchDown(MotionEvent ev, boolean intercept) {
1616788269814a678af976dfc7d6135993e172ce586Adam Cohen        Rect hitRect = new Rect();
1626788269814a678af976dfc7d6135993e172ce586Adam Cohen        int x = (int) ev.getX();
1636788269814a678af976dfc7d6135993e172ce586Adam Cohen        int y = (int) ev.getY();
1646788269814a678af976dfc7d6135993e172ce586Adam Cohen
165c2d6e897dbcb96b7b629e42002966368fbda2f95Adam Cohen        if (mBlockTouches) {
166c2d6e897dbcb96b7b629e42002966368fbda2f95Adam Cohen            return true;
167c2d6e897dbcb96b7b629e42002966368fbda2f95Adam Cohen        }
168c2d6e897dbcb96b7b629e42002966368fbda2f95Adam 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();
183424418bb50ccf5d9270650b70cc51f423da51a65Sunny Goyal        if (currentFolder != null && intercept) {
1841d9af7d1e75bad13bb10ad37f5900ed59882622eAdam Cohen            if (currentFolder.isEditingName()) {
1853371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                if (!isEventOverFolderTextRegion(currentFolder, ev)) {
1861d9af7d1e75bad13bb10ad37f5900ed59882622eAdam Cohen                    currentFolder.dismissEditingName();
18776fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen                    return true;
1882801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen                }
1892801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen            }
19076fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen
1911d9af7d1e75bad13bb10ad37f5900ed59882622eAdam Cohen            getDescendantRectRelativeToSelf(currentFolder, hitRect);
1923371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen            if (!isEventOverFolder(currentFolder, ev)) {
19376fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen                mLauncher.closeFolder();
19476fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen                return true;
19576fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen            }
1962801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen        }
1976788269814a678af976dfc7d6135993e172ce586Adam Cohen        return false;
1986788269814a678af976dfc7d6135993e172ce586Adam Cohen    }
1996788269814a678af976dfc7d6135993e172ce586Adam Cohen
20031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    @Override
20131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    public boolean onInterceptTouchEvent(MotionEvent ev) {
202b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen        int action = ev.getAction();
203b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen
204b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen        if (action == MotionEvent.ACTION_DOWN) {
20576fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen            if (handleTouchDown(ev, true)) {
2066788269814a678af976dfc7d6135993e172ce586Adam Cohen                return true;
207d1837cc69eb222371afdd30890f7215d117510f2Patrick Dubroy            }
208b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen        } else if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) {
209b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen            if (mTouchCompleteListener != null) {
210b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen                mTouchCompleteListener.onTouchComplete();
211b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen            }
212b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen            mTouchCompleteListener = null;
2131b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen        }
2146788269814a678af976dfc7d6135993e172ce586Adam Cohen        clearAllResizeFrames();
2154db52312c10e822162a21c60404f06f6e507f0d6Joe Onorato        return mDragController.onInterceptTouchEvent(ev);
21631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
21731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
21831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    @Override
2193371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen    public boolean onInterceptHoverEvent(MotionEvent ev) {
220023c71eb3b2bbe63272cb74baaf050c4188c89b0Michael Jurka        if (mLauncher == null || mLauncher.getWorkspace() == null) {
221023c71eb3b2bbe63272cb74baaf050c4188c89b0Michael Jurka            return false;
222023c71eb3b2bbe63272cb74baaf050c4188c89b0Michael Jurka        }
2233371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen        Folder currentFolder = mLauncher.getWorkspace().getOpenFolder();
2243371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen        if (currentFolder == null) {
2253371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen            return false;
2263371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen        } else {
2278b805b17158886035b38261eb611d8641701ae43Michael Jurka                AccessibilityManager accessibilityManager = (AccessibilityManager)
2288b805b17158886035b38261eb611d8641701ae43Michael Jurka                        getContext().getSystemService(Context.ACCESSIBILITY_SERVICE);
2298b805b17158886035b38261eb611d8641701ae43Michael Jurka            if (accessibilityManager.isTouchExplorationEnabled()) {
2303371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                final int action = ev.getAction();
2313371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                boolean isOverFolder;
2323371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                switch (action) {
2333371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                    case MotionEvent.ACTION_HOVER_ENTER:
2343371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                        isOverFolder = isEventOverFolder(currentFolder, ev);
2353371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                        if (!isOverFolder) {
2363371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                            sendTapOutsideFolderAccessibilityEvent(currentFolder.isEditingName());
2373371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                            mHoverPointClosesFolder = true;
2383371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                            return true;
2393371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                        }
240693fbc7f1737d89f11f9ab81558c109f0883ab0eMihail Dumitrescu                        mHoverPointClosesFolder = false;
241693fbc7f1737d89f11f9ab81558c109f0883ab0eMihail Dumitrescu                        break;
2423371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                    case MotionEvent.ACTION_HOVER_MOVE:
2433371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                        isOverFolder = isEventOverFolder(currentFolder, ev);
2443371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                        if (!isOverFolder && !mHoverPointClosesFolder) {
2453371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                            sendTapOutsideFolderAccessibilityEvent(currentFolder.isEditingName());
2463371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                            mHoverPointClosesFolder = true;
2473371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                            return true;
248693fbc7f1737d89f11f9ab81558c109f0883ab0eMihail Dumitrescu                        } else if (!isOverFolder) {
2493371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                            return true;
2503371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                        }
251693fbc7f1737d89f11f9ab81558c109f0883ab0eMihail Dumitrescu                        mHoverPointClosesFolder = false;
2523371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                }
2533371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen            }
2543371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen        }
2553371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen        return false;
2563371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen    }
2573371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen
2583371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen    private void sendTapOutsideFolderAccessibilityEvent(boolean isEditingName) {
2598b805b17158886035b38261eb611d8641701ae43Michael Jurka        AccessibilityManager accessibilityManager = (AccessibilityManager)
2608b805b17158886035b38261eb611d8641701ae43Michael Jurka                getContext().getSystemService(Context.ACCESSIBILITY_SERVICE);
2618b805b17158886035b38261eb611d8641701ae43Michael Jurka        if (accessibilityManager.isEnabled()) {
2623371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen            int stringId = isEditingName ? R.string.folder_tap_to_rename : R.string.folder_tap_to_close;
2633371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen            AccessibilityEvent event = AccessibilityEvent.obtain(
2643371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                    AccessibilityEvent.TYPE_VIEW_FOCUSED);
2653371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen            onInitializeAccessibilityEvent(event);
2668b805b17158886035b38261eb611d8641701ae43Michael Jurka            event.getText().add(getContext().getString(stringId));
2678b805b17158886035b38261eb611d8641701ae43Michael Jurka            accessibilityManager.sendAccessibilityEvent(event);
2683371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen        }
26983ca480941b3dd635b62347008fc8d7859d82002Winson Chung    }
27083ca480941b3dd635b62347008fc8d7859d82002Winson Chung
27183ca480941b3dd635b62347008fc8d7859d82002Winson Chung    @Override
27283ca480941b3dd635b62347008fc8d7859d82002Winson Chung    public boolean onRequestSendAccessibilityEvent(View child, AccessibilityEvent event) {
27383ca480941b3dd635b62347008fc8d7859d82002Winson Chung        Folder currentFolder = mLauncher.getWorkspace().getOpenFolder();
27483ca480941b3dd635b62347008fc8d7859d82002Winson Chung        if (currentFolder != null) {
27583ca480941b3dd635b62347008fc8d7859d82002Winson Chung            if (child == currentFolder) {
27683ca480941b3dd635b62347008fc8d7859d82002Winson Chung                return super.onRequestSendAccessibilityEvent(child, event);
27783ca480941b3dd635b62347008fc8d7859d82002Winson Chung            }
27883ca480941b3dd635b62347008fc8d7859d82002Winson Chung            // Skip propagating onRequestSendAccessibilityEvent all for other children
27983ca480941b3dd635b62347008fc8d7859d82002Winson Chung            // when a folder is open
28083ca480941b3dd635b62347008fc8d7859d82002Winson Chung            return false;
28183ca480941b3dd635b62347008fc8d7859d82002Winson Chung        }
28283ca480941b3dd635b62347008fc8d7859d82002Winson Chung        return super.onRequestSendAccessibilityEvent(child, event);
28383ca480941b3dd635b62347008fc8d7859d82002Winson Chung    }
28483ca480941b3dd635b62347008fc8d7859d82002Winson Chung
28583ca480941b3dd635b62347008fc8d7859d82002Winson Chung    @Override
28683ca480941b3dd635b62347008fc8d7859d82002Winson Chung    public void addChildrenForAccessibility(ArrayList<View> childrenForAccessibility) {
28783ca480941b3dd635b62347008fc8d7859d82002Winson Chung        Folder currentFolder = mLauncher.getWorkspace().getOpenFolder();
28883ca480941b3dd635b62347008fc8d7859d82002Winson Chung        if (currentFolder != null) {
28983ca480941b3dd635b62347008fc8d7859d82002Winson Chung            // Only add the folder as a child for accessibility when it is open
29083ca480941b3dd635b62347008fc8d7859d82002Winson Chung            childrenForAccessibility.add(currentFolder);
29183ca480941b3dd635b62347008fc8d7859d82002Winson Chung        } else {
29283ca480941b3dd635b62347008fc8d7859d82002Winson Chung            super.addChildrenForAccessibility(childrenForAccessibility);
29383ca480941b3dd635b62347008fc8d7859d82002Winson Chung        }
2943371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen    }
2953371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen
2963371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen    @Override
2973371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen    public boolean onHoverEvent(MotionEvent ev) {
2983371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen        // If we've received this, we've already done the necessary handling
2993371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen        // in onInterceptHoverEvent. Return true to consume the event.
3003371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen        return false;
3013371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen    }
3023371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen
3033371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen    @Override
30431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    public boolean onTouchEvent(MotionEvent ev) {
3056788269814a678af976dfc7d6135993e172ce586Adam Cohen        boolean handled = false;
3066788269814a678af976dfc7d6135993e172ce586Adam Cohen        int action = ev.getAction();
3076788269814a678af976dfc7d6135993e172ce586Adam Cohen
3086788269814a678af976dfc7d6135993e172ce586Adam Cohen        int x = (int) ev.getX();
3096788269814a678af976dfc7d6135993e172ce586Adam Cohen        int y = (int) ev.getY();
3106788269814a678af976dfc7d6135993e172ce586Adam Cohen
311c2d6e897dbcb96b7b629e42002966368fbda2f95Adam Cohen        if (mBlockTouches) {
312c2d6e897dbcb96b7b629e42002966368fbda2f95Adam Cohen            return true;
313c2d6e897dbcb96b7b629e42002966368fbda2f95Adam Cohen        }
314c2d6e897dbcb96b7b629e42002966368fbda2f95Adam Cohen
315b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen        if (action == MotionEvent.ACTION_DOWN) {
316b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen            if (handleTouchDown(ev, false)) {
317b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen                return true;
318b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen            }
319b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen        } else if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) {
320b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen            if (mTouchCompleteListener != null) {
321b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen                mTouchCompleteListener.onTouchComplete();
3226788269814a678af976dfc7d6135993e172ce586Adam Cohen            }
323b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen            mTouchCompleteListener = null;
3246788269814a678af976dfc7d6135993e172ce586Adam Cohen        }
3256788269814a678af976dfc7d6135993e172ce586Adam Cohen
3266788269814a678af976dfc7d6135993e172ce586Adam Cohen        if (mCurrentResizeFrame != null) {
3276788269814a678af976dfc7d6135993e172ce586Adam Cohen            handled = true;
3286788269814a678af976dfc7d6135993e172ce586Adam Cohen            switch (action) {
3296788269814a678af976dfc7d6135993e172ce586Adam Cohen                case MotionEvent.ACTION_MOVE:
3306788269814a678af976dfc7d6135993e172ce586Adam Cohen                    mCurrentResizeFrame.visualizeResizeForDelta(x - mXDown, y - mYDown);
3316788269814a678af976dfc7d6135993e172ce586Adam Cohen                    break;
3326788269814a678af976dfc7d6135993e172ce586Adam Cohen                case MotionEvent.ACTION_CANCEL:
3336788269814a678af976dfc7d6135993e172ce586Adam Cohen                case MotionEvent.ACTION_UP:
334bebf042666cffe52039b875a549a582abd78a431Adam Cohen                    mCurrentResizeFrame.visualizeResizeForDelta(x - mXDown, y - mYDown);
335bebf042666cffe52039b875a549a582abd78a431Adam Cohen                    mCurrentResizeFrame.onTouchUp();
3366788269814a678af976dfc7d6135993e172ce586Adam Cohen                    mCurrentResizeFrame = null;
3376788269814a678af976dfc7d6135993e172ce586Adam Cohen            }
3386788269814a678af976dfc7d6135993e172ce586Adam Cohen        }
3396788269814a678af976dfc7d6135993e172ce586Adam Cohen        if (handled) return true;
3404db52312c10e822162a21c60404f06f6e507f0d6Joe Onorato        return mDragController.onTouchEvent(ev);
34191a9c9636f10f1e12cd1f660b2e330634fbdc7dcRomain Guy    }
342ea3763c2672f77539538af8cdd395ad97058eaabRomain Guy
34335e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen    /**
34435e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen     * Determine the rect of the descendant in this DragLayer's coordinates
34535e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen     *
34635e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen     * @param descendant The descendant whose coordinates we want to find.
34735e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen     * @param r The rect into which to place the results.
34835e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen     * @return The factor by which this descendant is scaled relative to this DragLayer.
34935e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen     */
350ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen    public float getDescendantRectRelativeToSelf(View descendant, Rect r) {
351716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen        mTmpXY[0] = 0;
352716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen        mTmpXY[1] = 0;
353ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen        float scale = getDescendantCoordRelativeToSelf(descendant, mTmpXY);
3547d30a37007bac318db1c9af47a9af12d348042a5Adam Cohen
3558dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        r.set(mTmpXY[0], mTmpXY[1],
3567d30a37007bac318db1c9af47a9af12d348042a5Adam Cohen                (int) (mTmpXY[0] + scale * descendant.getMeasuredWidth()),
3577d30a37007bac318db1c9af47a9af12d348042a5Adam Cohen                (int) (mTmpXY[1] + scale * descendant.getMeasuredHeight()));
358ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen        return scale;
359716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen    }
36076fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen
361307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen    public float getLocationInDragLayer(View child, int[] loc) {
36235e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen        loc[0] = 0;
36335e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen        loc[1] = 0;
364307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen        return getDescendantCoordRelativeToSelf(child, loc);
36535e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen    }
36635e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen
3677d30a37007bac318db1c9af47a9af12d348042a5Adam Cohen    public float getDescendantCoordRelativeToSelf(View descendant, int[] coord) {
3687d30a37007bac318db1c9af47a9af12d348042a5Adam Cohen        return getDescendantCoordRelativeToSelf(descendant, coord, false);
3697d30a37007bac318db1c9af47a9af12d348042a5Adam Cohen    }
3707d30a37007bac318db1c9af47a9af12d348042a5Adam Cohen
37135e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen    /**
37235e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen     * Given a coordinate relative to the descendant, find the coordinate in this DragLayer's
37335e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen     * coordinates.
37435e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen     *
37535e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen     * @param descendant The descendant to which the passed coordinate is relative.
37635e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen     * @param coord The coordinate that we want mapped.
3777d30a37007bac318db1c9af47a9af12d348042a5Adam Cohen     * @param includeRootScroll Whether or not to account for the scroll of the root descendant:
3787d30a37007bac318db1c9af47a9af12d348042a5Adam Cohen     *          sometimes this is relevant as in a child's coordinates within the root descendant.
379307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen     * @return The factor by which this descendant is scaled relative to this DragLayer. Caution
380307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen     *         this scale factor is assumed to be equal in X and Y, and so if at any point this
381307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen     *         assumption fails, we will need to return a pair of scale factors.
38235e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen     */
3837d30a37007bac318db1c9af47a9af12d348042a5Adam Cohen    public float getDescendantCoordRelativeToSelf(View descendant, int[] coord,
3847d30a37007bac318db1c9af47a9af12d348042a5Adam Cohen            boolean includeRootScroll) {
385c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung        return Utilities.getDescendantCoordRelativeToParent(descendant, this,
386c9ca2980983ab21fc8631c7a65399d6d9c70f39cWinson Chung                coord, includeRootScroll);
387c9ca2980983ab21fc8631c7a65399d6d9c70f39cWinson Chung    }
388c9ca2980983ab21fc8631c7a65399d6d9c70f39cWinson Chung
3897d30a37007bac318db1c9af47a9af12d348042a5Adam Cohen    /**
3907d30a37007bac318db1c9af47a9af12d348042a5Adam Cohen     * Inverse of {@link #getDescendantCoordRelativeToSelf(View, int[])}.
3917d30a37007bac318db1c9af47a9af12d348042a5Adam Cohen     */
3927d30a37007bac318db1c9af47a9af12d348042a5Adam Cohen    public float mapCoordInSelfToDescendent(View descendant, int[] coord) {
393c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung        return Utilities.mapCoordInSelfToDescendent(descendant, this, coord);
39476fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen    }
39576fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen
3963e8f811f31a2275e778244427271f77f4116c08bAdam Cohen    public void getViewRectRelativeToSelf(View v, Rect r) {
3973e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        int[] loc = new int[2];
3988dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        getLocationInWindow(loc);
3993e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        int x = loc[0];
4003e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        int y = loc[1];
401716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen
4028dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        v.getLocationInWindow(loc);
4033e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        int vX = loc[0];
4043e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        int vY = loc[1];
405716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen
4063e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        int left = vX - x;
4073e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        int top = vY - y;
4083e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        r.set(left, top, left + v.getMeasuredWidth(), top + v.getMeasuredHeight());
409716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen    }
410716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen
411ea3763c2672f77539538af8cdd395ad97058eaabRomain Guy    @Override
412ea3763c2672f77539538af8cdd395ad97058eaabRomain Guy    public boolean dispatchUnhandledMove(View focused, int direction) {
413ea3763c2672f77539538af8cdd395ad97058eaabRomain Guy        return mDragController.dispatchUnhandledMove(focused, direction);
414ea3763c2672f77539538af8cdd395ad97058eaabRomain Guy    }
415120980bd00f5eecec5717f49a3d7db96571025a9Adam Cohen
416bc927f9c24001e250622ca9a2547ee5b65baef58Adam Cohen    @Override
417bc927f9c24001e250622ca9a2547ee5b65baef58Adam Cohen    public LayoutParams generateLayoutParams(AttributeSet attrs) {
418bc927f9c24001e250622ca9a2547ee5b65baef58Adam Cohen        return new LayoutParams(getContext(), attrs);
419bc927f9c24001e250622ca9a2547ee5b65baef58Adam Cohen    }
420bc927f9c24001e250622ca9a2547ee5b65baef58Adam Cohen
421bc927f9c24001e250622ca9a2547ee5b65baef58Adam Cohen    @Override
422bc927f9c24001e250622ca9a2547ee5b65baef58Adam Cohen    protected LayoutParams generateDefaultLayoutParams() {
423bc927f9c24001e250622ca9a2547ee5b65baef58Adam Cohen        return new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
424bc927f9c24001e250622ca9a2547ee5b65baef58Adam Cohen    }
425bc927f9c24001e250622ca9a2547ee5b65baef58Adam Cohen
426bc927f9c24001e250622ca9a2547ee5b65baef58Adam Cohen    // Override to allow type-checking of LayoutParams.
427bc927f9c24001e250622ca9a2547ee5b65baef58Adam Cohen    @Override
428bc927f9c24001e250622ca9a2547ee5b65baef58Adam Cohen    protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
429bc927f9c24001e250622ca9a2547ee5b65baef58Adam Cohen        return p instanceof LayoutParams;
430bc927f9c24001e250622ca9a2547ee5b65baef58Adam Cohen    }
431bc927f9c24001e250622ca9a2547ee5b65baef58Adam Cohen
432bc927f9c24001e250622ca9a2547ee5b65baef58Adam Cohen    @Override
433bc927f9c24001e250622ca9a2547ee5b65baef58Adam Cohen    protected LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
434bc927f9c24001e250622ca9a2547ee5b65baef58Adam Cohen        return new LayoutParams(p);
435bc927f9c24001e250622ca9a2547ee5b65baef58Adam Cohen    }
436bc927f9c24001e250622ca9a2547ee5b65baef58Adam Cohen
437bc927f9c24001e250622ca9a2547ee5b65baef58Adam Cohen    public static class LayoutParams extends InsettableFrameLayout.LayoutParams {
4386788269814a678af976dfc7d6135993e172ce586Adam Cohen        public int x, y;
4396788269814a678af976dfc7d6135993e172ce586Adam Cohen        public boolean customPosition = false;
4406788269814a678af976dfc7d6135993e172ce586Adam Cohen
441bc927f9c24001e250622ca9a2547ee5b65baef58Adam Cohen        public LayoutParams(Context c, AttributeSet attrs) {
442bc927f9c24001e250622ca9a2547ee5b65baef58Adam Cohen            super(c, attrs);
443bc927f9c24001e250622ca9a2547ee5b65baef58Adam Cohen        }
444bc927f9c24001e250622ca9a2547ee5b65baef58Adam Cohen
4456788269814a678af976dfc7d6135993e172ce586Adam Cohen        public LayoutParams(int width, int height) {
4466788269814a678af976dfc7d6135993e172ce586Adam Cohen            super(width, height);
4476788269814a678af976dfc7d6135993e172ce586Adam Cohen        }
4486788269814a678af976dfc7d6135993e172ce586Adam Cohen
449bc927f9c24001e250622ca9a2547ee5b65baef58Adam Cohen        public LayoutParams(ViewGroup.LayoutParams lp) {
450bc927f9c24001e250622ca9a2547ee5b65baef58Adam Cohen            super(lp);
451bc927f9c24001e250622ca9a2547ee5b65baef58Adam Cohen        }
452bc927f9c24001e250622ca9a2547ee5b65baef58Adam Cohen
4536788269814a678af976dfc7d6135993e172ce586Adam Cohen        public void setWidth(int width) {
4546788269814a678af976dfc7d6135993e172ce586Adam Cohen            this.width = width;
4556788269814a678af976dfc7d6135993e172ce586Adam Cohen        }
4566788269814a678af976dfc7d6135993e172ce586Adam Cohen
4576788269814a678af976dfc7d6135993e172ce586Adam Cohen        public int getWidth() {
4586788269814a678af976dfc7d6135993e172ce586Adam Cohen            return width;
4596788269814a678af976dfc7d6135993e172ce586Adam Cohen        }
4606788269814a678af976dfc7d6135993e172ce586Adam Cohen
4616788269814a678af976dfc7d6135993e172ce586Adam Cohen        public void setHeight(int height) {
4626788269814a678af976dfc7d6135993e172ce586Adam Cohen            this.height = height;
4636788269814a678af976dfc7d6135993e172ce586Adam Cohen        }
4646788269814a678af976dfc7d6135993e172ce586Adam Cohen
4656788269814a678af976dfc7d6135993e172ce586Adam Cohen        public int getHeight() {
4666788269814a678af976dfc7d6135993e172ce586Adam Cohen            return height;
4676788269814a678af976dfc7d6135993e172ce586Adam Cohen        }
4686788269814a678af976dfc7d6135993e172ce586Adam Cohen
4696788269814a678af976dfc7d6135993e172ce586Adam Cohen        public void setX(int x) {
4706788269814a678af976dfc7d6135993e172ce586Adam Cohen            this.x = x;
4716788269814a678af976dfc7d6135993e172ce586Adam Cohen        }
4726788269814a678af976dfc7d6135993e172ce586Adam Cohen
4736788269814a678af976dfc7d6135993e172ce586Adam Cohen        public int getX() {
4746788269814a678af976dfc7d6135993e172ce586Adam Cohen            return x;
4756788269814a678af976dfc7d6135993e172ce586Adam Cohen        }
4766788269814a678af976dfc7d6135993e172ce586Adam Cohen
4776788269814a678af976dfc7d6135993e172ce586Adam Cohen        public void setY(int y) {
4786788269814a678af976dfc7d6135993e172ce586Adam Cohen            this.y = y;
4796788269814a678af976dfc7d6135993e172ce586Adam Cohen        }
4806788269814a678af976dfc7d6135993e172ce586Adam Cohen
4816788269814a678af976dfc7d6135993e172ce586Adam Cohen        public int getY() {
4826788269814a678af976dfc7d6135993e172ce586Adam Cohen            return y;
4836788269814a678af976dfc7d6135993e172ce586Adam Cohen        }
4846788269814a678af976dfc7d6135993e172ce586Adam Cohen    }
4856788269814a678af976dfc7d6135993e172ce586Adam Cohen
4866788269814a678af976dfc7d6135993e172ce586Adam Cohen    protected void onLayout(boolean changed, int l, int t, int r, int b) {
4876788269814a678af976dfc7d6135993e172ce586Adam Cohen        super.onLayout(changed, l, t, r, b);
4886788269814a678af976dfc7d6135993e172ce586Adam Cohen        int count = getChildCount();
4896788269814a678af976dfc7d6135993e172ce586Adam Cohen        for (int i = 0; i < count; i++) {
4906788269814a678af976dfc7d6135993e172ce586Adam Cohen            View child = getChildAt(i);
4916788269814a678af976dfc7d6135993e172ce586Adam Cohen            final FrameLayout.LayoutParams flp = (FrameLayout.LayoutParams) child.getLayoutParams();
4926788269814a678af976dfc7d6135993e172ce586Adam Cohen            if (flp instanceof LayoutParams) {
4936788269814a678af976dfc7d6135993e172ce586Adam Cohen                final LayoutParams lp = (LayoutParams) flp;
4946788269814a678af976dfc7d6135993e172ce586Adam Cohen                if (lp.customPosition) {
4956788269814a678af976dfc7d6135993e172ce586Adam Cohen                    child.layout(lp.x, lp.y, lp.x + lp.width, lp.y + lp.height);
4966788269814a678af976dfc7d6135993e172ce586Adam Cohen                }
4976788269814a678af976dfc7d6135993e172ce586Adam Cohen            }
4986788269814a678af976dfc7d6135993e172ce586Adam Cohen        }
4996788269814a678af976dfc7d6135993e172ce586Adam Cohen    }
5006788269814a678af976dfc7d6135993e172ce586Adam Cohen
5016788269814a678af976dfc7d6135993e172ce586Adam Cohen    public void clearAllResizeFrames() {
5026788269814a678af976dfc7d6135993e172ce586Adam Cohen        if (mResizeFrames.size() > 0) {
5036788269814a678af976dfc7d6135993e172ce586Adam Cohen            for (AppWidgetResizeFrame frame: mResizeFrames) {
504bebf042666cffe52039b875a549a582abd78a431Adam Cohen                frame.commitResize();
5056788269814a678af976dfc7d6135993e172ce586Adam Cohen                removeView(frame);
5066788269814a678af976dfc7d6135993e172ce586Adam Cohen            }
5076788269814a678af976dfc7d6135993e172ce586Adam Cohen            mResizeFrames.clear();
5086788269814a678af976dfc7d6135993e172ce586Adam Cohen        }
5096788269814a678af976dfc7d6135993e172ce586Adam Cohen    }
5106788269814a678af976dfc7d6135993e172ce586Adam Cohen
5116788269814a678af976dfc7d6135993e172ce586Adam Cohen    public boolean hasResizeFrames() {
5126788269814a678af976dfc7d6135993e172ce586Adam Cohen        return mResizeFrames.size() > 0;
5136788269814a678af976dfc7d6135993e172ce586Adam Cohen    }
5146788269814a678af976dfc7d6135993e172ce586Adam Cohen
5156788269814a678af976dfc7d6135993e172ce586Adam Cohen    public boolean isWidgetBeingResized() {
5166788269814a678af976dfc7d6135993e172ce586Adam Cohen        return mCurrentResizeFrame != null;
5176788269814a678af976dfc7d6135993e172ce586Adam Cohen    }
5186788269814a678af976dfc7d6135993e172ce586Adam Cohen
5196788269814a678af976dfc7d6135993e172ce586Adam Cohen    public void addResizeFrame(ItemInfo itemInfo, LauncherAppWidgetHostView widget,
5206788269814a678af976dfc7d6135993e172ce586Adam Cohen            CellLayout cellLayout) {
5216788269814a678af976dfc7d6135993e172ce586Adam Cohen        AppWidgetResizeFrame resizeFrame = new AppWidgetResizeFrame(getContext(),
5223a9fcedbcd235372cd2ab64f825a0b5b3937f59eMichael Jurka                widget, cellLayout, this);
5236788269814a678af976dfc7d6135993e172ce586Adam Cohen
5246788269814a678af976dfc7d6135993e172ce586Adam Cohen        LayoutParams lp = new LayoutParams(-1, -1);
5256788269814a678af976dfc7d6135993e172ce586Adam Cohen        lp.customPosition = true;
5266788269814a678af976dfc7d6135993e172ce586Adam Cohen
5276788269814a678af976dfc7d6135993e172ce586Adam Cohen        addView(resizeFrame, lp);
5286788269814a678af976dfc7d6135993e172ce586Adam Cohen        mResizeFrames.add(resizeFrame);
5296788269814a678af976dfc7d6135993e172ce586Adam Cohen
5306788269814a678af976dfc7d6135993e172ce586Adam Cohen        resizeFrame.snapToWidget(false);
5316788269814a678af976dfc7d6135993e172ce586Adam Cohen    }
532716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen
533716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen    public void animateViewIntoPosition(DragView dragView, final View child) {
53428f852ab678d9750879b6d3549bf5da176cf1225Adam Cohen        animateViewIntoPosition(dragView, child, null, null);
535557d6ed50cc6560163440aa134870ef0bb11415bWinson Chung    }
536ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen
5377bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung    public void animateViewIntoPosition(DragView dragView, final int[] pos, float alpha,
5387bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung            float scaleX, float scaleY, int animationEndStyle, Runnable onFinishRunnable,
5397bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung            int duration) {
540b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen        Rect r = new Rect();
541b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen        getViewRectRelativeToSelf(dragView, r);
542b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen        final int fromX = r.left;
543b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen        final int fromY = r.top;
544b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen
5457bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung        animateViewIntoPosition(dragView, fromX, fromY, pos[0], pos[1], alpha, 1, 1, scaleX, scaleY,
546ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen                onFinishRunnable, animationEndStyle, duration, null);
547ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen    }
548ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen
549557d6ed50cc6560163440aa134870ef0bb11415bWinson Chung    public void animateViewIntoPosition(DragView dragView, final View child,
55028f852ab678d9750879b6d3549bf5da176cf1225Adam Cohen            final Runnable onFinishAnimationRunnable, View anchorView) {
55128f852ab678d9750879b6d3549bf5da176cf1225Adam Cohen        animateViewIntoPosition(dragView, child, -1, onFinishAnimationRunnable, anchorView);
552ed51cc9a12c50d12e7d30ed209a49f1a40858043Adam Cohen    }
553ed51cc9a12c50d12e7d30ed209a49f1a40858043Adam Cohen
554ed51cc9a12c50d12e7d30ed209a49f1a40858043Adam Cohen    public void animateViewIntoPosition(DragView dragView, final View child, int duration,
5556441de0ec2a71862798dd51180d0811b42edd514Adam Cohen            final Runnable onFinishAnimationRunnable, View anchorView) {
556a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        ShortcutAndWidgetContainer parentChildren = (ShortcutAndWidgetContainer) child.getParent();
557716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen        CellLayout.LayoutParams lp =  (CellLayout.LayoutParams) child.getLayoutParams();
558eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung        parentChildren.measureChild(child);
559716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen
5603e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        Rect r = new Rect();
5613e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        getViewRectRelativeToSelf(dragView, r);
562716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen
563716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen        int coord[] = new int[2];
564307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen        float childScale = child.getScaleX();
565307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen        coord[0] = lp.x + (int) (child.getMeasuredWidth() * (1 - childScale) / 2);
566307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen        coord[1] = lp.y + (int) (child.getMeasuredHeight() * (1 - childScale) / 2);
567eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung
5688dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        // Since the child hasn't necessarily been laid out, we force the lp to be updated with
569ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen        // the correct coordinates (above) and use these to determine the final location
570557d6ed50cc6560163440aa134870ef0bb11415bWinson Chung        float scale = getDescendantCoordRelativeToSelf((View) child.getParent(), coord);
571307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen        // We need to account for the scale of the child itself, as the above only accounts for
572307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen        // for the scale in parents.
573307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen        scale *= childScale;
574ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen        int toX = coord[0];
575ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen        int toY = coord[1];
576eeb5bbc9409978cc2ae52d48380399fcde3d9f85Winson Chung        float toScale = scale;
5774497ebf9a2726e2a7dbb7f3c49389308908f8454Andrew Flynn        if (child instanceof TextView) {
5784497ebf9a2726e2a7dbb7f3c49389308908f8454Andrew Flynn            TextView tv = (TextView) child;
579eeb5bbc9409978cc2ae52d48380399fcde3d9f85Winson Chung            // Account for the source scale of the icon (ie. from AllApps to Workspace, in which
580eeb5bbc9409978cc2ae52d48380399fcde3d9f85Winson Chung            // the workspace may have smaller icon bounds).
581eeb5bbc9409978cc2ae52d48380399fcde3d9f85Winson Chung            toScale = scale / dragView.getIntrinsicIconScaleFactor();
5824497ebf9a2726e2a7dbb7f3c49389308908f8454Andrew Flynn
5834497ebf9a2726e2a7dbb7f3c49389308908f8454Andrew Flynn            // The child may be scaled (always about the center of the view) so to account for it,
5844497ebf9a2726e2a7dbb7f3c49389308908f8454Andrew Flynn            // we have to offset the position by the scaled size.  Once we do that, we can center
5854497ebf9a2726e2a7dbb7f3c49389308908f8454Andrew Flynn            // the drag view about the scaled child view.
586eeb5bbc9409978cc2ae52d48380399fcde3d9f85Winson Chung            toY += Math.round(toScale * tv.getPaddingTop());
587eeb5bbc9409978cc2ae52d48380399fcde3d9f85Winson Chung            toY -= dragView.getMeasuredHeight() * (1 - toScale) / 2;
58895abbb330ce9bbaf23594245f0f8a795c8118038Sunny Goyal            if (dragView.getDragVisualizeOffset() != null) {
58995abbb330ce9bbaf23594245f0f8a795c8118038Sunny Goyal                toY -=  Math.round(toScale * dragView.getDragVisualizeOffset().y);
59095abbb330ce9bbaf23594245f0f8a795c8118038Sunny Goyal            }
59195abbb330ce9bbaf23594245f0f8a795c8118038Sunny Goyal
5924497ebf9a2726e2a7dbb7f3c49389308908f8454Andrew Flynn            toX -= (dragView.getMeasuredWidth() - Math.round(scale * child.getMeasuredWidth())) / 2;
5934497ebf9a2726e2a7dbb7f3c49389308908f8454Andrew Flynn        } else if (child instanceof FolderIcon) {
594ea359c6aee44c0fe3bb94f7002c3b49208b32b7fWinson Chung            // Account for holographic blur padding on the drag view
5955f8afe6280eae34620067696173e71943e1a30a3Winson Chung            toY += Math.round(scale * (child.getPaddingTop() - dragView.getDragRegionTop()));
596307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen            toY -= scale * Workspace.DRAG_BITMAP_PADDING / 2;
597307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen            toY -= (1 - scale) * dragView.getMeasuredHeight() / 2;
598ea359c6aee44c0fe3bb94f7002c3b49208b32b7fWinson Chung            // Center in the x coordinate about the target's drawable
599ea359c6aee44c0fe3bb94f7002c3b49208b32b7fWinson Chung            toX -= (dragView.getMeasuredWidth() - Math.round(scale * child.getMeasuredWidth())) / 2;
600ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen        } else {
601ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen            toY -= (Math.round(scale * (dragView.getHeight() - child.getMeasuredHeight()))) / 2;
602ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen            toX -= (Math.round(scale * (dragView.getMeasuredWidth()
603ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen                    - child.getMeasuredWidth()))) / 2;
604ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen        }
605716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen
606ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen        final int fromX = r.left;
607ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen        final int fromY = r.top;
608716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen        child.setVisibility(INVISIBLE);
6098dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        Runnable onCompleteRunnable = new Runnable() {
6108dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen            public void run() {
6118dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen                child.setVisibility(VISIBLE);
612d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                if (onFinishAnimationRunnable != null) {
613d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    onFinishAnimationRunnable.run();
614d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                }
6158dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen            }
6168dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        };
617eeb5bbc9409978cc2ae52d48380399fcde3d9f85Winson Chung        animateViewIntoPosition(dragView, fromX, fromY, toX, toY, 1, 1, 1, toScale, toScale,
618d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                onCompleteRunnable, ANIMATION_END_DISAPPEAR, duration, anchorView);
619557d6ed50cc6560163440aa134870ef0bb11415bWinson Chung    }
620557d6ed50cc6560163440aa134870ef0bb11415bWinson Chung
621d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen    public void animateViewIntoPosition(final DragView view, final int fromX, final int fromY,
622ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen            final int toX, final int toY, float finalAlpha, float initScaleX, float initScaleY,
623ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen            float finalScaleX, float finalScaleY, Runnable onCompleteRunnable,
624ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen            int animationEndStyle, int duration, View anchorView) {
6258dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        Rect from = new Rect(fromX, fromY, fromX +
6268dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen                view.getMeasuredWidth(), fromY + view.getMeasuredHeight());
6273e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        Rect to = new Rect(toX, toY, toX + view.getMeasuredWidth(), toY + view.getMeasuredHeight());
628ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen        animateView(view, from, to, finalAlpha, initScaleX, initScaleY, finalScaleX, finalScaleY, duration,
629ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen                null, null, onCompleteRunnable, animationEndStyle, anchorView);
6303e8f811f31a2275e778244427271f77f4116c08bAdam Cohen    }
6313e8f811f31a2275e778244427271f77f4116c08bAdam Cohen
632b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen    /**
633b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen     * This method animates a view at the end of a drag and drop animation.
634b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen     *
635b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen     * @param view The view to be animated. This view is drawn directly into DragLayer, and so
636b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen     *        doesn't need to be a child of DragLayer.
637b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen     * @param from The initial location of the view. Only the left and top parameters are used.
638b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen     * @param to The final location of the view. Only the left and top parameters are used. This
639b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen     *        location doesn't account for scaling, and so should be centered about the desired
640b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen     *        final location (including scaling).
641b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen     * @param finalAlpha The final alpha of the view, in case we want it to fade as it animates.
642b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen     * @param finalScale The final scale of the view. The view is scaled about its center.
643b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen     * @param duration The duration of the animation.
644b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen     * @param motionInterpolator The interpolator to use for the location of the view.
645b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen     * @param alphaInterpolator The interpolator to use for the alpha of the view.
646b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen     * @param onCompleteRunnable Optional runnable to run on animation completion.
647b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen     * @param fadeOut Whether or not to fade out the view once the animation completes. If true,
648b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen     *        the runnable will execute after the view is faded out.
6496441de0ec2a71862798dd51180d0811b42edd514Adam Cohen     * @param anchorView If not null, this represents the view which the animated view stays
6506441de0ec2a71862798dd51180d0811b42edd514Adam Cohen     *        anchored to in case scrolling is currently taking place. Note: currently this is
6516441de0ec2a71862798dd51180d0811b42edd514Adam Cohen     *        only used for the X dimension for the case of the workspace.
652b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen     */
6537bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung    public void animateView(final DragView view, final Rect from, final Rect to,
6547bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung            final float finalAlpha, final float initScaleX, final float initScaleY,
6557bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung            final float finalScaleX, final float finalScaleY, int duration,
6567bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung            final Interpolator motionInterpolator, final Interpolator alphaInterpolator,
6577bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung            final Runnable onCompleteRunnable, final int animationEndStyle, View anchorView) {
6587bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung
659716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen        // Calculate the duration of the animation based on the object's distance
660f7a29e83f06909b378dba39c83a522375682710aSunny Goyal        final float dist = (float) Math.hypot(to.left - from.left, to.top - from.top);
661716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen        final Resources res = getResources();
662716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen        final float maxDist = (float) res.getInteger(R.integer.config_dropAnimMaxDist);
6633e8f811f31a2275e778244427271f77f4116c08bAdam Cohen
6643e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        // If duration < 0, this is a cue to compute the duration based on the distance
6653e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        if (duration < 0) {
6663e8f811f31a2275e778244427271f77f4116c08bAdam Cohen            duration = res.getInteger(R.integer.config_dropAnimMaxDuration);
6673e8f811f31a2275e778244427271f77f4116c08bAdam Cohen            if (dist < maxDist) {
6688dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen                duration *= mCubicEaseOutInterpolator.getInterpolation(dist / maxDist);
6693e8f811f31a2275e778244427271f77f4116c08bAdam Cohen            }
67061b0c69d3fe331d3de338322396d5de691d58613Winson Chung            duration = Math.max(duration, res.getInteger(R.integer.config_dropAnimMinDuration));
671716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen        }
672716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen
673043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        // Fall back to cubic ease out interpolator for the animation if none is specified
674043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        TimeInterpolator interpolator = null;
6753e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        if (alphaInterpolator == null || motionInterpolator == null) {
676043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung            interpolator = mCubicEaseOutInterpolator;
6773e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        }
678716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen
679043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        // Animate the view
6807bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung        final float initAlpha = view.getAlpha();
681043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        final float dropViewScale = view.getScaleX();
682043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        AnimatorUpdateListener updateCb = new AnimatorUpdateListener() {
683043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung            @Override
684716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen            public void onAnimationUpdate(ValueAnimator animation) {
685716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen                final float percent = (Float) animation.getAnimatedValue();
6867bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung                final int width = view.getMeasuredWidth();
6877bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung                final int height = view.getMeasuredHeight();
688716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen
6893e8f811f31a2275e778244427271f77f4116c08bAdam Cohen                float alphaPercent = alphaInterpolator == null ? percent :
6903e8f811f31a2275e778244427271f77f4116c08bAdam Cohen                        alphaInterpolator.getInterpolation(percent);
6913e8f811f31a2275e778244427271f77f4116c08bAdam Cohen                float motionPercent = motionInterpolator == null ? percent :
6923e8f811f31a2275e778244427271f77f4116c08bAdam Cohen                        motionInterpolator.getInterpolation(percent);
693a1cdab039292f3d809528c0e2e38580b37864d8dWinson Chung
6947bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung                float initialScaleX = initScaleX * dropViewScale;
6957bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung                float initialScaleY = initScaleY * dropViewScale;
6967bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung                float scaleX = finalScaleX * percent + initialScaleX * (1 - percent);
6977bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung                float scaleY = finalScaleY * percent + initialScaleY * (1 - percent);
6987bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung                float alpha = finalAlpha * alphaPercent + initAlpha * (1 - alphaPercent);
6997bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung
7007bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung                float fromLeft = from.left + (initialScaleX - 1f) * width / 2;
7017bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung                float fromTop = from.top + (initialScaleY - 1f) * height / 2;
7027bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung
7037bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung                int x = (int) (fromLeft + Math.round(((to.left - fromLeft) * motionPercent)));
7047bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung                int y = (int) (fromTop + Math.round(((to.top - fromTop) * motionPercent)));
7057bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung
70628f852ab678d9750879b6d3549bf5da176cf1225Adam Cohen                int anchorAdjust = mAnchorView == null ? 0 : (int) (mAnchorView.getScaleX() *
70728f852ab678d9750879b6d3549bf5da176cf1225Adam Cohen                    (mAnchorViewInitialScrollX - mAnchorView.getScrollX()));
70828f852ab678d9750879b6d3549bf5da176cf1225Adam Cohen
70928f852ab678d9750879b6d3549bf5da176cf1225Adam Cohen                int xPos = x - mDropView.getScrollX() + anchorAdjust;
7107bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung                int yPos = y - mDropView.getScrollY();
7117bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung
7127bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung                mDropView.setTranslationX(xPos);
7137bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung                mDropView.setTranslationY(yPos);
7147bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung                mDropView.setScaleX(scaleX);
7157bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung                mDropView.setScaleY(scaleY);
7167bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung                mDropView.setAlpha(alpha);
717716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen            }
718043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        };
719043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        animateView(view, updateCb, duration, interpolator, onCompleteRunnable, animationEndStyle,
720043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung                anchorView);
721043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung    }
722043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung
723043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung    public void animateView(final DragView view, AnimatorUpdateListener updateCb, int duration,
724043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung            TimeInterpolator interpolator, final Runnable onCompleteRunnable,
725043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung            final int animationEndStyle, View anchorView) {
726043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        // Clean up the previous animations
727043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        if (mDropAnim != null) mDropAnim.cancel();
728043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        if (mFadeOutAnim != null) mFadeOutAnim.cancel();
729043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung
730043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        // Show the drop view if it was previously hidden
731043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        mDropView = view;
732043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        mDropView.cancelAnimation();
733043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        mDropView.resetLayoutParams();
734043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung
735043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        // Set the anchor view if the page is scrolling
736043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        if (anchorView != null) {
737043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung            mAnchorViewInitialScrollX = anchorView.getScrollX();
738043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        }
739043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        mAnchorView = anchorView;
740043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung
741043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        // Create and start the animation
742043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        mDropAnim = new ValueAnimator();
743043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        mDropAnim.setInterpolator(interpolator);
744043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        mDropAnim.setDuration(duration);
745043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        mDropAnim.setFloatValues(0f, 1f);
746043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        mDropAnim.addUpdateListener(updateCb);
7473e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        mDropAnim.addListener(new AnimatorListenerAdapter() {
7483e8f811f31a2275e778244427271f77f4116c08bAdam Cohen            public void onAnimationEnd(Animator animation) {
7498dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen                if (onCompleteRunnable != null) {
7508dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen                    onCompleteRunnable.run();
7518dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen                }
752ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen                switch (animationEndStyle) {
753ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen                case ANIMATION_END_DISAPPEAR:
754ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen                    clearAnimatedView();
755ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen                    break;
756ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen                case ANIMATION_END_FADE_OUT:
7578dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen                    fadeOutDragView();
758ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen                    break;
759ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen                case ANIMATION_END_REMAIN_VISIBLE:
760ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen                    break;
7613e8f811f31a2275e778244427271f77f4116c08bAdam Cohen                }
7623e8f811f31a2275e778244427271f77f4116c08bAdam Cohen            }
7633e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        });
764716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen        mDropAnim.start();
765716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen    }
766716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen
767ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen    public void clearAnimatedView() {
7687bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung        if (mDropAnim != null) {
7697bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung            mDropAnim.cancel();
7707bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung        }
7717bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung        if (mDropView != null) {
7722d783ce2f4b2e507bead0d723f0edcdf902dbd46Adam Cohen            mDragController.onDeferredEndDrag(mDropView);
7737bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung        }
774ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen        mDropView = null;
775ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen        invalidate();
776ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen    }
777ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen
778ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen    public View getAnimatedView() {
779ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen        return mDropView;
780ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen    }
781ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen
782091440a9cb9d4f42406631004aa484cbb79214caAdam Cohen    @Thunk void fadeOutDragView() {
7838dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        mFadeOutAnim = new ValueAnimator();
7848dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        mFadeOutAnim.setDuration(150);
7858dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        mFadeOutAnim.setFloatValues(0f, 1f);
7868dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        mFadeOutAnim.removeAllUpdateListeners();
7878dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        mFadeOutAnim.addUpdateListener(new AnimatorUpdateListener() {
7888dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen            public void onAnimationUpdate(ValueAnimator animation) {
7898dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen                final float percent = (Float) animation.getAnimatedValue();
7907bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung
7917bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung                float alpha = 1 - percent;
7927bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung                mDropView.setAlpha(alpha);
7938dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen            }
7948dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        });
7958dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        mFadeOutAnim.addListener(new AnimatorListenerAdapter() {
7968dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen            public void onAnimationEnd(Animator animation) {
7977bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung                if (mDropView != null) {
798043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung                    mDragController.onDeferredEndDrag(mDropView);
7997bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung                }
8008dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen                mDropView = null;
801ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen                invalidate();
8028dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen            }
8038dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        });
8048dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        mFadeOutAnim.start();
8058dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen    }
8068dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen
807716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen    @Override
8088b805b17158886035b38261eb611d8641701ae43Michael Jurka    public void onChildViewAdded(View parent, View child) {
809a6d0492e5f0dd4e1b43d4034a770241dc65f8f8cAdam Cohen        super.onChildViewAdded(parent, child);
810b670f195ffb7b4a0519fd0b337b68f7412159414Adam Cohen        if (mOverlayView != null) {
811b670f195ffb7b4a0519fd0b337b68f7412159414Adam Cohen            // ensure that the overlay view stays on top. we can't use drawing order for this
812b670f195ffb7b4a0519fd0b337b68f7412159414Adam Cohen            // because in API level 16 touch dispatch doesn't respect drawing order.
813b670f195ffb7b4a0519fd0b337b68f7412159414Adam Cohen            mOverlayView.bringToFront();
814b670f195ffb7b4a0519fd0b337b68f7412159414Adam Cohen        }
81521b411074e39fd10cbc8dd0220bb159da4af2c76Adam Cohen        updateChildIndices();
81621b411074e39fd10cbc8dd0220bb159da4af2c76Adam Cohen    }
81721b411074e39fd10cbc8dd0220bb159da4af2c76Adam Cohen
81821b411074e39fd10cbc8dd0220bb159da4af2c76Adam Cohen    @Override
8198b805b17158886035b38261eb611d8641701ae43Michael Jurka    public void onChildViewRemoved(View parent, View child) {
82021b411074e39fd10cbc8dd0220bb159da4af2c76Adam Cohen        updateChildIndices();
82121b411074e39fd10cbc8dd0220bb159da4af2c76Adam Cohen    }
82221b411074e39fd10cbc8dd0220bb159da4af2c76Adam Cohen
823432609a246819f3cf887a80c2ae56b61fc5ca25aAdam Cohen    @Override
824432609a246819f3cf887a80c2ae56b61fc5ca25aAdam Cohen    public void bringChildToFront(View child) {
825432609a246819f3cf887a80c2ae56b61fc5ca25aAdam Cohen        super.bringChildToFront(child);
826b670f195ffb7b4a0519fd0b337b68f7412159414Adam Cohen        if (child != mOverlayView && mOverlayView != null) {
827b670f195ffb7b4a0519fd0b337b68f7412159414Adam Cohen            // ensure that the overlay view stays on top. we can't use drawing order for this
828b670f195ffb7b4a0519fd0b337b68f7412159414Adam Cohen            // because in API level 16 touch dispatch doesn't respect drawing order.
829b670f195ffb7b4a0519fd0b337b68f7412159414Adam Cohen            mOverlayView.bringToFront();
830b670f195ffb7b4a0519fd0b337b68f7412159414Adam Cohen        }
831432609a246819f3cf887a80c2ae56b61fc5ca25aAdam Cohen        updateChildIndices();
832432609a246819f3cf887a80c2ae56b61fc5ca25aAdam Cohen    }
833432609a246819f3cf887a80c2ae56b61fc5ca25aAdam Cohen
83421b411074e39fd10cbc8dd0220bb159da4af2c76Adam Cohen    private void updateChildIndices() {
835432609a246819f3cf887a80c2ae56b61fc5ca25aAdam Cohen        mTopViewIndex = -1;
83655bd9725d5c0373b89f7b9bbd9547550ea3bbc63Jorim Jaggi        int childCount = getChildCount();
83755bd9725d5c0373b89f7b9bbd9547550ea3bbc63Jorim Jaggi        for (int i = 0; i < childCount; i++) {
838b670f195ffb7b4a0519fd0b337b68f7412159414Adam Cohen            if (getChildAt(i) instanceof DragView) {
839432609a246819f3cf887a80c2ae56b61fc5ca25aAdam Cohen                mTopViewIndex = i;
84055bd9725d5c0373b89f7b9bbd9547550ea3bbc63Jorim Jaggi            }
84121b411074e39fd10cbc8dd0220bb159da4af2c76Adam Cohen        }
8422d783ce2f4b2e507bead0d723f0edcdf902dbd46Adam Cohen        mChildCountOnLastUpdate = childCount;
84321b411074e39fd10cbc8dd0220bb159da4af2c76Adam Cohen    }
84421b411074e39fd10cbc8dd0220bb159da4af2c76Adam Cohen
84521b411074e39fd10cbc8dd0220bb159da4af2c76Adam Cohen    @Override
84621b411074e39fd10cbc8dd0220bb159da4af2c76Adam Cohen    protected int getChildDrawingOrder(int childCount, int i) {
8472d783ce2f4b2e507bead0d723f0edcdf902dbd46Adam Cohen        if (mChildCountOnLastUpdate != childCount) {
8482d783ce2f4b2e507bead0d723f0edcdf902dbd46Adam Cohen            // between platform versions 17 and 18, behavior for onChildViewRemoved / Added changed.
8492d783ce2f4b2e507bead0d723f0edcdf902dbd46Adam Cohen            // Pre-18, the child was not added / removed by the time of those callbacks. We need to
8502d783ce2f4b2e507bead0d723f0edcdf902dbd46Adam Cohen            // force update our representation of things here to avoid crashing on pre-18 devices
8512d783ce2f4b2e507bead0d723f0edcdf902dbd46Adam Cohen            // in certain instances.
8522d783ce2f4b2e507bead0d723f0edcdf902dbd46Adam Cohen            updateChildIndices();
8532d783ce2f4b2e507bead0d723f0edcdf902dbd46Adam Cohen        }
8542d783ce2f4b2e507bead0d723f0edcdf902dbd46Adam Cohen
855432609a246819f3cf887a80c2ae56b61fc5ca25aAdam Cohen        // i represents the current draw iteration
856432609a246819f3cf887a80c2ae56b61fc5ca25aAdam Cohen        if (mTopViewIndex == -1) {
857432609a246819f3cf887a80c2ae56b61fc5ca25aAdam Cohen            // in general we do nothing
85821b411074e39fd10cbc8dd0220bb159da4af2c76Adam Cohen            return i;
859432609a246819f3cf887a80c2ae56b61fc5ca25aAdam Cohen        } else if (i == childCount - 1) {
860432609a246819f3cf887a80c2ae56b61fc5ca25aAdam Cohen            // if we have a top index, we return it when drawing last item (highest z-order)
861432609a246819f3cf887a80c2ae56b61fc5ca25aAdam Cohen            return mTopViewIndex;
862432609a246819f3cf887a80c2ae56b61fc5ca25aAdam Cohen        } else if (i < mTopViewIndex) {
86321b411074e39fd10cbc8dd0220bb159da4af2c76Adam Cohen            return i;
86455bd9725d5c0373b89f7b9bbd9547550ea3bbc63Jorim Jaggi        } else {
865432609a246819f3cf887a80c2ae56b61fc5ca25aAdam Cohen            // for indexes greater than the top index, we fetch one item above to shift for the
866432609a246819f3cf887a80c2ae56b61fc5ca25aAdam Cohen            // displacement of the top index
867432609a246819f3cf887a80c2ae56b61fc5ca25aAdam Cohen            return i + 1;
86821b411074e39fd10cbc8dd0220bb159da4af2c76Adam Cohen        }
86921b411074e39fd10cbc8dd0220bb159da4af2c76Adam Cohen    }
870360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung
871360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung    void onEnterScrollArea(int direction) {
872360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung        mInScrollArea = true;
873360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung        invalidate();
874360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung    }
875360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung
876360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung    void onExitScrollArea() {
877360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung        mInScrollArea = false;
878360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung        invalidate();
879360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung    }
880360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung
881c50438c802355dff714b04f42a32e518cb9e91d8Adam Cohen    void showPageHints() {
882c50438c802355dff714b04f42a32e518cb9e91d8Adam Cohen        mShowPageHints = true;
883c50438c802355dff714b04f42a32e518cb9e91d8Adam Cohen        invalidate();
884c50438c802355dff714b04f42a32e518cb9e91d8Adam Cohen    }
885c50438c802355dff714b04f42a32e518cb9e91d8Adam Cohen
886c50438c802355dff714b04f42a32e518cb9e91d8Adam Cohen    void hidePageHints() {
887c50438c802355dff714b04f42a32e518cb9e91d8Adam Cohen        mShowPageHints = false;
888c50438c802355dff714b04f42a32e518cb9e91d8Adam Cohen        invalidate();
889c50438c802355dff714b04f42a32e518cb9e91d8Adam Cohen    }
890c50438c802355dff714b04f42a32e518cb9e91d8Adam Cohen
891fe1fe268b6d9ffd99218117795b3524a87e5110bWinson Chung    /**
892fe1fe268b6d9ffd99218117795b3524a87e5110bWinson Chung     * Note: this is a reimplementation of View.isLayoutRtl() since that is currently hidden api.
893fe1fe268b6d9ffd99218117795b3524a87e5110bWinson Chung     */
894fe1fe268b6d9ffd99218117795b3524a87e5110bWinson Chung    private boolean isLayoutRtl() {
895fe1fe268b6d9ffd99218117795b3524a87e5110bWinson Chung        return (getLayoutDirection() == LAYOUT_DIRECTION_RTL);
896fe1fe268b6d9ffd99218117795b3524a87e5110bWinson Chung    }
897fe1fe268b6d9ffd99218117795b3524a87e5110bWinson Chung
898360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung    @Override
899360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung    protected void dispatchDraw(Canvas canvas) {
9006c5891a9fce95eee3d87823d11d21889743e9c68Adam Cohen        // Draw the background gradient below children.
9016c5891a9fce95eee3d87823d11d21889743e9c68Adam Cohen        if (mBackground != null && mBackgroundAlpha > 0.0f) {
9026c5891a9fce95eee3d87823d11d21889743e9c68Adam Cohen            int alpha = (int) (mBackgroundAlpha * 255);
9036c5891a9fce95eee3d87823d11d21889743e9c68Adam Cohen            mBackground.setAlpha(alpha);
9046c5891a9fce95eee3d87823d11d21889743e9c68Adam Cohen            mBackground.setBounds(0, 0, getMeasuredWidth(), getMeasuredHeight());
9056c5891a9fce95eee3d87823d11d21889743e9c68Adam Cohen            mBackground.draw(canvas);
9066c5891a9fce95eee3d87823d11d21889743e9c68Adam Cohen        }
9076c5891a9fce95eee3d87823d11d21889743e9c68Adam Cohen
908360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung        super.dispatchDraw(canvas);
9098cc05507150fea5282b7581e1a268967a702bcc9Adam Cohen    }
910360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung
9118cc05507150fea5282b7581e1a268967a702bcc9Adam Cohen    private void drawPageHints(Canvas canvas) {
912c50438c802355dff714b04f42a32e518cb9e91d8Adam Cohen        if (mShowPageHints) {
913360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung            Workspace workspace = mLauncher.getWorkspace();
91461a9a5c359e3e14cb1beaf43dbdb54e00911fe80Adam Cohen            int width = getMeasuredWidth();
915360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung            Rect childRect = new Rect();
916c50438c802355dff714b04f42a32e518cb9e91d8Adam Cohen            getDescendantRectRelativeToSelf(workspace.getChildAt(workspace.getChildCount() - 1),
917c50438c802355dff714b04f42a32e518cb9e91d8Adam Cohen                    childRect);
918360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung
919360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung            int page = workspace.getNextPage();
920fe1fe268b6d9ffd99218117795b3524a87e5110bWinson Chung            final boolean isRtl = isLayoutRtl();
921fe1fe268b6d9ffd99218117795b3524a87e5110bWinson Chung            CellLayout leftPage = (CellLayout) workspace.getChildAt(isRtl ? page + 1 : page - 1);
922fe1fe268b6d9ffd99218117795b3524a87e5110bWinson Chung            CellLayout rightPage = (CellLayout) workspace.getChildAt(isRtl ? page - 1 : page + 1);
923360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung
924c50438c802355dff714b04f42a32e518cb9e91d8Adam Cohen            if (leftPage != null && leftPage.isDragTarget()) {
925c50438c802355dff714b04f42a32e518cb9e91d8Adam Cohen                Drawable left = mInScrollArea && leftPage.getIsDragOverlapping() ?
926c50438c802355dff714b04f42a32e518cb9e91d8Adam Cohen                        mLeftHoverDrawableActive : mLeftHoverDrawable;
927c50438c802355dff714b04f42a32e518cb9e91d8Adam Cohen                left.setBounds(0, childRect.top,
928c50438c802355dff714b04f42a32e518cb9e91d8Adam Cohen                        left.getIntrinsicWidth(), childRect.bottom);
929c50438c802355dff714b04f42a32e518cb9e91d8Adam Cohen                left.draw(canvas);
930c50438c802355dff714b04f42a32e518cb9e91d8Adam Cohen            }
931c50438c802355dff714b04f42a32e518cb9e91d8Adam Cohen            if (rightPage != null && rightPage.isDragTarget()) {
932c50438c802355dff714b04f42a32e518cb9e91d8Adam Cohen                Drawable right = mInScrollArea && rightPage.getIsDragOverlapping() ?
933c50438c802355dff714b04f42a32e518cb9e91d8Adam Cohen                        mRightHoverDrawableActive : mRightHoverDrawable;
934c50438c802355dff714b04f42a32e518cb9e91d8Adam Cohen                right.setBounds(width - right.getIntrinsicWidth(),
935360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung                        childRect.top, width, childRect.bottom);
936c50438c802355dff714b04f42a32e518cb9e91d8Adam Cohen                right.draw(canvas);
937360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung            }
938360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung        }
939360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung    }
940b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen
9418cc05507150fea5282b7581e1a268967a702bcc9Adam Cohen    protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
9428cc05507150fea5282b7581e1a268967a702bcc9Adam Cohen        boolean ret = super.drawChild(canvas, child, drawingTime);
9438cc05507150fea5282b7581e1a268967a702bcc9Adam Cohen
9448cc05507150fea5282b7581e1a268967a702bcc9Adam Cohen        // We want to draw the page hints above the workspace, but below the drag view.
9458cc05507150fea5282b7581e1a268967a702bcc9Adam Cohen        if (child instanceof Workspace) {
9468cc05507150fea5282b7581e1a268967a702bcc9Adam Cohen            drawPageHints(canvas);
9478cc05507150fea5282b7581e1a268967a702bcc9Adam Cohen        }
9488cc05507150fea5282b7581e1a268967a702bcc9Adam Cohen        return ret;
9498cc05507150fea5282b7581e1a268967a702bcc9Adam Cohen    }
9508cc05507150fea5282b7581e1a268967a702bcc9Adam Cohen
9516c5891a9fce95eee3d87823d11d21889743e9c68Adam Cohen    public void setBackgroundAlpha(float alpha) {
9526c5891a9fce95eee3d87823d11d21889743e9c68Adam Cohen        if (alpha != mBackgroundAlpha) {
9536c5891a9fce95eee3d87823d11d21889743e9c68Adam Cohen            mBackgroundAlpha = alpha;
9546c5891a9fce95eee3d87823d11d21889743e9c68Adam Cohen            invalidate();
9556c5891a9fce95eee3d87823d11d21889743e9c68Adam Cohen        }
9566c5891a9fce95eee3d87823d11d21889743e9c68Adam Cohen    }
9576c5891a9fce95eee3d87823d11d21889743e9c68Adam Cohen
9586c5891a9fce95eee3d87823d11d21889743e9c68Adam Cohen    public float getBackgroundAlpha() {
9596c5891a9fce95eee3d87823d11d21889743e9c68Adam Cohen        return mBackgroundAlpha;
9606c5891a9fce95eee3d87823d11d21889743e9c68Adam Cohen    }
9616c5891a9fce95eee3d87823d11d21889743e9c68Adam Cohen
962b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen    public void setTouchCompleteListener(TouchCompleteListener listener) {
963b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen        mTouchCompleteListener = listener;
964b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen    }
965b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen
966b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen    public interface TouchCompleteListener {
967b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen        public void onTouchComplete();
968b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen    }
96931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project}
970