summaryrefslogtreecommitdiffstats
path: root/remoting
diff options
context:
space:
mode:
authorlambroslambrou@chromium.org <lambroslambrou@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-11-01 11:52:58 +0000
committerlambroslambrou@chromium.org <lambroslambrou@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-11-01 11:52:58 +0000
commit99ab575fea9f14dab8bf92a7a402be8a79a6e87a (patch)
tree4cb29ae5d604f88725c0e50ccbd98576bb62e3e9 /remoting
parentb796c34f3ff3ff161acb7e36665225f6807ad4c1 (diff)
downloadchromium_src-99ab575fea9f14dab8bf92a7a402be8a79a6e87a.zip
chromium_src-99ab575fea9f14dab8bf92a7a402be8a79a6e87a.tar.gz
chromium_src-99ab575fea9f14dab8bf92a7a402be8a79a6e87a.tar.bz2
[Android Chromoting] Gesture detector for multiple-finger tap events.
This adds a gesture-detector for recognizing taps with multiple fingers, which simplifies the TrackingInputHandler implementation and makes tap-detection more robust. BUG=270348 Review URL: https://codereview.chromium.org/51463004 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@232333 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'remoting')
-rw-r--r--remoting/android/java/src/org/chromium/chromoting/TapGestureDetector.java151
-rw-r--r--remoting/android/java/src/org/chromium/chromoting/TrackingInputHandler.java89
2 files changed, 178 insertions, 62 deletions
diff --git a/remoting/android/java/src/org/chromium/chromoting/TapGestureDetector.java b/remoting/android/java/src/org/chromium/chromoting/TapGestureDetector.java
new file mode 100644
index 0000000..c0c2843
--- /dev/null
+++ b/remoting/android/java/src/org/chromium/chromoting/TapGestureDetector.java
@@ -0,0 +1,151 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chromoting;
+
+import android.content.Context;
+import android.graphics.PointF;
+import android.util.Log;
+import android.view.MotionEvent;
+import android.view.ViewConfiguration;
+
+import java.util.HashMap;
+
+/**
+ * This class detects multi-finger tap events. This is provided since the stock Android
+ * gesture-detectors only detect taps made with one finger.
+ */
+public class TapGestureDetector {
+ /** The listener for receiving notifications of tap gestures. */
+ public interface OnTapListener {
+ /**
+ * Notified when a tap event occurs.
+ *
+ * @param pointerCount The number of fingers that were tapped.
+ * @return True if the event is consumed.
+ */
+ boolean onTap(int pointerCount);
+ }
+
+ /** The listener to which notifications are sent. */
+ private OnTapListener mListener;
+
+ /** The maximum number of fingers seen in the gesture. */
+ private int mPointerCount = 0;
+
+ /**
+ * Stores the location of each down MotionEvent (by pointer ID), for detecting motion of any
+ * pointer beyond the TouchSlop region.
+ */
+ private HashMap<Integer, PointF> mInitialPositions = new HashMap<Integer, PointF>();
+
+ /**
+ * Threshold squared-distance, in pixels, to use for motion-detection. If a finger moves less
+ * than this distance, the gesture is still eligible to be a tap event.
+ */
+ private int mTouchSlopSquare;
+
+ /** Set to true whenever motion is detected in the gesture. */
+ private boolean mMotionOccurred = false;
+
+ public TapGestureDetector(Context context, OnTapListener listener) {
+ mListener = listener;
+ ViewConfiguration config = ViewConfiguration.get(context);
+ int touchSlop = config.getScaledTouchSlop();
+ mTouchSlopSquare = touchSlop * touchSlop;
+ }
+
+ /** Analyzes the touch event to determine whether to notify the listener. */
+ public boolean onTouchEvent(MotionEvent event) {
+ boolean handled = false;
+ switch (event.getActionMasked()) {
+ case MotionEvent.ACTION_DOWN:
+ case MotionEvent.ACTION_POINTER_DOWN:
+ trackDownEvent(event);
+ mPointerCount = Math.max(mPointerCount, event.getPointerCount());
+ break;
+
+ case MotionEvent.ACTION_MOVE:
+ if (!mMotionOccurred) {
+ mMotionOccurred = trackMoveEvent(event);
+ }
+ break;
+
+ case MotionEvent.ACTION_UP:
+ if (!mMotionOccurred) {
+ handled = mListener.onTap(mPointerCount);
+ }
+ reset();
+ break;
+
+ case MotionEvent.ACTION_POINTER_UP:
+ trackUpEvent(event);
+ break;
+
+ case MotionEvent.ACTION_CANCEL:
+ reset();
+ break;
+
+ default:
+ break;
+ }
+ return handled;
+ }
+
+ /** Stores the location of the ACTION_DOWN or ACTION_POINTER_DOWN event. */
+ private void trackDownEvent(MotionEvent event) {
+ int pointerIndex = 0;
+ if (event.getActionMasked() == MotionEvent.ACTION_POINTER_DOWN) {
+ pointerIndex = event.getActionIndex();
+ }
+ int pointerId = event.getPointerId(pointerIndex);
+ mInitialPositions.put(pointerId,
+ new PointF(event.getX(pointerIndex), event.getY(pointerIndex)));
+ }
+
+ /** Removes the ACTION_UP or ACTION_POINTER_UP event from the stored list. */
+ private void trackUpEvent(MotionEvent event) {
+ int pointerIndex = 0;
+ if (event.getActionMasked() == MotionEvent.ACTION_POINTER_UP) {
+ pointerIndex = event.getActionIndex();
+ }
+ int pointerId = event.getPointerId(pointerIndex);
+ mInitialPositions.remove(pointerId);
+ }
+
+ /**
+ * Processes an ACTION_MOVE event and returns whether a pointer moved beyond the TouchSlop
+ * threshold.
+ *
+ * @return True if motion was detected.
+ */
+ private boolean trackMoveEvent(MotionEvent event) {
+ int pointerCount = event.getPointerCount();
+ for (int i = 0; i < pointerCount; i++) {
+ int pointerId = event.getPointerId(i);
+ float currentX = event.getX(i);
+ float currentY = event.getY(i);
+ PointF downPoint = mInitialPositions.get(pointerId);
+ if (downPoint == null) {
+ // There was no corresponding DOWN event, so add it. This is an inconsistency
+ // which shouldn't normally occur.
+ mInitialPositions.put(pointerId, new PointF(currentX, currentY));
+ continue;
+ }
+ float deltaX = currentX - downPoint.x;
+ float deltaY = currentY - downPoint.y;
+ if (deltaX * deltaX + deltaY * deltaY > mTouchSlopSquare) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /** Cleans up any stored data for the gesture. */
+ private void reset() {
+ mPointerCount = 0;
+ mInitialPositions.clear();
+ mMotionOccurred = false;
+ }
+}
diff --git a/remoting/android/java/src/org/chromium/chromoting/TrackingInputHandler.java b/remoting/android/java/src/org/chromium/chromoting/TrackingInputHandler.java
index e7500d8..537f5aa 100644
--- a/remoting/android/java/src/org/chromium/chromoting/TrackingInputHandler.java
+++ b/remoting/android/java/src/org/chromium/chromoting/TrackingInputHandler.java
@@ -32,6 +32,7 @@ public class TrackingInputHandler implements TouchInputHandler {
private GestureDetector mScroller;
private ScaleGestureDetector mZoomer;
+ private TapGestureDetector mTapDetector;
/**
* The current cursor position is stored here as floats, so that the desktop image can be
@@ -39,16 +40,6 @@ public class TrackingInputHandler implements TouchInputHandler {
*/
private PointF mCursorPosition;
- private int mMouseButton;
-
- /**
- * Distinguish between finger tap and swipe. One-finger down then up should inject a
- * left-click event. But if the finger is dragged before being released, this should move
- * the cursor without injecting any button event. This flag is set when a motion event is
- * detected.
- */
- private boolean mFingerMoved = false;
-
public TrackingInputHandler(DesktopViewInterface viewer, Context context,
RenderData renderData) {
mViewer = viewer;
@@ -64,11 +55,9 @@ public class TrackingInputHandler implements TouchInputHandler {
mScroller.setIsLongpressEnabled(false);
mZoomer = new ScaleGestureDetector(context, listener);
+ mTapDetector = new TapGestureDetector(context, listener);
mCursorPosition = new PointF();
-
- mMouseButton = BUTTON_UNDEFINED;
- mFingerMoved = false;
}
/**
@@ -190,52 +179,7 @@ public class TrackingInputHandler implements TouchInputHandler {
// that they generate correct notifications.
boolean handled = mScroller.onTouchEvent(event);
handled = mZoomer.onTouchEvent(event) || handled;
-
- int pointerCount = event.getPointerCount();
-
- switch (event.getActionMasked()) {
- case MotionEvent.ACTION_DOWN:
- case MotionEvent.ACTION_POINTER_DOWN:
- switch (pointerCount) {
- case 1:
- mFingerMoved = false;
- mMouseButton = BUTTON_LEFT;
- break;
- case 2:
- mMouseButton = BUTTON_RIGHT;
- break;
- case 3:
- mMouseButton = BUTTON_UNDEFINED;
- // TODO(lambroslambrou): Add 3-finger-tap for middle-click, and use 3-finger
- // swipe to show the action-bar or keyboard.
- break;
- default:
- break;
- }
- break;
- case MotionEvent.ACTION_UP:
- if (mFingerMoved) {
- // Don't inject anything.
- mFingerMoved = false;
- } else {
- // The user pressed and released without moving. Inject a click event for a
- // mouse button according to how many fingers were used.
- injectButtonEvent(mMouseButton, true);
- injectButtonEvent(mMouseButton, false);
- handled = true;
- }
- break;
- case MotionEvent.ACTION_POINTER_UP:
- // |pointerCount| is the number of fingers that were on the screen prior to the UP
- // event.
- if (pointerCount == 3) {
- mViewer.showActionBar();
- handled = true;
- }
- break;
- default:
- break;
- }
+ handled = mTapDetector.onTouchEvent(event) || handled;
return handled;
}
@@ -256,7 +200,8 @@ public class TrackingInputHandler implements TouchInputHandler {
/** Responds to touch events filtered by the gesture detectors. */
private class GestureListener extends GestureDetector.SimpleOnGestureListener
- implements ScaleGestureDetector.OnScaleGestureListener {
+ implements ScaleGestureDetector.OnScaleGestureListener,
+ TapGestureDetector.OnTapListener {
/**
* Called when the user drags one or more fingers across the touchscreen.
*/
@@ -265,7 +210,6 @@ public class TrackingInputHandler implements TouchInputHandler {
if (e2.getPointerCount() != 1) {
return false;
}
- mFingerMoved = true;
float[] delta = {distanceX, distanceY};
synchronized (mRenderData) {
@@ -284,7 +228,6 @@ public class TrackingInputHandler implements TouchInputHandler {
if (Math.abs(detector.getScaleFactor() - 1) < MIN_ZOOM_DELTA) {
return false;
}
- mFingerMoved = true;
float scaleFactor = detector.getScaleFactor();
synchronized (mRenderData) {
@@ -315,5 +258,27 @@ public class TrackingInputHandler implements TouchInputHandler {
public void onScaleEnd(ScaleGestureDetector detector) {
onScale(detector);
}
+
+ /** Called when the user taps the screen with one or more fingers. */
+ @Override
+ public boolean onTap(int pointerCount) {
+ switch (pointerCount) {
+ case 1:
+ injectButtonEvent(BUTTON_LEFT, true);
+ injectButtonEvent(BUTTON_LEFT, false);
+ return true;
+ case 2:
+ injectButtonEvent(BUTTON_RIGHT, true);
+ injectButtonEvent(BUTTON_RIGHT, false);
+ return true;
+ case 3:
+ // TODO(lambroslambrou): Add 3-finger-tap for middle-click, and use 3-finger
+ // swipe to show the action-bar or keyboard.
+ mViewer.showActionBar();
+ return true;
+ default:
+ return false;
+ }
+ }
}
}