DragLayer.java revision c001cf562017d08cd48b67de8f377ca08881e70e
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
17fedca43d396d6fd7c46fbb2f37dfa7cfe3b31834Vadim Tryshevpackage com.android.launcher3.dragndrop;
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;
270fa93bc5c65a2d7d5e5f4e798499903759c48cc5Sunny Goyalimport android.graphics.Color;
286788269814a678af976dfc7d6135993e172ce586Adam Cohenimport android.graphics.Rect;
2995cdb3a0211650e76adb451588ce89fd585b178fTony Wickhamimport android.graphics.Region;
30360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chungimport android.graphics.drawable.Drawable;
3131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.util.AttributeSet;
32d6c8e7eeb13094ea1349897663ae28d8a3bf2773Vadim Tryshevimport android.view.DragEvent;
3326279c6d0917015eb4e6de0743b79edeea25f9bcDave Hawkeyimport android.view.KeyEvent;
3426279c6d0917015eb4e6de0743b79edeea25f9bcDave Hawkeyimport android.view.MotionEvent;
3526279c6d0917015eb4e6de0743b79edeea25f9bcDave Hawkeyimport android.view.View;
3626279c6d0917015eb4e6de0743b79edeea25f9bcDave Hawkeyimport android.view.ViewGroup;
373371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohenimport android.view.accessibility.AccessibilityEvent;
383371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohenimport android.view.accessibility.AccessibilityManager;
39716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohenimport android.view.animation.DecelerateInterpolator;
403e8f811f31a2275e778244427271f77f4116c08bAdam Cohenimport android.view.animation.Interpolator;
4131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.widget.FrameLayout;
42ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohenimport android.widget.TextView;
4331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
44fedca43d396d6fd7c46fbb2f37dfa7cfe3b31834Vadim Tryshevimport com.android.launcher3.AppWidgetResizeFrame;
45fedca43d396d6fd7c46fbb2f37dfa7cfe3b31834Vadim Tryshevimport com.android.launcher3.CellLayout;
461bce7fd342875be8f7c1f82c8cf21d0199c8d544Tony Wickhamimport com.android.launcher3.DropTargetBar;
47fedca43d396d6fd7c46fbb2f37dfa7cfe3b31834Vadim Tryshevimport com.android.launcher3.InsettableFrameLayout;
48fedca43d396d6fd7c46fbb2f37dfa7cfe3b31834Vadim Tryshevimport com.android.launcher3.ItemInfo;
49fedca43d396d6fd7c46fbb2f37dfa7cfe3b31834Vadim Tryshevimport com.android.launcher3.Launcher;
50fedca43d396d6fd7c46fbb2f37dfa7cfe3b31834Vadim Tryshevimport com.android.launcher3.LauncherAppWidgetHostView;
51dadb304b4682998c43b9c07bef45b9a9380f3287Tony Wickhamimport com.android.launcher3.PinchToOverviewListener;
52f9c184a619e4e4b82cf9e0bf318ca6d8deaaaee7Adam Cohenimport com.android.launcher3.R;
53fedca43d396d6fd7c46fbb2f37dfa7cfe3b31834Vadim Tryshevimport com.android.launcher3.ShortcutAndWidgetContainer;
54fedca43d396d6fd7c46fbb2f37dfa7cfe3b31834Vadim Tryshevimport com.android.launcher3.Utilities;
55fedca43d396d6fd7c46fbb2f37dfa7cfe3b31834Vadim Tryshevimport com.android.launcher3.Workspace;
56645764e3e5fa34d9adcddfc722d726b76f048306Hyunyoung Songimport com.android.launcher3.allapps.AllAppsTransitionController;
579c43182ff1d095b1bbaacedefe6e0f4c2deb17e3Tony Wickhamimport com.android.launcher3.config.FeatureFlags;
58261194387beebaa7927ec4e310274218b651494dSunny Goyalimport com.android.launcher3.folder.Folder;
59261194387beebaa7927ec4e310274218b651494dSunny Goyalimport com.android.launcher3.folder.FolderIcon;
603333b0ced8e6743c41909f6f6b916f1f9ec5a004Sunny Goyalimport com.android.launcher3.keyboard.ViewGroupFocusHelper;
611bce7fd342875be8f7c1f82c8cf21d0199c8d544Tony Wickhamimport com.android.launcher3.shortcuts.DeepShortcutsContainer;
62091440a9cb9d4f42406631004aa484cbb79214caAdam Cohenimport com.android.launcher3.util.Thunk;
63645764e3e5fa34d9adcddfc722d726b76f048306Hyunyoung Songimport com.android.launcher3.util.TouchController;
64bc927f9c24001e250622ca9a2547ee5b65baef58Adam Cohen
651d9af7d1e75bad13bb10ad37f5900ed59882622eAdam Cohenimport java.util.ArrayList;
666788269814a678af976dfc7d6135993e172ce586Adam Cohen
6731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project/**
680e26059548e429e5d1c973bebe4c561bead2926fMichael Jurka * A ViewGroup that coordinates dragging across its descendants
6931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project */
70a6d0492e5f0dd4e1b43d4034a770241dc65f8f8cAdam Cohenpublic class DragLayer extends InsettableFrameLayout {
710fa93bc5c65a2d7d5e5f4e798499903759c48cc5Sunny Goyal
72b135956e95d2d7479290af89d618892ed0e7327dSunny Goyal    public static final int ANIMATION_END_DISAPPEAR = 0;
73b135956e95d2d7479290af89d618892ed0e7327dSunny Goyal    public static final int ANIMATION_END_REMAIN_VISIBLE = 2;
74b135956e95d2d7479290af89d618892ed0e7327dSunny Goyal
750fa93bc5c65a2d7d5e5f4e798499903759c48cc5Sunny Goyal    // Scrim color without any alpha component.
760fa93bc5c65a2d7d5e5f4e798499903759c48cc5Sunny Goyal    private static final int SCRIM_COLOR = Color.BLACK & 0x00FFFFFF;
770fa93bc5c65a2d7d5e5f4e798499903759c48cc5Sunny Goyal
78b135956e95d2d7479290af89d618892ed0e7327dSunny Goyal    private final int[] mTmpXY = new int[2];
79b135956e95d2d7479290af89d618892ed0e7327dSunny Goyal
80091440a9cb9d4f42406631004aa484cbb79214caAdam Cohen    @Thunk DragController mDragController;
8131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
82716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen    private int mXDown, mYDown;
83716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen    private Launcher mLauncher;
84716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen
856788269814a678af976dfc7d6135993e172ce586Adam Cohen    // Variables relating to resizing widgets
86b135956e95d2d7479290af89d618892ed0e7327dSunny Goyal    private final ArrayList<AppWidgetResizeFrame> mResizeFrames = new ArrayList<>();
877066003b2032a49ae5e59dab9b706259bdeb7e6eSunny Goyal    private final boolean mIsRtl;
886788269814a678af976dfc7d6135993e172ce586Adam Cohen    private AppWidgetResizeFrame mCurrentResizeFrame;
89716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen
90716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen    // Variables relating to animation of views after drop
91716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen    private ValueAnimator mDropAnim = null;
92b135956e95d2d7479290af89d618892ed0e7327dSunny Goyal    private final TimeInterpolator mCubicEaseOutInterpolator = new DecelerateInterpolator(1.5f);
93091440a9cb9d4f42406631004aa484cbb79214caAdam Cohen    @Thunk DragView mDropView = null;
94091440a9cb9d4f42406631004aa484cbb79214caAdam Cohen    @Thunk int mAnchorViewInitialScrollX = 0;
95091440a9cb9d4f42406631004aa484cbb79214caAdam Cohen    @Thunk View mAnchorView = null;
968dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen
973371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen    private boolean mHoverPointClosesFolder = false;
98b135956e95d2d7479290af89d618892ed0e7327dSunny Goyal    private final Rect mHitRect = new Rect();
9995cdb3a0211650e76adb451588ce89fd585b178fTony Wickham    private final Rect mHighlightRect = new Rect();
1006788269814a678af976dfc7d6135993e172ce586Adam Cohen
101b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen    private TouchCompleteListener mTouchCompleteListener;
102b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen
103432609a246819f3cf887a80c2ae56b61fc5ca25aAdam Cohen    private View mOverlayView;
104432609a246819f3cf887a80c2ae56b61fc5ca25aAdam Cohen    private int mTopViewIndex;
1052d783ce2f4b2e507bead0d723f0edcdf902dbd46Adam Cohen    private int mChildCountOnLastUpdate = -1;
10655bd9725d5c0373b89f7b9bbd9547550ea3bbc63Jorim Jaggi
1076c5891a9fce95eee3d87823d11d21889743e9c68Adam Cohen    // Darkening scrim
1086c5891a9fce95eee3d87823d11d21889743e9c68Adam Cohen    private float mBackgroundAlpha = 0;
1096c5891a9fce95eee3d87823d11d21889743e9c68Adam Cohen
1100f97b7874fe29f36e7a40d2fe4b45d1e0e24fe1bTony Wickham    // Related to adjacent page hints
1110f97b7874fe29f36e7a40d2fe4b45d1e0e24fe1bTony Wickham    private final Rect mScrollChildPosition = new Rect();
1123333b0ced8e6743c41909f6f6b916f1f9ec5a004Sunny Goyal    private final ViewGroupFocusHelper mFocusIndicatorHelper;
1133333b0ced8e6743c41909f6f6b916f1f9ec5a004Sunny Goyal
1140f97b7874fe29f36e7a40d2fe4b45d1e0e24fe1bTony Wickham    private boolean mInScrollArea;
1150f97b7874fe29f36e7a40d2fe4b45d1e0e24fe1bTony Wickham    private boolean mShowPageHints;
1160f97b7874fe29f36e7a40d2fe4b45d1e0e24fe1bTony Wickham    private Drawable mLeftHoverDrawable;
1170f97b7874fe29f36e7a40d2fe4b45d1e0e24fe1bTony Wickham    private Drawable mRightHoverDrawable;
1180f97b7874fe29f36e7a40d2fe4b45d1e0e24fe1bTony Wickham    private Drawable mLeftHoverDrawableActive;
1190f97b7874fe29f36e7a40d2fe4b45d1e0e24fe1bTony Wickham    private Drawable mRightHoverDrawableActive;
1200f97b7874fe29f36e7a40d2fe4b45d1e0e24fe1bTony Wickham
121dadb304b4682998c43b9c07bef45b9a9380f3287Tony Wickham    // Related to pinch-to-go-to-overview gesture.
1229c43182ff1d095b1bbaacedefe6e0f4c2deb17e3Tony Wickham    private PinchToOverviewListener mPinchListener = null;
123645764e3e5fa34d9adcddfc722d726b76f048306Hyunyoung Song
124645764e3e5fa34d9adcddfc722d726b76f048306Hyunyoung Song    // Handles all apps pull up interaction
125645764e3e5fa34d9adcddfc722d726b76f048306Hyunyoung Song    private AllAppsTransitionController mAllAppsController;
126645764e3e5fa34d9adcddfc722d726b76f048306Hyunyoung Song
127645764e3e5fa34d9adcddfc722d726b76f048306Hyunyoung Song    private TouchController mActiveController;
12831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    /**
12931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * Used to create a new DragLayer from XML.
13031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     *
13131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param context The application's context.
1320e26059548e429e5d1c973bebe4c561bead2926fMichael Jurka     * @param attrs The attributes set containing the Workspace's customization values.
13331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     */
13431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    public DragLayer(Context context, AttributeSet attrs) {
13531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        super(context, attrs);
136be62afa34d58edab0fc9ba7499f0dd543039c903Winson Chung
137be62afa34d58edab0fc9ba7499f0dd543039c903Winson Chung        // Disable multitouch across the workspace/all apps/customize tray
138be62afa34d58edab0fc9ba7499f0dd543039c903Winson Chung        setMotionEventSplittingEnabled(false);
13921b411074e39fd10cbc8dd0220bb159da4af2c76Adam Cohen        setChildrenDrawingOrderEnabled(true);
140360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung
1410f97b7874fe29f36e7a40d2fe4b45d1e0e24fe1bTony Wickham        final Resources res = getResources();
1420f97b7874fe29f36e7a40d2fe4b45d1e0e24fe1bTony Wickham        mLeftHoverDrawable = res.getDrawable(R.drawable.page_hover_left);
1430f97b7874fe29f36e7a40d2fe4b45d1e0e24fe1bTony Wickham        mRightHoverDrawable = res.getDrawable(R.drawable.page_hover_right);
1440f97b7874fe29f36e7a40d2fe4b45d1e0e24fe1bTony Wickham        mLeftHoverDrawableActive = res.getDrawable(R.drawable.page_hover_left_active);
1450f97b7874fe29f36e7a40d2fe4b45d1e0e24fe1bTony Wickham        mRightHoverDrawableActive = res.getDrawable(R.drawable.page_hover_right_active);
1460f97b7874fe29f36e7a40d2fe4b45d1e0e24fe1bTony Wickham        mIsRtl = Utilities.isRtl(res);
1473333b0ced8e6743c41909f6f6b916f1f9ec5a004Sunny Goyal        mFocusIndicatorHelper = new ViewGroupFocusHelper(this);
14831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
14931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
150645764e3e5fa34d9adcddfc722d726b76f048306Hyunyoung Song    public void setup(Launcher launcher, DragController dragController,
151645764e3e5fa34d9adcddfc722d726b76f048306Hyunyoung Song            AllAppsTransitionController allAppsTransitionController) {
1524c98d9235d164680186180974719f551cf935d08Winson Chung        mLauncher = launcher;
153645764e3e5fa34d9adcddfc722d726b76f048306Hyunyoung Song        mDragController = dragController;
154645764e3e5fa34d9adcddfc722d726b76f048306Hyunyoung Song        mAllAppsController = allAppsTransitionController;
155dadb304b4682998c43b9c07bef45b9a9380f3287Tony Wickham
156e22172537b9235a5ba41b3054677dd7ed6d89f02Tony Wickham        boolean isAccessibilityEnabled = ((AccessibilityManager) mLauncher.getSystemService(
157e22172537b9235a5ba41b3054677dd7ed6d89f02Tony Wickham                Context.ACCESSIBILITY_SERVICE)).isEnabled();
158e22172537b9235a5ba41b3054677dd7ed6d89f02Tony Wickham        onAccessibilityStateChanged(isAccessibilityEnabled);
15931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
16076fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen
1613333b0ced8e6743c41909f6f6b916f1f9ec5a004Sunny Goyal    public ViewGroupFocusHelper getFocusIndicatorHelper() {
1623333b0ced8e6743c41909f6f6b916f1f9ec5a004Sunny Goyal        return mFocusIndicatorHelper;
1633333b0ced8e6743c41909f6f6b916f1f9ec5a004Sunny Goyal    }
1643333b0ced8e6743c41909f6f6b916f1f9ec5a004Sunny Goyal
16531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    @Override
16631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    public boolean dispatchKeyEvent(KeyEvent event) {
16700acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato        return mDragController.dispatchKeyEvent(event) || super.dispatchKeyEvent(event);
16831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
16931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
170e22172537b9235a5ba41b3054677dd7ed6d89f02Tony Wickham    public void onAccessibilityStateChanged(boolean isAccessibilityEnabled) {
171e22172537b9235a5ba41b3054677dd7ed6d89f02Tony Wickham        mPinchListener = FeatureFlags.LAUNCHER3_DISABLE_PINCH_TO_OVERVIEW || isAccessibilityEnabled
172e22172537b9235a5ba41b3054677dd7ed6d89f02Tony Wickham                ? null : new PinchToOverviewListener(mLauncher);
173e22172537b9235a5ba41b3054677dd7ed6d89f02Tony Wickham    }
174e22172537b9235a5ba41b3054677dd7ed6d89f02Tony Wickham
175b670f195ffb7b4a0519fd0b337b68f7412159414Adam Cohen    public void showOverlayView(View overlayView) {
176432609a246819f3cf887a80c2ae56b61fc5ca25aAdam Cohen        LayoutParams lp = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
177b670f195ffb7b4a0519fd0b337b68f7412159414Adam Cohen        mOverlayView = overlayView;
178b670f195ffb7b4a0519fd0b337b68f7412159414Adam Cohen        addView(overlayView, lp);
179b670f195ffb7b4a0519fd0b337b68f7412159414Adam Cohen
180b670f195ffb7b4a0519fd0b337b68f7412159414Adam Cohen        // ensure that the overlay view stays on top. we can't use drawing order for this
181b670f195ffb7b4a0519fd0b337b68f7412159414Adam Cohen        // because in API level 16 touch dispatch doesn't respect drawing order.
182b670f195ffb7b4a0519fd0b337b68f7412159414Adam Cohen        mOverlayView.bringToFront();
183432609a246819f3cf887a80c2ae56b61fc5ca25aAdam Cohen    }
184432609a246819f3cf887a80c2ae56b61fc5ca25aAdam Cohen
185432609a246819f3cf887a80c2ae56b61fc5ca25aAdam Cohen    public void dismissOverlayView() {
186432609a246819f3cf887a80c2ae56b61fc5ca25aAdam Cohen        removeView(mOverlayView);
187432609a246819f3cf887a80c2ae56b61fc5ca25aAdam Cohen    }
188432609a246819f3cf887a80c2ae56b61fc5ca25aAdam Cohen
1897744169812e0d35531e9de258785af1f2ec9bed3Hyunyoung Song    public boolean isEventOverPageIndicator(MotionEvent ev) {
1907744169812e0d35531e9de258785af1f2ec9bed3Hyunyoung Song        getDescendantRectRelativeToSelf(mLauncher.getWorkspace().getPageIndicator(), mHitRect);
1917744169812e0d35531e9de258785af1f2ec9bed3Hyunyoung Song        return mHitRect.contains((int) ev.getX(), (int) ev.getY());
1927744169812e0d35531e9de258785af1f2ec9bed3Hyunyoung Song    }
1937744169812e0d35531e9de258785af1f2ec9bed3Hyunyoung Song
194a9a8a4221709cc3fda48fd80d4213d25183b8bf7Hyunyoung Song    public boolean isEventOverHotseat(MotionEvent ev) {
1951bce7fd342875be8f7c1f82c8cf21d0199c8d544Tony Wickham        return isEventOverView(mLauncher.getHotseat(), ev);
196a9a8a4221709cc3fda48fd80d4213d25183b8bf7Hyunyoung Song    }
197a9a8a4221709cc3fda48fd80d4213d25183b8bf7Hyunyoung Song
1983371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen    private boolean isEventOverFolderTextRegion(Folder folder, MotionEvent ev) {
1991bce7fd342875be8f7c1f82c8cf21d0199c8d544Tony Wickham        return isEventOverView(folder.getEditTextRegion(), ev);
2003371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen    }
2013371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen
2023371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen    private boolean isEventOverFolder(Folder folder, MotionEvent ev) {
2031bce7fd342875be8f7c1f82c8cf21d0199c8d544Tony Wickham        return isEventOverView(folder, ev);
2043371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen    }
2053371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen
206ccc414bb1e18206d2a3d8d797070278bdb286354Sunny Goyal    private boolean isEventOverDropTargetBar(MotionEvent ev) {
2071bce7fd342875be8f7c1f82c8cf21d0199c8d544Tony Wickham        return isEventOverView(mLauncher.getDropTargetBar(), ev);
2081bce7fd342875be8f7c1f82c8cf21d0199c8d544Tony Wickham    }
2091bce7fd342875be8f7c1f82c8cf21d0199c8d544Tony Wickham
2101bce7fd342875be8f7c1f82c8cf21d0199c8d544Tony Wickham    private boolean isEventOverView(View view, MotionEvent ev) {
2111bce7fd342875be8f7c1f82c8cf21d0199c8d544Tony Wickham        getDescendantRectRelativeToSelf(view, mHitRect);
21247328fd53f43fd0c2ed14ad925dd04483f9229a0Sunny Goyal        return mHitRect.contains((int) ev.getX(), (int) ev.getY());
213ccc414bb1e18206d2a3d8d797070278bdb286354Sunny Goyal    }
214ccc414bb1e18206d2a3d8d797070278bdb286354Sunny Goyal
21576fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen    private boolean handleTouchDown(MotionEvent ev, boolean intercept) {
2166788269814a678af976dfc7d6135993e172ce586Adam Cohen        Rect hitRect = new Rect();
2176788269814a678af976dfc7d6135993e172ce586Adam Cohen        int x = (int) ev.getX();
2186788269814a678af976dfc7d6135993e172ce586Adam Cohen        int y = (int) ev.getY();
2196788269814a678af976dfc7d6135993e172ce586Adam Cohen
2206788269814a678af976dfc7d6135993e172ce586Adam Cohen        for (AppWidgetResizeFrame child: mResizeFrames) {
2216788269814a678af976dfc7d6135993e172ce586Adam Cohen            child.getHitRect(hitRect);
2226788269814a678af976dfc7d6135993e172ce586Adam Cohen            if (hitRect.contains(x, y)) {
2236788269814a678af976dfc7d6135993e172ce586Adam Cohen                if (child.beginResizeIfPointInRegion(x - child.getLeft(), y - child.getTop())) {
2246788269814a678af976dfc7d6135993e172ce586Adam Cohen                    mCurrentResizeFrame = child;
2256788269814a678af976dfc7d6135993e172ce586Adam Cohen                    mXDown = x;
2266788269814a678af976dfc7d6135993e172ce586Adam Cohen                    mYDown = y;
2276788269814a678af976dfc7d6135993e172ce586Adam Cohen                    requestDisallowInterceptTouchEvent(true);
2286788269814a678af976dfc7d6135993e172ce586Adam Cohen                    return true;
2296788269814a678af976dfc7d6135993e172ce586Adam Cohen                }
2306788269814a678af976dfc7d6135993e172ce586Adam Cohen            }
2316788269814a678af976dfc7d6135993e172ce586Adam Cohen        }
23276fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen
2332f2104ccdfd0f47d20e959982c52d36dfc7760ffTony Wickham        // Remove the shortcuts container when touching outside of it.
23449c8d29fddd341aa04459371aa5e869da2f52768Tony Wickham        DeepShortcutsContainer deepShortcutsContainer = mLauncher.getOpenShortcutsContainer();
2352f2104ccdfd0f47d20e959982c52d36dfc7760ffTony Wickham        if (deepShortcutsContainer != null) {
2362f2104ccdfd0f47d20e959982c52d36dfc7760ffTony Wickham            if (isEventOverView(deepShortcutsContainer, ev)) {
2372f2104ccdfd0f47d20e959982c52d36dfc7760ffTony Wickham                // Let the container handle the event.
2382f2104ccdfd0f47d20e959982c52d36dfc7760ffTony Wickham                return false;
2392f2104ccdfd0f47d20e959982c52d36dfc7760ffTony Wickham            } else {
2402f2104ccdfd0f47d20e959982c52d36dfc7760ffTony Wickham                if (isInAccessibleDrag()) {
2412f2104ccdfd0f47d20e959982c52d36dfc7760ffTony Wickham                    // Do not close the container if in drag and drop.
2422f2104ccdfd0f47d20e959982c52d36dfc7760ffTony Wickham                    if (!isEventOverDropTargetBar(ev)) {
2432f2104ccdfd0f47d20e959982c52d36dfc7760ffTony Wickham                        return true;
2442f2104ccdfd0f47d20e959982c52d36dfc7760ffTony Wickham                    }
2452f2104ccdfd0f47d20e959982c52d36dfc7760ffTony Wickham                } else {
24649c8d29fddd341aa04459371aa5e869da2f52768Tony Wickham                    mLauncher.closeShortcutsContainer();
2472f2104ccdfd0f47d20e959982c52d36dfc7760ffTony Wickham                    // We let touches on the original icon go through so that users can launch
2482f2104ccdfd0f47d20e959982c52d36dfc7760ffTony Wickham                    // the app with one tap if they don't find a shortcut they want.
2492f2104ccdfd0f47d20e959982c52d36dfc7760ffTony Wickham                    return !isEventOverView(deepShortcutsContainer.getDeferredDragIcon(), ev);
2502f2104ccdfd0f47d20e959982c52d36dfc7760ffTony Wickham                }
2512f2104ccdfd0f47d20e959982c52d36dfc7760ffTony Wickham            }
2522f2104ccdfd0f47d20e959982c52d36dfc7760ffTony Wickham        }
2532f2104ccdfd0f47d20e959982c52d36dfc7760ffTony Wickham
2541d9af7d1e75bad13bb10ad37f5900ed59882622eAdam Cohen        Folder currentFolder = mLauncher.getWorkspace().getOpenFolder();
255424418bb50ccf5d9270650b70cc51f423da51a65Sunny Goyal        if (currentFolder != null && intercept) {
2561d9af7d1e75bad13bb10ad37f5900ed59882622eAdam Cohen            if (currentFolder.isEditingName()) {
2573371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                if (!isEventOverFolderTextRegion(currentFolder, ev)) {
2581d9af7d1e75bad13bb10ad37f5900ed59882622eAdam Cohen                    currentFolder.dismissEditingName();
25976fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen                    return true;
2602801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen                }
2612801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen            }
26276fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen
2633371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen            if (!isEventOverFolder(currentFolder, ev)) {
264ccc414bb1e18206d2a3d8d797070278bdb286354Sunny Goyal                if (isInAccessibleDrag()) {
265ccc414bb1e18206d2a3d8d797070278bdb286354Sunny Goyal                    // Do not close the folder if in drag and drop.
266ccc414bb1e18206d2a3d8d797070278bdb286354Sunny Goyal                    if (!isEventOverDropTargetBar(ev)) {
267ccc414bb1e18206d2a3d8d797070278bdb286354Sunny Goyal                        return true;
268ccc414bb1e18206d2a3d8d797070278bdb286354Sunny Goyal                    }
269ccc414bb1e18206d2a3d8d797070278bdb286354Sunny Goyal                } else {
270ccc414bb1e18206d2a3d8d797070278bdb286354Sunny Goyal                    mLauncher.closeFolder();
271ccc414bb1e18206d2a3d8d797070278bdb286354Sunny Goyal                    return true;
272ccc414bb1e18206d2a3d8d797070278bdb286354Sunny Goyal                }
27376fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen            }
2742801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen        }
2756788269814a678af976dfc7d6135993e172ce586Adam Cohen        return false;
2766788269814a678af976dfc7d6135993e172ce586Adam Cohen    }
2776788269814a678af976dfc7d6135993e172ce586Adam Cohen
27831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    @Override
27931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    public boolean onInterceptTouchEvent(MotionEvent ev) {
280b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen        int action = ev.getAction();
281b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen
282b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen        if (action == MotionEvent.ACTION_DOWN) {
283c001cf562017d08cd48b67de8f377ca08881e70eHyunyoung Song            // Cancel discovery bounce animation when a user start interacting on anywhere on
284c001cf562017d08cd48b67de8f377ca08881e70eHyunyoung Song            // dray layer even if mAllAppsController is NOT the active controller.
285c001cf562017d08cd48b67de8f377ca08881e70eHyunyoung Song            // TODO: handle other input other than touch
286c001cf562017d08cd48b67de8f377ca08881e70eHyunyoung Song            mAllAppsController.cancelDiscoveryAnimation();
28776fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen            if (handleTouchDown(ev, true)) {
2886788269814a678af976dfc7d6135993e172ce586Adam Cohen                return true;
289d1837cc69eb222371afdd30890f7215d117510f2Patrick Dubroy            }
290b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen        } else if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) {
291b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen            if (mTouchCompleteListener != null) {
292b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen                mTouchCompleteListener.onTouchComplete();
293b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen            }
294b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen            mTouchCompleteListener = null;
2951b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen        }
2966788269814a678af976dfc7d6135993e172ce586Adam Cohen        clearAllResizeFrames();
297dadb304b4682998c43b9c07bef45b9a9380f3287Tony Wickham
298645764e3e5fa34d9adcddfc722d726b76f048306Hyunyoung Song        if (mDragController.onInterceptTouchEvent(ev)) {
299645764e3e5fa34d9adcddfc722d726b76f048306Hyunyoung Song            mActiveController = mDragController;
300645764e3e5fa34d9adcddfc722d726b76f048306Hyunyoung Song            return true;
301645764e3e5fa34d9adcddfc722d726b76f048306Hyunyoung Song        }
3021bce7fd342875be8f7c1f82c8cf21d0199c8d544Tony Wickham
303b11ae50fcb2bb07ee77645fdacdf90f67f58dae4Hyunyoung Song        if (FeatureFlags.LAUNCHER3_ALL_APPS_PULL_UP && mAllAppsController.onInterceptTouchEvent(ev)) {
304645764e3e5fa34d9adcddfc722d726b76f048306Hyunyoung Song            mActiveController = mAllAppsController;
305645764e3e5fa34d9adcddfc722d726b76f048306Hyunyoung Song            return true;
306645764e3e5fa34d9adcddfc722d726b76f048306Hyunyoung Song        }
307645764e3e5fa34d9adcddfc722d726b76f048306Hyunyoung Song
3089c43182ff1d095b1bbaacedefe6e0f4c2deb17e3Tony Wickham        if (mPinchListener != null && mPinchListener.onInterceptTouchEvent(ev)) {
309c5b31965d9bcb4c9899e2d1c45b5c95c70bac9f2Tony Wickham            // Stop listening for scrolling etc. (onTouchEvent() handles the rest of the pinch.)
310645764e3e5fa34d9adcddfc722d726b76f048306Hyunyoung Song            mActiveController = mPinchListener;
311c5b31965d9bcb4c9899e2d1c45b5c95c70bac9f2Tony Wickham            return true;
312dadb304b4682998c43b9c07bef45b9a9380f3287Tony Wickham        }
313645764e3e5fa34d9adcddfc722d726b76f048306Hyunyoung Song        return false;
31431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
31531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
31631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    @Override
3173371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen    public boolean onInterceptHoverEvent(MotionEvent ev) {
318023c71eb3b2bbe63272cb74baaf050c4188c89b0Michael Jurka        if (mLauncher == null || mLauncher.getWorkspace() == null) {
319023c71eb3b2bbe63272cb74baaf050c4188c89b0Michael Jurka            return false;
320023c71eb3b2bbe63272cb74baaf050c4188c89b0Michael Jurka        }
3213371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen        Folder currentFolder = mLauncher.getWorkspace().getOpenFolder();
3223371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen        if (currentFolder == null) {
3233371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen            return false;
3243371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen        } else {
3258b805b17158886035b38261eb611d8641701ae43Michael Jurka                AccessibilityManager accessibilityManager = (AccessibilityManager)
3268b805b17158886035b38261eb611d8641701ae43Michael Jurka                        getContext().getSystemService(Context.ACCESSIBILITY_SERVICE);
3278b805b17158886035b38261eb611d8641701ae43Michael Jurka            if (accessibilityManager.isTouchExplorationEnabled()) {
3283371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                final int action = ev.getAction();
329ccc414bb1e18206d2a3d8d797070278bdb286354Sunny Goyal                boolean isOverFolderOrSearchBar;
3303371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                switch (action) {
3313371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                    case MotionEvent.ACTION_HOVER_ENTER:
332ccc414bb1e18206d2a3d8d797070278bdb286354Sunny Goyal                        isOverFolderOrSearchBar = isEventOverFolder(currentFolder, ev) ||
333ccc414bb1e18206d2a3d8d797070278bdb286354Sunny Goyal                            (isInAccessibleDrag() && isEventOverDropTargetBar(ev));
334ccc414bb1e18206d2a3d8d797070278bdb286354Sunny Goyal                        if (!isOverFolderOrSearchBar) {
3353371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                            sendTapOutsideFolderAccessibilityEvent(currentFolder.isEditingName());
3363371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                            mHoverPointClosesFolder = true;
3373371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                            return true;
3383371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                        }
339693fbc7f1737d89f11f9ab81558c109f0883ab0eMihail Dumitrescu                        mHoverPointClosesFolder = false;
340693fbc7f1737d89f11f9ab81558c109f0883ab0eMihail Dumitrescu                        break;
3413371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                    case MotionEvent.ACTION_HOVER_MOVE:
342ccc414bb1e18206d2a3d8d797070278bdb286354Sunny Goyal                        isOverFolderOrSearchBar = isEventOverFolder(currentFolder, ev) ||
343ccc414bb1e18206d2a3d8d797070278bdb286354Sunny Goyal                            (isInAccessibleDrag() && isEventOverDropTargetBar(ev));
344ccc414bb1e18206d2a3d8d797070278bdb286354Sunny Goyal                        if (!isOverFolderOrSearchBar && !mHoverPointClosesFolder) {
3453371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                            sendTapOutsideFolderAccessibilityEvent(currentFolder.isEditingName());
3463371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                            mHoverPointClosesFolder = true;
3473371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                            return true;
348ccc414bb1e18206d2a3d8d797070278bdb286354Sunny Goyal                        } else if (!isOverFolderOrSearchBar) {
3493371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                            return true;
3503371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                        }
351693fbc7f1737d89f11f9ab81558c109f0883ab0eMihail Dumitrescu                        mHoverPointClosesFolder = false;
3523371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                }
3533371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen            }
3543371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen        }
3553371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen        return false;
3563371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen    }
3573371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen
3583371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen    private void sendTapOutsideFolderAccessibilityEvent(boolean isEditingName) {
3598b805b17158886035b38261eb611d8641701ae43Michael Jurka        AccessibilityManager accessibilityManager = (AccessibilityManager)
3608b805b17158886035b38261eb611d8641701ae43Michael Jurka                getContext().getSystemService(Context.ACCESSIBILITY_SERVICE);
3618b805b17158886035b38261eb611d8641701ae43Michael Jurka        if (accessibilityManager.isEnabled()) {
3623371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen            int stringId = isEditingName ? R.string.folder_tap_to_rename : R.string.folder_tap_to_close;
3633371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen            AccessibilityEvent event = AccessibilityEvent.obtain(
3643371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen                    AccessibilityEvent.TYPE_VIEW_FOCUSED);
3653371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen            onInitializeAccessibilityEvent(event);
3668b805b17158886035b38261eb611d8641701ae43Michael Jurka            event.getText().add(getContext().getString(stringId));
3678b805b17158886035b38261eb611d8641701ae43Michael Jurka            accessibilityManager.sendAccessibilityEvent(event);
3683371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen        }
36983ca480941b3dd635b62347008fc8d7859d82002Winson Chung    }
37083ca480941b3dd635b62347008fc8d7859d82002Winson Chung
371ccc414bb1e18206d2a3d8d797070278bdb286354Sunny Goyal    private boolean isInAccessibleDrag() {
372ae50284e0a838139c67caf0064a0977c871497faSunny Goyal        return mLauncher.getAccessibilityDelegate().isInAccessibleDrag();
373ccc414bb1e18206d2a3d8d797070278bdb286354Sunny Goyal    }
374ccc414bb1e18206d2a3d8d797070278bdb286354Sunny Goyal
37583ca480941b3dd635b62347008fc8d7859d82002Winson Chung    @Override
37683ca480941b3dd635b62347008fc8d7859d82002Winson Chung    public boolean onRequestSendAccessibilityEvent(View child, AccessibilityEvent event) {
37783ca480941b3dd635b62347008fc8d7859d82002Winson Chung        Folder currentFolder = mLauncher.getWorkspace().getOpenFolder();
37883ca480941b3dd635b62347008fc8d7859d82002Winson Chung        if (currentFolder != null) {
37983ca480941b3dd635b62347008fc8d7859d82002Winson Chung            if (child == currentFolder) {
38083ca480941b3dd635b62347008fc8d7859d82002Winson Chung                return super.onRequestSendAccessibilityEvent(child, event);
38183ca480941b3dd635b62347008fc8d7859d82002Winson Chung            }
382ccc414bb1e18206d2a3d8d797070278bdb286354Sunny Goyal
38347328fd53f43fd0c2ed14ad925dd04483f9229a0Sunny Goyal            if (isInAccessibleDrag() && child instanceof DropTargetBar) {
384ccc414bb1e18206d2a3d8d797070278bdb286354Sunny Goyal                return super.onRequestSendAccessibilityEvent(child, event);
385ccc414bb1e18206d2a3d8d797070278bdb286354Sunny Goyal            }
38683ca480941b3dd635b62347008fc8d7859d82002Winson Chung            // Skip propagating onRequestSendAccessibilityEvent all for other children
38783ca480941b3dd635b62347008fc8d7859d82002Winson Chung            // when a folder is open
38883ca480941b3dd635b62347008fc8d7859d82002Winson Chung            return false;
38983ca480941b3dd635b62347008fc8d7859d82002Winson Chung        }
39083ca480941b3dd635b62347008fc8d7859d82002Winson Chung        return super.onRequestSendAccessibilityEvent(child, event);
39183ca480941b3dd635b62347008fc8d7859d82002Winson Chung    }
39283ca480941b3dd635b62347008fc8d7859d82002Winson Chung
39383ca480941b3dd635b62347008fc8d7859d82002Winson Chung    @Override
39483ca480941b3dd635b62347008fc8d7859d82002Winson Chung    public void addChildrenForAccessibility(ArrayList<View> childrenForAccessibility) {
39583ca480941b3dd635b62347008fc8d7859d82002Winson Chung        Folder currentFolder = mLauncher.getWorkspace().getOpenFolder();
39683ca480941b3dd635b62347008fc8d7859d82002Winson Chung        if (currentFolder != null) {
39783ca480941b3dd635b62347008fc8d7859d82002Winson Chung            // Only add the folder as a child for accessibility when it is open
39883ca480941b3dd635b62347008fc8d7859d82002Winson Chung            childrenForAccessibility.add(currentFolder);
399ccc414bb1e18206d2a3d8d797070278bdb286354Sunny Goyal
400ccc414bb1e18206d2a3d8d797070278bdb286354Sunny Goyal            if (isInAccessibleDrag()) {
40147328fd53f43fd0c2ed14ad925dd04483f9229a0Sunny Goyal                childrenForAccessibility.add(mLauncher.getDropTargetBar());
402ccc414bb1e18206d2a3d8d797070278bdb286354Sunny Goyal            }
40383ca480941b3dd635b62347008fc8d7859d82002Winson Chung        } else {
40483ca480941b3dd635b62347008fc8d7859d82002Winson Chung            super.addChildrenForAccessibility(childrenForAccessibility);
40583ca480941b3dd635b62347008fc8d7859d82002Winson Chung        }
4063371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen    }
4073371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen
4083371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen    @Override
4093371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen    public boolean onHoverEvent(MotionEvent ev) {
4103371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen        // If we've received this, we've already done the necessary handling
4113371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen        // in onInterceptHoverEvent. Return true to consume the event.
4123371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen        return false;
4133371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen    }
4143371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen
4153371da0159cc54ff8ae1b1b26effb96445f208d5Adam Cohen    @Override
41631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    public boolean onTouchEvent(MotionEvent ev) {
4176788269814a678af976dfc7d6135993e172ce586Adam Cohen        boolean handled = false;
4186788269814a678af976dfc7d6135993e172ce586Adam Cohen        int action = ev.getAction();
4196788269814a678af976dfc7d6135993e172ce586Adam Cohen
4206788269814a678af976dfc7d6135993e172ce586Adam Cohen        int x = (int) ev.getX();
4216788269814a678af976dfc7d6135993e172ce586Adam Cohen        int y = (int) ev.getY();
4226788269814a678af976dfc7d6135993e172ce586Adam Cohen
423b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen        if (action == MotionEvent.ACTION_DOWN) {
424b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen            if (handleTouchDown(ev, false)) {
425b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen                return true;
426b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen            }
427b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen        } else if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) {
428b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen            if (mTouchCompleteListener != null) {
429b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen                mTouchCompleteListener.onTouchComplete();
4306788269814a678af976dfc7d6135993e172ce586Adam Cohen            }
431b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen            mTouchCompleteListener = null;
4326788269814a678af976dfc7d6135993e172ce586Adam Cohen        }
4336788269814a678af976dfc7d6135993e172ce586Adam Cohen
4346788269814a678af976dfc7d6135993e172ce586Adam Cohen        if (mCurrentResizeFrame != null) {
4356788269814a678af976dfc7d6135993e172ce586Adam Cohen            handled = true;
4366788269814a678af976dfc7d6135993e172ce586Adam Cohen            switch (action) {
4376788269814a678af976dfc7d6135993e172ce586Adam Cohen                case MotionEvent.ACTION_MOVE:
4386788269814a678af976dfc7d6135993e172ce586Adam Cohen                    mCurrentResizeFrame.visualizeResizeForDelta(x - mXDown, y - mYDown);
4396788269814a678af976dfc7d6135993e172ce586Adam Cohen                    break;
4406788269814a678af976dfc7d6135993e172ce586Adam Cohen                case MotionEvent.ACTION_CANCEL:
4416788269814a678af976dfc7d6135993e172ce586Adam Cohen                case MotionEvent.ACTION_UP:
442bebf042666cffe52039b875a549a582abd78a431Adam Cohen                    mCurrentResizeFrame.visualizeResizeForDelta(x - mXDown, y - mYDown);
443bebf042666cffe52039b875a549a582abd78a431Adam Cohen                    mCurrentResizeFrame.onTouchUp();
4446788269814a678af976dfc7d6135993e172ce586Adam Cohen                    mCurrentResizeFrame = null;
4456788269814a678af976dfc7d6135993e172ce586Adam Cohen            }
4466788269814a678af976dfc7d6135993e172ce586Adam Cohen        }
4476788269814a678af976dfc7d6135993e172ce586Adam Cohen        if (handled) return true;
448645764e3e5fa34d9adcddfc722d726b76f048306Hyunyoung Song        if (mActiveController != null) {
449645764e3e5fa34d9adcddfc722d726b76f048306Hyunyoung Song            return mActiveController.onTouchEvent(ev);
450645764e3e5fa34d9adcddfc722d726b76f048306Hyunyoung Song        }
451645764e3e5fa34d9adcddfc722d726b76f048306Hyunyoung Song        return false;
45291a9c9636f10f1e12cd1f660b2e330634fbdc7dcRomain Guy    }
453ea3763c2672f77539538af8cdd395ad97058eaabRomain Guy
454d6c8e7eeb13094ea1349897663ae28d8a3bf2773Vadim Tryshev    @Override
455d6c8e7eeb13094ea1349897663ae28d8a3bf2773Vadim Tryshev    public boolean onDragEvent (DragEvent event) {
456d6c8e7eeb13094ea1349897663ae28d8a3bf2773Vadim Tryshev        return mDragController.onDragEvent(event);
457d6c8e7eeb13094ea1349897663ae28d8a3bf2773Vadim Tryshev    }
458d6c8e7eeb13094ea1349897663ae28d8a3bf2773Vadim Tryshev
45935e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen    /**
46035e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen     * Determine the rect of the descendant in this DragLayer's coordinates
46135e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen     *
46235e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen     * @param descendant The descendant whose coordinates we want to find.
46335e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen     * @param r The rect into which to place the results.
46435e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen     * @return The factor by which this descendant is scaled relative to this DragLayer.
46535e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen     */
466ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen    public float getDescendantRectRelativeToSelf(View descendant, Rect r) {
467716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen        mTmpXY[0] = 0;
468716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen        mTmpXY[1] = 0;
469ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen        float scale = getDescendantCoordRelativeToSelf(descendant, mTmpXY);
4707d30a37007bac318db1c9af47a9af12d348042a5Adam Cohen
4718dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        r.set(mTmpXY[0], mTmpXY[1],
4727d30a37007bac318db1c9af47a9af12d348042a5Adam Cohen                (int) (mTmpXY[0] + scale * descendant.getMeasuredWidth()),
4737d30a37007bac318db1c9af47a9af12d348042a5Adam Cohen                (int) (mTmpXY[1] + scale * descendant.getMeasuredHeight()));
474ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen        return scale;
475716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen    }
47676fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen
477307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen    public float getLocationInDragLayer(View child, int[] loc) {
47835e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen        loc[0] = 0;
47935e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen        loc[1] = 0;
480307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen        return getDescendantCoordRelativeToSelf(child, loc);
48135e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen    }
48235e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen
4837d30a37007bac318db1c9af47a9af12d348042a5Adam Cohen    public float getDescendantCoordRelativeToSelf(View descendant, int[] coord) {
4847d30a37007bac318db1c9af47a9af12d348042a5Adam Cohen        return getDescendantCoordRelativeToSelf(descendant, coord, false);
4857d30a37007bac318db1c9af47a9af12d348042a5Adam Cohen    }
4867d30a37007bac318db1c9af47a9af12d348042a5Adam Cohen
48735e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen    /**
48835e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen     * Given a coordinate relative to the descendant, find the coordinate in this DragLayer's
48935e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen     * coordinates.
49035e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen     *
49135e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen     * @param descendant The descendant to which the passed coordinate is relative.
49235e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen     * @param coord The coordinate that we want mapped.
4937d30a37007bac318db1c9af47a9af12d348042a5Adam Cohen     * @param includeRootScroll Whether or not to account for the scroll of the root descendant:
4947d30a37007bac318db1c9af47a9af12d348042a5Adam Cohen     *          sometimes this is relevant as in a child's coordinates within the root descendant.
495307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen     * @return The factor by which this descendant is scaled relative to this DragLayer. Caution
496307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen     *         this scale factor is assumed to be equal in X and Y, and so if at any point this
497307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen     *         assumption fails, we will need to return a pair of scale factors.
49835e7e64d4b98e42c760e5e91489b7014a6ba9073Adam Cohen     */
4997d30a37007bac318db1c9af47a9af12d348042a5Adam Cohen    public float getDescendantCoordRelativeToSelf(View descendant, int[] coord,
5007d30a37007bac318db1c9af47a9af12d348042a5Adam Cohen            boolean includeRootScroll) {
501e8b5d20d94cb03878137a7fdf65d7a88270b73f8Sunny Goyal        return Utilities.getDescendantCoordRelativeToAncestor(descendant, this,
502c9ca2980983ab21fc8631c7a65399d6d9c70f39cWinson Chung                coord, includeRootScroll);
503c9ca2980983ab21fc8631c7a65399d6d9c70f39cWinson Chung    }
504c9ca2980983ab21fc8631c7a65399d6d9c70f39cWinson Chung
5057d30a37007bac318db1c9af47a9af12d348042a5Adam Cohen    /**
5067d30a37007bac318db1c9af47a9af12d348042a5Adam Cohen     * Inverse of {@link #getDescendantCoordRelativeToSelf(View, int[])}.
5077d30a37007bac318db1c9af47a9af12d348042a5Adam Cohen     */
5087d30a37007bac318db1c9af47a9af12d348042a5Adam Cohen    public float mapCoordInSelfToDescendent(View descendant, int[] coord) {
509c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung        return Utilities.mapCoordInSelfToDescendent(descendant, this, coord);
51076fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen    }
51176fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen
5123e8f811f31a2275e778244427271f77f4116c08bAdam Cohen    public void getViewRectRelativeToSelf(View v, Rect r) {
5133e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        int[] loc = new int[2];
5148dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        getLocationInWindow(loc);
5153e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        int x = loc[0];
5163e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        int y = loc[1];
517716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen
5188dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        v.getLocationInWindow(loc);
5193e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        int vX = loc[0];
5203e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        int vY = loc[1];
521716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen
5223e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        int left = vX - x;
5233e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        int top = vY - y;
5243e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        r.set(left, top, left + v.getMeasuredWidth(), top + v.getMeasuredHeight());
525716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen    }
526716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen
527ea3763c2672f77539538af8cdd395ad97058eaabRomain Guy    @Override
528ea3763c2672f77539538af8cdd395ad97058eaabRomain Guy    public boolean dispatchUnhandledMove(View focused, int direction) {
529ea3763c2672f77539538af8cdd395ad97058eaabRomain Guy        return mDragController.dispatchUnhandledMove(focused, direction);
530ea3763c2672f77539538af8cdd395ad97058eaabRomain Guy    }
531120980bd00f5eecec5717f49a3d7db96571025a9Adam Cohen
532bc927f9c24001e250622ca9a2547ee5b65baef58Adam Cohen    @Override
533bc927f9c24001e250622ca9a2547ee5b65baef58Adam Cohen    public LayoutParams generateLayoutParams(AttributeSet attrs) {
534bc927f9c24001e250622ca9a2547ee5b65baef58Adam Cohen        return new LayoutParams(getContext(), attrs);
535bc927f9c24001e250622ca9a2547ee5b65baef58Adam Cohen    }
536bc927f9c24001e250622ca9a2547ee5b65baef58Adam Cohen
537bc927f9c24001e250622ca9a2547ee5b65baef58Adam Cohen    @Override
538bc927f9c24001e250622ca9a2547ee5b65baef58Adam Cohen    protected LayoutParams generateDefaultLayoutParams() {
539bc927f9c24001e250622ca9a2547ee5b65baef58Adam Cohen        return new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
540bc927f9c24001e250622ca9a2547ee5b65baef58Adam Cohen    }
541bc927f9c24001e250622ca9a2547ee5b65baef58Adam Cohen
542bc927f9c24001e250622ca9a2547ee5b65baef58Adam Cohen    // Override to allow type-checking of LayoutParams.
543bc927f9c24001e250622ca9a2547ee5b65baef58Adam Cohen    @Override
544bc927f9c24001e250622ca9a2547ee5b65baef58Adam Cohen    protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
545bc927f9c24001e250622ca9a2547ee5b65baef58Adam Cohen        return p instanceof LayoutParams;
546bc927f9c24001e250622ca9a2547ee5b65baef58Adam Cohen    }
547bc927f9c24001e250622ca9a2547ee5b65baef58Adam Cohen
548bc927f9c24001e250622ca9a2547ee5b65baef58Adam Cohen    @Override
549bc927f9c24001e250622ca9a2547ee5b65baef58Adam Cohen    protected LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
550bc927f9c24001e250622ca9a2547ee5b65baef58Adam Cohen        return new LayoutParams(p);
551bc927f9c24001e250622ca9a2547ee5b65baef58Adam Cohen    }
552bc927f9c24001e250622ca9a2547ee5b65baef58Adam Cohen
553bc927f9c24001e250622ca9a2547ee5b65baef58Adam Cohen    public static class LayoutParams extends InsettableFrameLayout.LayoutParams {
5546788269814a678af976dfc7d6135993e172ce586Adam Cohen        public int x, y;
5556788269814a678af976dfc7d6135993e172ce586Adam Cohen        public boolean customPosition = false;
5566788269814a678af976dfc7d6135993e172ce586Adam Cohen
557bc927f9c24001e250622ca9a2547ee5b65baef58Adam Cohen        public LayoutParams(Context c, AttributeSet attrs) {
558bc927f9c24001e250622ca9a2547ee5b65baef58Adam Cohen            super(c, attrs);
559bc927f9c24001e250622ca9a2547ee5b65baef58Adam Cohen        }
560bc927f9c24001e250622ca9a2547ee5b65baef58Adam Cohen
5616788269814a678af976dfc7d6135993e172ce586Adam Cohen        public LayoutParams(int width, int height) {
5626788269814a678af976dfc7d6135993e172ce586Adam Cohen            super(width, height);
5636788269814a678af976dfc7d6135993e172ce586Adam Cohen        }
5646788269814a678af976dfc7d6135993e172ce586Adam Cohen
565bc927f9c24001e250622ca9a2547ee5b65baef58Adam Cohen        public LayoutParams(ViewGroup.LayoutParams lp) {
566bc927f9c24001e250622ca9a2547ee5b65baef58Adam Cohen            super(lp);
567bc927f9c24001e250622ca9a2547ee5b65baef58Adam Cohen        }
568bc927f9c24001e250622ca9a2547ee5b65baef58Adam Cohen
5696788269814a678af976dfc7d6135993e172ce586Adam Cohen        public void setWidth(int width) {
5706788269814a678af976dfc7d6135993e172ce586Adam Cohen            this.width = width;
5716788269814a678af976dfc7d6135993e172ce586Adam Cohen        }
5726788269814a678af976dfc7d6135993e172ce586Adam Cohen
5736788269814a678af976dfc7d6135993e172ce586Adam Cohen        public int getWidth() {
5746788269814a678af976dfc7d6135993e172ce586Adam Cohen            return width;
5756788269814a678af976dfc7d6135993e172ce586Adam Cohen        }
5766788269814a678af976dfc7d6135993e172ce586Adam Cohen
5776788269814a678af976dfc7d6135993e172ce586Adam Cohen        public void setHeight(int height) {
5786788269814a678af976dfc7d6135993e172ce586Adam Cohen            this.height = height;
5796788269814a678af976dfc7d6135993e172ce586Adam Cohen        }
5806788269814a678af976dfc7d6135993e172ce586Adam Cohen
5816788269814a678af976dfc7d6135993e172ce586Adam Cohen        public int getHeight() {
5826788269814a678af976dfc7d6135993e172ce586Adam Cohen            return height;
5836788269814a678af976dfc7d6135993e172ce586Adam Cohen        }
5846788269814a678af976dfc7d6135993e172ce586Adam Cohen
5856788269814a678af976dfc7d6135993e172ce586Adam Cohen        public void setX(int x) {
5866788269814a678af976dfc7d6135993e172ce586Adam Cohen            this.x = x;
5876788269814a678af976dfc7d6135993e172ce586Adam Cohen        }
5886788269814a678af976dfc7d6135993e172ce586Adam Cohen
5896788269814a678af976dfc7d6135993e172ce586Adam Cohen        public int getX() {
5906788269814a678af976dfc7d6135993e172ce586Adam Cohen            return x;
5916788269814a678af976dfc7d6135993e172ce586Adam Cohen        }
5926788269814a678af976dfc7d6135993e172ce586Adam Cohen
5936788269814a678af976dfc7d6135993e172ce586Adam Cohen        public void setY(int y) {
5946788269814a678af976dfc7d6135993e172ce586Adam Cohen            this.y = y;
5956788269814a678af976dfc7d6135993e172ce586Adam Cohen        }
5966788269814a678af976dfc7d6135993e172ce586Adam Cohen
5976788269814a678af976dfc7d6135993e172ce586Adam Cohen        public int getY() {
5986788269814a678af976dfc7d6135993e172ce586Adam Cohen            return y;
5996788269814a678af976dfc7d6135993e172ce586Adam Cohen        }
6006788269814a678af976dfc7d6135993e172ce586Adam Cohen    }
6016788269814a678af976dfc7d6135993e172ce586Adam Cohen
6026788269814a678af976dfc7d6135993e172ce586Adam Cohen    protected void onLayout(boolean changed, int l, int t, int r, int b) {
6036788269814a678af976dfc7d6135993e172ce586Adam Cohen        super.onLayout(changed, l, t, r, b);
6046788269814a678af976dfc7d6135993e172ce586Adam Cohen        int count = getChildCount();
6056788269814a678af976dfc7d6135993e172ce586Adam Cohen        for (int i = 0; i < count; i++) {
6066788269814a678af976dfc7d6135993e172ce586Adam Cohen            View child = getChildAt(i);
6076788269814a678af976dfc7d6135993e172ce586Adam Cohen            final FrameLayout.LayoutParams flp = (FrameLayout.LayoutParams) child.getLayoutParams();
6086788269814a678af976dfc7d6135993e172ce586Adam Cohen            if (flp instanceof LayoutParams) {
6096788269814a678af976dfc7d6135993e172ce586Adam Cohen                final LayoutParams lp = (LayoutParams) flp;
6106788269814a678af976dfc7d6135993e172ce586Adam Cohen                if (lp.customPosition) {
6116788269814a678af976dfc7d6135993e172ce586Adam Cohen                    child.layout(lp.x, lp.y, lp.x + lp.width, lp.y + lp.height);
6126788269814a678af976dfc7d6135993e172ce586Adam Cohen                }
6136788269814a678af976dfc7d6135993e172ce586Adam Cohen            }
6146788269814a678af976dfc7d6135993e172ce586Adam Cohen        }
6156788269814a678af976dfc7d6135993e172ce586Adam Cohen    }
6166788269814a678af976dfc7d6135993e172ce586Adam Cohen
6176788269814a678af976dfc7d6135993e172ce586Adam Cohen    public void clearAllResizeFrames() {
6186788269814a678af976dfc7d6135993e172ce586Adam Cohen        if (mResizeFrames.size() > 0) {
6196788269814a678af976dfc7d6135993e172ce586Adam Cohen            for (AppWidgetResizeFrame frame: mResizeFrames) {
620bebf042666cffe52039b875a549a582abd78a431Adam Cohen                frame.commitResize();
6216788269814a678af976dfc7d6135993e172ce586Adam Cohen                removeView(frame);
6226788269814a678af976dfc7d6135993e172ce586Adam Cohen            }
6236788269814a678af976dfc7d6135993e172ce586Adam Cohen            mResizeFrames.clear();
6246788269814a678af976dfc7d6135993e172ce586Adam Cohen        }
6256788269814a678af976dfc7d6135993e172ce586Adam Cohen    }
6266788269814a678af976dfc7d6135993e172ce586Adam Cohen
6276788269814a678af976dfc7d6135993e172ce586Adam Cohen    public boolean hasResizeFrames() {
6286788269814a678af976dfc7d6135993e172ce586Adam Cohen        return mResizeFrames.size() > 0;
6296788269814a678af976dfc7d6135993e172ce586Adam Cohen    }
6306788269814a678af976dfc7d6135993e172ce586Adam Cohen
6316788269814a678af976dfc7d6135993e172ce586Adam Cohen    public boolean isWidgetBeingResized() {
6326788269814a678af976dfc7d6135993e172ce586Adam Cohen        return mCurrentResizeFrame != null;
6336788269814a678af976dfc7d6135993e172ce586Adam Cohen    }
6346788269814a678af976dfc7d6135993e172ce586Adam Cohen
6356788269814a678af976dfc7d6135993e172ce586Adam Cohen    public void addResizeFrame(ItemInfo itemInfo, LauncherAppWidgetHostView widget,
6366788269814a678af976dfc7d6135993e172ce586Adam Cohen            CellLayout cellLayout) {
6376788269814a678af976dfc7d6135993e172ce586Adam Cohen        AppWidgetResizeFrame resizeFrame = new AppWidgetResizeFrame(getContext(),
6383a9fcedbcd235372cd2ab64f825a0b5b3937f59eMichael Jurka                widget, cellLayout, this);
6396788269814a678af976dfc7d6135993e172ce586Adam Cohen
6406788269814a678af976dfc7d6135993e172ce586Adam Cohen        LayoutParams lp = new LayoutParams(-1, -1);
6416788269814a678af976dfc7d6135993e172ce586Adam Cohen        lp.customPosition = true;
6426788269814a678af976dfc7d6135993e172ce586Adam Cohen
6436788269814a678af976dfc7d6135993e172ce586Adam Cohen        addView(resizeFrame, lp);
6446788269814a678af976dfc7d6135993e172ce586Adam Cohen        mResizeFrames.add(resizeFrame);
6456788269814a678af976dfc7d6135993e172ce586Adam Cohen
6466788269814a678af976dfc7d6135993e172ce586Adam Cohen        resizeFrame.snapToWidget(false);
6476788269814a678af976dfc7d6135993e172ce586Adam Cohen    }
648716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen
6497bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung    public void animateViewIntoPosition(DragView dragView, final int[] pos, float alpha,
6507bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung            float scaleX, float scaleY, int animationEndStyle, Runnable onFinishRunnable,
6517bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung            int duration) {
652b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen        Rect r = new Rect();
653b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen        getViewRectRelativeToSelf(dragView, r);
654b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen        final int fromX = r.left;
655b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen        final int fromY = r.top;
656b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen
6577bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung        animateViewIntoPosition(dragView, fromX, fromY, pos[0], pos[1], alpha, 1, 1, scaleX, scaleY,
658ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen                onFinishRunnable, animationEndStyle, duration, null);
659ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen    }
660ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen
661557d6ed50cc6560163440aa134870ef0bb11415bWinson Chung    public void animateViewIntoPosition(DragView dragView, final View child,
66228f852ab678d9750879b6d3549bf5da176cf1225Adam Cohen            final Runnable onFinishAnimationRunnable, View anchorView) {
66328f852ab678d9750879b6d3549bf5da176cf1225Adam Cohen        animateViewIntoPosition(dragView, child, -1, onFinishAnimationRunnable, anchorView);
664ed51cc9a12c50d12e7d30ed209a49f1a40858043Adam Cohen    }
665ed51cc9a12c50d12e7d30ed209a49f1a40858043Adam Cohen
666ed51cc9a12c50d12e7d30ed209a49f1a40858043Adam Cohen    public void animateViewIntoPosition(DragView dragView, final View child, int duration,
6676441de0ec2a71862798dd51180d0811b42edd514Adam Cohen            final Runnable onFinishAnimationRunnable, View anchorView) {
668a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        ShortcutAndWidgetContainer parentChildren = (ShortcutAndWidgetContainer) child.getParent();
669716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen        CellLayout.LayoutParams lp =  (CellLayout.LayoutParams) child.getLayoutParams();
670eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung        parentChildren.measureChild(child);
671716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen
6723e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        Rect r = new Rect();
6733e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        getViewRectRelativeToSelf(dragView, r);
674716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen
675716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen        int coord[] = new int[2];
676307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen        float childScale = child.getScaleX();
677307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen        coord[0] = lp.x + (int) (child.getMeasuredWidth() * (1 - childScale) / 2);
678307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen        coord[1] = lp.y + (int) (child.getMeasuredHeight() * (1 - childScale) / 2);
679eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung
6808dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        // Since the child hasn't necessarily been laid out, we force the lp to be updated with
681ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen        // the correct coordinates (above) and use these to determine the final location
682557d6ed50cc6560163440aa134870ef0bb11415bWinson Chung        float scale = getDescendantCoordRelativeToSelf((View) child.getParent(), coord);
683307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen        // We need to account for the scale of the child itself, as the above only accounts for
684307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen        // for the scale in parents.
685307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen        scale *= childScale;
686ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen        int toX = coord[0];
687ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen        int toY = coord[1];
688eeb5bbc9409978cc2ae52d48380399fcde3d9f85Winson Chung        float toScale = scale;
6894497ebf9a2726e2a7dbb7f3c49389308908f8454Andrew Flynn        if (child instanceof TextView) {
6904497ebf9a2726e2a7dbb7f3c49389308908f8454Andrew Flynn            TextView tv = (TextView) child;
691eeb5bbc9409978cc2ae52d48380399fcde3d9f85Winson Chung            // Account for the source scale of the icon (ie. from AllApps to Workspace, in which
692eeb5bbc9409978cc2ae52d48380399fcde3d9f85Winson Chung            // the workspace may have smaller icon bounds).
693eeb5bbc9409978cc2ae52d48380399fcde3d9f85Winson Chung            toScale = scale / dragView.getIntrinsicIconScaleFactor();
6944497ebf9a2726e2a7dbb7f3c49389308908f8454Andrew Flynn
6954497ebf9a2726e2a7dbb7f3c49389308908f8454Andrew Flynn            // The child may be scaled (always about the center of the view) so to account for it,
6964497ebf9a2726e2a7dbb7f3c49389308908f8454Andrew Flynn            // we have to offset the position by the scaled size.  Once we do that, we can center
6974497ebf9a2726e2a7dbb7f3c49389308908f8454Andrew Flynn            // the drag view about the scaled child view.
698eeb5bbc9409978cc2ae52d48380399fcde3d9f85Winson Chung            toY += Math.round(toScale * tv.getPaddingTop());
699eeb5bbc9409978cc2ae52d48380399fcde3d9f85Winson Chung            toY -= dragView.getMeasuredHeight() * (1 - toScale) / 2;
70095abbb330ce9bbaf23594245f0f8a795c8118038Sunny Goyal            if (dragView.getDragVisualizeOffset() != null) {
70195abbb330ce9bbaf23594245f0f8a795c8118038Sunny Goyal                toY -=  Math.round(toScale * dragView.getDragVisualizeOffset().y);
70295abbb330ce9bbaf23594245f0f8a795c8118038Sunny Goyal            }
70395abbb330ce9bbaf23594245f0f8a795c8118038Sunny Goyal
7044497ebf9a2726e2a7dbb7f3c49389308908f8454Andrew Flynn            toX -= (dragView.getMeasuredWidth() - Math.round(scale * child.getMeasuredWidth())) / 2;
7054497ebf9a2726e2a7dbb7f3c49389308908f8454Andrew Flynn        } else if (child instanceof FolderIcon) {
706ea359c6aee44c0fe3bb94f7002c3b49208b32b7fWinson Chung            // Account for holographic blur padding on the drag view
7075f8afe6280eae34620067696173e71943e1a30a3Winson Chung            toY += Math.round(scale * (child.getPaddingTop() - dragView.getDragRegionTop()));
708307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen            toY -= scale * Workspace.DRAG_BITMAP_PADDING / 2;
709307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen            toY -= (1 - scale) * dragView.getMeasuredHeight() / 2;
710ea359c6aee44c0fe3bb94f7002c3b49208b32b7fWinson Chung            // Center in the x coordinate about the target's drawable
711ea359c6aee44c0fe3bb94f7002c3b49208b32b7fWinson Chung            toX -= (dragView.getMeasuredWidth() - Math.round(scale * child.getMeasuredWidth())) / 2;
712ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen        } else {
713ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen            toY -= (Math.round(scale * (dragView.getHeight() - child.getMeasuredHeight()))) / 2;
714ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen            toX -= (Math.round(scale * (dragView.getMeasuredWidth()
715ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen                    - child.getMeasuredWidth()))) / 2;
716ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen        }
717716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen
718ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen        final int fromX = r.left;
719ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen        final int fromY = r.top;
720716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen        child.setVisibility(INVISIBLE);
7218dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        Runnable onCompleteRunnable = new Runnable() {
7228dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen            public void run() {
7238dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen                child.setVisibility(VISIBLE);
724d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                if (onFinishAnimationRunnable != null) {
725d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    onFinishAnimationRunnable.run();
726d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                }
7278dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen            }
7288dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        };
729eeb5bbc9409978cc2ae52d48380399fcde3d9f85Winson Chung        animateViewIntoPosition(dragView, fromX, fromY, toX, toY, 1, 1, 1, toScale, toScale,
730d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                onCompleteRunnable, ANIMATION_END_DISAPPEAR, duration, anchorView);
731557d6ed50cc6560163440aa134870ef0bb11415bWinson Chung    }
732557d6ed50cc6560163440aa134870ef0bb11415bWinson Chung
733d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen    public void animateViewIntoPosition(final DragView view, final int fromX, final int fromY,
734ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen            final int toX, final int toY, float finalAlpha, float initScaleX, float initScaleY,
735ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen            float finalScaleX, float finalScaleY, Runnable onCompleteRunnable,
736ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen            int animationEndStyle, int duration, View anchorView) {
7378dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        Rect from = new Rect(fromX, fromY, fromX +
7388dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen                view.getMeasuredWidth(), fromY + view.getMeasuredHeight());
7393e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        Rect to = new Rect(toX, toY, toX + view.getMeasuredWidth(), toY + view.getMeasuredHeight());
740ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen        animateView(view, from, to, finalAlpha, initScaleX, initScaleY, finalScaleX, finalScaleY, duration,
741ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen                null, null, onCompleteRunnable, animationEndStyle, anchorView);
7423e8f811f31a2275e778244427271f77f4116c08bAdam Cohen    }
7433e8f811f31a2275e778244427271f77f4116c08bAdam Cohen
744b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen    /**
745b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen     * This method animates a view at the end of a drag and drop animation.
746b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen     *
747b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen     * @param view The view to be animated. This view is drawn directly into DragLayer, and so
748b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen     *        doesn't need to be a child of DragLayer.
749b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen     * @param from The initial location of the view. Only the left and top parameters are used.
750b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen     * @param to The final location of the view. Only the left and top parameters are used. This
751b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen     *        location doesn't account for scaling, and so should be centered about the desired
752b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen     *        final location (including scaling).
753b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen     * @param finalAlpha The final alpha of the view, in case we want it to fade as it animates.
7546178f13e2d1f0c1a89cea74538b51993ef3439e3Sunny Goyal     * @param finalScaleX The final scale of the view. The view is scaled about its center.
7556178f13e2d1f0c1a89cea74538b51993ef3439e3Sunny Goyal     * @param finalScaleY The final scale of the view. The view is scaled about its center.
756b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen     * @param duration The duration of the animation.
757b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen     * @param motionInterpolator The interpolator to use for the location of the view.
758b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen     * @param alphaInterpolator The interpolator to use for the alpha of the view.
759b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen     * @param onCompleteRunnable Optional runnable to run on animation completion.
7606178f13e2d1f0c1a89cea74538b51993ef3439e3Sunny Goyal     * @param animationEndStyle Whether or not to fade out the view once the animation completes.
7616178f13e2d1f0c1a89cea74538b51993ef3439e3Sunny Goyal     *        {@link #ANIMATION_END_DISAPPEAR} or {@link #ANIMATION_END_REMAIN_VISIBLE}.
7626441de0ec2a71862798dd51180d0811b42edd514Adam Cohen     * @param anchorView If not null, this represents the view which the animated view stays
7636441de0ec2a71862798dd51180d0811b42edd514Adam Cohen     *        anchored to in case scrolling is currently taking place. Note: currently this is
7646441de0ec2a71862798dd51180d0811b42edd514Adam Cohen     *        only used for the X dimension for the case of the workspace.
765b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen     */
7667bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung    public void animateView(final DragView view, final Rect from, final Rect to,
7677bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung            final float finalAlpha, final float initScaleX, final float initScaleY,
7687bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung            final float finalScaleX, final float finalScaleY, int duration,
7697bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung            final Interpolator motionInterpolator, final Interpolator alphaInterpolator,
7707bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung            final Runnable onCompleteRunnable, final int animationEndStyle, View anchorView) {
7717bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung
772716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen        // Calculate the duration of the animation based on the object's distance
773f7a29e83f06909b378dba39c83a522375682710aSunny Goyal        final float dist = (float) Math.hypot(to.left - from.left, to.top - from.top);
774716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen        final Resources res = getResources();
775716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen        final float maxDist = (float) res.getInteger(R.integer.config_dropAnimMaxDist);
7763e8f811f31a2275e778244427271f77f4116c08bAdam Cohen
7773e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        // If duration < 0, this is a cue to compute the duration based on the distance
7783e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        if (duration < 0) {
7793e8f811f31a2275e778244427271f77f4116c08bAdam Cohen            duration = res.getInteger(R.integer.config_dropAnimMaxDuration);
7803e8f811f31a2275e778244427271f77f4116c08bAdam Cohen            if (dist < maxDist) {
7818dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen                duration *= mCubicEaseOutInterpolator.getInterpolation(dist / maxDist);
7823e8f811f31a2275e778244427271f77f4116c08bAdam Cohen            }
78361b0c69d3fe331d3de338322396d5de691d58613Winson Chung            duration = Math.max(duration, res.getInteger(R.integer.config_dropAnimMinDuration));
784716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen        }
785716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen
786043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        // Fall back to cubic ease out interpolator for the animation if none is specified
787043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        TimeInterpolator interpolator = null;
7883e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        if (alphaInterpolator == null || motionInterpolator == null) {
789043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung            interpolator = mCubicEaseOutInterpolator;
7903e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        }
791716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen
792043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        // Animate the view
7937bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung        final float initAlpha = view.getAlpha();
794043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        final float dropViewScale = view.getScaleX();
795043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        AnimatorUpdateListener updateCb = new AnimatorUpdateListener() {
796043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung            @Override
797716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen            public void onAnimationUpdate(ValueAnimator animation) {
798716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen                final float percent = (Float) animation.getAnimatedValue();
7997bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung                final int width = view.getMeasuredWidth();
8007bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung                final int height = view.getMeasuredHeight();
801716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen
8023e8f811f31a2275e778244427271f77f4116c08bAdam Cohen                float alphaPercent = alphaInterpolator == null ? percent :
8033e8f811f31a2275e778244427271f77f4116c08bAdam Cohen                        alphaInterpolator.getInterpolation(percent);
8043e8f811f31a2275e778244427271f77f4116c08bAdam Cohen                float motionPercent = motionInterpolator == null ? percent :
8053e8f811f31a2275e778244427271f77f4116c08bAdam Cohen                        motionInterpolator.getInterpolation(percent);
806a1cdab039292f3d809528c0e2e38580b37864d8dWinson Chung
8077bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung                float initialScaleX = initScaleX * dropViewScale;
8087bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung                float initialScaleY = initScaleY * dropViewScale;
8097bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung                float scaleX = finalScaleX * percent + initialScaleX * (1 - percent);
8107bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung                float scaleY = finalScaleY * percent + initialScaleY * (1 - percent);
8117bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung                float alpha = finalAlpha * alphaPercent + initAlpha * (1 - alphaPercent);
8127bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung
8137bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung                float fromLeft = from.left + (initialScaleX - 1f) * width / 2;
8147bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung                float fromTop = from.top + (initialScaleY - 1f) * height / 2;
8157bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung
8167bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung                int x = (int) (fromLeft + Math.round(((to.left - fromLeft) * motionPercent)));
8177bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung                int y = (int) (fromTop + Math.round(((to.top - fromTop) * motionPercent)));
8187bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung
81928f852ab678d9750879b6d3549bf5da176cf1225Adam Cohen                int anchorAdjust = mAnchorView == null ? 0 : (int) (mAnchorView.getScaleX() *
82028f852ab678d9750879b6d3549bf5da176cf1225Adam Cohen                    (mAnchorViewInitialScrollX - mAnchorView.getScrollX()));
82128f852ab678d9750879b6d3549bf5da176cf1225Adam Cohen
82228f852ab678d9750879b6d3549bf5da176cf1225Adam Cohen                int xPos = x - mDropView.getScrollX() + anchorAdjust;
8237bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung                int yPos = y - mDropView.getScrollY();
8247bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung
8257bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung                mDropView.setTranslationX(xPos);
8267bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung                mDropView.setTranslationY(yPos);
8277bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung                mDropView.setScaleX(scaleX);
8287bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung                mDropView.setScaleY(scaleY);
8297bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung                mDropView.setAlpha(alpha);
830716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen            }
831043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        };
832043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        animateView(view, updateCb, duration, interpolator, onCompleteRunnable, animationEndStyle,
833043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung                anchorView);
834043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung    }
835043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung
836043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung    public void animateView(final DragView view, AnimatorUpdateListener updateCb, int duration,
837043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung            TimeInterpolator interpolator, final Runnable onCompleteRunnable,
838043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung            final int animationEndStyle, View anchorView) {
839043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        // Clean up the previous animations
840043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        if (mDropAnim != null) mDropAnim.cancel();
841043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung
842043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        // Show the drop view if it was previously hidden
843043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        mDropView = view;
844043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        mDropView.cancelAnimation();
845d6c8e7eeb13094ea1349897663ae28d8a3bf2773Vadim Tryshev        mDropView.requestLayout();
846043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung
847043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        // Set the anchor view if the page is scrolling
848043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        if (anchorView != null) {
849043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung            mAnchorViewInitialScrollX = anchorView.getScrollX();
850043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        }
851043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        mAnchorView = anchorView;
852043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung
853043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        // Create and start the animation
854043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        mDropAnim = new ValueAnimator();
855043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        mDropAnim.setInterpolator(interpolator);
856043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        mDropAnim.setDuration(duration);
857043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        mDropAnim.setFloatValues(0f, 1f);
858043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        mDropAnim.addUpdateListener(updateCb);
8593e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        mDropAnim.addListener(new AnimatorListenerAdapter() {
8603e8f811f31a2275e778244427271f77f4116c08bAdam Cohen            public void onAnimationEnd(Animator animation) {
8618dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen                if (onCompleteRunnable != null) {
8628dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen                    onCompleteRunnable.run();
8638dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen                }
864ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen                switch (animationEndStyle) {
865ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen                case ANIMATION_END_DISAPPEAR:
866ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen                    clearAnimatedView();
867ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen                    break;
868ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen                case ANIMATION_END_REMAIN_VISIBLE:
869ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen                    break;
8703e8f811f31a2275e778244427271f77f4116c08bAdam Cohen                }
8713e8f811f31a2275e778244427271f77f4116c08bAdam Cohen            }
8723e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        });
873716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen        mDropAnim.start();
874716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen    }
875716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen
876ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen    public void clearAnimatedView() {
8777bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung        if (mDropAnim != null) {
8787bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung            mDropAnim.cancel();
8797bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung        }
8807bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung        if (mDropView != null) {
8812d783ce2f4b2e507bead0d723f0edcdf902dbd46Adam Cohen            mDragController.onDeferredEndDrag(mDropView);
8827bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung        }
883ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen        mDropView = null;
884ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen        invalidate();
885ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen    }
886ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen
887ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen    public View getAnimatedView() {
888ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen        return mDropView;
889ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen    }
890ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen
891716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen    @Override
8928b805b17158886035b38261eb611d8641701ae43Michael Jurka    public void onChildViewAdded(View parent, View child) {
893a6d0492e5f0dd4e1b43d4034a770241dc65f8f8cAdam Cohen        super.onChildViewAdded(parent, child);
894b670f195ffb7b4a0519fd0b337b68f7412159414Adam Cohen        if (mOverlayView != null) {
895b670f195ffb7b4a0519fd0b337b68f7412159414Adam Cohen            // ensure that the overlay view stays on top. we can't use drawing order for this
896b670f195ffb7b4a0519fd0b337b68f7412159414Adam Cohen            // because in API level 16 touch dispatch doesn't respect drawing order.
897b670f195ffb7b4a0519fd0b337b68f7412159414Adam Cohen            mOverlayView.bringToFront();
898b670f195ffb7b4a0519fd0b337b68f7412159414Adam Cohen        }
89921b411074e39fd10cbc8dd0220bb159da4af2c76Adam Cohen        updateChildIndices();
90021b411074e39fd10cbc8dd0220bb159da4af2c76Adam Cohen    }
90121b411074e39fd10cbc8dd0220bb159da4af2c76Adam Cohen
90221b411074e39fd10cbc8dd0220bb159da4af2c76Adam Cohen    @Override
9038b805b17158886035b38261eb611d8641701ae43Michael Jurka    public void onChildViewRemoved(View parent, View child) {
90421b411074e39fd10cbc8dd0220bb159da4af2c76Adam Cohen        updateChildIndices();
90521b411074e39fd10cbc8dd0220bb159da4af2c76Adam Cohen    }
90621b411074e39fd10cbc8dd0220bb159da4af2c76Adam Cohen
907432609a246819f3cf887a80c2ae56b61fc5ca25aAdam Cohen    @Override
908432609a246819f3cf887a80c2ae56b61fc5ca25aAdam Cohen    public void bringChildToFront(View child) {
909432609a246819f3cf887a80c2ae56b61fc5ca25aAdam Cohen        super.bringChildToFront(child);
910b670f195ffb7b4a0519fd0b337b68f7412159414Adam Cohen        if (child != mOverlayView && mOverlayView != null) {
911b670f195ffb7b4a0519fd0b337b68f7412159414Adam Cohen            // ensure that the overlay view stays on top. we can't use drawing order for this
912b670f195ffb7b4a0519fd0b337b68f7412159414Adam Cohen            // because in API level 16 touch dispatch doesn't respect drawing order.
913b670f195ffb7b4a0519fd0b337b68f7412159414Adam Cohen            mOverlayView.bringToFront();
914b670f195ffb7b4a0519fd0b337b68f7412159414Adam Cohen        }
915432609a246819f3cf887a80c2ae56b61fc5ca25aAdam Cohen        updateChildIndices();
916432609a246819f3cf887a80c2ae56b61fc5ca25aAdam Cohen    }
917432609a246819f3cf887a80c2ae56b61fc5ca25aAdam Cohen
91821b411074e39fd10cbc8dd0220bb159da4af2c76Adam Cohen    private void updateChildIndices() {
919432609a246819f3cf887a80c2ae56b61fc5ca25aAdam Cohen        mTopViewIndex = -1;
92055bd9725d5c0373b89f7b9bbd9547550ea3bbc63Jorim Jaggi        int childCount = getChildCount();
92155bd9725d5c0373b89f7b9bbd9547550ea3bbc63Jorim Jaggi        for (int i = 0; i < childCount; i++) {
922b670f195ffb7b4a0519fd0b337b68f7412159414Adam Cohen            if (getChildAt(i) instanceof DragView) {
923432609a246819f3cf887a80c2ae56b61fc5ca25aAdam Cohen                mTopViewIndex = i;
92455bd9725d5c0373b89f7b9bbd9547550ea3bbc63Jorim Jaggi            }
92521b411074e39fd10cbc8dd0220bb159da4af2c76Adam Cohen        }
9262d783ce2f4b2e507bead0d723f0edcdf902dbd46Adam Cohen        mChildCountOnLastUpdate = childCount;
92721b411074e39fd10cbc8dd0220bb159da4af2c76Adam Cohen    }
92821b411074e39fd10cbc8dd0220bb159da4af2c76Adam Cohen
92921b411074e39fd10cbc8dd0220bb159da4af2c76Adam Cohen    @Override
93021b411074e39fd10cbc8dd0220bb159da4af2c76Adam Cohen    protected int getChildDrawingOrder(int childCount, int i) {
9312d783ce2f4b2e507bead0d723f0edcdf902dbd46Adam Cohen        if (mChildCountOnLastUpdate != childCount) {
9322d783ce2f4b2e507bead0d723f0edcdf902dbd46Adam Cohen            // between platform versions 17 and 18, behavior for onChildViewRemoved / Added changed.
9332d783ce2f4b2e507bead0d723f0edcdf902dbd46Adam Cohen            // Pre-18, the child was not added / removed by the time of those callbacks. We need to
9342d783ce2f4b2e507bead0d723f0edcdf902dbd46Adam Cohen            // force update our representation of things here to avoid crashing on pre-18 devices
9352d783ce2f4b2e507bead0d723f0edcdf902dbd46Adam Cohen            // in certain instances.
9362d783ce2f4b2e507bead0d723f0edcdf902dbd46Adam Cohen            updateChildIndices();
9372d783ce2f4b2e507bead0d723f0edcdf902dbd46Adam Cohen        }
9382d783ce2f4b2e507bead0d723f0edcdf902dbd46Adam Cohen
939432609a246819f3cf887a80c2ae56b61fc5ca25aAdam Cohen        // i represents the current draw iteration
940432609a246819f3cf887a80c2ae56b61fc5ca25aAdam Cohen        if (mTopViewIndex == -1) {
941432609a246819f3cf887a80c2ae56b61fc5ca25aAdam Cohen            // in general we do nothing
94221b411074e39fd10cbc8dd0220bb159da4af2c76Adam Cohen            return i;
943432609a246819f3cf887a80c2ae56b61fc5ca25aAdam Cohen        } else if (i == childCount - 1) {
944432609a246819f3cf887a80c2ae56b61fc5ca25aAdam Cohen            // if we have a top index, we return it when drawing last item (highest z-order)
945432609a246819f3cf887a80c2ae56b61fc5ca25aAdam Cohen            return mTopViewIndex;
946432609a246819f3cf887a80c2ae56b61fc5ca25aAdam Cohen        } else if (i < mTopViewIndex) {
94721b411074e39fd10cbc8dd0220bb159da4af2c76Adam Cohen            return i;
94855bd9725d5c0373b89f7b9bbd9547550ea3bbc63Jorim Jaggi        } else {
949432609a246819f3cf887a80c2ae56b61fc5ca25aAdam Cohen            // for indexes greater than the top index, we fetch one item above to shift for the
950432609a246819f3cf887a80c2ae56b61fc5ca25aAdam Cohen            // displacement of the top index
951432609a246819f3cf887a80c2ae56b61fc5ca25aAdam Cohen            return i + 1;
95221b411074e39fd10cbc8dd0220bb159da4af2c76Adam Cohen        }
95321b411074e39fd10cbc8dd0220bb159da4af2c76Adam Cohen    }
954360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung
955e0c332365604976d999eb25d4bdcc49ec75b7a1cTony Wickham    void onEnterScrollArea() {
9560f97b7874fe29f36e7a40d2fe4b45d1e0e24fe1bTony Wickham        mInScrollArea = true;
9570f97b7874fe29f36e7a40d2fe4b45d1e0e24fe1bTony Wickham        invalidate();
9580f97b7874fe29f36e7a40d2fe4b45d1e0e24fe1bTony Wickham    }
9590f97b7874fe29f36e7a40d2fe4b45d1e0e24fe1bTony Wickham
9600f97b7874fe29f36e7a40d2fe4b45d1e0e24fe1bTony Wickham    void onExitScrollArea() {
9610f97b7874fe29f36e7a40d2fe4b45d1e0e24fe1bTony Wickham        mInScrollArea = false;
9620f97b7874fe29f36e7a40d2fe4b45d1e0e24fe1bTony Wickham        invalidate();
9630f97b7874fe29f36e7a40d2fe4b45d1e0e24fe1bTony Wickham    }
9640f97b7874fe29f36e7a40d2fe4b45d1e0e24fe1bTony Wickham
9650f97b7874fe29f36e7a40d2fe4b45d1e0e24fe1bTony Wickham    public void showPageHints() {
9660f97b7874fe29f36e7a40d2fe4b45d1e0e24fe1bTony Wickham        mShowPageHints = true;
9670f97b7874fe29f36e7a40d2fe4b45d1e0e24fe1bTony Wickham        Workspace workspace = mLauncher.getWorkspace();
9680f97b7874fe29f36e7a40d2fe4b45d1e0e24fe1bTony Wickham        getDescendantRectRelativeToSelf(workspace.getChildAt(workspace.numCustomPages()),
9690f97b7874fe29f36e7a40d2fe4b45d1e0e24fe1bTony Wickham                mScrollChildPosition);
9700f97b7874fe29f36e7a40d2fe4b45d1e0e24fe1bTony Wickham        invalidate();
9710f97b7874fe29f36e7a40d2fe4b45d1e0e24fe1bTony Wickham    }
9720f97b7874fe29f36e7a40d2fe4b45d1e0e24fe1bTony Wickham
9730f97b7874fe29f36e7a40d2fe4b45d1e0e24fe1bTony Wickham    public void hidePageHints() {
9740f97b7874fe29f36e7a40d2fe4b45d1e0e24fe1bTony Wickham        mShowPageHints = false;
9750f97b7874fe29f36e7a40d2fe4b45d1e0e24fe1bTony Wickham        invalidate();
9760f97b7874fe29f36e7a40d2fe4b45d1e0e24fe1bTony Wickham    }
9770f97b7874fe29f36e7a40d2fe4b45d1e0e24fe1bTony Wickham
97895cdb3a0211650e76adb451588ce89fd585b178fTony Wickham    public void invalidateScrim() {
97995cdb3a0211650e76adb451588ce89fd585b178fTony Wickham        if (mBackgroundAlpha > 0.0f) {
98095cdb3a0211650e76adb451588ce89fd585b178fTony Wickham            invalidate();
98195cdb3a0211650e76adb451588ce89fd585b178fTony Wickham        }
98295cdb3a0211650e76adb451588ce89fd585b178fTony Wickham    }
98395cdb3a0211650e76adb451588ce89fd585b178fTony Wickham
984360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung    @Override
985360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung    protected void dispatchDraw(Canvas canvas) {
9860fa93bc5c65a2d7d5e5f4e798499903759c48cc5Sunny Goyal        // Draw the background below children.
9870fa93bc5c65a2d7d5e5f4e798499903759c48cc5Sunny Goyal        if (mBackgroundAlpha > 0.0f) {
98895cdb3a0211650e76adb451588ce89fd585b178fTony Wickham            // Update the scroll position first to ensure scrim cutout is in the right place.
98995cdb3a0211650e76adb451588ce89fd585b178fTony Wickham            mLauncher.getWorkspace().computeScrollWithoutInvalidation();
99095cdb3a0211650e76adb451588ce89fd585b178fTony Wickham
9916c5891a9fce95eee3d87823d11d21889743e9c68Adam Cohen            int alpha = (int) (mBackgroundAlpha * 255);
99295cdb3a0211650e76adb451588ce89fd585b178fTony Wickham            CellLayout currCellLayout = mLauncher.getWorkspace().getCurrentDragOverlappingLayout();
99395cdb3a0211650e76adb451588ce89fd585b178fTony Wickham            canvas.save();
99495cdb3a0211650e76adb451588ce89fd585b178fTony Wickham            if (currCellLayout != null && currCellLayout != mLauncher.getHotseat().getLayout()) {
99595cdb3a0211650e76adb451588ce89fd585b178fTony Wickham                // Cut a hole in the darkening scrim on the page that should be highlighted, if any.
9966178f13e2d1f0c1a89cea74538b51993ef3439e3Sunny Goyal                getDescendantRectRelativeToSelf(currCellLayout, mHighlightRect);
99795cdb3a0211650e76adb451588ce89fd585b178fTony Wickham                canvas.clipRect(mHighlightRect, Region.Op.DIFFERENCE);
99895cdb3a0211650e76adb451588ce89fd585b178fTony Wickham            }
9990fa93bc5c65a2d7d5e5f4e798499903759c48cc5Sunny Goyal            canvas.drawColor((alpha << 24) | SCRIM_COLOR);
100095cdb3a0211650e76adb451588ce89fd585b178fTony Wickham            canvas.restore();
10016c5891a9fce95eee3d87823d11d21889743e9c68Adam Cohen        }
10026c5891a9fce95eee3d87823d11d21889743e9c68Adam Cohen
10033333b0ced8e6743c41909f6f6b916f1f9ec5a004Sunny Goyal        mFocusIndicatorHelper.draw(canvas);
1004360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung        super.dispatchDraw(canvas);
10058cc05507150fea5282b7581e1a268967a702bcc9Adam Cohen    }
1006360e63fd3e77247002b86da2a77bd8dfe8c8a807Winson Chung
10070f97b7874fe29f36e7a40d2fe4b45d1e0e24fe1bTony Wickham    private void drawPageHints(Canvas canvas) {
10080f97b7874fe29f36e7a40d2fe4b45d1e0e24fe1bTony Wickham        if (mShowPageHints) {
10090f97b7874fe29f36e7a40d2fe4b45d1e0e24fe1bTony Wickham            Workspace workspace = mLauncher.getWorkspace();
10100f97b7874fe29f36e7a40d2fe4b45d1e0e24fe1bTony Wickham            int width = getMeasuredWidth();
10110f97b7874fe29f36e7a40d2fe4b45d1e0e24fe1bTony Wickham            int page = workspace.getNextPage();
10120f97b7874fe29f36e7a40d2fe4b45d1e0e24fe1bTony Wickham            CellLayout leftPage = (CellLayout) workspace.getChildAt(mIsRtl ? page + 1 : page - 1);
10130f97b7874fe29f36e7a40d2fe4b45d1e0e24fe1bTony Wickham            CellLayout rightPage = (CellLayout) workspace.getChildAt(mIsRtl ? page - 1 : page + 1);
10140f97b7874fe29f36e7a40d2fe4b45d1e0e24fe1bTony Wickham
10150f97b7874fe29f36e7a40d2fe4b45d1e0e24fe1bTony Wickham            if (leftPage != null && leftPage.isDragTarget()) {
10160f97b7874fe29f36e7a40d2fe4b45d1e0e24fe1bTony Wickham                Drawable left = mInScrollArea && leftPage.getIsDragOverlapping() ?
10170f97b7874fe29f36e7a40d2fe4b45d1e0e24fe1bTony Wickham                        mLeftHoverDrawableActive : mLeftHoverDrawable;
10180f97b7874fe29f36e7a40d2fe4b45d1e0e24fe1bTony Wickham                left.setBounds(0, mScrollChildPosition.top,
10190f97b7874fe29f36e7a40d2fe4b45d1e0e24fe1bTony Wickham                        left.getIntrinsicWidth(), mScrollChildPosition.bottom);
10200f97b7874fe29f36e7a40d2fe4b45d1e0e24fe1bTony Wickham                left.draw(canvas);
10210f97b7874fe29f36e7a40d2fe4b45d1e0e24fe1bTony Wickham            }
10220f97b7874fe29f36e7a40d2fe4b45d1e0e24fe1bTony Wickham            if (rightPage != null && rightPage.isDragTarget()) {
10230f97b7874fe29f36e7a40d2fe4b45d1e0e24fe1bTony Wickham                Drawable right = mInScrollArea && rightPage.getIsDragOverlapping() ?
10240f97b7874fe29f36e7a40d2fe4b45d1e0e24fe1bTony Wickham                        mRightHoverDrawableActive : mRightHoverDrawable;
10250f97b7874fe29f36e7a40d2fe4b45d1e0e24fe1bTony Wickham                right.setBounds(width - right.getIntrinsicWidth(),
10260f97b7874fe29f36e7a40d2fe4b45d1e0e24fe1bTony Wickham                        mScrollChildPosition.top, width, mScrollChildPosition.bottom);
10270f97b7874fe29f36e7a40d2fe4b45d1e0e24fe1bTony Wickham                right.draw(canvas);
10280f97b7874fe29f36e7a40d2fe4b45d1e0e24fe1bTony Wickham            }
10290f97b7874fe29f36e7a40d2fe4b45d1e0e24fe1bTony Wickham        }
10300f97b7874fe29f36e7a40d2fe4b45d1e0e24fe1bTony Wickham    }
10310f97b7874fe29f36e7a40d2fe4b45d1e0e24fe1bTony Wickham
10320f97b7874fe29f36e7a40d2fe4b45d1e0e24fe1bTony Wickham    protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
10330f97b7874fe29f36e7a40d2fe4b45d1e0e24fe1bTony Wickham        boolean ret = super.drawChild(canvas, child, drawingTime);
10340f97b7874fe29f36e7a40d2fe4b45d1e0e24fe1bTony Wickham
10350f97b7874fe29f36e7a40d2fe4b45d1e0e24fe1bTony Wickham        // We want to draw the page hints above the workspace, but below the drag view.
10360f97b7874fe29f36e7a40d2fe4b45d1e0e24fe1bTony Wickham        if (child instanceof Workspace) {
10370f97b7874fe29f36e7a40d2fe4b45d1e0e24fe1bTony Wickham            drawPageHints(canvas);
10380f97b7874fe29f36e7a40d2fe4b45d1e0e24fe1bTony Wickham        }
10390f97b7874fe29f36e7a40d2fe4b45d1e0e24fe1bTony Wickham        return ret;
10400f97b7874fe29f36e7a40d2fe4b45d1e0e24fe1bTony Wickham    }
10410f97b7874fe29f36e7a40d2fe4b45d1e0e24fe1bTony Wickham
10426c5891a9fce95eee3d87823d11d21889743e9c68Adam Cohen    public void setBackgroundAlpha(float alpha) {
10436c5891a9fce95eee3d87823d11d21889743e9c68Adam Cohen        if (alpha != mBackgroundAlpha) {
10446c5891a9fce95eee3d87823d11d21889743e9c68Adam Cohen            mBackgroundAlpha = alpha;
10456c5891a9fce95eee3d87823d11d21889743e9c68Adam Cohen            invalidate();
10466c5891a9fce95eee3d87823d11d21889743e9c68Adam Cohen        }
10476c5891a9fce95eee3d87823d11d21889743e9c68Adam Cohen    }
10486c5891a9fce95eee3d87823d11d21889743e9c68Adam Cohen
10496c5891a9fce95eee3d87823d11d21889743e9c68Adam Cohen    public float getBackgroundAlpha() {
10506c5891a9fce95eee3d87823d11d21889743e9c68Adam Cohen        return mBackgroundAlpha;
10516c5891a9fce95eee3d87823d11d21889743e9c68Adam Cohen    }
10526c5891a9fce95eee3d87823d11d21889743e9c68Adam Cohen
1053b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen    public void setTouchCompleteListener(TouchCompleteListener listener) {
1054b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen        mTouchCompleteListener = listener;
1055b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen    }
1056b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen
1057b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen    public interface TouchCompleteListener {
1058b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen        public void onTouchComplete();
1059b0f3d74815417acc3a9d3dce90cbf34b772847f0Adam Cohen    }
106031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project}
1061