SystemGesturesPointerEventListener.java revision a4d22d718affbc7145d1012157feb819557b5c06
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; 2557306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlockimport android.view.MotionEvent; 26037aa8d434984840691378f3cc7d99d63dcc4076Craig Mautnerimport android.view.WindowManagerPolicy.PointerEventListener; 27a4d22d718affbc7145d1012157feb819557b5c06Michael Wrightimport android.widget.OverScroller; 2857306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock 2957306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock/* 3057306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock * Listens for system-wide input gestures, firing callbacks when detected. 3157306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock * @hide 3257306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock */ 33037aa8d434984840691378f3cc7d99d63dcc4076Craig Mautnerpublic class SystemGesturesPointerEventListener implements PointerEventListener { 3457306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock private static final String TAG = "SystemGestures"; 3557306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock private static final boolean DEBUG = false; 3657306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock private static final long SWIPE_TIMEOUT_MS = 500; 3757306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock private static final int MAX_TRACKED_POINTERS = 32; // max per input system 3857306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock private static final int UNTRACKED_POINTER = -1; 39a4d22d718affbc7145d1012157feb819557b5c06Michael Wright private static final int MAX_FLING_TIME_MILLIS = 5000; 4057306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock 41ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock private static final int SWIPE_NONE = 0; 42ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock private static final int SWIPE_FROM_TOP = 1; 43ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock private static final int SWIPE_FROM_BOTTOM = 2; 44ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock private static final int SWIPE_FROM_RIGHT = 3; 45ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock 46a4d22d718affbc7145d1012157feb819557b5c06Michael Wright private final Context mContext; 4757306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock private final int mSwipeStartThreshold; 489ba21fdc9ddf1d132215d29054b55af416561367John Spurlock private final int mSwipeDistanceThreshold; 4957306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock private final Callbacks mCallbacks; 5057306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock private final int[] mDownPointerId = new int[MAX_TRACKED_POINTERS]; 51ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock private final float[] mDownX = new float[MAX_TRACKED_POINTERS]; 5257306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock private final float[] mDownY = new float[MAX_TRACKED_POINTERS]; 5357306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock private final long[] mDownTime = new long[MAX_TRACKED_POINTERS]; 5457306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock 55a4d22d718affbc7145d1012157feb819557b5c06Michael Wright private GestureDetector mGestureDetector; 56a4d22d718affbc7145d1012157feb819557b5c06Michael Wright private OverScroller mOverscroller; 57a4d22d718affbc7145d1012157feb819557b5c06Michael Wright 58ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock int screenHeight; 59ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock int screenWidth; 6057306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock private int mDownPointers; 61ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock private boolean mSwipeFireable; 62ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock private boolean mDebugFireable; 63a4d22d718affbc7145d1012157feb819557b5c06Michael Wright private long mLastFlingTime; 6457306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock 65037aa8d434984840691378f3cc7d99d63dcc4076Craig Mautner public SystemGesturesPointerEventListener(Context context, Callbacks callbacks) { 66a4d22d718affbc7145d1012157feb819557b5c06Michael Wright mContext = context; 6757306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock mCallbacks = checkNull("callbacks", callbacks); 6857306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock mSwipeStartThreshold = checkNull("context", context).getResources() 6957306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock .getDimensionPixelSize(com.android.internal.R.dimen.status_bar_height); 709ba21fdc9ddf1d132215d29054b55af416561367John Spurlock mSwipeDistanceThreshold = mSwipeStartThreshold; 719ba21fdc9ddf1d132215d29054b55af416561367John Spurlock if (DEBUG) Slog.d(TAG, "mSwipeStartThreshold=" + mSwipeStartThreshold 729ba21fdc9ddf1d132215d29054b55af416561367John Spurlock + " mSwipeDistanceThreshold=" + mSwipeDistanceThreshold); 7357306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock } 7457306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock 7557306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock private static <T> T checkNull(String name, T arg) { 7657306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock if (arg == null) { 7757306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock throw new IllegalArgumentException(name + " must not be null"); 7857306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock } 7957306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock return arg; 8057306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock } 8157306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock 82a4d22d718affbc7145d1012157feb819557b5c06Michael Wright public void systemReady() { 83a4d22d718affbc7145d1012157feb819557b5c06Michael Wright Handler h = new Handler(Looper.myLooper()); 84a4d22d718affbc7145d1012157feb819557b5c06Michael Wright mGestureDetector = new GestureDetector(mContext, new FlingGestureDetector(), h); 85a4d22d718affbc7145d1012157feb819557b5c06Michael Wright mOverscroller = new OverScroller(mContext); 86a4d22d718affbc7145d1012157feb819557b5c06Michael Wright } 87a4d22d718affbc7145d1012157feb819557b5c06Michael Wright 8857306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock @Override 89037aa8d434984840691378f3cc7d99d63dcc4076Craig Mautner public void onPointerEvent(MotionEvent event) { 90a4d22d718affbc7145d1012157feb819557b5c06Michael Wright if (mGestureDetector != null) { 91a4d22d718affbc7145d1012157feb819557b5c06Michael Wright mGestureDetector.onTouchEvent(event); 92a4d22d718affbc7145d1012157feb819557b5c06Michael Wright } 9357306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock switch (event.getActionMasked()) { 9457306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock case MotionEvent.ACTION_DOWN: 95ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock mSwipeFireable = true; 96ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock mDebugFireable = true; 9757306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock mDownPointers = 0; 9857306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock captureDown(event, 0); 993595be4d19caaa7ddfbff0b979d135aaf5ac20b1Adrian Roos mCallbacks.onDown(); 10057306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock break; 10157306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock case MotionEvent.ACTION_POINTER_DOWN: 10257306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock captureDown(event, event.getActionIndex()); 103ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock if (mDebugFireable) { 104ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock mDebugFireable = event.getPointerCount() < 5; 105ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock if (!mDebugFireable) { 106ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock if (DEBUG) Slog.d(TAG, "Firing debug"); 107ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock mCallbacks.onDebug(); 108ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock } 109ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock } 11057306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock break; 11157306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock case MotionEvent.ACTION_MOVE: 112ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock if (mSwipeFireable) { 113ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock final int swipe = detectSwipe(event); 114ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock mSwipeFireable = swipe == SWIPE_NONE; 115ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock if (swipe == SWIPE_FROM_TOP) { 116ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock if (DEBUG) Slog.d(TAG, "Firing onSwipeFromTop"); 117ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock mCallbacks.onSwipeFromTop(); 118ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock } else if (swipe == SWIPE_FROM_BOTTOM) { 119ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock if (DEBUG) Slog.d(TAG, "Firing onSwipeFromBottom"); 120ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock mCallbacks.onSwipeFromBottom(); 121ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock } else if (swipe == SWIPE_FROM_RIGHT) { 122ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock if (DEBUG) Slog.d(TAG, "Firing onSwipeFromRight"); 123ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock mCallbacks.onSwipeFromRight(); 124ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock } 12557306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock } 12657306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock break; 12757306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock case MotionEvent.ACTION_UP: 12857306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock case MotionEvent.ACTION_CANCEL: 129ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock mSwipeFireable = false; 130ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock mDebugFireable = false; 1313595be4d19caaa7ddfbff0b979d135aaf5ac20b1Adrian Roos mCallbacks.onUpOrCancel(); 13257306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock break; 13357306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock default: 13457306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock if (DEBUG) Slog.d(TAG, "Ignoring " + event); 13557306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock } 13657306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock } 13757306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock 13857306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock private void captureDown(MotionEvent event, int pointerIndex) { 13957306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock final int pointerId = event.getPointerId(pointerIndex); 14057306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock final int i = findIndex(pointerId); 14157306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock if (DEBUG) Slog.d(TAG, "pointer " + pointerId + 14257306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock " down pointerIndex=" + pointerIndex + " trackingIndex=" + i); 14357306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock if (i != UNTRACKED_POINTER) { 144ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock mDownX[i] = event.getX(pointerIndex); 14557306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock mDownY[i] = event.getY(pointerIndex); 14657306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock mDownTime[i] = event.getEventTime(); 147ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock if (DEBUG) Slog.d(TAG, "pointer " + pointerId + 148ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock " down x=" + mDownX[i] + " y=" + mDownY[i]); 14957306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock } 15057306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock } 15157306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock 15257306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock private int findIndex(int pointerId) { 15357306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock for (int i = 0; i < mDownPointers; i++) { 15457306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock if (mDownPointerId[i] == pointerId) { 15557306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock return i; 15657306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock } 15757306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock } 15857306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock if (mDownPointers == MAX_TRACKED_POINTERS || pointerId == MotionEvent.INVALID_POINTER_ID) { 15957306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock return UNTRACKED_POINTER; 16057306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock } 16157306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock mDownPointerId[mDownPointers++] = pointerId; 16257306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock return mDownPointers - 1; 16357306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock } 16457306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock 165ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock private int detectSwipe(MotionEvent move) { 16657306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock final int historySize = move.getHistorySize(); 16757306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock final int pointerCount = move.getPointerCount(); 16857306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock for (int p = 0; p < pointerCount; p++) { 16957306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock final int pointerId = move.getPointerId(p); 17057306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock final int i = findIndex(pointerId); 17157306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock if (i != UNTRACKED_POINTER) { 17257306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock for (int h = 0; h < historySize; h++) { 17357306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock final long time = move.getHistoricalEventTime(h); 174ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock final float x = move.getHistoricalX(p, h); 17557306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock final float y = move.getHistoricalY(p, h); 176ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock final int swipe = detectSwipe(i, time, x, y); 177ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock if (swipe != SWIPE_NONE) { 178ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock return swipe; 17957306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock } 18057306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock } 181ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock final int swipe = detectSwipe(i, move.getEventTime(), move.getX(p), move.getY(p)); 182ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock if (swipe != SWIPE_NONE) { 183ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock return swipe; 18457306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock } 18557306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock } 18657306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock } 187ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock return SWIPE_NONE; 18857306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock } 18957306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock 190ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock private int detectSwipe(int i, long time, float x, float y) { 191ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock final float fromX = mDownX[i]; 19257306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock final float fromY = mDownY[i]; 19357306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock final long elapsed = time - mDownTime[i]; 19457306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock if (DEBUG) Slog.d(TAG, "pointer " + mDownPointerId[i] 195ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock + " moved (" + fromX + "->" + x + "," + fromY + "->" + y + ") in " + elapsed); 196ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock if (fromY <= mSwipeStartThreshold 1979ba21fdc9ddf1d132215d29054b55af416561367John Spurlock && y > fromY + mSwipeDistanceThreshold 198ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock && elapsed < SWIPE_TIMEOUT_MS) { 199ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock return SWIPE_FROM_TOP; 200ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock } 201ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock if (fromY >= screenHeight - mSwipeStartThreshold 2029ba21fdc9ddf1d132215d29054b55af416561367John Spurlock && y < fromY - mSwipeDistanceThreshold 203ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock && elapsed < SWIPE_TIMEOUT_MS) { 204ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock return SWIPE_FROM_BOTTOM; 205ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock } 206ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock if (fromX >= screenWidth - mSwipeStartThreshold 2079ba21fdc9ddf1d132215d29054b55af416561367John Spurlock && x < fromX - mSwipeDistanceThreshold 208ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock && elapsed < SWIPE_TIMEOUT_MS) { 209ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock return SWIPE_FROM_RIGHT; 210ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock } 211ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock return SWIPE_NONE; 21257306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock } 21357306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock 214a4d22d718affbc7145d1012157feb819557b5c06Michael Wright private final class FlingGestureDetector extends GestureDetector.SimpleOnGestureListener { 215a4d22d718affbc7145d1012157feb819557b5c06Michael Wright @Override 216a4d22d718affbc7145d1012157feb819557b5c06Michael Wright public boolean onSingleTapUp(MotionEvent e) { 217a4d22d718affbc7145d1012157feb819557b5c06Michael Wright if (!mOverscroller.isFinished()) { 218a4d22d718affbc7145d1012157feb819557b5c06Michael Wright mOverscroller.forceFinished(true); 219a4d22d718affbc7145d1012157feb819557b5c06Michael Wright } 220a4d22d718affbc7145d1012157feb819557b5c06Michael Wright return true; 221a4d22d718affbc7145d1012157feb819557b5c06Michael Wright } 222a4d22d718affbc7145d1012157feb819557b5c06Michael Wright @Override 223a4d22d718affbc7145d1012157feb819557b5c06Michael Wright public boolean onFling(MotionEvent down, MotionEvent up, 224a4d22d718affbc7145d1012157feb819557b5c06Michael Wright float velocityX, float velocityY) { 225a4d22d718affbc7145d1012157feb819557b5c06Michael Wright mOverscroller.computeScrollOffset(); 226a4d22d718affbc7145d1012157feb819557b5c06Michael Wright long now = SystemClock.uptimeMillis(); 227a4d22d718affbc7145d1012157feb819557b5c06Michael Wright 228a4d22d718affbc7145d1012157feb819557b5c06Michael Wright if (mLastFlingTime != 0 && now > mLastFlingTime + MAX_FLING_TIME_MILLIS) { 229a4d22d718affbc7145d1012157feb819557b5c06Michael Wright mOverscroller.forceFinished(true); 230a4d22d718affbc7145d1012157feb819557b5c06Michael Wright } 231a4d22d718affbc7145d1012157feb819557b5c06Michael Wright mOverscroller.fling(0, 0, (int)velocityX, (int)velocityY, 232a4d22d718affbc7145d1012157feb819557b5c06Michael Wright Integer.MIN_VALUE, Integer.MAX_VALUE, Integer.MIN_VALUE, Integer.MAX_VALUE); 233a4d22d718affbc7145d1012157feb819557b5c06Michael Wright int duration = mOverscroller.getDuration(); 234a4d22d718affbc7145d1012157feb819557b5c06Michael Wright if (duration > MAX_FLING_TIME_MILLIS) { 235a4d22d718affbc7145d1012157feb819557b5c06Michael Wright duration = MAX_FLING_TIME_MILLIS; 236a4d22d718affbc7145d1012157feb819557b5c06Michael Wright } 237a4d22d718affbc7145d1012157feb819557b5c06Michael Wright mLastFlingTime = now; 238a4d22d718affbc7145d1012157feb819557b5c06Michael Wright mCallbacks.onFling(duration); 239a4d22d718affbc7145d1012157feb819557b5c06Michael Wright return true; 240a4d22d718affbc7145d1012157feb819557b5c06Michael Wright } 241a4d22d718affbc7145d1012157feb819557b5c06Michael Wright } 242a4d22d718affbc7145d1012157feb819557b5c06Michael Wright 24357306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock interface Callbacks { 24457306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock void onSwipeFromTop(); 245ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock void onSwipeFromBottom(); 246ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock void onSwipeFromRight(); 247a4d22d718affbc7145d1012157feb819557b5c06Michael Wright void onFling(int durationMs); 2483595be4d19caaa7ddfbff0b979d135aaf5ac20b1Adrian Roos void onDown(); 2493595be4d19caaa7ddfbff0b979d135aaf5ac20b1Adrian Roos void onUpOrCancel(); 250ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock void onDebug(); 25157306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock } 25257306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock} 253