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; 4685d202b18ada8dc95f151087ab9778d1a31f7a30Adrian Roos private static final int SWIPE_FROM_LEFT = 4; 47ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock 48a4d22d718affbc7145d1012157feb819557b5c06Michael Wright private final Context mContext; 4957306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock private final int mSwipeStartThreshold; 509ba21fdc9ddf1d132215d29054b55af416561367John Spurlock private final int mSwipeDistanceThreshold; 5157306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock private final Callbacks mCallbacks; 5257306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock private final int[] mDownPointerId = new int[MAX_TRACKED_POINTERS]; 53ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock private final float[] mDownX = new float[MAX_TRACKED_POINTERS]; 5457306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock private final float[] mDownY = new float[MAX_TRACKED_POINTERS]; 5557306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock private final long[] mDownTime = new long[MAX_TRACKED_POINTERS]; 5657306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock 57a4d22d718affbc7145d1012157feb819557b5c06Michael Wright private GestureDetector mGestureDetector; 58a4d22d718affbc7145d1012157feb819557b5c06Michael Wright private OverScroller mOverscroller; 59a4d22d718affbc7145d1012157feb819557b5c06Michael Wright 60ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock int screenHeight; 61ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock int screenWidth; 6257306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock private int mDownPointers; 63ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock private boolean mSwipeFireable; 64ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock private boolean mDebugFireable; 65d2e7e355d836f18adcdb44db9c1931d1c3663ef1Jun Mukai private boolean mMouseHoveringAtEdge; 66a4d22d718affbc7145d1012157feb819557b5c06Michael Wright private long mLastFlingTime; 6757306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock 68037aa8d434984840691378f3cc7d99d63dcc4076Craig Mautner public SystemGesturesPointerEventListener(Context context, Callbacks callbacks) { 69a4d22d718affbc7145d1012157feb819557b5c06Michael Wright mContext = context; 7057306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock mCallbacks = checkNull("callbacks", callbacks); 7157306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock mSwipeStartThreshold = checkNull("context", context).getResources() 7257306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock .getDimensionPixelSize(com.android.internal.R.dimen.status_bar_height); 739ba21fdc9ddf1d132215d29054b55af416561367John Spurlock mSwipeDistanceThreshold = mSwipeStartThreshold; 749ba21fdc9ddf1d132215d29054b55af416561367John Spurlock if (DEBUG) Slog.d(TAG, "mSwipeStartThreshold=" + mSwipeStartThreshold 759ba21fdc9ddf1d132215d29054b55af416561367John Spurlock + " mSwipeDistanceThreshold=" + mSwipeDistanceThreshold); 7657306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock } 7757306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock 7857306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock private static <T> T checkNull(String name, T arg) { 7957306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock if (arg == null) { 8057306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock throw new IllegalArgumentException(name + " must not be null"); 8157306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock } 8257306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock return arg; 8357306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock } 8457306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock 85a4d22d718affbc7145d1012157feb819557b5c06Michael Wright public void systemReady() { 86a4d22d718affbc7145d1012157feb819557b5c06Michael Wright Handler h = new Handler(Looper.myLooper()); 87a4d22d718affbc7145d1012157feb819557b5c06Michael Wright mGestureDetector = new GestureDetector(mContext, new FlingGestureDetector(), h); 88a4d22d718affbc7145d1012157feb819557b5c06Michael Wright mOverscroller = new OverScroller(mContext); 89a4d22d718affbc7145d1012157feb819557b5c06Michael Wright } 90a4d22d718affbc7145d1012157feb819557b5c06Michael Wright 9157306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock @Override 92037aa8d434984840691378f3cc7d99d63dcc4076Craig Mautner public void onPointerEvent(MotionEvent event) { 93fb5168a3e3749dbb8517ad39f34d450e2aea49daDennis Kempin if (mGestureDetector != null && event.isTouchEvent()) { 94a4d22d718affbc7145d1012157feb819557b5c06Michael Wright mGestureDetector.onTouchEvent(event); 95a4d22d718affbc7145d1012157feb819557b5c06Michael Wright } 9657306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock switch (event.getActionMasked()) { 9757306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock case MotionEvent.ACTION_DOWN: 98ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock mSwipeFireable = true; 99ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock mDebugFireable = true; 10057306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock mDownPointers = 0; 10157306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock captureDown(event, 0); 102d2e7e355d836f18adcdb44db9c1931d1c3663ef1Jun Mukai if (mMouseHoveringAtEdge) { 103d2e7e355d836f18adcdb44db9c1931d1c3663ef1Jun Mukai mMouseHoveringAtEdge = false; 104d2e7e355d836f18adcdb44db9c1931d1c3663ef1Jun Mukai mCallbacks.onMouseLeaveFromEdge(); 105d2e7e355d836f18adcdb44db9c1931d1c3663ef1Jun Mukai } 1063595be4d19caaa7ddfbff0b979d135aaf5ac20b1Adrian Roos mCallbacks.onDown(); 10757306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock break; 10857306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock case MotionEvent.ACTION_POINTER_DOWN: 10957306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock captureDown(event, event.getActionIndex()); 110ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock if (mDebugFireable) { 111ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock mDebugFireable = event.getPointerCount() < 5; 112ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock if (!mDebugFireable) { 113ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock if (DEBUG) Slog.d(TAG, "Firing debug"); 114ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock mCallbacks.onDebug(); 115ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock } 116ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock } 11757306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock break; 11857306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock case MotionEvent.ACTION_MOVE: 119ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock if (mSwipeFireable) { 120ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock final int swipe = detectSwipe(event); 121ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock mSwipeFireable = swipe == SWIPE_NONE; 122ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock if (swipe == SWIPE_FROM_TOP) { 123ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock if (DEBUG) Slog.d(TAG, "Firing onSwipeFromTop"); 124ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock mCallbacks.onSwipeFromTop(); 125ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock } else if (swipe == SWIPE_FROM_BOTTOM) { 126ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock if (DEBUG) Slog.d(TAG, "Firing onSwipeFromBottom"); 127ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock mCallbacks.onSwipeFromBottom(); 128ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock } else if (swipe == SWIPE_FROM_RIGHT) { 129ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock if (DEBUG) Slog.d(TAG, "Firing onSwipeFromRight"); 130ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock mCallbacks.onSwipeFromRight(); 13185d202b18ada8dc95f151087ab9778d1a31f7a30Adrian Roos } else if (swipe == SWIPE_FROM_LEFT) { 13285d202b18ada8dc95f151087ab9778d1a31f7a30Adrian Roos if (DEBUG) Slog.d(TAG, "Firing onSwipeFromLeft"); 13385d202b18ada8dc95f151087ab9778d1a31f7a30Adrian Roos mCallbacks.onSwipeFromLeft(); 134ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock } 13557306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock } 13657306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock break; 137d2e7e355d836f18adcdb44db9c1931d1c3663ef1Jun Mukai case MotionEvent.ACTION_HOVER_MOVE: 138c5bd9bc8dce74966667012939a2f53b639ec10fdJun Mukai if (event.isFromSource(InputDevice.SOURCE_MOUSE)) { 139d2e7e355d836f18adcdb44db9c1931d1c3663ef1Jun Mukai if (!mMouseHoveringAtEdge && event.getY() == 0) { 140d2e7e355d836f18adcdb44db9c1931d1c3663ef1Jun Mukai mCallbacks.onMouseHoverAtTop(); 141d2e7e355d836f18adcdb44db9c1931d1c3663ef1Jun Mukai mMouseHoveringAtEdge = true; 142d2e7e355d836f18adcdb44db9c1931d1c3663ef1Jun Mukai } else if (!mMouseHoveringAtEdge && event.getY() >= screenHeight - 1) { 143d2e7e355d836f18adcdb44db9c1931d1c3663ef1Jun Mukai mCallbacks.onMouseHoverAtBottom(); 144d2e7e355d836f18adcdb44db9c1931d1c3663ef1Jun Mukai mMouseHoveringAtEdge = true; 145d2e7e355d836f18adcdb44db9c1931d1c3663ef1Jun Mukai } else if (mMouseHoveringAtEdge 146d2e7e355d836f18adcdb44db9c1931d1c3663ef1Jun Mukai && (event.getY() > 0 && event.getY() < screenHeight - 1)) { 147d2e7e355d836f18adcdb44db9c1931d1c3663ef1Jun Mukai mCallbacks.onMouseLeaveFromEdge(); 148d2e7e355d836f18adcdb44db9c1931d1c3663ef1Jun Mukai mMouseHoveringAtEdge = false; 149d2e7e355d836f18adcdb44db9c1931d1c3663ef1Jun Mukai } 150d2e7e355d836f18adcdb44db9c1931d1c3663ef1Jun Mukai } 151d2e7e355d836f18adcdb44db9c1931d1c3663ef1Jun Mukai break; 15257306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock case MotionEvent.ACTION_UP: 15357306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock case MotionEvent.ACTION_CANCEL: 154ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock mSwipeFireable = false; 155ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock mDebugFireable = false; 1563595be4d19caaa7ddfbff0b979d135aaf5ac20b1Adrian Roos mCallbacks.onUpOrCancel(); 15757306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock break; 15857306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock default: 15957306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock if (DEBUG) Slog.d(TAG, "Ignoring " + event); 16057306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock } 16157306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock } 16257306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock 16357306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock private void captureDown(MotionEvent event, int pointerIndex) { 16457306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock final int pointerId = event.getPointerId(pointerIndex); 16557306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock final int i = findIndex(pointerId); 16657306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock if (DEBUG) Slog.d(TAG, "pointer " + pointerId + 16757306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock " down pointerIndex=" + pointerIndex + " trackingIndex=" + i); 16857306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock if (i != UNTRACKED_POINTER) { 169ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock mDownX[i] = event.getX(pointerIndex); 17057306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock mDownY[i] = event.getY(pointerIndex); 17157306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock mDownTime[i] = event.getEventTime(); 172ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock if (DEBUG) Slog.d(TAG, "pointer " + pointerId + 173ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock " down x=" + mDownX[i] + " y=" + mDownY[i]); 17457306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock } 17557306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock } 17657306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock 17757306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock private int findIndex(int pointerId) { 17857306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock for (int i = 0; i < mDownPointers; i++) { 17957306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock if (mDownPointerId[i] == pointerId) { 18057306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock return i; 18157306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock } 18257306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock } 18357306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock if (mDownPointers == MAX_TRACKED_POINTERS || pointerId == MotionEvent.INVALID_POINTER_ID) { 18457306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock return UNTRACKED_POINTER; 18557306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock } 18657306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock mDownPointerId[mDownPointers++] = pointerId; 18757306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock return mDownPointers - 1; 18857306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock } 18957306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock 190ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock private int detectSwipe(MotionEvent move) { 19157306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock final int historySize = move.getHistorySize(); 19257306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock final int pointerCount = move.getPointerCount(); 19357306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock for (int p = 0; p < pointerCount; p++) { 19457306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock final int pointerId = move.getPointerId(p); 19557306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock final int i = findIndex(pointerId); 19657306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock if (i != UNTRACKED_POINTER) { 19757306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock for (int h = 0; h < historySize; h++) { 19857306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock final long time = move.getHistoricalEventTime(h); 199ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock final float x = move.getHistoricalX(p, h); 20057306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock final float y = move.getHistoricalY(p, h); 201ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock final int swipe = detectSwipe(i, time, x, y); 202ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock if (swipe != SWIPE_NONE) { 203ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock return swipe; 20457306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock } 20557306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock } 206ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock final int swipe = detectSwipe(i, move.getEventTime(), move.getX(p), move.getY(p)); 207ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock if (swipe != SWIPE_NONE) { 208ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock return swipe; 20957306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock } 21057306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock } 21157306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock } 212ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock return SWIPE_NONE; 21357306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock } 21457306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock 215ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock private int detectSwipe(int i, long time, float x, float y) { 216ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock final float fromX = mDownX[i]; 21757306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock final float fromY = mDownY[i]; 21857306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock final long elapsed = time - mDownTime[i]; 21957306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock if (DEBUG) Slog.d(TAG, "pointer " + mDownPointerId[i] 220ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock + " moved (" + fromX + "->" + x + "," + fromY + "->" + y + ") in " + elapsed); 221ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock if (fromY <= mSwipeStartThreshold 2229ba21fdc9ddf1d132215d29054b55af416561367John Spurlock && y > fromY + mSwipeDistanceThreshold 223ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock && elapsed < SWIPE_TIMEOUT_MS) { 224ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock return SWIPE_FROM_TOP; 225ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock } 226ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock if (fromY >= screenHeight - mSwipeStartThreshold 2279ba21fdc9ddf1d132215d29054b55af416561367John Spurlock && y < fromY - mSwipeDistanceThreshold 228ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock && elapsed < SWIPE_TIMEOUT_MS) { 229ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock return SWIPE_FROM_BOTTOM; 230ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock } 231ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock if (fromX >= screenWidth - mSwipeStartThreshold 2329ba21fdc9ddf1d132215d29054b55af416561367John Spurlock && x < fromX - mSwipeDistanceThreshold 233ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock && elapsed < SWIPE_TIMEOUT_MS) { 234ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock return SWIPE_FROM_RIGHT; 235ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock } 23685d202b18ada8dc95f151087ab9778d1a31f7a30Adrian Roos if (fromX <= mSwipeStartThreshold 23785d202b18ada8dc95f151087ab9778d1a31f7a30Adrian Roos && x > fromX + mSwipeDistanceThreshold 23885d202b18ada8dc95f151087ab9778d1a31f7a30Adrian Roos && elapsed < SWIPE_TIMEOUT_MS) { 23985d202b18ada8dc95f151087ab9778d1a31f7a30Adrian Roos return SWIPE_FROM_LEFT; 24085d202b18ada8dc95f151087ab9778d1a31f7a30Adrian Roos } 241ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock return SWIPE_NONE; 24257306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock } 24357306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock 244a4d22d718affbc7145d1012157feb819557b5c06Michael Wright private final class FlingGestureDetector extends GestureDetector.SimpleOnGestureListener { 245a4d22d718affbc7145d1012157feb819557b5c06Michael Wright @Override 246a4d22d718affbc7145d1012157feb819557b5c06Michael Wright public boolean onSingleTapUp(MotionEvent e) { 247a4d22d718affbc7145d1012157feb819557b5c06Michael Wright if (!mOverscroller.isFinished()) { 248a4d22d718affbc7145d1012157feb819557b5c06Michael Wright mOverscroller.forceFinished(true); 249a4d22d718affbc7145d1012157feb819557b5c06Michael Wright } 250a4d22d718affbc7145d1012157feb819557b5c06Michael Wright return true; 251a4d22d718affbc7145d1012157feb819557b5c06Michael Wright } 252a4d22d718affbc7145d1012157feb819557b5c06Michael Wright @Override 253a4d22d718affbc7145d1012157feb819557b5c06Michael Wright public boolean onFling(MotionEvent down, MotionEvent up, 254a4d22d718affbc7145d1012157feb819557b5c06Michael Wright float velocityX, float velocityY) { 255a4d22d718affbc7145d1012157feb819557b5c06Michael Wright mOverscroller.computeScrollOffset(); 256a4d22d718affbc7145d1012157feb819557b5c06Michael Wright long now = SystemClock.uptimeMillis(); 257a4d22d718affbc7145d1012157feb819557b5c06Michael Wright 258a4d22d718affbc7145d1012157feb819557b5c06Michael Wright if (mLastFlingTime != 0 && now > mLastFlingTime + MAX_FLING_TIME_MILLIS) { 259a4d22d718affbc7145d1012157feb819557b5c06Michael Wright mOverscroller.forceFinished(true); 260a4d22d718affbc7145d1012157feb819557b5c06Michael Wright } 261a4d22d718affbc7145d1012157feb819557b5c06Michael Wright mOverscroller.fling(0, 0, (int)velocityX, (int)velocityY, 262a4d22d718affbc7145d1012157feb819557b5c06Michael Wright Integer.MIN_VALUE, Integer.MAX_VALUE, Integer.MIN_VALUE, Integer.MAX_VALUE); 263a4d22d718affbc7145d1012157feb819557b5c06Michael Wright int duration = mOverscroller.getDuration(); 264a4d22d718affbc7145d1012157feb819557b5c06Michael Wright if (duration > MAX_FLING_TIME_MILLIS) { 265a4d22d718affbc7145d1012157feb819557b5c06Michael Wright duration = MAX_FLING_TIME_MILLIS; 266a4d22d718affbc7145d1012157feb819557b5c06Michael Wright } 267a4d22d718affbc7145d1012157feb819557b5c06Michael Wright mLastFlingTime = now; 268a4d22d718affbc7145d1012157feb819557b5c06Michael Wright mCallbacks.onFling(duration); 269a4d22d718affbc7145d1012157feb819557b5c06Michael Wright return true; 270a4d22d718affbc7145d1012157feb819557b5c06Michael Wright } 271a4d22d718affbc7145d1012157feb819557b5c06Michael Wright } 272a4d22d718affbc7145d1012157feb819557b5c06Michael Wright 27357306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock interface Callbacks { 27457306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock void onSwipeFromTop(); 275ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock void onSwipeFromBottom(); 276ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock void onSwipeFromRight(); 27785d202b18ada8dc95f151087ab9778d1a31f7a30Adrian Roos void onSwipeFromLeft(); 278a4d22d718affbc7145d1012157feb819557b5c06Michael Wright void onFling(int durationMs); 2793595be4d19caaa7ddfbff0b979d135aaf5ac20b1Adrian Roos void onDown(); 2803595be4d19caaa7ddfbff0b979d135aaf5ac20b1Adrian Roos void onUpOrCancel(); 281d2e7e355d836f18adcdb44db9c1931d1c3663ef1Jun Mukai void onMouseHoverAtTop(); 282d2e7e355d836f18adcdb44db9c1931d1c3663ef1Jun Mukai void onMouseHoverAtBottom(); 283d2e7e355d836f18adcdb44db9c1931d1c3663ef1Jun Mukai void onMouseLeaveFromEdge(); 284ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock void onDebug(); 28557306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock } 28657306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock} 287