DragLayer.java revision 95abbb330ce9bbaf23594245f0f8a795c8118038
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
8431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    /**
8531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * Used to create a new DragLayer from XML.
8631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     *
8731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param context The application's context.
880e26059548e429e5d1c973bebe4c561bead2926fMichael Jurka     * @param attrs The attributes set containing the Workspace's customization values.
8931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     */
9031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    public DragLayer(Context context, AttributeSet attrs) {
9131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        super(context, attrs);
92be62afa34d58edab0fc9ba7499f0dd543039c903Winson Chung
93be62afa34d58edab0fc9ba7499f0dd543039c903Winson Chung        // Disable multitouch across the workspace/all apps/customize tray
94be62afa34d58edab0fc9ba7499f0dd543039c903Winson Chung        setMotionEventSplittingEnabled(false);
9521b411074e39fd10cbc8dd0220bb159da4af2c76Adam Cohen        setChildrenDrawingOrderEnabled(true);
968b805b17158886035b38261eb611d8641701ae43Michael Jurka        setOnHierarchyChangeListener(this);
97360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung
986c5891a9fce95eee3d87823d11d21889743e9c68Adam Cohen        final Resources res = getResources();
996c5891a9fce95eee3d87823d11d21889743e9c68Adam Cohen        mLeftHoverDrawable = res.getDrawable(R.drawable.page_hover_left_holo);
1006c5891a9fce95eee3d87823d11d21889743e9c68Adam Cohen        mRightHoverDrawable = res.getDrawable(R.drawable.page_hover_right_holo);
1016c5891a9fce95eee3d87823d11d21889743e9c68Adam Cohen        mBackground = res.getDrawable(R.drawable.apps_customize_bg);
10231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
10331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
1044c98d9235d164680186180974719f551cf935d08Winson Chung    public void setup(Launcher launcher, DragController controller) {
1054c98d9235d164680186180974719f551cf935d08Winson Chung        mLauncher = launcher;
10600acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato        mDragController = controller;
10731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
10876fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen
10931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    @Override
11031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    public boolean dispatchKeyEvent(KeyEvent event) {
11100acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato        return mDragController.dispatchKeyEvent(event) || super.dispatchKeyEvent(event);
11231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
11331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
11477e1f47520958edd7ec04e203db65b932537bd1cJohn Spurlock    @Override
11577e1f47520958edd7ec04e203db65b932537bd1cJohn Spurlock    protected boolean fitSystemWindows(Rect insets) {
11677e1f47520958edd7ec04e203db65b932537bd1cJohn Spurlock        final int n = getChildCount();
11777e1f47520958edd7ec04e203db65b932537bd1cJohn Spurlock        for (int i = 0; i < n; i++) {
11877e1f47520958edd7ec04e203db65b932537bd1cJohn Spurlock            final View child = getChildAt(i);
11926279c6d0917015eb4e6de0743b79edeea25f9bcDave Hawkey            setInsets(child, insets, mInsets);
12077e1f47520958edd7ec04e203db65b932537bd1cJohn Spurlock        }
12177e1f47520958edd7ec04e203db65b932537bd1cJohn Spurlock        mInsets.set(insets);
12277e1f47520958edd7ec04e203db65b932537bd1cJohn Spurlock        return true; // I'll take it from here
12377e1f47520958edd7ec04e203db65b932537bd1cJohn Spurlock    }
12477e1f47520958edd7ec04e203db65b932537bd1cJohn Spurlock
12526279c6d0917015eb4e6de0743b79edeea25f9bcDave Hawkey    @Override
12626279c6d0917015eb4e6de0743b79edeea25f9bcDave Hawkey    public void addView(View child, int index, android.view.ViewGroup.LayoutParams params) {
12726279c6d0917015eb4e6de0743b79edeea25f9bcDave Hawkey        super.addView(child, index, params);
12826279c6d0917015eb4e6de0743b79edeea25f9bcDave Hawkey        setInsets(child, mInsets, new Rect());
12926279c6d0917015eb4e6de0743b79edeea25f9bcDave Hawkey    }
13026279c6d0917015eb4e6de0743b79edeea25f9bcDave Hawkey
131b670f195ffb7b4a0519fd0b337b68f7412159414Adam Cohen    public void showOverlayView(View overlayView) {
132432609a246819f3cf887a80c2ae56b61fc5ca25aAdam Cohen        LayoutParams lp = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
133b670f195ffb7b4a0519fd0b337b68f7412159414Adam Cohen        mOverlayView = overlayView;
134b670f195ffb7b4a0519fd0b337b68f7412159414Adam Cohen        addView(overlayView, lp);
135b670f195ffb7b4a0519fd0b337b68f7412159414Adam Cohen
136b670f195ffb7b4a0519fd0b337b68f7412159414Adam Cohen        // ensure that the overlay view stays on top. we can't use drawing order for this
137b670f195ffb7b4a0519fd0b337b68f7412159414Adam Cohen        // because in API level 16 touch dispatch doesn't respect drawing order.
138b670f195ffb7b4a0519fd0b337b68f7412159414Adam Cohen        mOverlayView.bringToFront();
139432609a246819f3cf887a80c2ae56b61fc5ca25aAdam Cohen    }
140432609a246819f3cf887a80c2ae56b61fc5ca25aAdam Cohen
141432609a246819f3cf887a80c2ae56b61fc5ca25aAdam Cohen    public void dismissOverlayView() {
142432609a246819f3cf887a80c2ae56b61fc5ca25aAdam Cohen        removeView(mOverlayView);
143432609a246819f3cf887a80c2ae56b61fc5ca25aAdam Cohen    }
144432609a246819f3cf887a80c2ae56b61fc5ca25aAdam Cohen
14526279c6d0917015eb4e6de0743b79edeea25f9bcDave Hawkey    private void setInsets(View child, Rect newInsets, Rect oldInsets) {
14626279c6d0917015eb4e6de0743b79edeea25f9bcDave Hawkey        final FrameLayout.LayoutParams flp = (FrameLayout.LayoutParams) child.getLayoutParams();
14726279c6d0917015eb4e6de0743b79edeea25f9bcDave Hawkey        if (child instanceof Insettable) {
14826279c6d0917015eb4e6de0743b79edeea25f9bcDave Hawkey            ((Insettable) child).setInsets(newInsets);
14926279c6d0917015eb4e6de0743b79edeea25f9bcDave Hawkey        } else {
15026279c6d0917015eb4e6de0743b79edeea25f9bcDave Hawkey            flp.topMargin += (newInsets.top - oldInsets.top);
15126279c6d0917015eb4e6de0743b79edeea25f9bcDave Hawkey            flp.leftMargin += (newInsets.left - oldInsets.left);
15226279c6d0917015eb4e6de0743b79edeea25f9bcDave Hawkey            flp.rightMargin += (newInsets.right - oldInsets.right);
15326279c6d0917015eb4e6de0743b79edeea25f9bcDave Hawkey            flp.bottomMargin += (newInsets.bottom - oldInsets.bottom);
15426279c6d0917015eb4e6de0743b79edeea25f9bcDave Hawkey        }
15526279c6d0917015eb4e6de0743b79edeea25f9bcDave Hawkey        child.setLayoutParams(flp);
15626279c6d0917015eb4e6de0743b79edeea25f9bcDave Hawkey    }
15726279c6d0917015eb4e6de0743b79edeea25f9bcDave Hawkey
1583371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen    private boolean isEventOverFolderTextRegion(Folder folder, MotionEvent ev) {
1593371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen        getDescendantRectRelativeToSelf(folder.getEditTextRegion(), mHitRect);
1603371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen        if (mHitRect.contains((int) ev.getX(), (int) ev.getY())) {
1613371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen            return true;
1623371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen        }
1633371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen        return false;
1643371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen    }
1653371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen
1663371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen    private boolean isEventOverFolder(Folder folder, MotionEvent ev) {
1673371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen        getDescendantRectRelativeToSelf(folder, mHitRect);
1683371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen        if (mHitRect.contains((int) ev.getX(), (int) ev.getY())) {
1693371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen            return true;
1703371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen        }
1713371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen        return false;
1723371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen    }
1733371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen
17476fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen    private boolean handleTouchDown(MotionEvent ev, boolean intercept) {
1756788269814a678af976dfc7d6135993e172ce586Adam Cohen        Rect hitRect = new Rect();
1766788269814a678af976dfc7d6135993e172ce586Adam Cohen        int x = (int) ev.getX();
1776788269814a678af976dfc7d6135993e172ce586Adam Cohen        int y = (int) ev.getY();
1786788269814a678af976dfc7d6135993e172ce586Adam Cohen
1796788269814a678af976dfc7d6135993e172ce586Adam Cohen        for (AppWidgetResizeFrame child: mResizeFrames) {
1806788269814a678af976dfc7d6135993e172ce586Adam Cohen            child.getHitRect(hitRect);
1816788269814a678af976dfc7d6135993e172ce586Adam Cohen            if (hitRect.contains(x, y)) {
1826788269814a678af976dfc7d6135993e172ce586Adam Cohen                if (child.beginResizeIfPointInRegion(x - child.getLeft(), y - child.getTop())) {
1836788269814a678af976dfc7d6135993e172ce586Adam Cohen                    mCurrentResizeFrame = child;
1846788269814a678af976dfc7d6135993e172ce586Adam Cohen                    mXDown = x;
1856788269814a678af976dfc7d6135993e172ce586Adam Cohen                    mYDown = y;
1866788269814a678af976dfc7d6135993e172ce586Adam Cohen                    requestDisallowInterceptTouchEvent(true);
1876788269814a678af976dfc7d6135993e172ce586Adam Cohen                    return true;
1886788269814a678af976dfc7d6135993e172ce586Adam Cohen                }
1896788269814a678af976dfc7d6135993e172ce586Adam Cohen            }
1906788269814a678af976dfc7d6135993e172ce586Adam Cohen        }
19176fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen
1921d9af7d1e75bad13bb10ad37f5900ed59882622eAdam Cohen        Folder currentFolder = mLauncher.getWorkspace().getOpenFolder();
193a694524047fda0a51dede4eefb1201a598d2d3a7Winson Chung        if (currentFolder != null && !mLauncher.getLauncherClings().isFolderClingVisible() &&
194a694524047fda0a51dede4eefb1201a598d2d3a7Winson Chung                intercept) {
1951d9af7d1e75bad13bb10ad37f5900ed59882622eAdam Cohen            if (currentFolder.isEditingName()) {
1963371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                if (!isEventOverFolderTextRegion(currentFolder, ev)) {
1971d9af7d1e75bad13bb10ad37f5900ed59882622eAdam Cohen                    currentFolder.dismissEditingName();
19876fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen                    return true;
1992801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen                }
2002801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen            }
20176fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen
2021d9af7d1e75bad13bb10ad37f5900ed59882622eAdam Cohen            getDescendantRectRelativeToSelf(currentFolder, hitRect);
2033371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen            if (!isEventOverFolder(currentFolder, ev)) {
20476fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen                mLauncher.closeFolder();
20576fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen                return true;
20676fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen            }
2072801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen        }
2086788269814a678af976dfc7d6135993e172ce586Adam Cohen        return false;
2096788269814a678af976dfc7d6135993e172ce586Adam Cohen    }
2106788269814a678af976dfc7d6135993e172ce586Adam Cohen
21131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    @Override
21231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    public boolean onInterceptTouchEvent(MotionEvent ev) {
213b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen        int action = ev.getAction();
214b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen
215b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen        if (action == MotionEvent.ACTION_DOWN) {
21676fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen            if (handleTouchDown(ev, true)) {
2176788269814a678af976dfc7d6135993e172ce586Adam Cohen                return true;
218d1837cc69eb222371afdd30890f7215d117510f2Patrick Dubroy            }
219b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen        } else if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) {
220b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen            if (mTouchCompleteListener != null) {
221b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen                mTouchCompleteListener.onTouchComplete();
222b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen            }
223b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen            mTouchCompleteListener = null;
2241b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen        }
2256788269814a678af976dfc7d6135993e172ce586Adam Cohen        clearAllResizeFrames();
2264db52312c10e822162a21c60404f06f6e507f0d6Joe Onorato        return mDragController.onInterceptTouchEvent(ev);
22731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
22831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
22931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    @Override
2303371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen    public boolean onInterceptHoverEvent(MotionEvent ev) {
231023c71eb3b2bbe63272cb74baaf050c4188c89b0Michael Jurka        if (mLauncher == null || mLauncher.getWorkspace() == null) {
232023c71eb3b2bbe63272cb74baaf050c4188c89b0Michael Jurka            return false;
233023c71eb3b2bbe63272cb74baaf050c4188c89b0Michael Jurka        }
2343371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen        Folder currentFolder = mLauncher.getWorkspace().getOpenFolder();
2353371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen        if (currentFolder == null) {
2363371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen            return false;
2373371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen        } else {
2388b805b17158886035b38261eb611d8641701ae43Michael Jurka                AccessibilityManager accessibilityManager = (AccessibilityManager)
2398b805b17158886035b38261eb611d8641701ae43Michael Jurka                        getContext().getSystemService(Context.ACCESSIBILITY_SERVICE);
2408b805b17158886035b38261eb611d8641701ae43Michael Jurka            if (accessibilityManager.isTouchExplorationEnabled()) {
2413371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                final int action = ev.getAction();
2423371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                boolean isOverFolder;
2433371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                switch (action) {
2443371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                    case MotionEvent.ACTION_HOVER_ENTER:
2453371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                        isOverFolder = isEventOverFolder(currentFolder, ev);
2463371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                        if (!isOverFolder) {
2473371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                            sendTapOutsideFolderAccessibilityEvent(currentFolder.isEditingName());
2483371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                            mHoverPointClosesFolder = true;
2493371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                            return true;
2503371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                        }
251693fbc7f1737d89f11f9ab81558c109f0883ab0eMihail Dumitrescu                        mHoverPointClosesFolder = false;
252693fbc7f1737d89f11f9ab81558c109f0883ab0eMihail Dumitrescu                        break;
2533371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                    case MotionEvent.ACTION_HOVER_MOVE:
2543371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                        isOverFolder = isEventOverFolder(currentFolder, ev);
2553371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                        if (!isOverFolder && !mHoverPointClosesFolder) {
2563371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                            sendTapOutsideFolderAccessibilityEvent(currentFolder.isEditingName());
2573371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                            mHoverPointClosesFolder = true;
2583371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                            return true;
259693fbc7f1737d89f11f9ab81558c109f0883ab0eMihail Dumitrescu                        } else if (!isOverFolder) {
2603371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                            return true;
2613371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                        }
262693fbc7f1737d89f11f9ab81558c109f0883ab0eMihail Dumitrescu                        mHoverPointClosesFolder = false;
2633371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                }
2643371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen            }
2653371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen        }
2663371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen        return false;
2673371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen    }
2683371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen
2693371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen    private void sendTapOutsideFolderAccessibilityEvent(boolean isEditingName) {
2708b805b17158886035b38261eb611d8641701ae43Michael Jurka        AccessibilityManager accessibilityManager = (AccessibilityManager)
2718b805b17158886035b38261eb611d8641701ae43Michael Jurka                getContext().getSystemService(Context.ACCESSIBILITY_SERVICE);
2728b805b17158886035b38261eb611d8641701ae43Michael Jurka        if (accessibilityManager.isEnabled()) {
2733371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen            int stringId = isEditingName ? R.string.folder_tap_to_rename : R.string.folder_tap_to_close;
2743371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen            AccessibilityEvent event = AccessibilityEvent.obtain(
2753371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                    AccessibilityEvent.TYPE_VIEW_FOCUSED);
2763371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen            onInitializeAccessibilityEvent(event);
2778b805b17158886035b38261eb611d8641701ae43Michael Jurka            event.getText().add(getContext().getString(stringId));
2788b805b17158886035b38261eb611d8641701ae43Michael Jurka            accessibilityManager.sendAccessibilityEvent(event);
2793371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen        }
28083ca480941b3dd635b62347008fc8d7859d82002Winson Chung    }
28183ca480941b3dd635b62347008fc8d7859d82002Winson Chung
28283ca480941b3dd635b62347008fc8d7859d82002Winson Chung    @Override
28383ca480941b3dd635b62347008fc8d7859d82002Winson Chung    public boolean onRequestSendAccessibilityEvent(View child, AccessibilityEvent event) {
28483ca480941b3dd635b62347008fc8d7859d82002Winson Chung        Folder currentFolder = mLauncher.getWorkspace().getOpenFolder();
28583ca480941b3dd635b62347008fc8d7859d82002Winson Chung        if (currentFolder != null) {
28683ca480941b3dd635b62347008fc8d7859d82002Winson Chung            if (child == currentFolder) {
28783ca480941b3dd635b62347008fc8d7859d82002Winson Chung                return super.onRequestSendAccessibilityEvent(child, event);
28883ca480941b3dd635b62347008fc8d7859d82002Winson Chung            }
28983ca480941b3dd635b62347008fc8d7859d82002Winson Chung            // Skip propagating onRequestSendAccessibilityEvent all for other children
29083ca480941b3dd635b62347008fc8d7859d82002Winson Chung            // when a folder is open
29183ca480941b3dd635b62347008fc8d7859d82002Winson Chung            return false;
29283ca480941b3dd635b62347008fc8d7859d82002Winson Chung        }
29383ca480941b3dd635b62347008fc8d7859d82002Winson Chung        return super.onRequestSendAccessibilityEvent(child, event);
29483ca480941b3dd635b62347008fc8d7859d82002Winson Chung    }
29583ca480941b3dd635b62347008fc8d7859d82002Winson Chung
29683ca480941b3dd635b62347008fc8d7859d82002Winson Chung    @Override
29783ca480941b3dd635b62347008fc8d7859d82002Winson Chung    public void addChildrenForAccessibility(ArrayList<View> childrenForAccessibility) {
29883ca480941b3dd635b62347008fc8d7859d82002Winson Chung        Folder currentFolder = mLauncher.getWorkspace().getOpenFolder();
29983ca480941b3dd635b62347008fc8d7859d82002Winson Chung        if (currentFolder != null) {
30083ca480941b3dd635b62347008fc8d7859d82002Winson Chung            // Only add the folder as a child for accessibility when it is open
30183ca480941b3dd635b62347008fc8d7859d82002Winson Chung            childrenForAccessibility.add(currentFolder);
30283ca480941b3dd635b62347008fc8d7859d82002Winson Chung        } else {
30383ca480941b3dd635b62347008fc8d7859d82002Winson Chung            super.addChildrenForAccessibility(childrenForAccessibility);
30483ca480941b3dd635b62347008fc8d7859d82002Winson Chung        }
3053371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen    }
3063371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen
3073371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen    @Override
3083371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen    public boolean onHoverEvent(MotionEvent ev) {
3093371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen        // If we've received this, we've already done the necessary handling
3103371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen        // in onInterceptHoverEvent. Return true to consume the event.
3113371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen        return false;
3123371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen    }
3133371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen
3143371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen    @Override
31531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    public boolean onTouchEvent(MotionEvent ev) {
3166788269814a678af976dfc7d6135993e172ce586Adam Cohen        boolean handled = false;
3176788269814a678af976dfc7d6135993e172ce586Adam Cohen        int action = ev.getAction();
3186788269814a678af976dfc7d6135993e172ce586Adam Cohen
3196788269814a678af976dfc7d6135993e172ce586Adam Cohen        int x = (int) ev.getX();
3206788269814a678af976dfc7d6135993e172ce586Adam Cohen        int y = (int) ev.getY();
3216788269814a678af976dfc7d6135993e172ce586Adam Cohen
322b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen        if (action == MotionEvent.ACTION_DOWN) {
323b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen            if (handleTouchDown(ev, false)) {
324b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen                return true;
325b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen            }
326b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen        } else if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) {
327b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen            if (mTouchCompleteListener != null) {
328b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen                mTouchCompleteListener.onTouchComplete();
3296788269814a678af976dfc7d6135993e172ce586Adam Cohen            }
330b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen            mTouchCompleteListener = null;
3316788269814a678af976dfc7d6135993e172ce586Adam Cohen        }
3326788269814a678af976dfc7d6135993e172ce586Adam Cohen
3336788269814a678af976dfc7d6135993e172ce586Adam Cohen        if (mCurrentResizeFrame != null) {
3346788269814a678af976dfc7d6135993e172ce586Adam Cohen            handled = true;
3356788269814a678af976dfc7d6135993e172ce586Adam Cohen            switch (action) {
3366788269814a678af976dfc7d6135993e172ce586Adam Cohen                case MotionEvent.ACTION_MOVE:
3376788269814a678af976dfc7d6135993e172ce586Adam Cohen                    mCurrentResizeFrame.visualizeResizeForDelta(x - mXDown, y - mYDown);
3386788269814a678af976dfc7d6135993e172ce586Adam Cohen                    break;
3396788269814a678af976dfc7d6135993e172ce586Adam Cohen                case MotionEvent.ACTION_CANCEL:
3406788269814a678af976dfc7d6135993e172ce586Adam Cohen                case MotionEvent.ACTION_UP:
341bebf042666cffe52039b875a549a582abd78a431Adam Cohen                    mCurrentResizeFrame.visualizeResizeForDelta(x - mXDown, y - mYDown);
342bebf042666cffe52039b875a549a582abd78a431Adam Cohen                    mCurrentResizeFrame.onTouchUp();
3436788269814a678af976dfc7d6135993e172ce586Adam Cohen                    mCurrentResizeFrame = null;
3446788269814a678af976dfc7d6135993e172ce586Adam Cohen            }
3456788269814a678af976dfc7d6135993e172ce586Adam Cohen        }
3466788269814a678af976dfc7d6135993e172ce586Adam Cohen        if (handled) return true;
3474db52312c10e822162a21c60404f06f6e507f0d6Joe Onorato        return mDragController.onTouchEvent(ev);
34891a9c9636f10f1e12cd1f660b2e330634fbdc7dcRomain Guy    }
349ea3763c2672f77539538af8cdd395ad97058eaabRomain Guy
35035e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen    /**
35135e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen     * Determine the rect of the descendant in this DragLayer's coordinates
35235e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen     *
35335e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen     * @param descendant The descendant whose coordinates we want to find.
35435e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen     * @param r The rect into which to place the results.
35535e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen     * @return The factor by which this descendant is scaled relative to this DragLayer.
35635e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen     */
357ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen    public float getDescendantRectRelativeToSelf(View descendant, Rect r) {
358716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen        mTmpXY[0] = 0;
359716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen        mTmpXY[1] = 0;
360ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen        float scale = getDescendantCoordRelativeToSelf(descendant, mTmpXY);
3617d30a37007bac318db1c9af47a9af12d348042a5Adam Cohen
3628dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        r.set(mTmpXY[0], mTmpXY[1],
3637d30a37007bac318db1c9af47a9af12d348042a5Adam Cohen                (int) (mTmpXY[0] + scale * descendant.getMeasuredWidth()),
3647d30a37007bac318db1c9af47a9af12d348042a5Adam Cohen                (int) (mTmpXY[1] + scale * descendant.getMeasuredHeight()));
365ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen        return scale;
366716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen    }
36776fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen
368307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen    public float getLocationInDragLayer(View child, int[] loc) {
36935e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen        loc[0] = 0;
37035e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen        loc[1] = 0;
371307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen        return getDescendantCoordRelativeToSelf(child, loc);
37235e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen    }
37335e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen
3747d30a37007bac318db1c9af47a9af12d348042a5Adam Cohen    public float getDescendantCoordRelativeToSelf(View descendant, int[] coord) {
3757d30a37007bac318db1c9af47a9af12d348042a5Adam Cohen        return getDescendantCoordRelativeToSelf(descendant, coord, false);
3767d30a37007bac318db1c9af47a9af12d348042a5Adam Cohen    }
3777d30a37007bac318db1c9af47a9af12d348042a5Adam Cohen
37835e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen    /**
37935e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen     * Given a coordinate relative to the descendant, find the coordinate in this DragLayer's
38035e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen     * coordinates.
38135e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen     *
38235e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen     * @param descendant The descendant to which the passed coordinate is relative.
38335e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen     * @param coord The coordinate that we want mapped.
3847d30a37007bac318db1c9af47a9af12d348042a5Adam Cohen     * @param includeRootScroll Whether or not to account for the scroll of the root descendant:
3857d30a37007bac318db1c9af47a9af12d348042a5Adam Cohen     *          sometimes this is relevant as in a child's coordinates within the root descendant.
386307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen     * @return The factor by which this descendant is scaled relative to this DragLayer. Caution
387307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen     *         this scale factor is assumed to be equal in X and Y, and so if at any point this
388307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen     *         assumption fails, we will need to return a pair of scale factors.
38935e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen     */
3907d30a37007bac318db1c9af47a9af12d348042a5Adam Cohen    public float getDescendantCoordRelativeToSelf(View descendant, int[] coord,
3917d30a37007bac318db1c9af47a9af12d348042a5Adam Cohen            boolean includeRootScroll) {
392c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung        return Utilities.getDescendantCoordRelativeToParent(descendant, this,
393c9ca2980983ab21fc8631c7a65399d6d9c70f39cWinson Chung                coord, includeRootScroll);
394c9ca2980983ab21fc8631c7a65399d6d9c70f39cWinson Chung    }
395c9ca2980983ab21fc8631c7a65399d6d9c70f39cWinson Chung
3967d30a37007bac318db1c9af47a9af12d348042a5Adam Cohen    /**
3977d30a37007bac318db1c9af47a9af12d348042a5Adam Cohen     * Inverse of {@link #getDescendantCoordRelativeToSelf(View, int[])}.
3987d30a37007bac318db1c9af47a9af12d348042a5Adam Cohen     */
3997d30a37007bac318db1c9af47a9af12d348042a5Adam Cohen    public float mapCoordInSelfToDescendent(View descendant, int[] coord) {
400c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung        return Utilities.mapCoordInSelfToDescendent(descendant, this, coord);
40176fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen    }
40276fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen
4033e8f811f31a2275e778244427271f77f4116c08bAdam Cohen    public void getViewRectRelativeToSelf(View v, Rect r) {
4043e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        int[] loc = new int[2];
4058dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        getLocationInWindow(loc);
4063e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        int x = loc[0];
4073e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        int y = loc[1];
408716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen
4098dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        v.getLocationInWindow(loc);
4103e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        int vX = loc[0];
4113e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        int vY = loc[1];
412716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen
4133e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        int left = vX - x;
4143e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        int top = vY - y;
4153e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        r.set(left, top, left + v.getMeasuredWidth(), top + v.getMeasuredHeight());
416716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen    }
417716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen
418ea3763c2672f77539538af8cdd395ad97058eaabRomain Guy    @Override
419ea3763c2672f77539538af8cdd395ad97058eaabRomain Guy    public boolean dispatchUnhandledMove(View focused, int direction) {
420ea3763c2672f77539538af8cdd395ad97058eaabRomain Guy        return mDragController.dispatchUnhandledMove(focused, direction);
421ea3763c2672f77539538af8cdd395ad97058eaabRomain Guy    }
422120980bd00f5eecec5717f49a3d7db96571025a9Adam Cohen
4236788269814a678af976dfc7d6135993e172ce586Adam Cohen    public static class LayoutParams extends FrameLayout.LayoutParams {
4246788269814a678af976dfc7d6135993e172ce586Adam Cohen        public int x, y;
4256788269814a678af976dfc7d6135993e172ce586Adam Cohen        public boolean customPosition = false;
4266788269814a678af976dfc7d6135993e172ce586Adam Cohen
4276788269814a678af976dfc7d6135993e172ce586Adam Cohen        /**
4286788269814a678af976dfc7d6135993e172ce586Adam Cohen         * {@inheritDoc}
4296788269814a678af976dfc7d6135993e172ce586Adam Cohen         */
4306788269814a678af976dfc7d6135993e172ce586Adam Cohen        public LayoutParams(int width, int height) {
4316788269814a678af976dfc7d6135993e172ce586Adam Cohen            super(width, height);
4326788269814a678af976dfc7d6135993e172ce586Adam Cohen        }
4336788269814a678af976dfc7d6135993e172ce586Adam Cohen
4346788269814a678af976dfc7d6135993e172ce586Adam Cohen        public void setWidth(int width) {
4356788269814a678af976dfc7d6135993e172ce586Adam Cohen            this.width = width;
4366788269814a678af976dfc7d6135993e172ce586Adam Cohen        }
4376788269814a678af976dfc7d6135993e172ce586Adam Cohen
4386788269814a678af976dfc7d6135993e172ce586Adam Cohen        public int getWidth() {
4396788269814a678af976dfc7d6135993e172ce586Adam Cohen            return width;
4406788269814a678af976dfc7d6135993e172ce586Adam Cohen        }
4416788269814a678af976dfc7d6135993e172ce586Adam Cohen
4426788269814a678af976dfc7d6135993e172ce586Adam Cohen        public void setHeight(int height) {
4436788269814a678af976dfc7d6135993e172ce586Adam Cohen            this.height = height;
4446788269814a678af976dfc7d6135993e172ce586Adam Cohen        }
4456788269814a678af976dfc7d6135993e172ce586Adam Cohen
4466788269814a678af976dfc7d6135993e172ce586Adam Cohen        public int getHeight() {
4476788269814a678af976dfc7d6135993e172ce586Adam Cohen            return height;
4486788269814a678af976dfc7d6135993e172ce586Adam Cohen        }
4496788269814a678af976dfc7d6135993e172ce586Adam Cohen
4506788269814a678af976dfc7d6135993e172ce586Adam Cohen        public void setX(int x) {
4516788269814a678af976dfc7d6135993e172ce586Adam Cohen            this.x = x;
4526788269814a678af976dfc7d6135993e172ce586Adam Cohen        }
4536788269814a678af976dfc7d6135993e172ce586Adam Cohen
4546788269814a678af976dfc7d6135993e172ce586Adam Cohen        public int getX() {
4556788269814a678af976dfc7d6135993e172ce586Adam Cohen            return x;
4566788269814a678af976dfc7d6135993e172ce586Adam Cohen        }
4576788269814a678af976dfc7d6135993e172ce586Adam Cohen
4586788269814a678af976dfc7d6135993e172ce586Adam Cohen        public void setY(int y) {
4596788269814a678af976dfc7d6135993e172ce586Adam Cohen            this.y = y;
4606788269814a678af976dfc7d6135993e172ce586Adam Cohen        }
4616788269814a678af976dfc7d6135993e172ce586Adam Cohen
4626788269814a678af976dfc7d6135993e172ce586Adam Cohen        public int getY() {
4636788269814a678af976dfc7d6135993e172ce586Adam Cohen            return y;
4646788269814a678af976dfc7d6135993e172ce586Adam Cohen        }
4656788269814a678af976dfc7d6135993e172ce586Adam Cohen    }
4666788269814a678af976dfc7d6135993e172ce586Adam Cohen
4676788269814a678af976dfc7d6135993e172ce586Adam Cohen    protected void onLayout(boolean changed, int l, int t, int r, int b) {
4686788269814a678af976dfc7d6135993e172ce586Adam Cohen        super.onLayout(changed, l, t, r, b);
4696788269814a678af976dfc7d6135993e172ce586Adam Cohen        int count = getChildCount();
4706788269814a678af976dfc7d6135993e172ce586Adam Cohen        for (int i = 0; i < count; i++) {
4716788269814a678af976dfc7d6135993e172ce586Adam Cohen            View child = getChildAt(i);
4726788269814a678af976dfc7d6135993e172ce586Adam Cohen            final FrameLayout.LayoutParams flp = (FrameLayout.LayoutParams) child.getLayoutParams();
4736788269814a678af976dfc7d6135993e172ce586Adam Cohen            if (flp instanceof LayoutParams) {
4746788269814a678af976dfc7d6135993e172ce586Adam Cohen                final LayoutParams lp = (LayoutParams) flp;
4756788269814a678af976dfc7d6135993e172ce586Adam Cohen                if (lp.customPosition) {
4766788269814a678af976dfc7d6135993e172ce586Adam Cohen                    child.layout(lp.x, lp.y, lp.x + lp.width, lp.y + lp.height);
4776788269814a678af976dfc7d6135993e172ce586Adam Cohen                }
4786788269814a678af976dfc7d6135993e172ce586Adam Cohen            }
4796788269814a678af976dfc7d6135993e172ce586Adam Cohen        }
4806788269814a678af976dfc7d6135993e172ce586Adam Cohen    }
4816788269814a678af976dfc7d6135993e172ce586Adam Cohen
4826788269814a678af976dfc7d6135993e172ce586Adam Cohen    public void clearAllResizeFrames() {
4836788269814a678af976dfc7d6135993e172ce586Adam Cohen        if (mResizeFrames.size() > 0) {
4846788269814a678af976dfc7d6135993e172ce586Adam Cohen            for (AppWidgetResizeFrame frame: mResizeFrames) {
485bebf042666cffe52039b875a549a582abd78a431Adam Cohen                frame.commitResize();
4866788269814a678af976dfc7d6135993e172ce586Adam Cohen                removeView(frame);
4876788269814a678af976dfc7d6135993e172ce586Adam Cohen            }
4886788269814a678af976dfc7d6135993e172ce586Adam Cohen            mResizeFrames.clear();
4896788269814a678af976dfc7d6135993e172ce586Adam Cohen        }
4906788269814a678af976dfc7d6135993e172ce586Adam Cohen    }
4916788269814a678af976dfc7d6135993e172ce586Adam Cohen
4926788269814a678af976dfc7d6135993e172ce586Adam Cohen    public boolean hasResizeFrames() {
4936788269814a678af976dfc7d6135993e172ce586Adam Cohen        return mResizeFrames.size() > 0;
4946788269814a678af976dfc7d6135993e172ce586Adam Cohen    }
4956788269814a678af976dfc7d6135993e172ce586Adam Cohen
4966788269814a678af976dfc7d6135993e172ce586Adam Cohen    public boolean isWidgetBeingResized() {
4976788269814a678af976dfc7d6135993e172ce586Adam Cohen        return mCurrentResizeFrame != null;
4986788269814a678af976dfc7d6135993e172ce586Adam Cohen    }
4996788269814a678af976dfc7d6135993e172ce586Adam Cohen
5006788269814a678af976dfc7d6135993e172ce586Adam Cohen    public void addResizeFrame(ItemInfo itemInfo, LauncherAppWidgetHostView widget,
5016788269814a678af976dfc7d6135993e172ce586Adam Cohen            CellLayout cellLayout) {
5026788269814a678af976dfc7d6135993e172ce586Adam Cohen        AppWidgetResizeFrame resizeFrame = new AppWidgetResizeFrame(getContext(),
5033a9fcedbcd235372cd2ab64f825a0b5b3937f59eMichael Jurka                widget, cellLayout, this);
5046788269814a678af976dfc7d6135993e172ce586Adam Cohen
5056788269814a678af976dfc7d6135993e172ce586Adam Cohen        LayoutParams lp = new LayoutParams(-1, -1);
5066788269814a678af976dfc7d6135993e172ce586Adam Cohen        lp.customPosition = true;
5076788269814a678af976dfc7d6135993e172ce586Adam Cohen
5086788269814a678af976dfc7d6135993e172ce586Adam Cohen        addView(resizeFrame, lp);
5096788269814a678af976dfc7d6135993e172ce586Adam Cohen        mResizeFrames.add(resizeFrame);
5106788269814a678af976dfc7d6135993e172ce586Adam Cohen
5116788269814a678af976dfc7d6135993e172ce586Adam Cohen        resizeFrame.snapToWidget(false);
5126788269814a678af976dfc7d6135993e172ce586Adam Cohen    }
513716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen
514716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen    public void animateViewIntoPosition(DragView dragView, final View child) {
51528f852ab678d9750879b6d3549bf5da176cf1225Adam Cohen        animateViewIntoPosition(dragView, child, null, null);
516557d6ed50cc6560163440aa134870ef0bb11415bWinson Chung    }
517ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen
5187bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung    public void animateViewIntoPosition(DragView dragView, final int[] pos, float alpha,
5197bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung            float scaleX, float scaleY, int animationEndStyle, Runnable onFinishRunnable,
5207bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung            int duration) {
521b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen        Rect r = new Rect();
522b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen        getViewRectRelativeToSelf(dragView, r);
523b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen        final int fromX = r.left;
524b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen        final int fromY = r.top;
525b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen
5267bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung        animateViewIntoPosition(dragView, fromX, fromY, pos[0], pos[1], alpha, 1, 1, scaleX, scaleY,
527ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen                onFinishRunnable, animationEndStyle, duration, null);
528ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen    }
529ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen
530557d6ed50cc6560163440aa134870ef0bb11415bWinson Chung    public void animateViewIntoPosition(DragView dragView, final View child,
53128f852ab678d9750879b6d3549bf5da176cf1225Adam Cohen            final Runnable onFinishAnimationRunnable, View anchorView) {
53228f852ab678d9750879b6d3549bf5da176cf1225Adam Cohen        animateViewIntoPosition(dragView, child, -1, onFinishAnimationRunnable, anchorView);
533ed51cc9a12c50d12e7d30ed209a49f1a40858043Adam Cohen    }
534ed51cc9a12c50d12e7d30ed209a49f1a40858043Adam Cohen
535ed51cc9a12c50d12e7d30ed209a49f1a40858043Adam Cohen    public void animateViewIntoPosition(DragView dragView, final View child, int duration,
5366441de0ec2a71862798dd51180d0811b42edd514Adam Cohen            final Runnable onFinishAnimationRunnable, View anchorView) {
537a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        ShortcutAndWidgetContainer parentChildren = (ShortcutAndWidgetContainer) child.getParent();
538716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen        CellLayout.LayoutParams lp =  (CellLayout.LayoutParams) child.getLayoutParams();
539eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung        parentChildren.measureChild(child);
540716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen
5413e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        Rect r = new Rect();
5423e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        getViewRectRelativeToSelf(dragView, r);
543716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen
544716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen        int coord[] = new int[2];
545307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen        float childScale = child.getScaleX();
546307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen        coord[0] = lp.x + (int) (child.getMeasuredWidth() * (1 - childScale) / 2);
547307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen        coord[1] = lp.y + (int) (child.getMeasuredHeight() * (1 - childScale) / 2);
548eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung
5498dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        // Since the child hasn't necessarily been laid out, we force the lp to be updated with
550ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen        // the correct coordinates (above) and use these to determine the final location
551557d6ed50cc6560163440aa134870ef0bb11415bWinson Chung        float scale = getDescendantCoordRelativeToSelf((View) child.getParent(), coord);
552307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen        // We need to account for the scale of the child itself, as the above only accounts for
553307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen        // for the scale in parents.
554307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen        scale *= childScale;
555ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen        int toX = coord[0];
556ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen        int toY = coord[1];
557eeb5bbc9409978cc2ae52d48380399fcde3d9f85Winson Chung        float toScale = scale;
5584497ebf9a2726e2a7dbb7f3c49389308908f8454Andrew Flynn        if (child instanceof TextView) {
5594497ebf9a2726e2a7dbb7f3c49389308908f8454Andrew Flynn            TextView tv = (TextView) child;
560eeb5bbc9409978cc2ae52d48380399fcde3d9f85Winson Chung            // Account for the source scale of the icon (ie. from AllApps to Workspace, in which
561eeb5bbc9409978cc2ae52d48380399fcde3d9f85Winson Chung            // the workspace may have smaller icon bounds).
562eeb5bbc9409978cc2ae52d48380399fcde3d9f85Winson Chung            toScale = scale / dragView.getIntrinsicIconScaleFactor();
5634497ebf9a2726e2a7dbb7f3c49389308908f8454Andrew Flynn
5644497ebf9a2726e2a7dbb7f3c49389308908f8454Andrew Flynn            // The child may be scaled (always about the center of the view) so to account for it,
5654497ebf9a2726e2a7dbb7f3c49389308908f8454Andrew Flynn            // we have to offset the position by the scaled size.  Once we do that, we can center
5664497ebf9a2726e2a7dbb7f3c49389308908f8454Andrew Flynn            // the drag view about the scaled child view.
567eeb5bbc9409978cc2ae52d48380399fcde3d9f85Winson Chung            toY += Math.round(toScale * tv.getPaddingTop());
568eeb5bbc9409978cc2ae52d48380399fcde3d9f85Winson Chung            toY -= dragView.getMeasuredHeight() * (1 - toScale) / 2;
56995abbb330ce9bbaf23594245f0f8a795c8118038Sunny Goyal            if (dragView.getDragVisualizeOffset() != null) {
57095abbb330ce9bbaf23594245f0f8a795c8118038Sunny Goyal                toY -=  Math.round(toScale * dragView.getDragVisualizeOffset().y);
57195abbb330ce9bbaf23594245f0f8a795c8118038Sunny Goyal            }
57295abbb330ce9bbaf23594245f0f8a795c8118038Sunny Goyal
5734497ebf9a2726e2a7dbb7f3c49389308908f8454Andrew Flynn            toX -= (dragView.getMeasuredWidth() - Math.round(scale * child.getMeasuredWidth())) / 2;
5744497ebf9a2726e2a7dbb7f3c49389308908f8454Andrew Flynn        } else if (child instanceof FolderIcon) {
575ea359c6aee44c0fe3bb94f7002c3b49208b32b7fWinson Chung            // Account for holographic blur padding on the drag view
5765f8afe6280eae34620067696173e71943e1a30a3Winson Chung            toY += Math.round(scale * (child.getPaddingTop() - dragView.getDragRegionTop()));
577307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen            toY -= scale * Workspace.DRAG_BITMAP_PADDING / 2;
578307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen            toY -= (1 - scale) * dragView.getMeasuredHeight() / 2;
579ea359c6aee44c0fe3bb94f7002c3b49208b32b7fWinson Chung            // Center in the x coordinate about the target's drawable
580ea359c6aee44c0fe3bb94f7002c3b49208b32b7fWinson Chung            toX -= (dragView.getMeasuredWidth() - Math.round(scale * child.getMeasuredWidth())) / 2;
581ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen        } else {
582ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen            toY -= (Math.round(scale * (dragView.getHeight() - child.getMeasuredHeight()))) / 2;
583ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen            toX -= (Math.round(scale * (dragView.getMeasuredWidth()
584ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen                    - child.getMeasuredWidth()))) / 2;
585ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen        }
586716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen
587ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen        final int fromX = r.left;
588ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen        final int fromY = r.top;
589716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen        child.setVisibility(INVISIBLE);
5908dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        Runnable onCompleteRunnable = new Runnable() {
5918dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen            public void run() {
5928dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen                child.setVisibility(VISIBLE);
593d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                if (onFinishAnimationRunnable != null) {
594d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    onFinishAnimationRunnable.run();
595d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                }
5968dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen            }
5978dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        };
598eeb5bbc9409978cc2ae52d48380399fcde3d9f85Winson Chung        animateViewIntoPosition(dragView, fromX, fromY, toX, toY, 1, 1, 1, toScale, toScale,
599d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                onCompleteRunnable, ANIMATION_END_DISAPPEAR, duration, anchorView);
600557d6ed50cc6560163440aa134870ef0bb11415bWinson Chung    }
601557d6ed50cc6560163440aa134870ef0bb11415bWinson Chung
602d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen    public void animateViewIntoPosition(final DragView view, final int fromX, final int fromY,
603ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen            final int toX, final int toY, float finalAlpha, float initScaleX, float initScaleY,
604ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen            float finalScaleX, float finalScaleY, Runnable onCompleteRunnable,
605ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen            int animationEndStyle, int duration, View anchorView) {
6068dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        Rect from = new Rect(fromX, fromY, fromX +
6078dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen                view.getMeasuredWidth(), fromY + view.getMeasuredHeight());
6083e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        Rect to = new Rect(toX, toY, toX + view.getMeasuredWidth(), toY + view.getMeasuredHeight());
609ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen        animateView(view, from, to, finalAlpha, initScaleX, initScaleY, finalScaleX, finalScaleY, duration,
610ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen                null, null, onCompleteRunnable, animationEndStyle, anchorView);
6113e8f811f31a2275e778244427271f77f4116c08bAdam Cohen    }
6123e8f811f31a2275e778244427271f77f4116c08bAdam Cohen
613b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen    /**
614b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen     * This method animates a view at the end of a drag and drop animation.
615b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen     *
616b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen     * @param view The view to be animated. This view is drawn directly into DragLayer, and so
617b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen     *        doesn't need to be a child of DragLayer.
618b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen     * @param from The initial location of the view. Only the left and top parameters are used.
619b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen     * @param to The final location of the view. Only the left and top parameters are used. This
620b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen     *        location doesn't account for scaling, and so should be centered about the desired
621b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen     *        final location (including scaling).
622b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen     * @param finalAlpha The final alpha of the view, in case we want it to fade as it animates.
623b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen     * @param finalScale The final scale of the view. The view is scaled about its center.
624b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen     * @param duration The duration of the animation.
625b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen     * @param motionInterpolator The interpolator to use for the location of the view.
626b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen     * @param alphaInterpolator The interpolator to use for the alpha of the view.
627b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen     * @param onCompleteRunnable Optional runnable to run on animation completion.
628b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen     * @param fadeOut Whether or not to fade out the view once the animation completes. If true,
629b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen     *        the runnable will execute after the view is faded out.
6306441de0ec2a71862798dd51180d0811b42edd514Adam Cohen     * @param anchorView If not null, this represents the view which the animated view stays
6316441de0ec2a71862798dd51180d0811b42edd514Adam Cohen     *        anchored to in case scrolling is currently taking place. Note: currently this is
6326441de0ec2a71862798dd51180d0811b42edd514Adam Cohen     *        only used for the X dimension for the case of the workspace.
633b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen     */
6347bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung    public void animateView(final DragView view, final Rect from, final Rect to,
6357bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung            final float finalAlpha, final float initScaleX, final float initScaleY,
6367bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung            final float finalScaleX, final float finalScaleY, int duration,
6377bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung            final Interpolator motionInterpolator, final Interpolator alphaInterpolator,
6387bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung            final Runnable onCompleteRunnable, final int animationEndStyle, View anchorView) {
6397bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung
640716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen        // Calculate the duration of the animation based on the object's distance
6413e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        final float dist = (float) Math.sqrt(Math.pow(to.left - from.left, 2) +
6423e8f811f31a2275e778244427271f77f4116c08bAdam Cohen                Math.pow(to.top - from.top, 2));
643716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen        final Resources res = getResources();
644716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen        final float maxDist = (float) res.getInteger(R.integer.config_dropAnimMaxDist);
6453e8f811f31a2275e778244427271f77f4116c08bAdam Cohen
6463e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        // If duration < 0, this is a cue to compute the duration based on the distance
6473e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        if (duration < 0) {
6483e8f811f31a2275e778244427271f77f4116c08bAdam Cohen            duration = res.getInteger(R.integer.config_dropAnimMaxDuration);
6493e8f811f31a2275e778244427271f77f4116c08bAdam Cohen            if (dist < maxDist) {
6508dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen                duration *= mCubicEaseOutInterpolator.getInterpolation(dist / maxDist);
6513e8f811f31a2275e778244427271f77f4116c08bAdam Cohen            }
65261b0c69d3fe331d3de338322396d5de691d58613Winson Chung            duration = Math.max(duration, res.getInteger(R.integer.config_dropAnimMinDuration));
653716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen        }
654716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen
655043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        // Fall back to cubic ease out interpolator for the animation if none is specified
656043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        TimeInterpolator interpolator = null;
6573e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        if (alphaInterpolator == null || motionInterpolator == null) {
658043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung            interpolator = mCubicEaseOutInterpolator;
6593e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        }
660716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen
661043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        // Animate the view
6627bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung        final float initAlpha = view.getAlpha();
663043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        final float dropViewScale = view.getScaleX();
664043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        AnimatorUpdateListener updateCb = new AnimatorUpdateListener() {
665043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung            @Override
666716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen            public void onAnimationUpdate(ValueAnimator animation) {
667716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen                final float percent = (Float) animation.getAnimatedValue();
6687bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung                final int width = view.getMeasuredWidth();
6697bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung                final int height = view.getMeasuredHeight();
670716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen
6713e8f811f31a2275e778244427271f77f4116c08bAdam Cohen                float alphaPercent = alphaInterpolator == null ? percent :
6723e8f811f31a2275e778244427271f77f4116c08bAdam Cohen                        alphaInterpolator.getInterpolation(percent);
6733e8f811f31a2275e778244427271f77f4116c08bAdam Cohen                float motionPercent = motionInterpolator == null ? percent :
6743e8f811f31a2275e778244427271f77f4116c08bAdam Cohen                        motionInterpolator.getInterpolation(percent);
675a1cdab039292f3d809528c0e2e38580b37864d8dWinson Chung
6767bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung                float initialScaleX = initScaleX * dropViewScale;
6777bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung                float initialScaleY = initScaleY * dropViewScale;
6787bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung                float scaleX = finalScaleX * percent + initialScaleX * (1 - percent);
6797bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung                float scaleY = finalScaleY * percent + initialScaleY * (1 - percent);
6807bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung                float alpha = finalAlpha * alphaPercent + initAlpha * (1 - alphaPercent);
6817bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung
6827bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung                float fromLeft = from.left + (initialScaleX - 1f) * width / 2;
6837bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung                float fromTop = from.top + (initialScaleY - 1f) * height / 2;
6847bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung
6857bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung                int x = (int) (fromLeft + Math.round(((to.left - fromLeft) * motionPercent)));
6867bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung                int y = (int) (fromTop + Math.round(((to.top - fromTop) * motionPercent)));
6877bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung
68828f852ab678d9750879b6d3549bf5da176cf1225Adam Cohen                int anchorAdjust = mAnchorView == null ? 0 : (int) (mAnchorView.getScaleX() *
68928f852ab678d9750879b6d3549bf5da176cf1225Adam Cohen                    (mAnchorViewInitialScrollX - mAnchorView.getScrollX()));
69028f852ab678d9750879b6d3549bf5da176cf1225Adam Cohen
69128f852ab678d9750879b6d3549bf5da176cf1225Adam Cohen                int xPos = x - mDropView.getScrollX() + anchorAdjust;
6927bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung                int yPos = y - mDropView.getScrollY();
6937bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung
6947bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung                mDropView.setTranslationX(xPos);
6957bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung                mDropView.setTranslationY(yPos);
6967bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung                mDropView.setScaleX(scaleX);
6977bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung                mDropView.setScaleY(scaleY);
6987bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung                mDropView.setAlpha(alpha);
699716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen            }
700043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        };
701043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        animateView(view, updateCb, duration, interpolator, onCompleteRunnable, animationEndStyle,
702043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung                anchorView);
703043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung    }
704043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung
705043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung    public void animateView(final DragView view, AnimatorUpdateListener updateCb, int duration,
706043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung            TimeInterpolator interpolator, final Runnable onCompleteRunnable,
707043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung            final int animationEndStyle, View anchorView) {
708043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        // Clean up the previous animations
709043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        if (mDropAnim != null) mDropAnim.cancel();
710043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        if (mFadeOutAnim != null) mFadeOutAnim.cancel();
711043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung
712043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        // Show the drop view if it was previously hidden
713043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        mDropView = view;
714043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        mDropView.cancelAnimation();
715043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        mDropView.resetLayoutParams();
716043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung
717043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        // Set the anchor view if the page is scrolling
718043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        if (anchorView != null) {
719043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung            mAnchorViewInitialScrollX = anchorView.getScrollX();
720043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        }
721043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        mAnchorView = anchorView;
722043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung
723043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        // Create and start the animation
724043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        mDropAnim = new ValueAnimator();
725043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        mDropAnim.setInterpolator(interpolator);
726043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        mDropAnim.setDuration(duration);
727043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        mDropAnim.setFloatValues(0f, 1f);
728043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        mDropAnim.addUpdateListener(updateCb);
7293e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        mDropAnim.addListener(new AnimatorListenerAdapter() {
7303e8f811f31a2275e778244427271f77f4116c08bAdam Cohen            public void onAnimationEnd(Animator animation) {
7318dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen                if (onCompleteRunnable != null) {
7328dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen                    onCompleteRunnable.run();
7338dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen                }
734ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen                switch (animationEndStyle) {
735ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen                case ANIMATION_END_DISAPPEAR:
736ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen                    clearAnimatedView();
737ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen                    break;
738ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen                case ANIMATION_END_FADE_OUT:
7398dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen                    fadeOutDragView();
740ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen                    break;
741ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen                case ANIMATION_END_REMAIN_VISIBLE:
742ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen                    break;
7433e8f811f31a2275e778244427271f77f4116c08bAdam Cohen                }
7443e8f811f31a2275e778244427271f77f4116c08bAdam Cohen            }
7453e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        });
746716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen        mDropAnim.start();
747716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen    }
748716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen
749ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen    public void clearAnimatedView() {
7507bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung        if (mDropAnim != null) {
7517bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung            mDropAnim.cancel();
7527bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung        }
7537bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung        if (mDropView != null) {
7542d783ce2f4b2e507bead0d723f0edcdf902dbd46Adam Cohen            mDragController.onDeferredEndDrag(mDropView);
7557bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung        }
756ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen        mDropView = null;
757ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen        invalidate();
758ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen    }
759ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen
760ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen    public View getAnimatedView() {
761ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen        return mDropView;
762ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen    }
763ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen
7648dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen    private void fadeOutDragView() {
7658dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        mFadeOutAnim = new ValueAnimator();
7668dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        mFadeOutAnim.setDuration(150);
7678dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        mFadeOutAnim.setFloatValues(0f, 1f);
7688dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        mFadeOutAnim.removeAllUpdateListeners();
7698dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        mFadeOutAnim.addUpdateListener(new AnimatorUpdateListener() {
7708dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen            public void onAnimationUpdate(ValueAnimator animation) {
7718dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen                final float percent = (Float) animation.getAnimatedValue();
7727bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung
7737bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung                float alpha = 1 - percent;
7747bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung                mDropView.setAlpha(alpha);
7758dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen            }
7768dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        });
7778dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        mFadeOutAnim.addListener(new AnimatorListenerAdapter() {
7788dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen            public void onAnimationEnd(Animator animation) {
7797bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung                if (mDropView != null) {
780043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung                    mDragController.onDeferredEndDrag(mDropView);
7817bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung                }
7828dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen                mDropView = null;
783ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen                invalidate();
7848dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen            }
7858dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        });
7868dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        mFadeOutAnim.start();
7878dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen    }
7888dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen
789716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen    @Override
7908b805b17158886035b38261eb611d8641701ae43Michael Jurka    public void onChildViewAdded(View parent, View child) {
791b670f195ffb7b4a0519fd0b337b68f7412159414Adam Cohen        if (mOverlayView != null) {
792b670f195ffb7b4a0519fd0b337b68f7412159414Adam Cohen            // ensure that the overlay view stays on top. we can't use drawing order for this
793b670f195ffb7b4a0519fd0b337b68f7412159414Adam Cohen            // because in API level 16 touch dispatch doesn't respect drawing order.
794b670f195ffb7b4a0519fd0b337b68f7412159414Adam Cohen            mOverlayView.bringToFront();
795b670f195ffb7b4a0519fd0b337b68f7412159414Adam Cohen        }
79621b411074e39fd10cbc8dd0220bb159da4af2c76Adam Cohen        updateChildIndices();
79721b411074e39fd10cbc8dd0220bb159da4af2c76Adam Cohen    }
79821b411074e39fd10cbc8dd0220bb159da4af2c76Adam Cohen
79921b411074e39fd10cbc8dd0220bb159da4af2c76Adam Cohen    @Override
8008b805b17158886035b38261eb611d8641701ae43Michael Jurka    public void onChildViewRemoved(View parent, View child) {
80121b411074e39fd10cbc8dd0220bb159da4af2c76Adam Cohen        updateChildIndices();
80221b411074e39fd10cbc8dd0220bb159da4af2c76Adam Cohen    }
80321b411074e39fd10cbc8dd0220bb159da4af2c76Adam Cohen
804432609a246819f3cf887a80c2ae56b61fc5ca25aAdam Cohen    @Override
805432609a246819f3cf887a80c2ae56b61fc5ca25aAdam Cohen    public void bringChildToFront(View child) {
806432609a246819f3cf887a80c2ae56b61fc5ca25aAdam Cohen        super.bringChildToFront(child);
807b670f195ffb7b4a0519fd0b337b68f7412159414Adam Cohen        if (child != mOverlayView && mOverlayView != null) {
808b670f195ffb7b4a0519fd0b337b68f7412159414Adam Cohen            // ensure that the overlay view stays on top. we can't use drawing order for this
809b670f195ffb7b4a0519fd0b337b68f7412159414Adam Cohen            // because in API level 16 touch dispatch doesn't respect drawing order.
810b670f195ffb7b4a0519fd0b337b68f7412159414Adam Cohen            mOverlayView.bringToFront();
811b670f195ffb7b4a0519fd0b337b68f7412159414Adam Cohen        }
812432609a246819f3cf887a80c2ae56b61fc5ca25aAdam Cohen        updateChildIndices();
813432609a246819f3cf887a80c2ae56b61fc5ca25aAdam Cohen    }
814432609a246819f3cf887a80c2ae56b61fc5ca25aAdam Cohen
81521b411074e39fd10cbc8dd0220bb159da4af2c76Adam Cohen    private void updateChildIndices() {
816432609a246819f3cf887a80c2ae56b61fc5ca25aAdam Cohen        mTopViewIndex = -1;
81755bd9725d5c0373b89f7b9bbd9547550ea3bbc63Jorim Jaggi        int childCount = getChildCount();
81855bd9725d5c0373b89f7b9bbd9547550ea3bbc63Jorim Jaggi        for (int i = 0; i < childCount; i++) {
819b670f195ffb7b4a0519fd0b337b68f7412159414Adam Cohen            if (getChildAt(i) instanceof DragView) {
820432609a246819f3cf887a80c2ae56b61fc5ca25aAdam Cohen                mTopViewIndex = i;
82155bd9725d5c0373b89f7b9bbd9547550ea3bbc63Jorim Jaggi            }
82221b411074e39fd10cbc8dd0220bb159da4af2c76Adam Cohen        }
8232d783ce2f4b2e507bead0d723f0edcdf902dbd46Adam Cohen        mChildCountOnLastUpdate = childCount;
82421b411074e39fd10cbc8dd0220bb159da4af2c76Adam Cohen    }
82521b411074e39fd10cbc8dd0220bb159da4af2c76Adam Cohen
82621b411074e39fd10cbc8dd0220bb159da4af2c76Adam Cohen    @Override
82721b411074e39fd10cbc8dd0220bb159da4af2c76Adam Cohen    protected int getChildDrawingOrder(int childCount, int i) {
8282d783ce2f4b2e507bead0d723f0edcdf902dbd46Adam Cohen        if (mChildCountOnLastUpdate != childCount) {
8292d783ce2f4b2e507bead0d723f0edcdf902dbd46Adam Cohen            // between platform versions 17 and 18, behavior for onChildViewRemoved / Added changed.
8302d783ce2f4b2e507bead0d723f0edcdf902dbd46Adam Cohen            // Pre-18, the child was not added / removed by the time of those callbacks. We need to
8312d783ce2f4b2e507bead0d723f0edcdf902dbd46Adam Cohen            // force update our representation of things here to avoid crashing on pre-18 devices
8322d783ce2f4b2e507bead0d723f0edcdf902dbd46Adam Cohen            // in certain instances.
8332d783ce2f4b2e507bead0d723f0edcdf902dbd46Adam Cohen            updateChildIndices();
8342d783ce2f4b2e507bead0d723f0edcdf902dbd46Adam Cohen        }
8352d783ce2f4b2e507bead0d723f0edcdf902dbd46Adam Cohen
836432609a246819f3cf887a80c2ae56b61fc5ca25aAdam Cohen        // i represents the current draw iteration
837432609a246819f3cf887a80c2ae56b61fc5ca25aAdam Cohen        if (mTopViewIndex == -1) {
838432609a246819f3cf887a80c2ae56b61fc5ca25aAdam Cohen            // in general we do nothing
83921b411074e39fd10cbc8dd0220bb159da4af2c76Adam Cohen            return i;
840432609a246819f3cf887a80c2ae56b61fc5ca25aAdam Cohen        } else if (i == childCount - 1) {
841432609a246819f3cf887a80c2ae56b61fc5ca25aAdam Cohen            // if we have a top index, we return it when drawing last item (highest z-order)
842432609a246819f3cf887a80c2ae56b61fc5ca25aAdam Cohen            return mTopViewIndex;
843432609a246819f3cf887a80c2ae56b61fc5ca25aAdam Cohen        } else if (i < mTopViewIndex) {
84421b411074e39fd10cbc8dd0220bb159da4af2c76Adam Cohen            return i;
84555bd9725d5c0373b89f7b9bbd9547550ea3bbc63Jorim Jaggi        } else {
846432609a246819f3cf887a80c2ae56b61fc5ca25aAdam Cohen            // for indexes greater than the top index, we fetch one item above to shift for the
847432609a246819f3cf887a80c2ae56b61fc5ca25aAdam Cohen            // displacement of the top index
848432609a246819f3cf887a80c2ae56b61fc5ca25aAdam Cohen            return i + 1;
84921b411074e39fd10cbc8dd0220bb159da4af2c76Adam Cohen        }
85021b411074e39fd10cbc8dd0220bb159da4af2c76Adam Cohen    }
851360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung
852360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung    private boolean mInScrollArea;
853360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung    private Drawable mLeftHoverDrawable;
854360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung    private Drawable mRightHoverDrawable;
855360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung
856360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung    void onEnterScrollArea(int direction) {
857360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung        mInScrollArea = true;
858360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung        invalidate();
859360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung    }
860360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung
861360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung    void onExitScrollArea() {
862360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung        mInScrollArea = false;
863360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung        invalidate();
864360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung    }
865360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung
866fe1fe268b6d9ffd99218117795b3524a87e5110bWinson Chung    /**
867fe1fe268b6d9ffd99218117795b3524a87e5110bWinson Chung     * Note: this is a reimplementation of View.isLayoutRtl() since that is currently hidden api.
868fe1fe268b6d9ffd99218117795b3524a87e5110bWinson Chung     */
869fe1fe268b6d9ffd99218117795b3524a87e5110bWinson Chung    private boolean isLayoutRtl() {
870fe1fe268b6d9ffd99218117795b3524a87e5110bWinson Chung        return (getLayoutDirection() == LAYOUT_DIRECTION_RTL);
871fe1fe268b6d9ffd99218117795b3524a87e5110bWinson Chung    }
872fe1fe268b6d9ffd99218117795b3524a87e5110bWinson Chung
873360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung    @Override
874360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung    protected void dispatchDraw(Canvas canvas) {
8756c5891a9fce95eee3d87823d11d21889743e9c68Adam Cohen        // Draw the background gradient below children.
8766c5891a9fce95eee3d87823d11d21889743e9c68Adam Cohen        if (mBackground != null && mBackgroundAlpha > 0.0f) {
8776c5891a9fce95eee3d87823d11d21889743e9c68Adam Cohen            int alpha = (int) (mBackgroundAlpha * 255);
8786c5891a9fce95eee3d87823d11d21889743e9c68Adam Cohen            mBackground.setAlpha(alpha);
8796c5891a9fce95eee3d87823d11d21889743e9c68Adam Cohen            mBackground.setBounds(0, 0, getMeasuredWidth(), getMeasuredHeight());
8806c5891a9fce95eee3d87823d11d21889743e9c68Adam Cohen            mBackground.draw(canvas);
8816c5891a9fce95eee3d87823d11d21889743e9c68Adam Cohen        }
8826c5891a9fce95eee3d87823d11d21889743e9c68Adam Cohen
883360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung        super.dispatchDraw(canvas);
884360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung
8856c5891a9fce95eee3d87823d11d21889743e9c68Adam Cohen        // Draw screen hover indicators above children.
886e4f9891f01bdc10d8f96e4e2429e2f4d0558238bDaniel Sandler        if (mInScrollArea && !LauncherAppState.getInstance().isScreenLarge()) {
887360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung            Workspace workspace = mLauncher.getWorkspace();
88861a9a5c359e3e14cb1beaf43dbdb54e00911fe80Adam Cohen            int width = getMeasuredWidth();
889360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung            Rect childRect = new Rect();
890360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung            getDescendantRectRelativeToSelf(workspace.getChildAt(0), childRect);
891360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung
892360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung            int page = workspace.getNextPage();
893fe1fe268b6d9ffd99218117795b3524a87e5110bWinson Chung            final boolean isRtl = isLayoutRtl();
894fe1fe268b6d9ffd99218117795b3524a87e5110bWinson Chung            CellLayout leftPage = (CellLayout) workspace.getChildAt(isRtl ? page + 1 : page - 1);
895fe1fe268b6d9ffd99218117795b3524a87e5110bWinson Chung            CellLayout rightPage = (CellLayout) workspace.getChildAt(isRtl ? page - 1 : page + 1);
896360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung
897360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung            if (leftPage != null && leftPage.getIsDragOverlapping()) {
898360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung                mLeftHoverDrawable.setBounds(0, childRect.top,
899360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung                        mLeftHoverDrawable.getIntrinsicWidth(), childRect.bottom);
900360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung                mLeftHoverDrawable.draw(canvas);
901360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung            } else if (rightPage != null && rightPage.getIsDragOverlapping()) {
902360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung                mRightHoverDrawable.setBounds(width - mRightHoverDrawable.getIntrinsicWidth(),
903360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung                        childRect.top, width, childRect.bottom);
904360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung                mRightHoverDrawable.draw(canvas);
905360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung            }
906360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung        }
907360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung    }
908b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen
9096c5891a9fce95eee3d87823d11d21889743e9c68Adam Cohen    public void setBackgroundAlpha(float alpha) {
9106c5891a9fce95eee3d87823d11d21889743e9c68Adam Cohen        if (alpha != mBackgroundAlpha) {
9116c5891a9fce95eee3d87823d11d21889743e9c68Adam Cohen            mBackgroundAlpha = alpha;
9126c5891a9fce95eee3d87823d11d21889743e9c68Adam Cohen            invalidate();
9136c5891a9fce95eee3d87823d11d21889743e9c68Adam Cohen        }
9146c5891a9fce95eee3d87823d11d21889743e9c68Adam Cohen    }
9156c5891a9fce95eee3d87823d11d21889743e9c68Adam Cohen
9166c5891a9fce95eee3d87823d11d21889743e9c68Adam Cohen    public float getBackgroundAlpha() {
9176c5891a9fce95eee3d87823d11d21889743e9c68Adam Cohen        return mBackgroundAlpha;
9186c5891a9fce95eee3d87823d11d21889743e9c68Adam Cohen    }
9196c5891a9fce95eee3d87823d11d21889743e9c68Adam Cohen
920b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen    public void setTouchCompleteListener(TouchCompleteListener listener) {
921b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen        mTouchCompleteListener = listener;
922b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen    }
923b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen
924b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen    public interface TouchCompleteListener {
925b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen        public void onTouchComplete();
926b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen    }
92731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project}
928