SystemGesturesPointerEventListener.java revision 3595be4d19caaa7ddfbff0b979d135aaf5ac20b1
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;
2057306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlockimport android.util.Slog;
2157306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlockimport android.view.MotionEvent;
22037aa8d434984840691378f3cc7d99d63dcc4076Craig Mautnerimport android.view.WindowManagerPolicy.PointerEventListener;
2357306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock
2457306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock/*
2557306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock * Listens for system-wide input gestures, firing callbacks when detected.
2657306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock * @hide
2757306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock */
28037aa8d434984840691378f3cc7d99d63dcc4076Craig Mautnerpublic class SystemGesturesPointerEventListener implements PointerEventListener {
2957306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock    private static final String TAG = "SystemGestures";
3057306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock    private static final boolean DEBUG = false;
3157306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock    private static final long SWIPE_TIMEOUT_MS = 500;
3257306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock    private static final int MAX_TRACKED_POINTERS = 32;  // max per input system
3357306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock    private static final int UNTRACKED_POINTER = -1;
3457306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock
35ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock    private static final int SWIPE_NONE = 0;
36ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock    private static final int SWIPE_FROM_TOP = 1;
37ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock    private static final int SWIPE_FROM_BOTTOM = 2;
38ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock    private static final int SWIPE_FROM_RIGHT = 3;
39ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock
4057306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock    private final int mSwipeStartThreshold;
419ba21fdc9ddf1d132215d29054b55af416561367John Spurlock    private final int mSwipeDistanceThreshold;
4257306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock    private final Callbacks mCallbacks;
4357306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock    private final int[] mDownPointerId = new int[MAX_TRACKED_POINTERS];
44ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock    private final float[] mDownX = new float[MAX_TRACKED_POINTERS];
4557306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock    private final float[] mDownY = new float[MAX_TRACKED_POINTERS];
4657306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock    private final long[] mDownTime = new long[MAX_TRACKED_POINTERS];
4757306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock
48ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock    int screenHeight;
49ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock    int screenWidth;
5057306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock    private int mDownPointers;
51ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock    private boolean mSwipeFireable;
52ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock    private boolean mDebugFireable;
5357306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock
54037aa8d434984840691378f3cc7d99d63dcc4076Craig Mautner    public SystemGesturesPointerEventListener(Context context, Callbacks callbacks) {
5557306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock        mCallbacks = checkNull("callbacks", callbacks);
5657306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock        mSwipeStartThreshold = checkNull("context", context).getResources()
5757306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock                .getDimensionPixelSize(com.android.internal.R.dimen.status_bar_height);
589ba21fdc9ddf1d132215d29054b55af416561367John Spurlock        mSwipeDistanceThreshold = mSwipeStartThreshold;
599ba21fdc9ddf1d132215d29054b55af416561367John Spurlock        if (DEBUG) Slog.d(TAG,  "mSwipeStartThreshold=" + mSwipeStartThreshold
609ba21fdc9ddf1d132215d29054b55af416561367John Spurlock                + " mSwipeDistanceThreshold=" + mSwipeDistanceThreshold);
6157306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock    }
6257306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock
6357306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock    private static <T> T checkNull(String name, T arg) {
6457306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock        if (arg == null) {
6557306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock            throw new IllegalArgumentException(name + " must not be null");
6657306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock        }
6757306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock        return arg;
6857306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock    }
6957306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock
7057306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock    @Override
71037aa8d434984840691378f3cc7d99d63dcc4076Craig Mautner    public void onPointerEvent(MotionEvent event) {
7257306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock        switch (event.getActionMasked()) {
7357306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock            case MotionEvent.ACTION_DOWN:
74ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock                mSwipeFireable = true;
75ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock                mDebugFireable = true;
7657306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock                mDownPointers = 0;
7757306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock                captureDown(event, 0);
783595be4d19caaa7ddfbff0b979d135aaf5ac20b1Adrian Roos                mCallbacks.onDown();
7957306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock                break;
8057306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock            case MotionEvent.ACTION_POINTER_DOWN:
8157306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock                captureDown(event, event.getActionIndex());
82ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock                if (mDebugFireable) {
83ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock                    mDebugFireable = event.getPointerCount() < 5;
84ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock                    if (!mDebugFireable) {
85ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock                        if (DEBUG) Slog.d(TAG, "Firing debug");
86ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock                        mCallbacks.onDebug();
87ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock                    }
88ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock                }
8957306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock                break;
9057306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock            case MotionEvent.ACTION_MOVE:
91ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock                if (mSwipeFireable) {
92ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock                    final int swipe = detectSwipe(event);
93ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock                    mSwipeFireable = swipe == SWIPE_NONE;
94ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock                    if (swipe == SWIPE_FROM_TOP) {
95ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock                        if (DEBUG) Slog.d(TAG, "Firing onSwipeFromTop");
96ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock                        mCallbacks.onSwipeFromTop();
97ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock                    } else if (swipe == SWIPE_FROM_BOTTOM) {
98ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock                        if (DEBUG) Slog.d(TAG, "Firing onSwipeFromBottom");
99ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock                        mCallbacks.onSwipeFromBottom();
100ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock                    } else if (swipe == SWIPE_FROM_RIGHT) {
101ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock                        if (DEBUG) Slog.d(TAG, "Firing onSwipeFromRight");
102ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock                        mCallbacks.onSwipeFromRight();
103ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock                    }
10457306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock                }
10557306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock                break;
10657306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock            case MotionEvent.ACTION_UP:
10757306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock            case MotionEvent.ACTION_CANCEL:
108ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock                mSwipeFireable = false;
109ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock                mDebugFireable = false;
1103595be4d19caaa7ddfbff0b979d135aaf5ac20b1Adrian Roos                mCallbacks.onUpOrCancel();
11157306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock                break;
11257306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock            default:
11357306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock                if (DEBUG) Slog.d(TAG, "Ignoring " + event);
11457306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock        }
11557306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock    }
11657306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock
11757306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock    private void captureDown(MotionEvent event, int pointerIndex) {
11857306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock        final int pointerId = event.getPointerId(pointerIndex);
11957306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock        final int i = findIndex(pointerId);
12057306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock        if (DEBUG) Slog.d(TAG, "pointer " + pointerId +
12157306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock                " down pointerIndex=" + pointerIndex + " trackingIndex=" + i);
12257306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock        if (i != UNTRACKED_POINTER) {
123ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock            mDownX[i] = event.getX(pointerIndex);
12457306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock            mDownY[i] = event.getY(pointerIndex);
12557306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock            mDownTime[i] = event.getEventTime();
126ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock            if (DEBUG) Slog.d(TAG, "pointer " + pointerId +
127ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock                    " down x=" + mDownX[i] + " y=" + mDownY[i]);
12857306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock        }
12957306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock    }
13057306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock
13157306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock    private int findIndex(int pointerId) {
13257306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock        for (int i = 0; i < mDownPointers; i++) {
13357306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock            if (mDownPointerId[i] == pointerId) {
13457306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock                return i;
13557306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock            }
13657306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock        }
13757306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock        if (mDownPointers == MAX_TRACKED_POINTERS || pointerId == MotionEvent.INVALID_POINTER_ID) {
13857306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock            return UNTRACKED_POINTER;
13957306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock        }
14057306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock        mDownPointerId[mDownPointers++] = pointerId;
14157306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock        return mDownPointers - 1;
14257306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock    }
14357306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock
144ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock    private int detectSwipe(MotionEvent move) {
14557306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock        final int historySize = move.getHistorySize();
14657306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock        final int pointerCount = move.getPointerCount();
14757306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock        for (int p = 0; p < pointerCount; p++) {
14857306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock            final int pointerId = move.getPointerId(p);
14957306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock            final int i = findIndex(pointerId);
15057306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock            if (i != UNTRACKED_POINTER) {
15157306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock                for (int h = 0; h < historySize; h++) {
15257306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock                    final long time = move.getHistoricalEventTime(h);
153ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock                    final float x = move.getHistoricalX(p, h);
15457306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock                    final float y = move.getHistoricalY(p,  h);
155ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock                    final int swipe = detectSwipe(i, time, x, y);
156ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock                    if (swipe != SWIPE_NONE) {
157ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock                        return swipe;
15857306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock                    }
15957306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock                }
160ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock                final int swipe = detectSwipe(i, move.getEventTime(), move.getX(p), move.getY(p));
161ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock                if (swipe != SWIPE_NONE) {
162ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock                    return swipe;
16357306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock                }
16457306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock            }
16557306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock        }
166ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock        return SWIPE_NONE;
16757306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock    }
16857306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock
169ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock    private int detectSwipe(int i, long time, float x, float y) {
170ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock        final float fromX = mDownX[i];
17157306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock        final float fromY = mDownY[i];
17257306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock        final long elapsed = time - mDownTime[i];
17357306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock        if (DEBUG) Slog.d(TAG, "pointer " + mDownPointerId[i]
174ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock                + " moved (" + fromX + "->" + x + "," + fromY + "->" + y + ") in " + elapsed);
175ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock        if (fromY <= mSwipeStartThreshold
1769ba21fdc9ddf1d132215d29054b55af416561367John Spurlock                && y > fromY + mSwipeDistanceThreshold
177ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock                && elapsed < SWIPE_TIMEOUT_MS) {
178ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock            return SWIPE_FROM_TOP;
179ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock        }
180ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock        if (fromY >= screenHeight - mSwipeStartThreshold
1819ba21fdc9ddf1d132215d29054b55af416561367John Spurlock                && y < fromY - mSwipeDistanceThreshold
182ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock                && elapsed < SWIPE_TIMEOUT_MS) {
183ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock            return SWIPE_FROM_BOTTOM;
184ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock        }
185ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock        if (fromX >= screenWidth - mSwipeStartThreshold
1869ba21fdc9ddf1d132215d29054b55af416561367John Spurlock                && x < fromX - mSwipeDistanceThreshold
187ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock                && elapsed < SWIPE_TIMEOUT_MS) {
188ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock            return SWIPE_FROM_RIGHT;
189ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock        }
190ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock        return SWIPE_NONE;
19157306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock    }
19257306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock
19357306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock    interface Callbacks {
19457306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock        void onSwipeFromTop();
195ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock        void onSwipeFromBottom();
196ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock        void onSwipeFromRight();
1973595be4d19caaa7ddfbff0b979d135aaf5ac20b1Adrian Roos        void onDown();
1983595be4d19caaa7ddfbff0b979d135aaf5ac20b1Adrian Roos        void onUpOrCancel();
199ad3e6cb4db99ad33fcfc61f236d37cd83446866dJohn Spurlock        void onDebug();
20057306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock    }
20157306e6b79a87518b5739fc5717cd1cd47c75eaeJohn Spurlock}
202