DragLayer.java revision 693fbc7f1737d89f11f9ab81558c109f0883ab0e
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();
6821b411074e39fd10cbc8dd0220bb159da4af2c76Adam Cohen    private int mWorkspaceIndex = -1;
69ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen    private int mQsbIndex = -1;
70ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen    public static final int ANIMATION_END_DISAPPEAR = 0;
71ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen    public static final int ANIMATION_END_FADE_OUT = 1;
72ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen    public static final int ANIMATION_END_REMAIN_VISIBLE = 2;
736788269814a678af976dfc7d6135993e172ce586Adam Cohen
74b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen    private TouchCompleteListener mTouchCompleteListener;
75b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen
7677e1f47520958edd7ec04e203db65b932537bd1cJohn Spurlock    private final Rect mInsets = new Rect();
7777e1f47520958edd7ec04e203db65b932537bd1cJohn Spurlock
7831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    /**
7931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * Used to create a new DragLayer from XML.
8031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     *
8131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param context The application's context.
820e26059548e429e5d1c973bebe4c561bead2926fMichael Jurka     * @param attrs The attributes set containing the Workspace's customization values.
8331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     */
8431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    public DragLayer(Context context, AttributeSet attrs) {
8531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        super(context, attrs);
86be62afa34d58edab0fc9ba7499f0dd543039c903Winson Chung
87be62afa34d58edab0fc9ba7499f0dd543039c903Winson Chung        // Disable multitouch across the workspace/all apps/customize tray
88be62afa34d58edab0fc9ba7499f0dd543039c903Winson Chung        setMotionEventSplittingEnabled(false);
8921b411074e39fd10cbc8dd0220bb159da4af2c76Adam Cohen        setChildrenDrawingOrderEnabled(true);
908b805b17158886035b38261eb611d8641701ae43Michael Jurka        setOnHierarchyChangeListener(this);
91360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung
92360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung        mLeftHoverDrawable = getResources().getDrawable(R.drawable.page_hover_left_holo);
93360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung        mRightHoverDrawable = getResources().getDrawable(R.drawable.page_hover_right_holo);
9431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
9531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
964c98d9235d164680186180974719f551cf935d08Winson Chung    public void setup(Launcher launcher, DragController controller) {
974c98d9235d164680186180974719f551cf935d08Winson Chung        mLauncher = launcher;
9800acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato        mDragController = controller;
9931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
10076fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen
10131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    @Override
10231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    public boolean dispatchKeyEvent(KeyEvent event) {
10300acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato        return mDragController.dispatchKeyEvent(event) || super.dispatchKeyEvent(event);
10431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
10531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
10677e1f47520958edd7ec04e203db65b932537bd1cJohn Spurlock    @Override
10777e1f47520958edd7ec04e203db65b932537bd1cJohn Spurlock    protected boolean fitSystemWindows(Rect insets) {
10877e1f47520958edd7ec04e203db65b932537bd1cJohn Spurlock        final int n = getChildCount();
10977e1f47520958edd7ec04e203db65b932537bd1cJohn Spurlock        for (int i = 0; i < n; i++) {
11077e1f47520958edd7ec04e203db65b932537bd1cJohn Spurlock            final View child = getChildAt(i);
11126279c6d0917015eb4e6de0743b79edeea25f9bcDave Hawkey            setInsets(child, insets, mInsets);
11277e1f47520958edd7ec04e203db65b932537bd1cJohn Spurlock        }
11377e1f47520958edd7ec04e203db65b932537bd1cJohn Spurlock        mInsets.set(insets);
11477e1f47520958edd7ec04e203db65b932537bd1cJohn Spurlock        return true; // I'll take it from here
11577e1f47520958edd7ec04e203db65b932537bd1cJohn Spurlock    }
11677e1f47520958edd7ec04e203db65b932537bd1cJohn Spurlock
11726279c6d0917015eb4e6de0743b79edeea25f9bcDave Hawkey    @Override
11826279c6d0917015eb4e6de0743b79edeea25f9bcDave Hawkey    public void addView(View child, int index, android.view.ViewGroup.LayoutParams params) {
11926279c6d0917015eb4e6de0743b79edeea25f9bcDave Hawkey        super.addView(child, index, params);
12026279c6d0917015eb4e6de0743b79edeea25f9bcDave Hawkey        setInsets(child, mInsets, new Rect());
12126279c6d0917015eb4e6de0743b79edeea25f9bcDave Hawkey    }
12226279c6d0917015eb4e6de0743b79edeea25f9bcDave Hawkey
12326279c6d0917015eb4e6de0743b79edeea25f9bcDave Hawkey    private void setInsets(View child, Rect newInsets, Rect oldInsets) {
12426279c6d0917015eb4e6de0743b79edeea25f9bcDave Hawkey        final FrameLayout.LayoutParams flp = (FrameLayout.LayoutParams) child.getLayoutParams();
12526279c6d0917015eb4e6de0743b79edeea25f9bcDave Hawkey        if (child instanceof Insettable) {
12626279c6d0917015eb4e6de0743b79edeea25f9bcDave Hawkey            ((Insettable) child).setInsets(newInsets);
12726279c6d0917015eb4e6de0743b79edeea25f9bcDave Hawkey        } else {
12826279c6d0917015eb4e6de0743b79edeea25f9bcDave Hawkey            flp.topMargin += (newInsets.top - oldInsets.top);
12926279c6d0917015eb4e6de0743b79edeea25f9bcDave Hawkey            flp.leftMargin += (newInsets.left - oldInsets.left);
13026279c6d0917015eb4e6de0743b79edeea25f9bcDave Hawkey            flp.rightMargin += (newInsets.right - oldInsets.right);
13126279c6d0917015eb4e6de0743b79edeea25f9bcDave Hawkey            flp.bottomMargin += (newInsets.bottom - oldInsets.bottom);
13226279c6d0917015eb4e6de0743b79edeea25f9bcDave Hawkey        }
13326279c6d0917015eb4e6de0743b79edeea25f9bcDave Hawkey        child.setLayoutParams(flp);
13426279c6d0917015eb4e6de0743b79edeea25f9bcDave Hawkey    }
13526279c6d0917015eb4e6de0743b79edeea25f9bcDave Hawkey
1363371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen    private boolean isEventOverFolderTextRegion(Folder folder, MotionEvent ev) {
1373371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen        getDescendantRectRelativeToSelf(folder.getEditTextRegion(), mHitRect);
1383371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen        if (mHitRect.contains((int) ev.getX(), (int) ev.getY())) {
1393371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen            return true;
1403371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen        }
1413371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen        return false;
1423371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen    }
1433371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen
1443371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen    private boolean isEventOverFolder(Folder folder, MotionEvent ev) {
1453371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen        getDescendantRectRelativeToSelf(folder, mHitRect);
1463371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen        if (mHitRect.contains((int) ev.getX(), (int) ev.getY())) {
1473371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen            return true;
1483371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen        }
1493371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen        return false;
1503371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen    }
1513371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen
15276fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen    private boolean handleTouchDown(MotionEvent ev, boolean intercept) {
1536788269814a678af976dfc7d6135993e172ce586Adam Cohen        Rect hitRect = new Rect();
1546788269814a678af976dfc7d6135993e172ce586Adam Cohen        int x = (int) ev.getX();
1556788269814a678af976dfc7d6135993e172ce586Adam Cohen        int y = (int) ev.getY();
1566788269814a678af976dfc7d6135993e172ce586Adam Cohen
1576788269814a678af976dfc7d6135993e172ce586Adam Cohen        for (AppWidgetResizeFrame child: mResizeFrames) {
1586788269814a678af976dfc7d6135993e172ce586Adam Cohen            child.getHitRect(hitRect);
1596788269814a678af976dfc7d6135993e172ce586Adam Cohen            if (hitRect.contains(x, y)) {
1606788269814a678af976dfc7d6135993e172ce586Adam Cohen                if (child.beginResizeIfPointInRegion(x - child.getLeft(), y - child.getTop())) {
1616788269814a678af976dfc7d6135993e172ce586Adam Cohen                    mCurrentResizeFrame = child;
1626788269814a678af976dfc7d6135993e172ce586Adam Cohen                    mXDown = x;
1636788269814a678af976dfc7d6135993e172ce586Adam Cohen                    mYDown = y;
1646788269814a678af976dfc7d6135993e172ce586Adam Cohen                    requestDisallowInterceptTouchEvent(true);
1656788269814a678af976dfc7d6135993e172ce586Adam Cohen                    return true;
1666788269814a678af976dfc7d6135993e172ce586Adam Cohen                }
1676788269814a678af976dfc7d6135993e172ce586Adam Cohen            }
1686788269814a678af976dfc7d6135993e172ce586Adam Cohen        }
16976fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen
1701d9af7d1e75bad13bb10ad37f5900ed59882622eAdam Cohen        Folder currentFolder = mLauncher.getWorkspace().getOpenFolder();
1717d7541e7b48fdc114c24b3b0aa75e70d7228041eWinson Chung        if (currentFolder != null && !mLauncher.isFolderClingVisible() && intercept) {
1721d9af7d1e75bad13bb10ad37f5900ed59882622eAdam Cohen            if (currentFolder.isEditingName()) {
1733371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                if (!isEventOverFolderTextRegion(currentFolder, ev)) {
1741d9af7d1e75bad13bb10ad37f5900ed59882622eAdam Cohen                    currentFolder.dismissEditingName();
17576fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen                    return true;
1762801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen                }
1772801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen            }
17876fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen
1791d9af7d1e75bad13bb10ad37f5900ed59882622eAdam Cohen            getDescendantRectRelativeToSelf(currentFolder, hitRect);
1803371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen            if (!isEventOverFolder(currentFolder, ev)) {
18176fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen                mLauncher.closeFolder();
18276fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen                return true;
18376fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen            }
1842801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen        }
1856788269814a678af976dfc7d6135993e172ce586Adam Cohen        return false;
1866788269814a678af976dfc7d6135993e172ce586Adam Cohen    }
1876788269814a678af976dfc7d6135993e172ce586Adam Cohen
18831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    @Override
18931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    public boolean onInterceptTouchEvent(MotionEvent ev) {
190b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen        int action = ev.getAction();
191b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen
192b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen        if (action == MotionEvent.ACTION_DOWN) {
19376fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen            if (handleTouchDown(ev, true)) {
1946788269814a678af976dfc7d6135993e172ce586Adam Cohen                return true;
195d1837cc69eb222371afdd30890f7215d117510f2Patrick Dubroy            }
196b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen        } else if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) {
197b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen            if (mTouchCompleteListener != null) {
198b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen                mTouchCompleteListener.onTouchComplete();
199b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen            }
200b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen            mTouchCompleteListener = null;
2011b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen        }
2026788269814a678af976dfc7d6135993e172ce586Adam Cohen        clearAllResizeFrames();
2034db52312c10e822162a21c60404f06f6e507f0d6Joe Onorato        return mDragController.onInterceptTouchEvent(ev);
20431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
20531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
20631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    @Override
2073371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen    public boolean onInterceptHoverEvent(MotionEvent ev) {
208023c71eb3b2bbe63272cb74baaf050c4188c89b0Michael Jurka        if (mLauncher == null || mLauncher.getWorkspace() == null) {
209023c71eb3b2bbe63272cb74baaf050c4188c89b0Michael Jurka            return false;
210023c71eb3b2bbe63272cb74baaf050c4188c89b0Michael Jurka        }
2113371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen        Folder currentFolder = mLauncher.getWorkspace().getOpenFolder();
2123371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen        if (currentFolder == null) {
2133371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen            return false;
2143371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen        } else {
2158b805b17158886035b38261eb611d8641701ae43Michael Jurka                AccessibilityManager accessibilityManager = (AccessibilityManager)
2168b805b17158886035b38261eb611d8641701ae43Michael Jurka                        getContext().getSystemService(Context.ACCESSIBILITY_SERVICE);
2178b805b17158886035b38261eb611d8641701ae43Michael Jurka            if (accessibilityManager.isTouchExplorationEnabled()) {
2183371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                final int action = ev.getAction();
2193371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                boolean isOverFolder;
2203371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                switch (action) {
2213371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                    case MotionEvent.ACTION_HOVER_ENTER:
2223371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                        isOverFolder = isEventOverFolder(currentFolder, ev);
2233371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                        if (!isOverFolder) {
2243371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                            sendTapOutsideFolderAccessibilityEvent(currentFolder.isEditingName());
2253371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                            mHoverPointClosesFolder = true;
2263371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                            return true;
2273371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                        }
228693fbc7f1737d89f11f9ab81558c109f0883ab0eMihail Dumitrescu                        mHoverPointClosesFolder = false;
229693fbc7f1737d89f11f9ab81558c109f0883ab0eMihail Dumitrescu                        break;
2303371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                    case MotionEvent.ACTION_HOVER_MOVE:
2313371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                        isOverFolder = isEventOverFolder(currentFolder, ev);
2323371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                        if (!isOverFolder && !mHoverPointClosesFolder) {
2333371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                            sendTapOutsideFolderAccessibilityEvent(currentFolder.isEditingName());
2343371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                            mHoverPointClosesFolder = true;
2353371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                            return true;
236693fbc7f1737d89f11f9ab81558c109f0883ab0eMihail Dumitrescu                        } else if (!isOverFolder) {
2373371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                            return true;
2383371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                        }
239693fbc7f1737d89f11f9ab81558c109f0883ab0eMihail Dumitrescu                        mHoverPointClosesFolder = false;
2403371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                }
2413371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen            }
2423371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen        }
2433371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen        return false;
2443371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen    }
2453371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen
2463371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen    private void sendTapOutsideFolderAccessibilityEvent(boolean isEditingName) {
2478b805b17158886035b38261eb611d8641701ae43Michael Jurka        AccessibilityManager accessibilityManager = (AccessibilityManager)
2488b805b17158886035b38261eb611d8641701ae43Michael Jurka                getContext().getSystemService(Context.ACCESSIBILITY_SERVICE);
2498b805b17158886035b38261eb611d8641701ae43Michael Jurka        if (accessibilityManager.isEnabled()) {
2503371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen            int stringId = isEditingName ? R.string.folder_tap_to_rename : R.string.folder_tap_to_close;
2513371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen            AccessibilityEvent event = AccessibilityEvent.obtain(
2523371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                    AccessibilityEvent.TYPE_VIEW_FOCUSED);
2533371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen            onInitializeAccessibilityEvent(event);
2548b805b17158886035b38261eb611d8641701ae43Michael Jurka            event.getText().add(getContext().getString(stringId));
2558b805b17158886035b38261eb611d8641701ae43Michael Jurka            accessibilityManager.sendAccessibilityEvent(event);
2563371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen        }
25783ca480941b3dd635b62347008fc8d7859d82002Winson Chung    }
25883ca480941b3dd635b62347008fc8d7859d82002Winson Chung
25983ca480941b3dd635b62347008fc8d7859d82002Winson Chung    @Override
26083ca480941b3dd635b62347008fc8d7859d82002Winson Chung    public boolean onRequestSendAccessibilityEvent(View child, AccessibilityEvent event) {
26183ca480941b3dd635b62347008fc8d7859d82002Winson Chung        Folder currentFolder = mLauncher.getWorkspace().getOpenFolder();
26283ca480941b3dd635b62347008fc8d7859d82002Winson Chung        if (currentFolder != null) {
26383ca480941b3dd635b62347008fc8d7859d82002Winson Chung            if (child == currentFolder) {
26483ca480941b3dd635b62347008fc8d7859d82002Winson Chung                return super.onRequestSendAccessibilityEvent(child, event);
26583ca480941b3dd635b62347008fc8d7859d82002Winson Chung            }
26683ca480941b3dd635b62347008fc8d7859d82002Winson Chung            // Skip propagating onRequestSendAccessibilityEvent all for other children
26783ca480941b3dd635b62347008fc8d7859d82002Winson Chung            // when a folder is open
26883ca480941b3dd635b62347008fc8d7859d82002Winson Chung            return false;
26983ca480941b3dd635b62347008fc8d7859d82002Winson Chung        }
27083ca480941b3dd635b62347008fc8d7859d82002Winson Chung        return super.onRequestSendAccessibilityEvent(child, event);
27183ca480941b3dd635b62347008fc8d7859d82002Winson Chung    }
27283ca480941b3dd635b62347008fc8d7859d82002Winson Chung
27383ca480941b3dd635b62347008fc8d7859d82002Winson Chung    @Override
27483ca480941b3dd635b62347008fc8d7859d82002Winson Chung    public void addChildrenForAccessibility(ArrayList<View> childrenForAccessibility) {
27583ca480941b3dd635b62347008fc8d7859d82002Winson Chung        Folder currentFolder = mLauncher.getWorkspace().getOpenFolder();
27683ca480941b3dd635b62347008fc8d7859d82002Winson Chung        if (currentFolder != null) {
27783ca480941b3dd635b62347008fc8d7859d82002Winson Chung            // Only add the folder as a child for accessibility when it is open
27883ca480941b3dd635b62347008fc8d7859d82002Winson Chung            childrenForAccessibility.add(currentFolder);
27983ca480941b3dd635b62347008fc8d7859d82002Winson Chung        } else {
28083ca480941b3dd635b62347008fc8d7859d82002Winson Chung            super.addChildrenForAccessibility(childrenForAccessibility);
28183ca480941b3dd635b62347008fc8d7859d82002Winson Chung        }
2823371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen    }
2833371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen
2843371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen    @Override
2853371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen    public boolean onHoverEvent(MotionEvent ev) {
2863371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen        // If we've received this, we've already done the necessary handling
2873371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen        // in onInterceptHoverEvent. Return true to consume the event.
2883371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen        return false;
2893371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen    }
2903371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen
2913371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen    @Override
29231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    public boolean onTouchEvent(MotionEvent ev) {
2936788269814a678af976dfc7d6135993e172ce586Adam Cohen        boolean handled = false;
2946788269814a678af976dfc7d6135993e172ce586Adam Cohen        int action = ev.getAction();
2956788269814a678af976dfc7d6135993e172ce586Adam Cohen
2966788269814a678af976dfc7d6135993e172ce586Adam Cohen        int x = (int) ev.getX();
2976788269814a678af976dfc7d6135993e172ce586Adam Cohen        int y = (int) ev.getY();
2986788269814a678af976dfc7d6135993e172ce586Adam Cohen
299b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen        if (action == MotionEvent.ACTION_DOWN) {
300b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen            if (handleTouchDown(ev, false)) {
301b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen                return true;
302b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen            }
303b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen        } else if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) {
304b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen            if (mTouchCompleteListener != null) {
305b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen                mTouchCompleteListener.onTouchComplete();
3066788269814a678af976dfc7d6135993e172ce586Adam Cohen            }
307b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen            mTouchCompleteListener = null;
3086788269814a678af976dfc7d6135993e172ce586Adam Cohen        }
3096788269814a678af976dfc7d6135993e172ce586Adam Cohen
3106788269814a678af976dfc7d6135993e172ce586Adam Cohen        if (mCurrentResizeFrame != null) {
3116788269814a678af976dfc7d6135993e172ce586Adam Cohen            handled = true;
3126788269814a678af976dfc7d6135993e172ce586Adam Cohen            switch (action) {
3136788269814a678af976dfc7d6135993e172ce586Adam Cohen                case MotionEvent.ACTION_MOVE:
3146788269814a678af976dfc7d6135993e172ce586Adam Cohen                    mCurrentResizeFrame.visualizeResizeForDelta(x - mXDown, y - mYDown);
3156788269814a678af976dfc7d6135993e172ce586Adam Cohen                    break;
3166788269814a678af976dfc7d6135993e172ce586Adam Cohen                case MotionEvent.ACTION_CANCEL:
3176788269814a678af976dfc7d6135993e172ce586Adam Cohen                case MotionEvent.ACTION_UP:
318bebf042666cffe52039b875a549a582abd78a431Adam Cohen                    mCurrentResizeFrame.visualizeResizeForDelta(x - mXDown, y - mYDown);
319bebf042666cffe52039b875a549a582abd78a431Adam Cohen                    mCurrentResizeFrame.onTouchUp();
3206788269814a678af976dfc7d6135993e172ce586Adam Cohen                    mCurrentResizeFrame = null;
3216788269814a678af976dfc7d6135993e172ce586Adam Cohen            }
3226788269814a678af976dfc7d6135993e172ce586Adam Cohen        }
3236788269814a678af976dfc7d6135993e172ce586Adam Cohen        if (handled) return true;
3244db52312c10e822162a21c60404f06f6e507f0d6Joe Onorato        return mDragController.onTouchEvent(ev);
32591a9c9636f10f1e12cd1f660b2e330634fbdc7dcRomain Guy    }
326ea3763c2672f77539538af8cdd395ad97058eaabRomain Guy
32735e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen    /**
32835e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen     * Determine the rect of the descendant in this DragLayer's coordinates
32935e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen     *
33035e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen     * @param descendant The descendant whose coordinates we want to find.
33135e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen     * @param r The rect into which to place the results.
33235e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen     * @return The factor by which this descendant is scaled relative to this DragLayer.
33335e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen     */
334ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen    public float getDescendantRectRelativeToSelf(View descendant, Rect r) {
335716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen        mTmpXY[0] = 0;
336716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen        mTmpXY[1] = 0;
337ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen        float scale = getDescendantCoordRelativeToSelf(descendant, mTmpXY);
3387d30a37007bac318db1c9af47a9af12d348042a5Adam Cohen
3398dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        r.set(mTmpXY[0], mTmpXY[1],
3407d30a37007bac318db1c9af47a9af12d348042a5Adam Cohen                (int) (mTmpXY[0] + scale * descendant.getMeasuredWidth()),
3417d30a37007bac318db1c9af47a9af12d348042a5Adam Cohen                (int) (mTmpXY[1] + scale * descendant.getMeasuredHeight()));
342ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen        return scale;
343716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen    }
34476fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen
345307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen    public float getLocationInDragLayer(View child, int[] loc) {
34635e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen        loc[0] = 0;
34735e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen        loc[1] = 0;
348307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen        return getDescendantCoordRelativeToSelf(child, loc);
34935e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen    }
35035e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen
3517d30a37007bac318db1c9af47a9af12d348042a5Adam Cohen    public float getDescendantCoordRelativeToSelf(View descendant, int[] coord) {
3527d30a37007bac318db1c9af47a9af12d348042a5Adam Cohen        return getDescendantCoordRelativeToSelf(descendant, coord, false);
3537d30a37007bac318db1c9af47a9af12d348042a5Adam Cohen    }
3547d30a37007bac318db1c9af47a9af12d348042a5Adam Cohen
35535e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen    /**
35635e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen     * Given a coordinate relative to the descendant, find the coordinate in this DragLayer's
35735e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen     * coordinates.
35835e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen     *
35935e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen     * @param descendant The descendant to which the passed coordinate is relative.
36035e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen     * @param coord The coordinate that we want mapped.
3617d30a37007bac318db1c9af47a9af12d348042a5Adam Cohen     * @param includeRootScroll Whether or not to account for the scroll of the root descendant:
3627d30a37007bac318db1c9af47a9af12d348042a5Adam Cohen     *          sometimes this is relevant as in a child's coordinates within the root descendant.
363307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen     * @return The factor by which this descendant is scaled relative to this DragLayer. Caution
364307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen     *         this scale factor is assumed to be equal in X and Y, and so if at any point this
365307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen     *         assumption fails, we will need to return a pair of scale factors.
36635e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen     */
3677d30a37007bac318db1c9af47a9af12d348042a5Adam Cohen    public float getDescendantCoordRelativeToSelf(View descendant, int[] coord,
3687d30a37007bac318db1c9af47a9af12d348042a5Adam Cohen            boolean includeRootScroll) {
369c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung        return Utilities.getDescendantCoordRelativeToParent(descendant, this,
370c9ca2980983ab21fc8631c7a65399d6d9c70f39cWinson Chung                coord, includeRootScroll);
371c9ca2980983ab21fc8631c7a65399d6d9c70f39cWinson Chung    }
372c9ca2980983ab21fc8631c7a65399d6d9c70f39cWinson Chung
3737d30a37007bac318db1c9af47a9af12d348042a5Adam Cohen    /**
3747d30a37007bac318db1c9af47a9af12d348042a5Adam Cohen     * Inverse of {@link #getDescendantCoordRelativeToSelf(View, int[])}.
3757d30a37007bac318db1c9af47a9af12d348042a5Adam Cohen     */
3767d30a37007bac318db1c9af47a9af12d348042a5Adam Cohen    public float mapCoordInSelfToDescendent(View descendant, int[] coord) {
377c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung        return Utilities.mapCoordInSelfToDescendent(descendant, this, coord);
37876fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen    }
37976fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen
3803e8f811f31a2275e778244427271f77f4116c08bAdam Cohen    public void getViewRectRelativeToSelf(View v, Rect r) {
3813e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        int[] loc = new int[2];
3828dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        getLocationInWindow(loc);
3833e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        int x = loc[0];
3843e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        int y = loc[1];
385716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen
3868dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        v.getLocationInWindow(loc);
3873e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        int vX = loc[0];
3883e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        int vY = loc[1];
389716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen
3903e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        int left = vX - x;
3913e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        int top = vY - y;
3923e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        r.set(left, top, left + v.getMeasuredWidth(), top + v.getMeasuredHeight());
393716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen    }
394716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen
395ea3763c2672f77539538af8cdd395ad97058eaabRomain Guy    @Override
396ea3763c2672f77539538af8cdd395ad97058eaabRomain Guy    public boolean dispatchUnhandledMove(View focused, int direction) {
397ea3763c2672f77539538af8cdd395ad97058eaabRomain Guy        return mDragController.dispatchUnhandledMove(focused, direction);
398ea3763c2672f77539538af8cdd395ad97058eaabRomain Guy    }
399120980bd00f5eecec5717f49a3d7db96571025a9Adam Cohen
4006788269814a678af976dfc7d6135993e172ce586Adam Cohen    public static class LayoutParams extends FrameLayout.LayoutParams {
4016788269814a678af976dfc7d6135993e172ce586Adam Cohen        public int x, y;
4026788269814a678af976dfc7d6135993e172ce586Adam Cohen        public boolean customPosition = false;
4036788269814a678af976dfc7d6135993e172ce586Adam Cohen
4046788269814a678af976dfc7d6135993e172ce586Adam Cohen        /**
4056788269814a678af976dfc7d6135993e172ce586Adam Cohen         * {@inheritDoc}
4066788269814a678af976dfc7d6135993e172ce586Adam Cohen         */
4076788269814a678af976dfc7d6135993e172ce586Adam Cohen        public LayoutParams(int width, int height) {
4086788269814a678af976dfc7d6135993e172ce586Adam Cohen            super(width, height);
4096788269814a678af976dfc7d6135993e172ce586Adam Cohen        }
4106788269814a678af976dfc7d6135993e172ce586Adam Cohen
4116788269814a678af976dfc7d6135993e172ce586Adam Cohen        public void setWidth(int width) {
4126788269814a678af976dfc7d6135993e172ce586Adam Cohen            this.width = width;
4136788269814a678af976dfc7d6135993e172ce586Adam Cohen        }
4146788269814a678af976dfc7d6135993e172ce586Adam Cohen
4156788269814a678af976dfc7d6135993e172ce586Adam Cohen        public int getWidth() {
4166788269814a678af976dfc7d6135993e172ce586Adam Cohen            return width;
4176788269814a678af976dfc7d6135993e172ce586Adam Cohen        }
4186788269814a678af976dfc7d6135993e172ce586Adam Cohen
4196788269814a678af976dfc7d6135993e172ce586Adam Cohen        public void setHeight(int height) {
4206788269814a678af976dfc7d6135993e172ce586Adam Cohen            this.height = height;
4216788269814a678af976dfc7d6135993e172ce586Adam Cohen        }
4226788269814a678af976dfc7d6135993e172ce586Adam Cohen
4236788269814a678af976dfc7d6135993e172ce586Adam Cohen        public int getHeight() {
4246788269814a678af976dfc7d6135993e172ce586Adam Cohen            return height;
4256788269814a678af976dfc7d6135993e172ce586Adam Cohen        }
4266788269814a678af976dfc7d6135993e172ce586Adam Cohen
4276788269814a678af976dfc7d6135993e172ce586Adam Cohen        public void setX(int x) {
4286788269814a678af976dfc7d6135993e172ce586Adam Cohen            this.x = x;
4296788269814a678af976dfc7d6135993e172ce586Adam Cohen        }
4306788269814a678af976dfc7d6135993e172ce586Adam Cohen
4316788269814a678af976dfc7d6135993e172ce586Adam Cohen        public int getX() {
4326788269814a678af976dfc7d6135993e172ce586Adam Cohen            return x;
4336788269814a678af976dfc7d6135993e172ce586Adam Cohen        }
4346788269814a678af976dfc7d6135993e172ce586Adam Cohen
4356788269814a678af976dfc7d6135993e172ce586Adam Cohen        public void setY(int y) {
4366788269814a678af976dfc7d6135993e172ce586Adam Cohen            this.y = y;
4376788269814a678af976dfc7d6135993e172ce586Adam Cohen        }
4386788269814a678af976dfc7d6135993e172ce586Adam Cohen
4396788269814a678af976dfc7d6135993e172ce586Adam Cohen        public int getY() {
4406788269814a678af976dfc7d6135993e172ce586Adam Cohen            return y;
4416788269814a678af976dfc7d6135993e172ce586Adam Cohen        }
4426788269814a678af976dfc7d6135993e172ce586Adam Cohen    }
4436788269814a678af976dfc7d6135993e172ce586Adam Cohen
4446788269814a678af976dfc7d6135993e172ce586Adam Cohen    protected void onLayout(boolean changed, int l, int t, int r, int b) {
4456788269814a678af976dfc7d6135993e172ce586Adam Cohen        super.onLayout(changed, l, t, r, b);
4466788269814a678af976dfc7d6135993e172ce586Adam Cohen        int count = getChildCount();
4476788269814a678af976dfc7d6135993e172ce586Adam Cohen        for (int i = 0; i < count; i++) {
4486788269814a678af976dfc7d6135993e172ce586Adam Cohen            View child = getChildAt(i);
4496788269814a678af976dfc7d6135993e172ce586Adam Cohen            final FrameLayout.LayoutParams flp = (FrameLayout.LayoutParams) child.getLayoutParams();
4506788269814a678af976dfc7d6135993e172ce586Adam Cohen            if (flp instanceof LayoutParams) {
4516788269814a678af976dfc7d6135993e172ce586Adam Cohen                final LayoutParams lp = (LayoutParams) flp;
4526788269814a678af976dfc7d6135993e172ce586Adam Cohen                if (lp.customPosition) {
4536788269814a678af976dfc7d6135993e172ce586Adam Cohen                    child.layout(lp.x, lp.y, lp.x + lp.width, lp.y + lp.height);
4546788269814a678af976dfc7d6135993e172ce586Adam Cohen                }
4556788269814a678af976dfc7d6135993e172ce586Adam Cohen            }
4566788269814a678af976dfc7d6135993e172ce586Adam Cohen        }
4576788269814a678af976dfc7d6135993e172ce586Adam Cohen    }
4586788269814a678af976dfc7d6135993e172ce586Adam Cohen
4596788269814a678af976dfc7d6135993e172ce586Adam Cohen    public void clearAllResizeFrames() {
4606788269814a678af976dfc7d6135993e172ce586Adam Cohen        if (mResizeFrames.size() > 0) {
4616788269814a678af976dfc7d6135993e172ce586Adam Cohen            for (AppWidgetResizeFrame frame: mResizeFrames) {
462bebf042666cffe52039b875a549a582abd78a431Adam Cohen                frame.commitResize();
4636788269814a678af976dfc7d6135993e172ce586Adam Cohen                removeView(frame);
4646788269814a678af976dfc7d6135993e172ce586Adam Cohen            }
4656788269814a678af976dfc7d6135993e172ce586Adam Cohen            mResizeFrames.clear();
4666788269814a678af976dfc7d6135993e172ce586Adam Cohen        }
4676788269814a678af976dfc7d6135993e172ce586Adam Cohen    }
4686788269814a678af976dfc7d6135993e172ce586Adam Cohen
4696788269814a678af976dfc7d6135993e172ce586Adam Cohen    public boolean hasResizeFrames() {
4706788269814a678af976dfc7d6135993e172ce586Adam Cohen        return mResizeFrames.size() > 0;
4716788269814a678af976dfc7d6135993e172ce586Adam Cohen    }
4726788269814a678af976dfc7d6135993e172ce586Adam Cohen
4736788269814a678af976dfc7d6135993e172ce586Adam Cohen    public boolean isWidgetBeingResized() {
4746788269814a678af976dfc7d6135993e172ce586Adam Cohen        return mCurrentResizeFrame != null;
4756788269814a678af976dfc7d6135993e172ce586Adam Cohen    }
4766788269814a678af976dfc7d6135993e172ce586Adam Cohen
4776788269814a678af976dfc7d6135993e172ce586Adam Cohen    public void addResizeFrame(ItemInfo itemInfo, LauncherAppWidgetHostView widget,
4786788269814a678af976dfc7d6135993e172ce586Adam Cohen            CellLayout cellLayout) {
4796788269814a678af976dfc7d6135993e172ce586Adam Cohen        AppWidgetResizeFrame resizeFrame = new AppWidgetResizeFrame(getContext(),
4803a9fcedbcd235372cd2ab64f825a0b5b3937f59eMichael Jurka                widget, cellLayout, this);
4816788269814a678af976dfc7d6135993e172ce586Adam Cohen
4826788269814a678af976dfc7d6135993e172ce586Adam Cohen        LayoutParams lp = new LayoutParams(-1, -1);
4836788269814a678af976dfc7d6135993e172ce586Adam Cohen        lp.customPosition = true;
4846788269814a678af976dfc7d6135993e172ce586Adam Cohen
4856788269814a678af976dfc7d6135993e172ce586Adam Cohen        addView(resizeFrame, lp);
4866788269814a678af976dfc7d6135993e172ce586Adam Cohen        mResizeFrames.add(resizeFrame);
4876788269814a678af976dfc7d6135993e172ce586Adam Cohen
4886788269814a678af976dfc7d6135993e172ce586Adam Cohen        resizeFrame.snapToWidget(false);
4896788269814a678af976dfc7d6135993e172ce586Adam Cohen    }
490716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen
491716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen    public void animateViewIntoPosition(DragView dragView, final View child) {
49228f852ab678d9750879b6d3549bf5da176cf1225Adam Cohen        animateViewIntoPosition(dragView, child, null, null);
493557d6ed50cc6560163440aa134870ef0bb11415bWinson Chung    }
494ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen
4957bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung    public void animateViewIntoPosition(DragView dragView, final int[] pos, float alpha,
4967bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung            float scaleX, float scaleY, int animationEndStyle, Runnable onFinishRunnable,
4977bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung            int duration) {
498b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen        Rect r = new Rect();
499b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen        getViewRectRelativeToSelf(dragView, r);
500b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen        final int fromX = r.left;
501b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen        final int fromY = r.top;
502b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen
5037bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung        animateViewIntoPosition(dragView, fromX, fromY, pos[0], pos[1], alpha, 1, 1, scaleX, scaleY,
504ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen                onFinishRunnable, animationEndStyle, duration, null);
505ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen    }
506ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen
507557d6ed50cc6560163440aa134870ef0bb11415bWinson Chung    public void animateViewIntoPosition(DragView dragView, final View child,
50828f852ab678d9750879b6d3549bf5da176cf1225Adam Cohen            final Runnable onFinishAnimationRunnable, View anchorView) {
50928f852ab678d9750879b6d3549bf5da176cf1225Adam Cohen        animateViewIntoPosition(dragView, child, -1, onFinishAnimationRunnable, anchorView);
510ed51cc9a12c50d12e7d30ed209a49f1a40858043Adam Cohen    }
511ed51cc9a12c50d12e7d30ed209a49f1a40858043Adam Cohen
512ed51cc9a12c50d12e7d30ed209a49f1a40858043Adam Cohen    public void animateViewIntoPosition(DragView dragView, final View child, int duration,
5136441de0ec2a71862798dd51180d0811b42edd514Adam Cohen            final Runnable onFinishAnimationRunnable, View anchorView) {
514a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        ShortcutAndWidgetContainer parentChildren = (ShortcutAndWidgetContainer) child.getParent();
515716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen        CellLayout.LayoutParams lp =  (CellLayout.LayoutParams) child.getLayoutParams();
516eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung        parentChildren.measureChild(child);
517716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen
5183e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        Rect r = new Rect();
5193e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        getViewRectRelativeToSelf(dragView, r);
520716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen
521716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen        int coord[] = new int[2];
522307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen        float childScale = child.getScaleX();
523307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen        coord[0] = lp.x + (int) (child.getMeasuredWidth() * (1 - childScale) / 2);
524307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen        coord[1] = lp.y + (int) (child.getMeasuredHeight() * (1 - childScale) / 2);
525eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung
5268dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        // Since the child hasn't necessarily been laid out, we force the lp to be updated with
527ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen        // the correct coordinates (above) and use these to determine the final location
528557d6ed50cc6560163440aa134870ef0bb11415bWinson Chung        float scale = getDescendantCoordRelativeToSelf((View) child.getParent(), coord);
529307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen        // We need to account for the scale of the child itself, as the above only accounts for
530307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen        // for the scale in parents.
531307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen        scale *= childScale;
532ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen        int toX = coord[0];
533ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen        int toY = coord[1];
534eeb5bbc9409978cc2ae52d48380399fcde3d9f85Winson Chung        float toScale = scale;
5354497ebf9a2726e2a7dbb7f3c49389308908f8454Andrew Flynn        if (child instanceof TextView) {
5364497ebf9a2726e2a7dbb7f3c49389308908f8454Andrew Flynn            TextView tv = (TextView) child;
537eeb5bbc9409978cc2ae52d48380399fcde3d9f85Winson Chung            // Account for the source scale of the icon (ie. from AllApps to Workspace, in which
538eeb5bbc9409978cc2ae52d48380399fcde3d9f85Winson Chung            // the workspace may have smaller icon bounds).
539eeb5bbc9409978cc2ae52d48380399fcde3d9f85Winson Chung            toScale = scale / dragView.getIntrinsicIconScaleFactor();
5404497ebf9a2726e2a7dbb7f3c49389308908f8454Andrew Flynn
5414497ebf9a2726e2a7dbb7f3c49389308908f8454Andrew Flynn            // The child may be scaled (always about the center of the view) so to account for it,
5424497ebf9a2726e2a7dbb7f3c49389308908f8454Andrew Flynn            // we have to offset the position by the scaled size.  Once we do that, we can center
5434497ebf9a2726e2a7dbb7f3c49389308908f8454Andrew Flynn            // the drag view about the scaled child view.
544eeb5bbc9409978cc2ae52d48380399fcde3d9f85Winson Chung            toY += Math.round(toScale * tv.getPaddingTop());
545eeb5bbc9409978cc2ae52d48380399fcde3d9f85Winson Chung            toY -= dragView.getMeasuredHeight() * (1 - toScale) / 2;
5464497ebf9a2726e2a7dbb7f3c49389308908f8454Andrew Flynn            toX -= (dragView.getMeasuredWidth() - Math.round(scale * child.getMeasuredWidth())) / 2;
5474497ebf9a2726e2a7dbb7f3c49389308908f8454Andrew Flynn        } else if (child instanceof FolderIcon) {
548ea359c6aee44c0fe3bb94f7002c3b49208b32b7fWinson Chung            // Account for holographic blur padding on the drag view
5495f8afe6280eae34620067696173e71943e1a30a3Winson Chung            toY += Math.round(scale * (child.getPaddingTop() - dragView.getDragRegionTop()));
550307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen            toY -= scale * Workspace.DRAG_BITMAP_PADDING / 2;
551307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen            toY -= (1 - scale) * dragView.getMeasuredHeight() / 2;
552ea359c6aee44c0fe3bb94f7002c3b49208b32b7fWinson Chung            // Center in the x coordinate about the target's drawable
553ea359c6aee44c0fe3bb94f7002c3b49208b32b7fWinson Chung            toX -= (dragView.getMeasuredWidth() - Math.round(scale * child.getMeasuredWidth())) / 2;
554ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen        } else {
555ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen            toY -= (Math.round(scale * (dragView.getHeight() - child.getMeasuredHeight()))) / 2;
556ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen            toX -= (Math.round(scale * (dragView.getMeasuredWidth()
557ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen                    - child.getMeasuredWidth()))) / 2;
558ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen        }
559716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen
560ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen        final int fromX = r.left;
561ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen        final int fromY = r.top;
562716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen        child.setVisibility(INVISIBLE);
5638dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        Runnable onCompleteRunnable = new Runnable() {
5648dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen            public void run() {
5658dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen                child.setVisibility(VISIBLE);
566d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                if (onFinishAnimationRunnable != null) {
567d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    onFinishAnimationRunnable.run();
568d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                }
5698dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen            }
5708dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        };
571eeb5bbc9409978cc2ae52d48380399fcde3d9f85Winson Chung        animateViewIntoPosition(dragView, fromX, fromY, toX, toY, 1, 1, 1, toScale, toScale,
572d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                onCompleteRunnable, ANIMATION_END_DISAPPEAR, duration, anchorView);
573557d6ed50cc6560163440aa134870ef0bb11415bWinson Chung    }
574557d6ed50cc6560163440aa134870ef0bb11415bWinson Chung
575d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen    public void animateViewIntoPosition(final DragView view, final int fromX, final int fromY,
576ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen            final int toX, final int toY, float finalAlpha, float initScaleX, float initScaleY,
577ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen            float finalScaleX, float finalScaleY, Runnable onCompleteRunnable,
578ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen            int animationEndStyle, int duration, View anchorView) {
5798dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        Rect from = new Rect(fromX, fromY, fromX +
5808dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen                view.getMeasuredWidth(), fromY + view.getMeasuredHeight());
5813e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        Rect to = new Rect(toX, toY, toX + view.getMeasuredWidth(), toY + view.getMeasuredHeight());
582ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen        animateView(view, from, to, finalAlpha, initScaleX, initScaleY, finalScaleX, finalScaleY, duration,
583ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen                null, null, onCompleteRunnable, animationEndStyle, anchorView);
5843e8f811f31a2275e778244427271f77f4116c08bAdam Cohen    }
5853e8f811f31a2275e778244427271f77f4116c08bAdam Cohen
586b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen    /**
587b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen     * This method animates a view at the end of a drag and drop animation.
588b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen     *
589b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen     * @param view The view to be animated. This view is drawn directly into DragLayer, and so
590b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen     *        doesn't need to be a child of DragLayer.
591b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen     * @param from The initial location of the view. Only the left and top parameters are used.
592b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen     * @param to The final location of the view. Only the left and top parameters are used. This
593b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen     *        location doesn't account for scaling, and so should be centered about the desired
594b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen     *        final location (including scaling).
595b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen     * @param finalAlpha The final alpha of the view, in case we want it to fade as it animates.
596b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen     * @param finalScale The final scale of the view. The view is scaled about its center.
597b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen     * @param duration The duration of the animation.
598b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen     * @param motionInterpolator The interpolator to use for the location of the view.
599b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen     * @param alphaInterpolator The interpolator to use for the alpha of the view.
600b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen     * @param onCompleteRunnable Optional runnable to run on animation completion.
601b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen     * @param fadeOut Whether or not to fade out the view once the animation completes. If true,
602b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen     *        the runnable will execute after the view is faded out.
6036441de0ec2a71862798dd51180d0811b42edd514Adam Cohen     * @param anchorView If not null, this represents the view which the animated view stays
6046441de0ec2a71862798dd51180d0811b42edd514Adam Cohen     *        anchored to in case scrolling is currently taking place. Note: currently this is
6056441de0ec2a71862798dd51180d0811b42edd514Adam Cohen     *        only used for the X dimension for the case of the workspace.
606b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen     */
6077bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung    public void animateView(final DragView view, final Rect from, final Rect to,
6087bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung            final float finalAlpha, final float initScaleX, final float initScaleY,
6097bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung            final float finalScaleX, final float finalScaleY, int duration,
6107bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung            final Interpolator motionInterpolator, final Interpolator alphaInterpolator,
6117bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung            final Runnable onCompleteRunnable, final int animationEndStyle, View anchorView) {
6127bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung
613716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen        // Calculate the duration of the animation based on the object's distance
6143e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        final float dist = (float) Math.sqrt(Math.pow(to.left - from.left, 2) +
6153e8f811f31a2275e778244427271f77f4116c08bAdam Cohen                Math.pow(to.top - from.top, 2));
616716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen        final Resources res = getResources();
617716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen        final float maxDist = (float) res.getInteger(R.integer.config_dropAnimMaxDist);
6183e8f811f31a2275e778244427271f77f4116c08bAdam Cohen
6193e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        // If duration < 0, this is a cue to compute the duration based on the distance
6203e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        if (duration < 0) {
6213e8f811f31a2275e778244427271f77f4116c08bAdam Cohen            duration = res.getInteger(R.integer.config_dropAnimMaxDuration);
6223e8f811f31a2275e778244427271f77f4116c08bAdam Cohen            if (dist < maxDist) {
6238dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen                duration *= mCubicEaseOutInterpolator.getInterpolation(dist / maxDist);
6243e8f811f31a2275e778244427271f77f4116c08bAdam Cohen            }
62561b0c69d3fe331d3de338322396d5de691d58613Winson Chung            duration = Math.max(duration, res.getInteger(R.integer.config_dropAnimMinDuration));
626716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen        }
627716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen
628043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        // Fall back to cubic ease out interpolator for the animation if none is specified
629043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        TimeInterpolator interpolator = null;
6303e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        if (alphaInterpolator == null || motionInterpolator == null) {
631043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung            interpolator = mCubicEaseOutInterpolator;
6323e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        }
633716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen
634043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        // Animate the view
6357bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung        final float initAlpha = view.getAlpha();
636043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        final float dropViewScale = view.getScaleX();
637043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        AnimatorUpdateListener updateCb = new AnimatorUpdateListener() {
638043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung            @Override
639716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen            public void onAnimationUpdate(ValueAnimator animation) {
640716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen                final float percent = (Float) animation.getAnimatedValue();
6417bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung                final int width = view.getMeasuredWidth();
6427bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung                final int height = view.getMeasuredHeight();
643716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen
6443e8f811f31a2275e778244427271f77f4116c08bAdam Cohen                float alphaPercent = alphaInterpolator == null ? percent :
6453e8f811f31a2275e778244427271f77f4116c08bAdam Cohen                        alphaInterpolator.getInterpolation(percent);
6463e8f811f31a2275e778244427271f77f4116c08bAdam Cohen                float motionPercent = motionInterpolator == null ? percent :
6473e8f811f31a2275e778244427271f77f4116c08bAdam Cohen                        motionInterpolator.getInterpolation(percent);
648a1cdab039292f3d809528c0e2e38580b37864d8dWinson Chung
6497bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung                float initialScaleX = initScaleX * dropViewScale;
6507bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung                float initialScaleY = initScaleY * dropViewScale;
6517bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung                float scaleX = finalScaleX * percent + initialScaleX * (1 - percent);
6527bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung                float scaleY = finalScaleY * percent + initialScaleY * (1 - percent);
6537bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung                float alpha = finalAlpha * alphaPercent + initAlpha * (1 - alphaPercent);
6547bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung
6557bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung                float fromLeft = from.left + (initialScaleX - 1f) * width / 2;
6567bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung                float fromTop = from.top + (initialScaleY - 1f) * height / 2;
6577bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung
6587bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung                int x = (int) (fromLeft + Math.round(((to.left - fromLeft) * motionPercent)));
6597bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung                int y = (int) (fromTop + Math.round(((to.top - fromTop) * motionPercent)));
6607bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung
66128f852ab678d9750879b6d3549bf5da176cf1225Adam Cohen                int anchorAdjust = mAnchorView == null ? 0 : (int) (mAnchorView.getScaleX() *
66228f852ab678d9750879b6d3549bf5da176cf1225Adam Cohen                    (mAnchorViewInitialScrollX - mAnchorView.getScrollX()));
66328f852ab678d9750879b6d3549bf5da176cf1225Adam Cohen
66428f852ab678d9750879b6d3549bf5da176cf1225Adam Cohen                int xPos = x - mDropView.getScrollX() + anchorAdjust;
6657bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung                int yPos = y - mDropView.getScrollY();
6667bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung
6677bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung                mDropView.setTranslationX(xPos);
6687bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung                mDropView.setTranslationY(yPos);
6697bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung                mDropView.setScaleX(scaleX);
6707bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung                mDropView.setScaleY(scaleY);
6717bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung                mDropView.setAlpha(alpha);
672716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen            }
673043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        };
674043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        animateView(view, updateCb, duration, interpolator, onCompleteRunnable, animationEndStyle,
675043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung                anchorView);
676043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung    }
677043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung
678043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung    public void animateView(final DragView view, AnimatorUpdateListener updateCb, int duration,
679043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung            TimeInterpolator interpolator, final Runnable onCompleteRunnable,
680043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung            final int animationEndStyle, View anchorView) {
681043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        // Clean up the previous animations
682043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        if (mDropAnim != null) mDropAnim.cancel();
683043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        if (mFadeOutAnim != null) mFadeOutAnim.cancel();
684043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung
685043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        // Show the drop view if it was previously hidden
686043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        mDropView = view;
687043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        mDropView.cancelAnimation();
688043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        mDropView.resetLayoutParams();
689043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung
690043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        // Set the anchor view if the page is scrolling
691043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        if (anchorView != null) {
692043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung            mAnchorViewInitialScrollX = anchorView.getScrollX();
693043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        }
694043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        mAnchorView = anchorView;
695043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung
696043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        // Create and start the animation
697043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        mDropAnim = new ValueAnimator();
698043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        mDropAnim.setInterpolator(interpolator);
699043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        mDropAnim.setDuration(duration);
700043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        mDropAnim.setFloatValues(0f, 1f);
701043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        mDropAnim.addUpdateListener(updateCb);
7023e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        mDropAnim.addListener(new AnimatorListenerAdapter() {
7033e8f811f31a2275e778244427271f77f4116c08bAdam Cohen            public void onAnimationEnd(Animator animation) {
7048dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen                if (onCompleteRunnable != null) {
7058dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen                    onCompleteRunnable.run();
7068dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen                }
707ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen                switch (animationEndStyle) {
708ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen                case ANIMATION_END_DISAPPEAR:
709ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen                    clearAnimatedView();
710ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen                    break;
711ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen                case ANIMATION_END_FADE_OUT:
7128dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen                    fadeOutDragView();
713ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen                    break;
714ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen                case ANIMATION_END_REMAIN_VISIBLE:
715ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen                    break;
7163e8f811f31a2275e778244427271f77f4116c08bAdam Cohen                }
7173e8f811f31a2275e778244427271f77f4116c08bAdam Cohen            }
7183e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        });
719716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen        mDropAnim.start();
720716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen    }
721716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen
722ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen    public void clearAnimatedView() {
7237bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung        if (mDropAnim != null) {
7247bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung            mDropAnim.cancel();
7257bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung        }
7267bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung        if (mDropView != null) {
727043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung            mDragController.onDeferredEndDrag(mDropView);
7287bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung        }
729ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen        mDropView = null;
730ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen        invalidate();
731ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen    }
732ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen
733ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen    public View getAnimatedView() {
734ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen        return mDropView;
735ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen    }
736ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen
7378dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen    private void fadeOutDragView() {
7388dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        mFadeOutAnim = new ValueAnimator();
7398dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        mFadeOutAnim.setDuration(150);
7408dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        mFadeOutAnim.setFloatValues(0f, 1f);
7418dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        mFadeOutAnim.removeAllUpdateListeners();
7428dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        mFadeOutAnim.addUpdateListener(new AnimatorUpdateListener() {
7438dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen            public void onAnimationUpdate(ValueAnimator animation) {
7448dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen                final float percent = (Float) animation.getAnimatedValue();
7457bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung
7467bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung                float alpha = 1 - percent;
7477bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung                mDropView.setAlpha(alpha);
7488dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen            }
7498dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        });
7508dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        mFadeOutAnim.addListener(new AnimatorListenerAdapter() {
7518dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen            public void onAnimationEnd(Animator animation) {
7527bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung                if (mDropView != null) {
753043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung                    mDragController.onDeferredEndDrag(mDropView);
7547bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung                }
7558dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen                mDropView = null;
756ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen                invalidate();
7578dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen            }
7588dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        });
7598dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        mFadeOutAnim.start();
7608dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen    }
7618dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen
762716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen    @Override
7638b805b17158886035b38261eb611d8641701ae43Michael Jurka    public void onChildViewAdded(View parent, View child) {
76421b411074e39fd10cbc8dd0220bb159da4af2c76Adam Cohen        updateChildIndices();
76521b411074e39fd10cbc8dd0220bb159da4af2c76Adam Cohen    }
76621b411074e39fd10cbc8dd0220bb159da4af2c76Adam Cohen
76721b411074e39fd10cbc8dd0220bb159da4af2c76Adam Cohen    @Override
7688b805b17158886035b38261eb611d8641701ae43Michael Jurka    public void onChildViewRemoved(View parent, View child) {
76921b411074e39fd10cbc8dd0220bb159da4af2c76Adam Cohen        updateChildIndices();
77021b411074e39fd10cbc8dd0220bb159da4af2c76Adam Cohen    }
77121b411074e39fd10cbc8dd0220bb159da4af2c76Adam Cohen
77221b411074e39fd10cbc8dd0220bb159da4af2c76Adam Cohen    private void updateChildIndices() {
77321b411074e39fd10cbc8dd0220bb159da4af2c76Adam Cohen        if (mLauncher != null) {
77421b411074e39fd10cbc8dd0220bb159da4af2c76Adam Cohen            mWorkspaceIndex = indexOfChild(mLauncher.getWorkspace());
775ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen            mQsbIndex = indexOfChild(mLauncher.getSearchBar());
77621b411074e39fd10cbc8dd0220bb159da4af2c76Adam Cohen        }
77721b411074e39fd10cbc8dd0220bb159da4af2c76Adam Cohen    }
77821b411074e39fd10cbc8dd0220bb159da4af2c76Adam Cohen
77921b411074e39fd10cbc8dd0220bb159da4af2c76Adam Cohen    @Override
78021b411074e39fd10cbc8dd0220bb159da4af2c76Adam Cohen    protected int getChildDrawingOrder(int childCount, int i) {
781e29c55ac322f3386327fa5b61e79b00ba3e5d428Adam Cohen        // TODO: We have turned off this custom drawing order because it now effects touch
782e29c55ac322f3386327fa5b61e79b00ba3e5d428Adam Cohen        // dispatch order. We need to sort that issue out and then decide how to go about this.
783cc8befac3550c81d04ea206c170adae36c9a6c93Daniel Sandler        if (true || LauncherAppState.isScreenLandscape(getContext()) ||
784e29c55ac322f3386327fa5b61e79b00ba3e5d428Adam Cohen                mWorkspaceIndex == -1 || mQsbIndex == -1 ||
78521b411074e39fd10cbc8dd0220bb159da4af2c76Adam Cohen                mLauncher.getWorkspace().isDrawingBackgroundGradient()) {
78621b411074e39fd10cbc8dd0220bb159da4af2c76Adam Cohen            return i;
78721b411074e39fd10cbc8dd0220bb159da4af2c76Adam Cohen        }
78821b411074e39fd10cbc8dd0220bb159da4af2c76Adam Cohen
78921b411074e39fd10cbc8dd0220bb159da4af2c76Adam Cohen        // This ensures that the workspace is drawn above the hotseat and qsb,
79021b411074e39fd10cbc8dd0220bb159da4af2c76Adam Cohen        // except when the workspace is drawing a background gradient, in which
79121b411074e39fd10cbc8dd0220bb159da4af2c76Adam Cohen        // case we want the workspace to stay behind these elements.
792ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen        if (i == mQsbIndex) {
79321b411074e39fd10cbc8dd0220bb159da4af2c76Adam Cohen            return mWorkspaceIndex;
79421b411074e39fd10cbc8dd0220bb159da4af2c76Adam Cohen        } else if (i == mWorkspaceIndex) {
795ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen            return mQsbIndex;
79621b411074e39fd10cbc8dd0220bb159da4af2c76Adam Cohen        } else {
79721b411074e39fd10cbc8dd0220bb159da4af2c76Adam Cohen            return i;
79821b411074e39fd10cbc8dd0220bb159da4af2c76Adam Cohen        }
79921b411074e39fd10cbc8dd0220bb159da4af2c76Adam Cohen    }
800360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung
801360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung    private boolean mInScrollArea;
802360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung    private Drawable mLeftHoverDrawable;
803360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung    private Drawable mRightHoverDrawable;
804360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung
805360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung    void onEnterScrollArea(int direction) {
806360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung        mInScrollArea = true;
807360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung        invalidate();
808360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung    }
809360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung
810360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung    void onExitScrollArea() {
811360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung        mInScrollArea = false;
812360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung        invalidate();
813360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung    }
814360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung
815fe1fe268b6d9ffd99218117795b3524a87e5110bWinson Chung    /**
816fe1fe268b6d9ffd99218117795b3524a87e5110bWinson Chung     * Note: this is a reimplementation of View.isLayoutRtl() since that is currently hidden api.
817fe1fe268b6d9ffd99218117795b3524a87e5110bWinson Chung     */
818fe1fe268b6d9ffd99218117795b3524a87e5110bWinson Chung    private boolean isLayoutRtl() {
819fe1fe268b6d9ffd99218117795b3524a87e5110bWinson Chung        return (getLayoutDirection() == LAYOUT_DIRECTION_RTL);
820fe1fe268b6d9ffd99218117795b3524a87e5110bWinson Chung    }
821fe1fe268b6d9ffd99218117795b3524a87e5110bWinson Chung
822360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung    @Override
823360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung    protected void dispatchDraw(Canvas canvas) {
824360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung        super.dispatchDraw(canvas);
825360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung
826e4f9891f01bdc10d8f96e4e2429e2f4d0558238bDaniel Sandler        if (mInScrollArea && !LauncherAppState.getInstance().isScreenLarge()) {
827360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung            Workspace workspace = mLauncher.getWorkspace();
82861a9a5c359e3e14cb1beaf43dbdb54e00911fe80Adam Cohen            int width = getMeasuredWidth();
829360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung            Rect childRect = new Rect();
830360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung            getDescendantRectRelativeToSelf(workspace.getChildAt(0), childRect);
831360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung
832360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung            int page = workspace.getNextPage();
833fe1fe268b6d9ffd99218117795b3524a87e5110bWinson Chung            final boolean isRtl = isLayoutRtl();
834fe1fe268b6d9ffd99218117795b3524a87e5110bWinson Chung            CellLayout leftPage = (CellLayout) workspace.getChildAt(isRtl ? page + 1 : page - 1);
835fe1fe268b6d9ffd99218117795b3524a87e5110bWinson Chung            CellLayout rightPage = (CellLayout) workspace.getChildAt(isRtl ? page - 1 : page + 1);
836360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung
837360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung            if (leftPage != null && leftPage.getIsDragOverlapping()) {
838360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung                mLeftHoverDrawable.setBounds(0, childRect.top,
839360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung                        mLeftHoverDrawable.getIntrinsicWidth(), childRect.bottom);
840360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung                mLeftHoverDrawable.draw(canvas);
841360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung            } else if (rightPage != null && rightPage.getIsDragOverlapping()) {
842360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung                mRightHoverDrawable.setBounds(width - mRightHoverDrawable.getIntrinsicWidth(),
843360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung                        childRect.top, width, childRect.bottom);
844360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung                mRightHoverDrawable.draw(canvas);
845360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung            }
846360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung        }
847360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung    }
848b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen
849b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen    public void setTouchCompleteListener(TouchCompleteListener listener) {
850b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen        mTouchCompleteListener = listener;
851b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen    }
852b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen
853b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen    public interface TouchCompleteListener {
854b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen        public void onTouchComplete();
855b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen    }
85631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project}
857