DragController.java revision 8ef85c7a01376a98ce64d8fceb423a6f58e60d9d
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
17a5902524d4403885eb4c50360bf3465c6be796efJoe Onoratopackage com.android.launcher2;
1831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
1900acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onoratoimport android.content.Context;
2000acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onoratoimport android.graphics.Bitmap;
21b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chungimport android.graphics.Point;
22043f2af567178b82b0b41f12d379e7dd12da2936Winson Chungimport android.graphics.PointF;
2300acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onoratoimport android.graphics.Rect;
2400acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onoratoimport android.os.Handler;
250280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurkaimport android.os.IBinder;
2600acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onoratoimport android.os.Vibrator;
2700acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onoratoimport android.util.Log;
2800acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onoratoimport android.view.KeyEvent;
2900acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onoratoimport android.view.MotionEvent;
30043f2af567178b82b0b41f12d379e7dd12da2936Winson Chungimport android.view.VelocityTracker;
310280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurkaimport android.view.View;
32a16fd5a6bd5371d40a5679261d416f06f8efa022Patrick Dubroyimport android.view.ViewConfiguration;
3300acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onoratoimport android.view.inputmethod.InputMethodManager;
3400acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato
35120980bd00f5eecec5717f49a3d7db96571025a9Adam Cohenimport com.android.launcher.R;
36c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen
37c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohenimport java.util.ArrayList;
3831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
3931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project/**
4000acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato * Class for initiating a drag within a view or across multiple views.
4131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project */
4200acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onoratopublic class DragController {
43ea3763c2672f77539538af8cdd395ad97058eaabRomain Guy    @SuppressWarnings({"UnusedDeclaration"})
442e5c432a0aa7e83031575df73bed43a297e2eed3Joe Onorato    private static final String TAG = "Launcher.DragController";
452e5c432a0aa7e83031575df73bed43a297e2eed3Joe Onorato
4600acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato    /** Indicates the drag is a move.  */
4700acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato    public static int DRAG_ACTION_MOVE = 0;
4800acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato
4900acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato    /** Indicates the drag is a copy.  */
5000acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato    public static int DRAG_ACTION_COPY = 1;
5100acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato
52aa15ffe60e28b923ebf3e3162ce427ca6feae803Winson Chung    private static final int SCROLL_DELAY = 500;
53aa15ffe60e28b923ebf3e3162ce427ca6feae803Winson Chung    private static final int RESCROLL_DELAY = 750;
5461b0c69d3fe331d3de338322396d5de691d58613Winson Chung    private static final int VIBRATE_DURATION = 15;
5500acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato
5600acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato    private static final boolean PROFILE_DRAWING_DURING_DRAG = false;
5700acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato
5800acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato    private static final int SCROLL_OUTSIDE_ZONE = 0;
5900acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato    private static final int SCROLL_WAITING_IN_ZONE = 1;
6000acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato
6154fa3b95557c283976e8c1aa8a157b460b0b4513Patrick Dubroy    static final int SCROLL_NONE = -1;
621262e369484ce7f2565655ed80e6299232c70bd7Patrick Dubroy    static final int SCROLL_LEFT = 0;
631262e369484ce7f2565655ed80e6299232c70bd7Patrick Dubroy    static final int SCROLL_RIGHT = 1;
6400acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato
65043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung    private static final float MAX_FLING_DEGREES = 35f;
669658b1e65932f0149a596f451e0bd966e7ee4e74Winson Chung    private static final int FLING_TO_DELETE_THRESHOLD_Y_VELOCITY = -1500;
67043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung
688dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen    private Launcher mLauncher;
6900acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato    private Handler mHandler;
708ef85c7a01376a98ce64d8fceb423a6f58e60d9dJeff Brown    private final Vibrator mVibrator;
7100acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato
7200acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato    // temporaries to avoid gc thrash
7300acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato    private Rect mRectTemp = new Rect();
7400acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato    private final int[] mCoordinatesTemp = new int[2];
7500acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato
7600acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato    /** Whether or not we're dragging. */
7700acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato    private boolean mDragging;
7800acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato
7900acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato    /** X coordinate of the down event. */
80e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen    private int mMotionDownX;
8100acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato
8200acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato    /** Y coordinate of the down event. */
83e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen    private int mMotionDownY;
8400acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato
85658db74c24817892f1a379b16620744f38f60e40Joe Onorato    /** the area at the edge of the screen that makes the workspace go left
86658db74c24817892f1a379b16620744f38f60e40Joe Onorato     *   or right while you're dragging.
87658db74c24817892f1a379b16620744f38f60e40Joe Onorato     */
88658db74c24817892f1a379b16620744f38f60e40Joe Onorato    private int mScrollZone;
89658db74c24817892f1a379b16620744f38f60e40Joe Onorato
909932a9b1e66fed4b5f38ce50f13d56331bbdcd7eAdam Cohen    private DropTarget.DragObject mDragObject;
9100acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato
9200acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato    /** Who can receive drop events */
9300acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato    private ArrayList<DropTarget> mDropTargets = new ArrayList<DropTarget>();
944ed6278e518cc6894cb150b606382e8e6a012599Patrick Dubroy    private ArrayList<DragListener> mListeners = new ArrayList<DragListener>();
95043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung    private DropTarget mFlingToDeleteDropTarget;
9600acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato
9700acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato    /** The window token used as the parent for the DragView. */
9800acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato    private IBinder mWindowToken;
9900acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato
10000acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato    /** The view that will be scrolled when dragging to the left and right edges of the screen. */
10100acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato    private View mScrollView;
10200acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato
103ea3763c2672f77539538af8cdd395ad97058eaabRomain Guy    private View mMoveTarget;
104ea3763c2672f77539538af8cdd395ad97058eaabRomain Guy
10500acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato    private DragScroller mDragScroller;
10600acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato    private int mScrollState = SCROLL_OUTSIDE_ZONE;
10700acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato    private ScrollRunnable mScrollRunnable = new ScrollRunnable();
10800acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato
10900acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato    private DropTarget mLastDropTarget;
11000acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato
11100acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato    private InputMethodManager mInputMethodManager;
11200acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato
113a16fd5a6bd5371d40a5679261d416f06f8efa022Patrick Dubroy    private int mLastTouch[] = new int[2];
114318eee06ae69ac5ef8fddde984eb2f7601d2101dWinson Chung    private long mLastTouchUpTime = -1;
115a16fd5a6bd5371d40a5679261d416f06f8efa022Patrick Dubroy    private int mDistanceSinceScroll = 0;
116a16fd5a6bd5371d40a5679261d416f06f8efa022Patrick Dubroy
117273c1022405bcc5e0840450b9195622e7476c9ddWinson Chung    private int mTmpPoint[] = new int[2];
118273c1022405bcc5e0840450b9195622e7476c9ddWinson Chung    private Rect mDragLayerRect = new Rect();
119273c1022405bcc5e0840450b9195622e7476c9ddWinson Chung
120043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung    protected int mFlingToDeleteThresholdVelocity;
121043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung    private VelocityTracker mVelocityTracker;
122043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung
12331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    /**
12431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * Interface to receive notifications when a drag starts or stops
12531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     */
12631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    interface DragListener {
12731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
12831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        /**
12931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project         * A drag has begun
13031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project         *
13131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project         * @param source An object representing where the drag originated
13231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project         * @param info The data associated with the object that is being dragged
13331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project         * @param dragAction The drag action: either {@link DragController#DRAG_ACTION_MOVE}
13431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project         *        or {@link DragController#DRAG_ACTION_COPY}
13531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project         */
1365162ea9b1f41dbebe00fd9ec4d1e15a697971439Joe Onorato        void onDragStart(DragSource source, Object info, int dragAction);
13731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
13831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        /**
139e3193b93ad7bf33e2e45319084a99b9fc986622bWinson Chung         * The drag has ended
14031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project         */
14131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        void onDragEnd();
14231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
14331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
14431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    /**
14500acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato     * Used to create a new DragLayer from XML.
14600acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato     *
14700acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato     * @param context The application's context.
14831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     */
1498dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen    public DragController(Launcher launcher) {
1508dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        mLauncher = launcher;
15100acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato        mHandler = new Handler();
1528dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        mScrollZone = launcher.getResources().getDimensionPixelSize(R.dimen.scroll_zone);
153043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        mVelocityTracker = VelocityTracker.obtain();
1548ef85c7a01376a98ce64d8fceb423a6f58e60d9dJeff Brown        mVibrator = (Vibrator)launcher.getSystemService(Context.VIBRATOR_SERVICE);
155043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung
156043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        float density = launcher.getResources().getDisplayMetrics().density;
157043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        mFlingToDeleteThresholdVelocity = (int) (FLING_TO_DELETE_THRESHOLD_Y_VELOCITY * density);
15800acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato    }
15931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
1601262e369484ce7f2565655ed80e6299232c70bd7Patrick Dubroy    public boolean dragging() {
1611262e369484ce7f2565655ed80e6299232c70bd7Patrick Dubroy        return mDragging;
1621262e369484ce7f2565655ed80e6299232c70bd7Patrick Dubroy    }
1631262e369484ce7f2565655ed80e6299232c70bd7Patrick Dubroy
16431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    /**
1655162ea9b1f41dbebe00fd9ec4d1e15a697971439Joe Onorato     * Starts a drag.
166a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka     *
16731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param v The view that is being dragged
16831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param source An object representing where the drag originated
169ea3763c2672f77539538af8cdd395ad97058eaabRomain Guy     * @param dragInfo The data associated with the object that is being dragged
17031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param dragAction The drag action: either {@link #DRAG_ACTION_MOVE} or
17131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     *        {@link #DRAG_ACTION_COPY}
17231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     */
17300acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato    public void startDrag(View v, DragSource source, Object dragInfo, int dragAction) {
174a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka        startDrag(v, source, dragInfo, dragAction, null);
175a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka    }
176a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka
177a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka    /**
178a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka     * Starts a drag.
179a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka     *
180a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka     * @param v The view that is being dragged
181a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka     * @param source An object representing where the drag originated
182a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka     * @param dragInfo The data associated with the object that is being dragged
183a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka     * @param dragAction The drag action: either {@link #DRAG_ACTION_MOVE} or
184a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka     *        {@link #DRAG_ACTION_COPY}
185a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka     * @param dragRegion Coordinates within the bitmap b for the position of item being dragged.
186a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka     *          Makes dragging feel more precise, e.g. you can clip out a transparent border
187a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka     */
188a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka    public void startDrag(View v, DragSource source, Object dragInfo, int dragAction,
189a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka            Rect dragRegion) {
1905162ea9b1f41dbebe00fd9ec4d1e15a697971439Joe Onorato        Bitmap b = getViewBitmap(v);
1915162ea9b1f41dbebe00fd9ec4d1e15a697971439Joe Onorato
1923f8175a86e24b3568d1f5b12e1d3d5efcc57d691Daniel Sandler        if (b == null) {
1933f8175a86e24b3568d1f5b12e1d3d5efcc57d691Daniel Sandler            // out of memory?
1943f8175a86e24b3568d1f5b12e1d3d5efcc57d691Daniel Sandler            return;
1953f8175a86e24b3568d1f5b12e1d3d5efcc57d691Daniel Sandler        }
1963f8175a86e24b3568d1f5b12e1d3d5efcc57d691Daniel Sandler
1975162ea9b1f41dbebe00fd9ec4d1e15a697971439Joe Onorato        int[] loc = mCoordinatesTemp;
1988dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        mLauncher.getDragLayer().getLocationInDragLayer(v, loc);
1998dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        int dragLayerX = loc[0];
2008dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        int dragLayerY = loc[1];
2015162ea9b1f41dbebe00fd9ec4d1e15a697971439Joe Onorato
20272d598400da7cef9c7fc4f99bb1fcd7ff0710011Winson Chung        startDrag(b, dragLayerX, dragLayerY, source, dragInfo, dragAction, null, dragRegion, 1f);
2035162ea9b1f41dbebe00fd9ec4d1e15a697971439Joe Onorato        b.recycle();
2045162ea9b1f41dbebe00fd9ec4d1e15a697971439Joe Onorato
2055162ea9b1f41dbebe00fd9ec4d1e15a697971439Joe Onorato        if (dragAction == DRAG_ACTION_MOVE) {
2065162ea9b1f41dbebe00fd9ec4d1e15a697971439Joe Onorato            v.setVisibility(View.GONE);
2075162ea9b1f41dbebe00fd9ec4d1e15a697971439Joe Onorato        }
2085162ea9b1f41dbebe00fd9ec4d1e15a697971439Joe Onorato    }
2095162ea9b1f41dbebe00fd9ec4d1e15a697971439Joe Onorato
2105162ea9b1f41dbebe00fd9ec4d1e15a697971439Joe Onorato    /**
2115162ea9b1f41dbebe00fd9ec4d1e15a697971439Joe Onorato     * Starts a drag.
212a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka     *
213e3193b93ad7bf33e2e45319084a99b9fc986622bWinson Chung     * @param v The view that is being dragged
214e3193b93ad7bf33e2e45319084a99b9fc986622bWinson Chung     * @param bmp The bitmap that represents the view being dragged
215e3193b93ad7bf33e2e45319084a99b9fc986622bWinson Chung     * @param source An object representing where the drag originated
216e3193b93ad7bf33e2e45319084a99b9fc986622bWinson Chung     * @param dragInfo The data associated with the object that is being dragged
217e3193b93ad7bf33e2e45319084a99b9fc986622bWinson Chung     * @param dragAction The drag action: either {@link #DRAG_ACTION_MOVE} or
218e3193b93ad7bf33e2e45319084a99b9fc986622bWinson Chung     *        {@link #DRAG_ACTION_COPY}
219e3193b93ad7bf33e2e45319084a99b9fc986622bWinson Chung     * @param dragRegion Coordinates within the bitmap b for the position of item being dragged.
220e3193b93ad7bf33e2e45319084a99b9fc986622bWinson Chung     *          Makes dragging feel more precise, e.g. you can clip out a transparent border
221e3193b93ad7bf33e2e45319084a99b9fc986622bWinson Chung     */
222e3193b93ad7bf33e2e45319084a99b9fc986622bWinson Chung    public void startDrag(View v, Bitmap bmp, DragSource source, Object dragInfo, int dragAction,
22372d598400da7cef9c7fc4f99bb1fcd7ff0710011Winson Chung            Rect dragRegion, float initialDragViewScale) {
224e3193b93ad7bf33e2e45319084a99b9fc986622bWinson Chung        int[] loc = mCoordinatesTemp;
2258dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        mLauncher.getDragLayer().getLocationInDragLayer(v, loc);
22672d598400da7cef9c7fc4f99bb1fcd7ff0710011Winson Chung        int dragLayerX = loc[0] + v.getPaddingLeft() +
22772d598400da7cef9c7fc4f99bb1fcd7ff0710011Winson Chung                (int) ((initialDragViewScale * bmp.getWidth() - bmp.getWidth()) / 2);
22872d598400da7cef9c7fc4f99bb1fcd7ff0710011Winson Chung        int dragLayerY = loc[1] + v.getPaddingTop() +
22972d598400da7cef9c7fc4f99bb1fcd7ff0710011Winson Chung                (int) ((initialDragViewScale * bmp.getHeight() - bmp.getHeight()) / 2);
230e3193b93ad7bf33e2e45319084a99b9fc986622bWinson Chung
23172d598400da7cef9c7fc4f99bb1fcd7ff0710011Winson Chung        startDrag(bmp, dragLayerX, dragLayerY, source, dragInfo, dragAction, null, dragRegion,
23272d598400da7cef9c7fc4f99bb1fcd7ff0710011Winson Chung                initialDragViewScale);
233e3193b93ad7bf33e2e45319084a99b9fc986622bWinson Chung
234e3193b93ad7bf33e2e45319084a99b9fc986622bWinson Chung        if (dragAction == DRAG_ACTION_MOVE) {
235e3193b93ad7bf33e2e45319084a99b9fc986622bWinson Chung            v.setVisibility(View.GONE);
236e3193b93ad7bf33e2e45319084a99b9fc986622bWinson Chung        }
237e3193b93ad7bf33e2e45319084a99b9fc986622bWinson Chung    }
238e3193b93ad7bf33e2e45319084a99b9fc986622bWinson Chung
239e3193b93ad7bf33e2e45319084a99b9fc986622bWinson Chung    /**
240e3193b93ad7bf33e2e45319084a99b9fc986622bWinson Chung     * Starts a drag.
241e3193b93ad7bf33e2e45319084a99b9fc986622bWinson Chung     *
2425162ea9b1f41dbebe00fd9ec4d1e15a697971439Joe Onorato     * @param b The bitmap to display as the drag image.  It will be re-scaled to the
2435162ea9b1f41dbebe00fd9ec4d1e15a697971439Joe Onorato     *          enlarged size.
2448dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen     * @param dragLayerX The x position in the DragLayer of the left-top of the bitmap.
2458dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen     * @param dragLayerY The y position in the DragLayer of the left-top of the bitmap.
2465162ea9b1f41dbebe00fd9ec4d1e15a697971439Joe Onorato     * @param source An object representing where the drag originated
247ea3763c2672f77539538af8cdd395ad97058eaabRomain Guy     * @param dragInfo The data associated with the object that is being dragged
2485162ea9b1f41dbebe00fd9ec4d1e15a697971439Joe Onorato     * @param dragAction The drag action: either {@link #DRAG_ACTION_MOVE} or
2495162ea9b1f41dbebe00fd9ec4d1e15a697971439Joe Onorato     *        {@link #DRAG_ACTION_COPY}
250a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka     * @param dragRegion Coordinates within the bitmap b for the position of item being dragged.
251a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka     *          Makes dragging feel more precise, e.g. you can clip out a transparent border
252a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka     */
2538dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen    public void startDrag(Bitmap b, int dragLayerX, int dragLayerY,
25472d598400da7cef9c7fc4f99bb1fcd7ff0710011Winson Chung            DragSource source, Object dragInfo, int dragAction, Point dragOffset, Rect dragRegion,
25572d598400da7cef9c7fc4f99bb1fcd7ff0710011Winson Chung            float initialDragViewScale) {
25600acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato        if (PROFILE_DRAWING_DURING_DRAG) {
25700acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato            android.os.Debug.startMethodTracing("Launcher");
25800acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato        }
25900acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato
26000acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato        // Hide soft keyboard, if visible
26100acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato        if (mInputMethodManager == null) {
26200acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato            mInputMethodManager = (InputMethodManager)
2638dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen                    mLauncher.getSystemService(Context.INPUT_METHOD_SERVICE);
26400acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato        }
26500acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato        mInputMethodManager.hideSoftInputFromWindow(mWindowToken, 0);
26600acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato
2674ed6278e518cc6894cb150b606382e8e6a012599Patrick Dubroy        for (DragListener listener : mListeners) {
2684ed6278e518cc6894cb150b606382e8e6a012599Patrick Dubroy            listener.onDragStart(source, dragInfo, dragAction);
26900acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato        }
27000acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato
2718dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        final int registrationX = mMotionDownX - dragLayerX;
2728dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        final int registrationY = mMotionDownY - dragLayerY;
27300acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato
274a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka        final int dragRegionLeft = dragRegion == null ? 0 : dragRegion.left;
275a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka        final int dragRegionTop = dragRegion == null ? 0 : dragRegion.top;
276e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen
27700acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato        mDragging = true;
278cb3382b1bfe1a534b1b44f5c4def9b2db605ac90Adam Cohen
2799932a9b1e66fed4b5f38ce50f13d56331bbdcd7eAdam Cohen        mDragObject = new DropTarget.DragObject();
2809932a9b1e66fed4b5f38ce50f13d56331bbdcd7eAdam Cohen
281bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen        mDragObject.dragComplete = false;
2828dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        mDragObject.xOffset = mMotionDownX - (dragLayerX + dragRegionLeft);
2838dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        mDragObject.yOffset = mMotionDownY - (dragLayerY + dragRegionTop);
284cb3382b1bfe1a534b1b44f5c4def9b2db605ac90Adam Cohen        mDragObject.dragSource = source;
285cb3382b1bfe1a534b1b44f5c4def9b2db605ac90Adam Cohen        mDragObject.dragInfo = dragInfo;
28600acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato
28700acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato        mVibrator.vibrate(VIBRATE_DURATION);
28800acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato
2898dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        final DragView dragView = mDragObject.dragView = new DragView(mLauncher, b, registrationX,
29072d598400da7cef9c7fc4f99bb1fcd7ff0710011Winson Chung                registrationY, 0, 0, b.getWidth(), b.getHeight(), initialDragViewScale);
291a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka
292b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung        if (dragOffset != null) {
293b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung            dragView.setDragVisualizeOffset(new Point(dragOffset));
294b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung        }
295a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka        if (dragRegion != null) {
296e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen            dragView.setDragRegion(new Rect(dragRegion));
297a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka        }
298a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka
2998dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        dragView.show(mMotionDownX, mMotionDownY);
3008dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        handleMoveEvent(mMotionDownX, mMotionDownY);
30100acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato    }
30200acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato
30300acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato    /**
30400acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato     * Draw the view into a bitmap.
30500acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato     */
306120980bd00f5eecec5717f49a3d7db96571025a9Adam Cohen    Bitmap getViewBitmap(View v) {
30700acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato        v.clearFocus();
30800acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato        v.setPressed(false);
30900acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato
31000acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato        boolean willNotCache = v.willNotCacheDrawing();
31100acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato        v.setWillNotCacheDrawing(false);
31200acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato
31300acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato        // Reset the drawing cache background color to fully transparent
31400acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato        // for the duration of this operation
31500acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato        int color = v.getDrawingCacheBackgroundColor();
31600acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato        v.setDrawingCacheBackgroundColor(0);
317120980bd00f5eecec5717f49a3d7db96571025a9Adam Cohen        float alpha = v.getAlpha();
318120980bd00f5eecec5717f49a3d7db96571025a9Adam Cohen        v.setAlpha(1.0f);
31900acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato
32000acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato        if (color != 0) {
32100acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato            v.destroyDrawingCache();
32200acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato        }
32300acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato        v.buildDrawingCache();
32400acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato        Bitmap cacheBitmap = v.getDrawingCache();
3253f8175a86e24b3568d1f5b12e1d3d5efcc57d691Daniel Sandler        if (cacheBitmap == null) {
3263f8175a86e24b3568d1f5b12e1d3d5efcc57d691Daniel Sandler            Log.e(TAG, "failed getViewBitmap(" + v + ")", new RuntimeException());
3273f8175a86e24b3568d1f5b12e1d3d5efcc57d691Daniel Sandler            return null;
3283f8175a86e24b3568d1f5b12e1d3d5efcc57d691Daniel Sandler        }
32900acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato
33000acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato        Bitmap bitmap = Bitmap.createBitmap(cacheBitmap);
33100acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato
33200acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato        // Restore the view
33300acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato        v.destroyDrawingCache();
334120980bd00f5eecec5717f49a3d7db96571025a9Adam Cohen        v.setAlpha(alpha);
33500acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato        v.setWillNotCacheDrawing(willNotCache);
33600acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato        v.setDrawingCacheBackgroundColor(color);
33700acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato
33800acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato        return bitmap;
33900acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato    }
34000acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato
34100acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato    /**
34200acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato     * Call this from a drag source view like this:
34300acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato     *
34400acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato     * <pre>
34500acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato     *  @Override
34600acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato     *  public boolean dispatchKeyEvent(KeyEvent event) {
34700acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato     *      return mDragController.dispatchKeyEvent(this, event)
34800acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato     *              || super.dispatchKeyEvent(event);
34900acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato     * </pre>
35000acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato     */
351ea3763c2672f77539538af8cdd395ad97058eaabRomain Guy    @SuppressWarnings({"UnusedDeclaration"})
35200acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato    public boolean dispatchKeyEvent(KeyEvent event) {
35300acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato        return mDragging;
35400acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato    }
35500acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato
356304dcde0e301c2f1a0b2bdc80ea8617930691b6eWinson Chung    public boolean isDragging() {
357304dcde0e301c2f1a0b2bdc80ea8617930691b6eWinson Chung        return mDragging;
358304dcde0e301c2f1a0b2bdc80ea8617930691b6eWinson Chung    }
359304dcde0e301c2f1a0b2bdc80ea8617930691b6eWinson Chung
36024b6fd854f75f21700a330c2f0d11938e5dfeab6Joe Onorato    /**
36124b6fd854f75f21700a330c2f0d11938e5dfeab6Joe Onorato     * Stop dragging without dropping.
36224b6fd854f75f21700a330c2f0d11938e5dfeab6Joe Onorato     */
36324b6fd854f75f21700a330c2f0d11938e5dfeab6Joe Onorato    public void cancelDrag() {
364621e6406fadba27d6cff1c38b31d5cdf99c0f97aWinson Chung        if (mDragging) {
365c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung            if (mLastDropTarget != null) {
366c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung                mLastDropTarget.onDragExit(mDragObject);
367c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung            }
36841bb19d2775836e30ebf42f681b4617bc71600aaWinson Chung            mDragObject.deferDragViewCleanupPostAnimation = false;
36936cc09b07b19198f4ea886583cef462ade27192cAdam Cohen            mDragObject.cancelled = true;
370bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen            mDragObject.dragComplete = true;
371a48487a814c07a9f1f45eb3ffe3d873b3dc31b3bWinson Chung            mDragObject.dragSource.onDropCompleted(null, mDragObject, false, false);
372621e6406fadba27d6cff1c38b31d5cdf99c0f97aWinson Chung        }
37324b6fd854f75f21700a330c2f0d11938e5dfeab6Joe Onorato        endDrag();
37424b6fd854f75f21700a330c2f0d11938e5dfeab6Joe Onorato    }
375a182096cb20e0580dfca6661b2e5871c8886c834Winson Chung    public void onAppsRemoved(ArrayList<ApplicationInfo> apps, Context context) {
376a182096cb20e0580dfca6661b2e5871c8886c834Winson Chung        // Cancel the current drag if we are removing an app that we are dragging
377a182096cb20e0580dfca6661b2e5871c8886c834Winson Chung        if (mDragObject != null) {
378a182096cb20e0580dfca6661b2e5871c8886c834Winson Chung            Object rawDragInfo = mDragObject.dragInfo;
379a182096cb20e0580dfca6661b2e5871c8886c834Winson Chung            if (rawDragInfo instanceof ShortcutInfo) {
380a182096cb20e0580dfca6661b2e5871c8886c834Winson Chung                ShortcutInfo dragInfo = (ShortcutInfo) rawDragInfo;
381a182096cb20e0580dfca6661b2e5871c8886c834Winson Chung                for (ApplicationInfo info : apps) {
3827bcadad93f97e79d95ae879fe165de2e2371f613Michael Jurka                    // Added null checks to prevent NPE we've seen in the wild
3837bcadad93f97e79d95ae879fe165de2e2371f613Michael Jurka                    if (dragInfo != null &&
3847bcadad93f97e79d95ae879fe165de2e2371f613Michael Jurka                        dragInfo.intent != null &&
3857bcadad93f97e79d95ae879fe165de2e2371f613Michael Jurka                        info.intent != null &&
3867bcadad93f97e79d95ae879fe165de2e2371f613Michael Jurka                        dragInfo.intent.getComponent().equals(info.intent.getComponent())) {
387a182096cb20e0580dfca6661b2e5871c8886c834Winson Chung                        cancelDrag();
388a182096cb20e0580dfca6661b2e5871c8886c834Winson Chung                        return;
389a182096cb20e0580dfca6661b2e5871c8886c834Winson Chung                    }
390a182096cb20e0580dfca6661b2e5871c8886c834Winson Chung                }
391a182096cb20e0580dfca6661b2e5871c8886c834Winson Chung            }
392a182096cb20e0580dfca6661b2e5871c8886c834Winson Chung        }
393a182096cb20e0580dfca6661b2e5871c8886c834Winson Chung    }
39424b6fd854f75f21700a330c2f0d11938e5dfeab6Joe Onorato
39500acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato    private void endDrag() {
39600acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato        if (mDragging) {
39700acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato            mDragging = false;
398aa15ffe60e28b923ebf3e3162ce427ca6feae803Winson Chung            clearScrollRunnable();
399043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung            boolean isDeferred = false;
400cb3382b1bfe1a534b1b44f5c4def9b2db605ac90Adam Cohen            if (mDragObject.dragView != null) {
401043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung                isDeferred = mDragObject.deferDragViewCleanupPostAnimation;
402043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung                if (!isDeferred) {
4037bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung                    mDragObject.dragView.remove();
4047bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung                }
405cb3382b1bfe1a534b1b44f5c4def9b2db605ac90Adam Cohen                mDragObject.dragView = null;
40600acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato            }
407043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung
408043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung            // Only end the drag if we are not deferred
409043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung            if (!isDeferred) {
410043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung                for (DragListener listener : mListeners) {
411043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung                    listener.onDragEnd();
412043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung                }
413043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung            }
414043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        }
415043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung
416043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        releaseVelocityTracker();
417043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung    }
418043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung
419043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung    /**
420043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung     * This only gets called as a result of drag view cleanup being deferred in endDrag();
421043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung     */
422043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung    void onDeferredEndDrag(DragView dragView) {
423043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        dragView.remove();
424043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung
425043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        // If we skipped calling onDragEnd() before, do it now
426043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        for (DragListener listener : mListeners) {
427043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung            listener.onDragEnd();
42800acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato        }
42900acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato    }
43000acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato
431a48487a814c07a9f1f45eb3ffe3d873b3dc31b3bWinson Chung    void onDeferredEndFling(DropTarget.DragObject d) {
432a48487a814c07a9f1f45eb3ffe3d873b3dc31b3bWinson Chung        d.dragSource.onFlingToDeleteCompleted();
433a48487a814c07a9f1f45eb3ffe3d873b3dc31b3bWinson Chung    }
434a48487a814c07a9f1f45eb3ffe3d873b3dc31b3bWinson Chung
43500acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato    /**
436273c1022405bcc5e0840450b9195622e7476c9ddWinson Chung     * Clamps the position to the drag layer bounds.
437273c1022405bcc5e0840450b9195622e7476c9ddWinson Chung     */
438273c1022405bcc5e0840450b9195622e7476c9ddWinson Chung    private int[] getClampedDragLayerPos(float x, float y) {
439273c1022405bcc5e0840450b9195622e7476c9ddWinson Chung        mLauncher.getDragLayer().getLocalVisibleRect(mDragLayerRect);
440273c1022405bcc5e0840450b9195622e7476c9ddWinson Chung        mTmpPoint[0] = (int) Math.max(mDragLayerRect.left, Math.min(x, mDragLayerRect.right - 1));
441273c1022405bcc5e0840450b9195622e7476c9ddWinson Chung        mTmpPoint[1] = (int) Math.max(mDragLayerRect.top, Math.min(y, mDragLayerRect.bottom - 1));
442273c1022405bcc5e0840450b9195622e7476c9ddWinson Chung        return mTmpPoint;
443273c1022405bcc5e0840450b9195622e7476c9ddWinson Chung    }
444273c1022405bcc5e0840450b9195622e7476c9ddWinson Chung
445a2413751e3a698aef9c87411a639637883856939Winson Chung    long getLastGestureUpTime() {
446a2413751e3a698aef9c87411a639637883856939Winson Chung        if (mDragging) {
447a2413751e3a698aef9c87411a639637883856939Winson Chung            return System.currentTimeMillis();
448a2413751e3a698aef9c87411a639637883856939Winson Chung        } else {
449a2413751e3a698aef9c87411a639637883856939Winson Chung            return mLastTouchUpTime;
450a2413751e3a698aef9c87411a639637883856939Winson Chung        }
451a2413751e3a698aef9c87411a639637883856939Winson Chung    }
452a2413751e3a698aef9c87411a639637883856939Winson Chung
453a2413751e3a698aef9c87411a639637883856939Winson Chung    void resetLastGestureUpTime() {
454a2413751e3a698aef9c87411a639637883856939Winson Chung        mLastTouchUpTime = -1;
455a2413751e3a698aef9c87411a639637883856939Winson Chung    }
456a2413751e3a698aef9c87411a639637883856939Winson Chung
457273c1022405bcc5e0840450b9195622e7476c9ddWinson Chung    /**
45800acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato     * Call this from a drag source view.
45900acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato     */
46000acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato    public boolean onInterceptTouchEvent(MotionEvent ev) {
4619c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato        if (false) {
462a30ce8e6b25e41f392a41fd4d0d3e0a424a84dadJoe Onorato            Log.d(Launcher.TAG, "DragController.onInterceptTouchEvent " + ev + " mDragging="
4639c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato                    + mDragging);
4649c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato        }
46500acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato
466043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        // Update the velocity tracker
467043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        acquireVelocityTrackerAndAddMovement(ev);
468043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung
469043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        final int action = ev.getAction();
470273c1022405bcc5e0840450b9195622e7476c9ddWinson Chung        final int[] dragLayerPos = getClampedDragLayerPos(ev.getX(), ev.getY());
471273c1022405bcc5e0840450b9195622e7476c9ddWinson Chung        final int dragLayerX = dragLayerPos[0];
472273c1022405bcc5e0840450b9195622e7476c9ddWinson Chung        final int dragLayerY = dragLayerPos[1];
47300acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato
47400acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato        switch (action) {
47500acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato            case MotionEvent.ACTION_MOVE:
47600acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato                break;
47700acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato            case MotionEvent.ACTION_DOWN:
47800acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato                // Remember location of down touch
4798dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen                mMotionDownX = dragLayerX;
4808dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen                mMotionDownY = dragLayerY;
48100acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato                mLastDropTarget = null;
48200acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato                break;
48300acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato            case MotionEvent.ACTION_UP:
484a2413751e3a698aef9c87411a639637883856939Winson Chung                mLastTouchUpTime = System.currentTimeMillis();
48500acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato                if (mDragging) {
486043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung                    PointF vec = isFlingingToDelete(mDragObject.dragSource);
487043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung                    if (vec != null) {
488043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung                        dropOnFlingToDeleteTarget(dragLayerX, dragLayerY, vec);
489043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung                    } else {
490043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung                        drop(dragLayerX, dragLayerY);
491043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung                    }
49200acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato                }
49300acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato                endDrag();
49400acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato                break;
495621e6406fadba27d6cff1c38b31d5cdf99c0f97aWinson Chung            case MotionEvent.ACTION_CANCEL:
496621e6406fadba27d6cff1c38b31d5cdf99c0f97aWinson Chung                cancelDrag();
497621e6406fadba27d6cff1c38b31d5cdf99c0f97aWinson Chung                break;
49800acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato        }
49900acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato
50000acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato        return mDragging;
50100acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato    }
50200acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato
50300acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato    /**
504ea3763c2672f77539538af8cdd395ad97058eaabRomain Guy     * Sets the view that should handle move events.
505ea3763c2672f77539538af8cdd395ad97058eaabRomain Guy     */
506ea3763c2672f77539538af8cdd395ad97058eaabRomain Guy    void setMoveTarget(View view) {
507ea3763c2672f77539538af8cdd395ad97058eaabRomain Guy        mMoveTarget = view;
508ea3763c2672f77539538af8cdd395ad97058eaabRomain Guy    }
509ea3763c2672f77539538af8cdd395ad97058eaabRomain Guy
510ea3763c2672f77539538af8cdd395ad97058eaabRomain Guy    public boolean dispatchUnhandledMove(View focused, int direction) {
511ea3763c2672f77539538af8cdd395ad97058eaabRomain Guy        return mMoveTarget != null && mMoveTarget.dispatchUnhandledMove(focused, direction);
512ea3763c2672f77539538af8cdd395ad97058eaabRomain Guy    }
513ea3763c2672f77539538af8cdd395ad97058eaabRomain Guy
514aa15ffe60e28b923ebf3e3162ce427ca6feae803Winson Chung    private void clearScrollRunnable() {
515aa15ffe60e28b923ebf3e3162ce427ca6feae803Winson Chung        mHandler.removeCallbacks(mScrollRunnable);
516aa15ffe60e28b923ebf3e3162ce427ca6feae803Winson Chung        if (mScrollState == SCROLL_WAITING_IN_ZONE) {
517aa15ffe60e28b923ebf3e3162ce427ca6feae803Winson Chung            mScrollState = SCROLL_OUTSIDE_ZONE;
518aa15ffe60e28b923ebf3e3162ce427ca6feae803Winson Chung            mScrollRunnable.setDirection(SCROLL_RIGHT);
519aa15ffe60e28b923ebf3e3162ce427ca6feae803Winson Chung            mDragScroller.onExitScrollArea();
520aa15ffe60e28b923ebf3e3162ce427ca6feae803Winson Chung        }
521aa15ffe60e28b923ebf3e3162ce427ca6feae803Winson Chung    }
522aa15ffe60e28b923ebf3e3162ce427ca6feae803Winson Chung
523de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy    private void handleMoveEvent(int x, int y) {
524cb3382b1bfe1a534b1b44f5c4def9b2db605ac90Adam Cohen        mDragObject.dragView.move(x, y);
525de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy
526de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy        // Drop on someone?
527de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy        final int[] coordinates = mCoordinatesTemp;
528de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy        DropTarget dropTarget = findDropTarget(x, y, coordinates);
529cb3382b1bfe1a534b1b44f5c4def9b2db605ac90Adam Cohen        mDragObject.x = coordinates[0];
530cb3382b1bfe1a534b1b44f5c4def9b2db605ac90Adam Cohen        mDragObject.y = coordinates[1];
531de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy        if (dropTarget != null) {
532cb3382b1bfe1a534b1b44f5c4def9b2db605ac90Adam Cohen            DropTarget delegate = dropTarget.getDropTargetDelegate(mDragObject);
533de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy            if (delegate != null) {
534de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy                dropTarget = delegate;
535de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy            }
536de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy
537de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy            if (mLastDropTarget != dropTarget) {
538de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy                if (mLastDropTarget != null) {
539cb3382b1bfe1a534b1b44f5c4def9b2db605ac90Adam Cohen                    mLastDropTarget.onDragExit(mDragObject);
540de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy                }
541cb3382b1bfe1a534b1b44f5c4def9b2db605ac90Adam Cohen                dropTarget.onDragEnter(mDragObject);
542de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy            }
543cb3382b1bfe1a534b1b44f5c4def9b2db605ac90Adam Cohen            dropTarget.onDragOver(mDragObject);
544de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy        } else {
545de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy            if (mLastDropTarget != null) {
546cb3382b1bfe1a534b1b44f5c4def9b2db605ac90Adam Cohen                mLastDropTarget.onDragExit(mDragObject);
547de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy            }
548de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy        }
549de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy        mLastDropTarget = dropTarget;
550de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy
551a16fd5a6bd5371d40a5679261d416f06f8efa022Patrick Dubroy        // After a scroll, the touch point will still be in the scroll region.
552a16fd5a6bd5371d40a5679261d416f06f8efa022Patrick Dubroy        // Rather than scrolling immediately, require a bit of twiddling to scroll again
5538dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        final int slop = ViewConfiguration.get(mLauncher).getScaledWindowTouchSlop();
554a16fd5a6bd5371d40a5679261d416f06f8efa022Patrick Dubroy        mDistanceSinceScroll +=
555a16fd5a6bd5371d40a5679261d416f06f8efa022Patrick Dubroy            Math.sqrt(Math.pow(mLastTouch[0] - x, 2) + Math.pow(mLastTouch[1] - y, 2));
556a16fd5a6bd5371d40a5679261d416f06f8efa022Patrick Dubroy        mLastTouch[0] = x;
557a16fd5a6bd5371d40a5679261d416f06f8efa022Patrick Dubroy        mLastTouch[1] = y;
558aa15ffe60e28b923ebf3e3162ce427ca6feae803Winson Chung        final int delay = mDistanceSinceScroll < slop ? RESCROLL_DELAY : SCROLL_DELAY;
559a16fd5a6bd5371d40a5679261d416f06f8efa022Patrick Dubroy
5603f4e1423804d64a38cb69e4511d7b80783564827Winson Chung        if (x < mScrollZone) {
561aa15ffe60e28b923ebf3e3162ce427ca6feae803Winson Chung            if (mScrollState == SCROLL_OUTSIDE_ZONE) {
562de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy                mScrollState = SCROLL_WAITING_IN_ZONE;
5633e0839e5f830ab7e64223ebe186d97729eda3e22Winson Chung                if (mDragScroller.onEnterScrollArea(x, y, SCROLL_LEFT)) {
5643e0839e5f830ab7e64223ebe186d97729eda3e22Winson Chung                    mScrollRunnable.setDirection(SCROLL_LEFT);
565aa15ffe60e28b923ebf3e3162ce427ca6feae803Winson Chung                    mHandler.postDelayed(mScrollRunnable, delay);
5663e0839e5f830ab7e64223ebe186d97729eda3e22Winson Chung                }
567de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy            }
5683f4e1423804d64a38cb69e4511d7b80783564827Winson Chung        } else if (x > mScrollView.getWidth() - mScrollZone) {
569aa15ffe60e28b923ebf3e3162ce427ca6feae803Winson Chung            if (mScrollState == SCROLL_OUTSIDE_ZONE) {
570de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy                mScrollState = SCROLL_WAITING_IN_ZONE;
5713e0839e5f830ab7e64223ebe186d97729eda3e22Winson Chung                if (mDragScroller.onEnterScrollArea(x, y, SCROLL_RIGHT)) {
5723e0839e5f830ab7e64223ebe186d97729eda3e22Winson Chung                    mScrollRunnable.setDirection(SCROLL_RIGHT);
573aa15ffe60e28b923ebf3e3162ce427ca6feae803Winson Chung                    mHandler.postDelayed(mScrollRunnable, delay);
5743e0839e5f830ab7e64223ebe186d97729eda3e22Winson Chung                }
575de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy            }
576de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy        } else {
577aa15ffe60e28b923ebf3e3162ce427ca6feae803Winson Chung            clearScrollRunnable();
578de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy        }
579de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy    }
580de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy
5813bc21c35fa167ac233e19df0c9a01b0a07173ed8Winson Chung    public void forceMoveEvent() {
5823bc21c35fa167ac233e19df0c9a01b0a07173ed8Winson Chung        if (mDragging) {
5833bc21c35fa167ac233e19df0c9a01b0a07173ed8Winson Chung            handleMoveEvent(mDragObject.x, mDragObject.y);
5843bc21c35fa167ac233e19df0c9a01b0a07173ed8Winson Chung        }
5853bc21c35fa167ac233e19df0c9a01b0a07173ed8Winson Chung    }
5863bc21c35fa167ac233e19df0c9a01b0a07173ed8Winson Chung
587ea3763c2672f77539538af8cdd395ad97058eaabRomain Guy    /**
58800acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato     * Call this from a drag source view.
58900acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato     */
59000acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato    public boolean onTouchEvent(MotionEvent ev) {
59100acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato        if (!mDragging) {
59200acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato            return false;
59300acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato        }
59400acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato
595043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        // Update the velocity tracker
596043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        acquireVelocityTrackerAndAddMovement(ev);
597043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung
59800acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato        final int action = ev.getAction();
599273c1022405bcc5e0840450b9195622e7476c9ddWinson Chung        final int[] dragLayerPos = getClampedDragLayerPos(ev.getX(), ev.getY());
600273c1022405bcc5e0840450b9195622e7476c9ddWinson Chung        final int dragLayerX = dragLayerPos[0];
601273c1022405bcc5e0840450b9195622e7476c9ddWinson Chung        final int dragLayerY = dragLayerPos[1];
60200acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato
60300acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato        switch (action) {
60400acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato        case MotionEvent.ACTION_DOWN:
60500acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato            // Remember where the motion event started
6068dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen            mMotionDownX = dragLayerX;
6078dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen            mMotionDownY = dragLayerY;
60800acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato
6098dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen            if ((dragLayerX < mScrollZone) || (dragLayerX > mScrollView.getWidth() - mScrollZone)) {
61000acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato                mScrollState = SCROLL_WAITING_IN_ZONE;
61100acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato                mHandler.postDelayed(mScrollRunnable, SCROLL_DELAY);
61200acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato            } else {
61300acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato                mScrollState = SCROLL_OUTSIDE_ZONE;
61400acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato            }
61500acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato            break;
61600acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato        case MotionEvent.ACTION_MOVE:
6178dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen            handleMoveEvent(dragLayerX, dragLayerY);
61800acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato            break;
61900acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato        case MotionEvent.ACTION_UP:
620b0a6bbeeab0960419dcd1f695c209ca0ec36ab8aPatrick Dubroy            // Ensure that we've processed a move event at the current pointer location.
6218dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen            handleMoveEvent(dragLayerX, dragLayerY);
6223bc21c35fa167ac233e19df0c9a01b0a07173ed8Winson Chung            mHandler.removeCallbacks(mScrollRunnable);
623043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung
62400acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato            if (mDragging) {
625043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung                PointF vec = isFlingingToDelete(mDragObject.dragSource);
626043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung                if (vec != null) {
627043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung                    dropOnFlingToDeleteTarget(dragLayerX, dragLayerY, vec);
628043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung                } else {
629043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung                    drop(dragLayerX, dragLayerY);
630043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung                }
63100acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato            }
63200acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato            endDrag();
63300acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato            break;
63400acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato        case MotionEvent.ACTION_CANCEL:
6353bc21c35fa167ac233e19df0c9a01b0a07173ed8Winson Chung            mHandler.removeCallbacks(mScrollRunnable);
63624b6fd854f75f21700a330c2f0d11938e5dfeab6Joe Onorato            cancelDrag();
637621e6406fadba27d6cff1c38b31d5cdf99c0f97aWinson Chung            break;
63800acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato        }
63900acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato
64000acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato        return true;
64100acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato    }
64200acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato
643043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung    /**
644043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung     * Determines whether the user flung the current item to delete it.
645043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung     *
646043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung     * @return the vector at which the item was flung, or null if no fling was detected.
647043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung     */
648043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung    private PointF isFlingingToDelete(DragSource source) {
649043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        if (mFlingToDeleteDropTarget == null) return null;
650043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        if (!source.supportsFlingToDelete()) return null;
651043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung
652043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        ViewConfiguration config = ViewConfiguration.get(mLauncher);
653043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        mVelocityTracker.computeCurrentVelocity(1000, config.getScaledMaximumFlingVelocity());
654043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung
655043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        if (mVelocityTracker.getYVelocity() < mFlingToDeleteThresholdVelocity) {
656043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung            // Do a quick dot product test to ensure that we are flinging upwards
657043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung            PointF vel = new PointF(mVelocityTracker.getXVelocity(),
658043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung                    mVelocityTracker.getYVelocity());
659043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung            PointF upVec = new PointF(0f, -1f);
660043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung            float theta = (float) Math.acos(((vel.x * upVec.x) + (vel.y * upVec.y)) /
661043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung                    (vel.length() * upVec.length()));
662043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung            if (theta <= Math.toRadians(MAX_FLING_DEGREES)) {
663043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung                return vel;
664043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung            }
665043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        }
666043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        return null;
667043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung    }
668043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung
669043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung    private void dropOnFlingToDeleteTarget(float x, float y, PointF vel) {
670043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        final int[] coordinates = mCoordinatesTemp;
671043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung
672043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        mDragObject.x = coordinates[0];
673043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        mDragObject.y = coordinates[1];
674043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung
675043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        // Clean up dragging on the target if it's not the current fling delete target otherwise,
676043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        // start dragging to it.
677043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        if (mLastDropTarget != null && mFlingToDeleteDropTarget != mLastDropTarget) {
678043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung            mLastDropTarget.onDragExit(mDragObject);
679043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        }
680043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung
681043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        // Drop onto the fling-to-delete target
682043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        boolean accepted = false;
683043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        mFlingToDeleteDropTarget.onDragEnter(mDragObject);
684232decb008661d82ed2ca6d5f3080ee5a50d3be1Winson Chung        // We must set dragComplete to true _only_ after we "enter" the fling-to-delete target for
685232decb008661d82ed2ca6d5f3080ee5a50d3be1Winson Chung        // "drop"
686232decb008661d82ed2ca6d5f3080ee5a50d3be1Winson Chung        mDragObject.dragComplete = true;
687043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        mFlingToDeleteDropTarget.onDragExit(mDragObject);
688043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        if (mFlingToDeleteDropTarget.acceptDrop(mDragObject)) {
689043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung            mFlingToDeleteDropTarget.onFlingToDelete(mDragObject, mDragObject.x, mDragObject.y,
690043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung                    vel);
691043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung            accepted = true;
692043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        }
693a48487a814c07a9f1f45eb3ffe3d873b3dc31b3bWinson Chung        mDragObject.dragSource.onDropCompleted((View) mFlingToDeleteDropTarget, mDragObject, true,
694043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung                accepted);
695043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung    }
696043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung
697b0a6bbeeab0960419dcd1f695c209ca0ec36ab8aPatrick Dubroy    private void drop(float x, float y) {
69800acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato        final int[] coordinates = mCoordinatesTemp;
699b0a6bbeeab0960419dcd1f695c209ca0ec36ab8aPatrick Dubroy        final DropTarget dropTarget = findDropTarget((int) x, (int) y, coordinates);
70000acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato
701cb3382b1bfe1a534b1b44f5c4def9b2db605ac90Adam Cohen        mDragObject.x = coordinates[0];
702cb3382b1bfe1a534b1b44f5c4def9b2db605ac90Adam Cohen        mDragObject.y = coordinates[1];
703b0a6bbeeab0960419dcd1f695c209ca0ec36ab8aPatrick Dubroy        boolean accepted = false;
70400acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato        if (dropTarget != null) {
705bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen            mDragObject.dragComplete = true;
706cb3382b1bfe1a534b1b44f5c4def9b2db605ac90Adam Cohen            dropTarget.onDragExit(mDragObject);
707cb3382b1bfe1a534b1b44f5c4def9b2db605ac90Adam Cohen            if (dropTarget.acceptDrop(mDragObject)) {
708cb3382b1bfe1a534b1b44f5c4def9b2db605ac90Adam Cohen                dropTarget.onDrop(mDragObject);
709b0a6bbeeab0960419dcd1f695c209ca0ec36ab8aPatrick Dubroy                accepted = true;
71000acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato            }
71100acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato        }
712a48487a814c07a9f1f45eb3ffe3d873b3dc31b3bWinson Chung        mDragObject.dragSource.onDropCompleted((View) dropTarget, mDragObject, false, accepted);
71300acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato    }
71400acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato
71500acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato    private DropTarget findDropTarget(int x, int y, int[] dropCoordinates) {
71600acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato        final Rect r = mRectTemp;
71700acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato
71800acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato        final ArrayList<DropTarget> dropTargets = mDropTargets;
71900acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato        final int count = dropTargets.size();
72000acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato        for (int i=count-1; i>=0; i--) {
721440c360bc395c43683fa9ca226e59f9e35f9e926Patrick Dubroy            DropTarget target = dropTargets.get(i);
7220280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka            if (!target.isDropEnabled())
7230280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                continue;
7240280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka
72500acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato            target.getHitRect(r);
726440c360bc395c43683fa9ca226e59f9e35f9e926Patrick Dubroy
7278dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen            // Convert the hit rect to DragLayer coordinates
7288dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen            target.getLocationInDragLayer(dropCoordinates);
72900acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato            r.offset(dropCoordinates[0] - target.getLeft(), dropCoordinates[1] - target.getTop());
730440c360bc395c43683fa9ca226e59f9e35f9e926Patrick Dubroy
731cb3382b1bfe1a534b1b44f5c4def9b2db605ac90Adam Cohen            mDragObject.x = x;
732cb3382b1bfe1a534b1b44f5c4def9b2db605ac90Adam Cohen            mDragObject.y = y;
73300acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato            if (r.contains(x, y)) {
734cb3382b1bfe1a534b1b44f5c4def9b2db605ac90Adam Cohen                DropTarget delegate = target.getDropTargetDelegate(mDragObject);
735440c360bc395c43683fa9ca226e59f9e35f9e926Patrick Dubroy                if (delegate != null) {
736440c360bc395c43683fa9ca226e59f9e35f9e926Patrick Dubroy                    target = delegate;
7378dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen                    target.getLocationInDragLayer(dropCoordinates);
738440c360bc395c43683fa9ca226e59f9e35f9e926Patrick Dubroy                }
739440c360bc395c43683fa9ca226e59f9e35f9e926Patrick Dubroy
740440c360bc395c43683fa9ca226e59f9e35f9e926Patrick Dubroy                // Make dropCoordinates relative to the DropTarget
74100acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato                dropCoordinates[0] = x - dropCoordinates[0];
74200acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato                dropCoordinates[1] = y - dropCoordinates[1];
743440c360bc395c43683fa9ca226e59f9e35f9e926Patrick Dubroy
74400acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato                return target;
74500acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato            }
74600acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato        }
74700acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato        return null;
74800acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato    }
74900acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato
75000acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato    public void setDragScoller(DragScroller scroller) {
75100acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato        mDragScroller = scroller;
75200acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato    }
75300acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato
75400acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato    public void setWindowToken(IBinder token) {
75500acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato        mWindowToken = token;
75600acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato    }
75700acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato
75831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    /**
75931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * Sets the drag listner which will be notified when a drag starts or ends.
76031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     */
7614ed6278e518cc6894cb150b606382e8e6a012599Patrick Dubroy    public void addDragListener(DragListener l) {
7624ed6278e518cc6894cb150b606382e8e6a012599Patrick Dubroy        mListeners.add(l);
76300acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato    }
76400acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato
76531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    /**
76631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * Remove a previously installed drag listener.
76731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     */
76800acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato    public void removeDragListener(DragListener l) {
7694ed6278e518cc6894cb150b606382e8e6a012599Patrick Dubroy        mListeners.remove(l);
77000acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato    }
77100acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato
77200acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato    /**
77300acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato     * Add a DropTarget to the list of potential places to receive drop events.
77400acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato     */
77500acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato    public void addDropTarget(DropTarget target) {
77600acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato        mDropTargets.add(target);
77700acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato    }
77800acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato
77900acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato    /**
78000acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato     * Don't send drop events to <em>target</em> any more.
78100acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato     */
78200acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato    public void removeDropTarget(DropTarget target) {
78300acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato        mDropTargets.remove(target);
78400acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato    }
78500acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato
78600acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato    /**
787043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung     * Sets the current fling-to-delete drop target.
788043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung     */
789043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung    public void setFlingToDeleteDropTarget(DropTarget target) {
790043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        mFlingToDeleteDropTarget = target;
791043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung    }
792043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung
793043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung    private void acquireVelocityTrackerAndAddMovement(MotionEvent ev) {
794043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        if (mVelocityTracker == null) {
795043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung            mVelocityTracker = VelocityTracker.obtain();
796043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        }
797043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        mVelocityTracker.addMovement(ev);
798043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung    }
799043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung
800043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung    private void releaseVelocityTracker() {
801043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        if (mVelocityTracker != null) {
802043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung            mVelocityTracker.recycle();
803043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung            mVelocityTracker = null;
804043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        }
805043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung    }
806043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung
807043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung    /**
80800acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato     * Set which view scrolls for touch events near the edge of the screen.
80900acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato     */
81000acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato    public void setScrollView(View v) {
81100acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato        mScrollView = v;
81200acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato    }
81300acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato
8145f445425606b2c27276a79e9e871cf7f67b1b719Patrick Dubroy    DragView getDragView() {
815cb3382b1bfe1a534b1b44f5c4def9b2db605ac90Adam Cohen        return mDragObject.dragView;
8165f445425606b2c27276a79e9e871cf7f67b1b719Patrick Dubroy    }
8175f445425606b2c27276a79e9e871cf7f67b1b719Patrick Dubroy
81800acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato    private class ScrollRunnable implements Runnable {
81900acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato        private int mDirection;
82000acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato
82100acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato        ScrollRunnable() {
82200acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato        }
82300acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato
82400acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato        public void run() {
82500acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato            if (mDragScroller != null) {
82600acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato                if (mDirection == SCROLL_LEFT) {
82700acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato                    mDragScroller.scrollLeft();
82800acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato                } else {
82900acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato                    mDragScroller.scrollRight();
83000acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato                }
83100acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato                mScrollState = SCROLL_OUTSIDE_ZONE;
832a16fd5a6bd5371d40a5679261d416f06f8efa022Patrick Dubroy                mDistanceSinceScroll = 0;
833a16fd5a6bd5371d40a5679261d416f06f8efa022Patrick Dubroy                mDragScroller.onExitScrollArea();
834aa15ffe60e28b923ebf3e3162ce427ca6feae803Winson Chung
835aa15ffe60e28b923ebf3e3162ce427ca6feae803Winson Chung                if (isDragging()) {
836aa15ffe60e28b923ebf3e3162ce427ca6feae803Winson Chung                    // Force an update so that we can requeue the scroller if necessary
8373bc21c35fa167ac233e19df0c9a01b0a07173ed8Winson Chung                    forceMoveEvent();
838aa15ffe60e28b923ebf3e3162ce427ca6feae803Winson Chung                }
83900acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato            }
84000acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato        }
84100acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato
84200acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato        void setDirection(int direction) {
84300acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato            mDirection = direction;
84400acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato        }
84500acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato    }
84631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project}
847