SystemGesturesPointerEventListener.java revision 994652991b5e3b5f85540af6aeb04609401509ed
157306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock/*
257306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock * Copyright (C) 2013 The Android Open Source Project
357306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock *
457306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock * Licensed under the Apache License, Version 2.0 (the "License");
557306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock * you may not use this file except in compliance with the License.
657306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock * You may obtain a copy of the License at
757306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock *
857306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock *      http://www.apache.org/licenses/LICENSE-2.0
957306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock *
1057306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock * Unless required by applicable law or agreed to in writing, software
1157306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock * distributed under the License is distributed on an "AS IS" BASIS,
1257306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1357306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock * See the License for the specific language governing permissions and
1457306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock * limitations under the License.
1557306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock */
1657306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock
17b10e33ff804a831c71be9303146cea892b9aeb5dJorim Jaggipackage com.android.server.policy;
1857306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock
1957306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlockimport android.content.Context;
20a4d22d718affbc7145d1012157feb819557b5c06Michael Wrightimport android.os.Handler;
21a4d22d718affbc7145d1012157feb819557b5c06Michael Wrightimport android.os.Looper;
22a4d22d718affbc7145d1012157feb819557b5c06Michael Wrightimport android.os.SystemClock;
2357306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlockimport android.util.Slog;
24a4d22d718affbc7145d1012157feb819557b5c06Michael Wrightimport android.view.GestureDetector;
25994652991b5e3b5f85540af6aeb04609401509edJun Mukaiimport android.view.InputDevice;
2657306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlockimport android.view.MotionEvent;
27037aa8d434984840691378f3cc7d99d63dcc4076Craig Mautnerimport android.view.WindowManagerPolicy.PointerEventListener;
28a4d22d718affbc7145d1012157feb819557b5c06Michael Wrightimport android.widget.OverScroller;
2957306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock
3057306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock/*
3157306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock * Listens for system-wide input gestures, firing callbacks when detected.
3257306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock * @hide
3357306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock */
34037aa8d434984840691378f3cc7d99d63dcc4076Craig Mautnerpublic class SystemGesturesPointerEventListener implements PointerEventListener {
3557306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock    private static final String TAG = "SystemGestures";
3657306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock    private static final boolean DEBUG = false;
3757306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock    private static final long SWIPE_TIMEOUT_MS = 500;
3857306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock    private static final int MAX_TRACKED_POINTERS = 32;  // max per input system
3957306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock    private static final int UNTRACKED_POINTER = -1;
40a4d22d718affbc7145d1012157feb819557b5c06Michael Wright    private static final int MAX_FLING_TIME_MILLIS = 5000;
4157306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock
42ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock    private static final int SWIPE_NONE = 0;
43ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock    private static final int SWIPE_FROM_TOP = 1;
44ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock    private static final int SWIPE_FROM_BOTTOM = 2;
45ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock    private static final int SWIPE_FROM_RIGHT = 3;
46ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock
47a4d22d718affbc7145d1012157feb819557b5c06Michael Wright    private final Context mContext;
4857306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock    private final int mSwipeStartThreshold;
499ba21fdc9ddf1d132215d29054b55af416561367John Spurlock    private final int mSwipeDistanceThreshold;
5057306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock    private final Callbacks mCallbacks;
5157306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock    private final int[] mDownPointerId = new int[MAX_TRACKED_POINTERS];
52ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock    private final float[] mDownX = new float[MAX_TRACKED_POINTERS];
5357306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock    private final float[] mDownY = new float[MAX_TRACKED_POINTERS];
5457306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock    private final long[] mDownTime = new long[MAX_TRACKED_POINTERS];
5557306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock
56a4d22d718affbc7145d1012157feb819557b5c06Michael Wright    private GestureDetector mGestureDetector;
57a4d22d718affbc7145d1012157feb819557b5c06Michael Wright    private OverScroller mOverscroller;
58a4d22d718affbc7145d1012157feb819557b5c06Michael Wright
59ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock    int screenHeight;
60ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock    int screenWidth;
6157306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock    private int mDownPointers;
62ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock    private boolean mSwipeFireable;
63ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock    private boolean mDebugFireable;
64d2e7e355d836f18adcdb44db9c1931d1c3663ef1Jun Mukai    private boolean mMouseHoveringAtEdge;
65a4d22d718affbc7145d1012157feb819557b5c06Michael Wright    private long mLastFlingTime;
6657306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock
67037aa8d434984840691378f3cc7d99d63dcc4076Craig Mautner    public SystemGesturesPointerEventListener(Context context, Callbacks callbacks) {
68a4d22d718affbc7145d1012157feb819557b5c06Michael Wright        mContext = context;
6957306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock        mCallbacks = checkNull("callbacks", callbacks);
7057306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock        mSwipeStartThreshold = checkNull("context", context).getResources()
7157306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock                .getDimensionPixelSize(com.android.internal.R.dimen.status_bar_height);
729ba21fdc9ddf1d132215d29054b55af416561367John Spurlock        mSwipeDistanceThreshold = mSwipeStartThreshold;
739ba21fdc9ddf1d132215d29054b55af416561367John Spurlock        if (DEBUG) Slog.d(TAG,  "mSwipeStartThreshold=" + mSwipeStartThreshold
749ba21fdc9ddf1d132215d29054b55af416561367John Spurlock                + " mSwipeDistanceThreshold=" + mSwipeDistanceThreshold);
7557306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock    }
7657306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock
7757306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock    private static <T> T checkNull(String name, T arg) {
7857306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock        if (arg == null) {
7957306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock            throw new IllegalArgumentException(name + " must not be null");
8057306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock        }
8157306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock        return arg;
8257306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock    }
8357306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock
84a4d22d718affbc7145d1012157feb819557b5c06Michael Wright    public void systemReady() {
85a4d22d718affbc7145d1012157feb819557b5c06Michael Wright        Handler h = new Handler(Looper.myLooper());
86a4d22d718affbc7145d1012157feb819557b5c06Michael Wright        mGestureDetector = new GestureDetector(mContext, new FlingGestureDetector(), h);
87a4d22d718affbc7145d1012157feb819557b5c06Michael Wright        mOverscroller = new OverScroller(mContext);
88a4d22d718affbc7145d1012157feb819557b5c06Michael Wright    }
89a4d22d718affbc7145d1012157feb819557b5c06Michael Wright
9057306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock    @Override
91037aa8d434984840691378f3cc7d99d63dcc4076Craig Mautner    public void onPointerEvent(MotionEvent event) {
92a4d22d718affbc7145d1012157feb819557b5c06Michael Wright        if (mGestureDetector != null) {
93a4d22d718affbc7145d1012157feb819557b5c06Michael Wright            mGestureDetector.onTouchEvent(event);
94a4d22d718affbc7145d1012157feb819557b5c06Michael Wright        }
9557306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock        switch (event.getActionMasked()) {
9657306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock            case MotionEvent.ACTION_DOWN:
97ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock                mSwipeFireable = true;
98ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock                mDebugFireable = true;
9957306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock                mDownPointers = 0;
10057306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock                captureDown(event, 0);
101d2e7e355d836f18adcdb44db9c1931d1c3663ef1Jun Mukai                if (mMouseHoveringAtEdge) {
102d2e7e355d836f18adcdb44db9c1931d1c3663ef1Jun Mukai                    mMouseHoveringAtEdge = false;
103d2e7e355d836f18adcdb44db9c1931d1c3663ef1Jun Mukai                    mCallbacks.onMouseLeaveFromEdge();
104d2e7e355d836f18adcdb44db9c1931d1c3663ef1Jun Mukai                }
1053595be4d19caaa7ddfbff0b979d135aaf5ac20b1Adrian Roos                mCallbacks.onDown();
10657306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock                break;
10757306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock            case MotionEvent.ACTION_POINTER_DOWN:
10857306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock                captureDown(event, event.getActionIndex());
109ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock                if (mDebugFireable) {
110ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock                    mDebugFireable = event.getPointerCount() < 5;
111ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock                    if (!mDebugFireable) {
112ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock                        if (DEBUG) Slog.d(TAG, "Firing debug");
113ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock                        mCallbacks.onDebug();
114ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock                    }
115ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock                }
11657306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock                break;
11757306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock            case MotionEvent.ACTION_MOVE:
118ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock                if (mSwipeFireable) {
119ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock                    final int swipe = detectSwipe(event);
120ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock                    mSwipeFireable = swipe == SWIPE_NONE;
121ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock                    if (swipe == SWIPE_FROM_TOP) {
122ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock                        if (DEBUG) Slog.d(TAG, "Firing onSwipeFromTop");
123ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock                        mCallbacks.onSwipeFromTop();
124ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock                    } else if (swipe == SWIPE_FROM_BOTTOM) {
125ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock                        if (DEBUG) Slog.d(TAG, "Firing onSwipeFromBottom");
126ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock                        mCallbacks.onSwipeFromBottom();
127ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock                    } else if (swipe == SWIPE_FROM_RIGHT) {
128ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock                        if (DEBUG) Slog.d(TAG, "Firing onSwipeFromRight");
129ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock                        mCallbacks.onSwipeFromRight();
130ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock                    }
13157306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock                }
13257306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock                break;
133d2e7e355d836f18adcdb44db9c1931d1c3663ef1Jun Mukai            case MotionEvent.ACTION_HOVER_MOVE:
134994652991b5e3b5f85540af6aeb04609401509edJun Mukai                if (event.getDevice().getSources() == InputDevice.SOURCE_MOUSE) {
135d2e7e355d836f18adcdb44db9c1931d1c3663ef1Jun Mukai                    if (!mMouseHoveringAtEdge && event.getY() == 0) {
136d2e7e355d836f18adcdb44db9c1931d1c3663ef1Jun Mukai                        mCallbacks.onMouseHoverAtTop();
137d2e7e355d836f18adcdb44db9c1931d1c3663ef1Jun Mukai                        mMouseHoveringAtEdge = true;
138d2e7e355d836f18adcdb44db9c1931d1c3663ef1Jun Mukai                    } else if (!mMouseHoveringAtEdge && event.getY() >= screenHeight - 1) {
139d2e7e355d836f18adcdb44db9c1931d1c3663ef1Jun Mukai                        mCallbacks.onMouseHoverAtBottom();
140d2e7e355d836f18adcdb44db9c1931d1c3663ef1Jun Mukai                        mMouseHoveringAtEdge = true;
141d2e7e355d836f18adcdb44db9c1931d1c3663ef1Jun Mukai                    } else if (mMouseHoveringAtEdge
142d2e7e355d836f18adcdb44db9c1931d1c3663ef1Jun Mukai                            && (event.getY() > 0 && event.getY() < screenHeight - 1)) {
143d2e7e355d836f18adcdb44db9c1931d1c3663ef1Jun Mukai                        mCallbacks.onMouseLeaveFromEdge();
144d2e7e355d836f18adcdb44db9c1931d1c3663ef1Jun Mukai                        mMouseHoveringAtEdge = false;
145d2e7e355d836f18adcdb44db9c1931d1c3663ef1Jun Mukai                    }
146d2e7e355d836f18adcdb44db9c1931d1c3663ef1Jun Mukai                }
147d2e7e355d836f18adcdb44db9c1931d1c3663ef1Jun Mukai                break;
14857306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock            case MotionEvent.ACTION_UP:
14957306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock            case MotionEvent.ACTION_CANCEL:
150ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock                mSwipeFireable = false;
151ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock                mDebugFireable = false;
1523595be4d19caaa7ddfbff0b979d135aaf5ac20b1Adrian Roos                mCallbacks.onUpOrCancel();
15357306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock                break;
15457306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock            default:
15557306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock                if (DEBUG) Slog.d(TAG, "Ignoring " + event);
15657306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock        }
15757306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock    }
15857306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock
15957306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock    private void captureDown(MotionEvent event, int pointerIndex) {
16057306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock        final int pointerId = event.getPointerId(pointerIndex);
16157306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock        final int i = findIndex(pointerId);
16257306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock        if (DEBUG) Slog.d(TAG, "pointer " + pointerId +
16357306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock                " down pointerIndex=" + pointerIndex + " trackingIndex=" + i);
16457306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock        if (i != UNTRACKED_POINTER) {
165ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock            mDownX[i] = event.getX(pointerIndex);
16657306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock            mDownY[i] = event.getY(pointerIndex);
16757306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock            mDownTime[i] = event.getEventTime();
168ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock            if (DEBUG) Slog.d(TAG, "pointer " + pointerId +
169ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock                    " down x=" + mDownX[i] + " y=" + mDownY[i]);
17057306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock        }
17157306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock    }
17257306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock
17357306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock    private int findIndex(int pointerId) {
17457306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock        for (int i = 0; i < mDownPointers; i++) {
17557306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock            if (mDownPointerId[i] == pointerId) {
17657306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock                return i;
17757306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock            }
17857306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock        }
17957306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock        if (mDownPointers == MAX_TRACKED_POINTERS || pointerId == MotionEvent.INVALID_POINTER_ID) {
18057306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock            return UNTRACKED_POINTER;
18157306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock        }
18257306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock        mDownPointerId[mDownPointers++] = pointerId;
18357306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock        return mDownPointers - 1;
18457306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock    }
18557306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock
186ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock    private int detectSwipe(MotionEvent move) {
18757306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock        final int historySize = move.getHistorySize();
18857306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock        final int pointerCount = move.getPointerCount();
18957306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock        for (int p = 0; p < pointerCount; p++) {
19057306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock            final int pointerId = move.getPointerId(p);
19157306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock            final int i = findIndex(pointerId);
19257306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock            if (i != UNTRACKED_POINTER) {
19357306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock                for (int h = 0; h < historySize; h++) {
19457306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock                    final long time = move.getHistoricalEventTime(h);
195ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock                    final float x = move.getHistoricalX(p, h);
19657306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock                    final float y = move.getHistoricalY(p,  h);
197ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock                    final int swipe = detectSwipe(i, time, x, y);
198ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock                    if (swipe != SWIPE_NONE) {
199ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock                        return swipe;
20057306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock                    }
20157306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock                }
202ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock                final int swipe = detectSwipe(i, move.getEventTime(), move.getX(p), move.getY(p));
203ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock                if (swipe != SWIPE_NONE) {
204ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock                    return swipe;
20557306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock                }
20657306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock            }
20757306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock        }
208ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock        return SWIPE_NONE;
20957306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock    }
21057306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock
211ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock    private int detectSwipe(int i, long time, float x, float y) {
212ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock        final float fromX = mDownX[i];
21357306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock        final float fromY = mDownY[i];
21457306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock        final long elapsed = time - mDownTime[i];
21557306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock        if (DEBUG) Slog.d(TAG, "pointer " + mDownPointerId[i]
216ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock                + " moved (" + fromX + "->" + x + "," + fromY + "->" + y + ") in " + elapsed);
217ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock        if (fromY <= mSwipeStartThreshold
2189ba21fdc9ddf1d132215d29054b55af416561367John Spurlock                && y > fromY + mSwipeDistanceThreshold
219ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock                && elapsed < SWIPE_TIMEOUT_MS) {
220ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock            return SWIPE_FROM_TOP;
221ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock        }
222ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock        if (fromY >= screenHeight - mSwipeStartThreshold
2239ba21fdc9ddf1d132215d29054b55af416561367John Spurlock                && y < fromY - mSwipeDistanceThreshold
224ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock                && elapsed < SWIPE_TIMEOUT_MS) {
225ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock            return SWIPE_FROM_BOTTOM;
226ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock        }
227ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock        if (fromX >= screenWidth - mSwipeStartThreshold
2289ba21fdc9ddf1d132215d29054b55af416561367John Spurlock                && x < fromX - mSwipeDistanceThreshold
229ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock                && elapsed < SWIPE_TIMEOUT_MS) {
230ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock            return SWIPE_FROM_RIGHT;
231ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock        }
232ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock        return SWIPE_NONE;
23357306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock    }
23457306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock
235a4d22d718affbc7145d1012157feb819557b5c06Michael Wright    private final class FlingGestureDetector extends GestureDetector.SimpleOnGestureListener {
236a4d22d718affbc7145d1012157feb819557b5c06Michael Wright        @Override
237a4d22d718affbc7145d1012157feb819557b5c06Michael Wright        public boolean onSingleTapUp(MotionEvent e) {
238a4d22d718affbc7145d1012157feb819557b5c06Michael Wright            if (!mOverscroller.isFinished()) {
239a4d22d718affbc7145d1012157feb819557b5c06Michael Wright                mOverscroller.forceFinished(true);
240a4d22d718affbc7145d1012157feb819557b5c06Michael Wright            }
241a4d22d718affbc7145d1012157feb819557b5c06Michael Wright            return true;
242a4d22d718affbc7145d1012157feb819557b5c06Michael Wright        }
243a4d22d718affbc7145d1012157feb819557b5c06Michael Wright        @Override
244a4d22d718affbc7145d1012157feb819557b5c06Michael Wright        public boolean onFling(MotionEvent down, MotionEvent up,
245a4d22d718affbc7145d1012157feb819557b5c06Michael Wright                float velocityX, float velocityY) {
246a4d22d718affbc7145d1012157feb819557b5c06Michael Wright            mOverscroller.computeScrollOffset();
247a4d22d718affbc7145d1012157feb819557b5c06Michael Wright            long now = SystemClock.uptimeMillis();
248a4d22d718affbc7145d1012157feb819557b5c06Michael Wright
249a4d22d718affbc7145d1012157feb819557b5c06Michael Wright            if (mLastFlingTime != 0 && now > mLastFlingTime + MAX_FLING_TIME_MILLIS) {
250a4d22d718affbc7145d1012157feb819557b5c06Michael Wright                mOverscroller.forceFinished(true);
251a4d22d718affbc7145d1012157feb819557b5c06Michael Wright            }
252a4d22d718affbc7145d1012157feb819557b5c06Michael Wright            mOverscroller.fling(0, 0, (int)velocityX, (int)velocityY,
253a4d22d718affbc7145d1012157feb819557b5c06Michael Wright                    Integer.MIN_VALUE, Integer.MAX_VALUE, Integer.MIN_VALUE, Integer.MAX_VALUE);
254a4d22d718affbc7145d1012157feb819557b5c06Michael Wright            int duration = mOverscroller.getDuration();
255a4d22d718affbc7145d1012157feb819557b5c06Michael Wright            if (duration > MAX_FLING_TIME_MILLIS) {
256a4d22d718affbc7145d1012157feb819557b5c06Michael Wright                duration = MAX_FLING_TIME_MILLIS;
257a4d22d718affbc7145d1012157feb819557b5c06Michael Wright            }
258a4d22d718affbc7145d1012157feb819557b5c06Michael Wright            mLastFlingTime = now;
259a4d22d718affbc7145d1012157feb819557b5c06Michael Wright            mCallbacks.onFling(duration);
260a4d22d718affbc7145d1012157feb819557b5c06Michael Wright            return true;
261a4d22d718affbc7145d1012157feb819557b5c06Michael Wright        }
262a4d22d718affbc7145d1012157feb819557b5c06Michael Wright    }
263a4d22d718affbc7145d1012157feb819557b5c06Michael Wright
26457306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock    interface Callbacks {
26557306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock        void onSwipeFromTop();
266ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock        void onSwipeFromBottom();
267ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock        void onSwipeFromRight();
268a4d22d718affbc7145d1012157feb819557b5c06Michael Wright        void onFling(int durationMs);
2693595be4d19caaa7ddfbff0b979d135aaf5ac20b1Adrian Roos        void onDown();
2703595be4d19caaa7ddfbff0b979d135aaf5ac20b1Adrian Roos        void onUpOrCancel();
271d2e7e355d836f18adcdb44db9c1931d1c3663ef1Jun Mukai        void onMouseHoverAtTop();
272d2e7e355d836f18adcdb44db9c1931d1c3663ef1Jun Mukai        void onMouseHoverAtBottom();
273d2e7e355d836f18adcdb44db9c1931d1c3663ef1Jun Mukai        void onMouseLeaveFromEdge();
274ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock        void onDebug();
27557306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock    }
27657306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock}
277