Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(293)

Side by Side Diff: remoting/android/java/src/org/chromium/chromoting/InputMonitor.java

Issue 2097273002: [Chromoting] Add InputMonitor and InputState (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 4 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 package org.chromium.chromoting;
6
7 import android.content.Context;
8 import android.graphics.Rect;
9 import android.view.GestureDetector;
10 import android.view.MotionEvent;
11 import android.view.ScaleGestureDetector;
12 import android.view.ViewConfiguration;
13
14 import org.chromium.base.VisibleForTesting;
15 import org.chromium.chromoting.InputState.DetectedAction;
16 import org.chromium.chromoting.InputState.StartAction;
17
18 /**
19 * A combination of existing Android and chromium motion and touch detectors, an d provide a set of
20 * {@link Event} when each kind of touch behavior has been detected.
21 */
22 public final class InputMonitor
23 implements GestureDetector.OnGestureListener,
24 ScaleGestureDetector.OnScaleGestureListener,
25 TapGestureDetector.OnTapListener {
26 /** Tap with one or more fingers. */
27 private final Event.Raisable<TapEventParameter> mOnTap;
28
29 /** Long press and hold with one or more fingers. */
30 private final Event.Raisable<TapEventParameter> mOnPressAndHold;
31
32 /** Any motion event received. */
33 private final Event.Raisable<MotionEvent> mOnTouchEvent;
34
35 /** Scroll with two fingers. */
36 private final Event.Raisable<TwoPointsEventParameter> mOnScroll;
37
38 /** Fling with two fingers. */
39 private final Event.Raisable<TwoPointsEventParameter> mOnScrollFling;
40
41 /** Fling with one finger. */
42 private final Event.Raisable<TwoPointsEventParameter> mOnFling;
43
44 /** Scale with two fingers. */
45 private final Event.Raisable<ScaleEventParameter> mOnScale;
46
47 /** Swipe with three or more fingers. */
48 private final Event.Raisable<TwoPointsEventParameter> mOnSwipe;
49
50 /** Move with one finger. */
51 private final Event.Raisable<TwoPointsEventParameter> mOnMove;
52
53 private final InputState.Settable mInputState;
54 private final int mEdgeSlopInPx;
55 private final float mSwipeThreshold;
56 private final GestureDetector mScroller;
57 private final ScaleGestureDetector mZoomer;
58 private final TapGestureDetector mTapDetector;
59 private final SwipePinchDetector mSwipePinchDetector;
60
61 // Controls whether InputMonitor treats a scrolling with four or more finger s as a swipe.
62 // TouchInputHandler treats a gesture with three fingers as a swipe. To make sure we can easily
Lambros 2016/07/14 18:58:07 I don't see the need for this flag and I don't thi
Hzj_jie 2016/07/14 23:18:06 Personally I think swiping with three or four fing
63 // test the differences between TouchInputHandler and InputMonitor, we can s et this variable to
Lambros 2016/07/14 18:58:07 Also, better to avoid flags that make code behave
Hzj_jie 2016/07/14 23:18:06 Done.
64 // false to force InputMonitor to behave consistently as TouchInputHandler.
65 private final boolean mSwipeWithMoreFingers;
66
67 private Rect mPanGestureBounds;
68
69 @VisibleForTesting
70 InputMonitor(DesktopViewInterface view, Context context, boolean swipeWithMo reFingers) {
71 mOnTap = new Event.Raisable<>();
72 mOnPressAndHold = new Event.Raisable<>();
73 mOnTouchEvent = new Event.Raisable<>();
74 mOnScroll = new Event.Raisable<>();
75 mOnScrollFling = new Event.Raisable<>();
76 mOnFling = new Event.Raisable<>();
77 mOnScale = new Event.Raisable<>();
78 mOnSwipe = new Event.Raisable<>();
79 mOnMove = new Event.Raisable<>();
80 mInputState = new InputState.Settable();
81 mEdgeSlopInPx = ViewConfiguration.get(context).getScaledEdgeSlop();
82 mSwipeThreshold = 40 * context.getResources().getDisplayMetrics().densit y;
83 mScroller = new GestureDetector(context, this, null, false);
84 mScroller.setIsLongpressEnabled(false);
85 mZoomer = new ScaleGestureDetector(context, this);
86 mTapDetector = new TapGestureDetector(context, this);
87 mSwipePinchDetector = new SwipePinchDetector(context);
88 view.onClientSizeChanged().add(
89 new Event.ParameterRunnable<SizeChangedEventParameter>() {
90 @Override
91 public void run(SizeChangedEventParameter param) {
92 handleClientSizeChanged(param);
93 }
94 });
95 // Currently we support only touch events.
96 view.onTouch().add(
97 new Event.ParameterRunnable<TouchEventParameter>() {
98 @Override
99 public void run(TouchEventParameter param) {
100 handleTouch(param);
101 }
102 });
103 mSwipeWithMoreFingers = swipeWithMoreFingers;
104 }
105
106 public InputMonitor(DesktopViewInterface view, Context context) {
107 this(view, context, true);
108 }
109
110 // -------------- Getters -------------------------------------------------- -----------
111 public Event<TapEventParameter> onTap() {
112 return mOnTap;
113 }
114
115 public Event<TapEventParameter> onPressAndHold() {
116 return mOnPressAndHold;
117 }
118
119 public Event<MotionEvent> onTouchEvent() {
120 return mOnTouchEvent;
121 }
122
123 public Event<TwoPointsEventParameter> onScroll() {
124 return mOnScroll;
125 }
126
127 public Event<TwoPointsEventParameter> onScrollFling() {
128 return mOnScrollFling;
129 }
130
131 public Event<TwoPointsEventParameter> onFling() {
132 return mOnFling;
133 }
134
135 public Event<ScaleEventParameter> onScale() {
136 return mOnScale;
137 }
138
139 public Event<TwoPointsEventParameter> onSwipe() {
140 return mOnSwipe;
141 }
142
143 public Event<TwoPointsEventParameter> onMove() {
144 return mOnMove;
145 }
146
147 public InputState inputState() {
148 return mInputState;
149 }
150
151 // -------------- Implementations of GestureDetector.OnGestureListener ----- -----------
152
153 /** Called whenever a gesture starts. Always accepts the gesture so it isn't ignored. */
154 @Override
155 public boolean onDown(MotionEvent e) {
156 return true;
157 }
158
159 /** Called when a fling gesture is recognized. */
160 @Override
161 public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, floa t velocityY) {
162 if (mInputState.suppressFling()) {
163 return false;
164 }
165
166 if (mInputState.scrollFling()) {
167 mInputState.setDetectedAction(DetectedAction.AFTER_SCROLL_FLING);
168 mOnScrollFling.raise(new TwoPointsEventParameter(e1, e2, velocityX, velocityY));
169 return true;
170 }
171
172 if (mInputState.suppressCursorMovement()) {
173 return false;
174 }
175
176 mInputState.setDetectedAction(DetectedAction.FLING);
177 mOnFling.raise(new TwoPointsEventParameter(e1, e2, velocityX, velocityY) );
178 return true;
179 }
180
181 /** Called when a long-press is triggered for one or more fingers. */
182 @Override
183 public void onLongPress(MotionEvent e) {}
184
185 /** Called when the user drags one or more fingers across the touchscreen. * /
186 @Override
187 public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, flo at distanceY) {
188 if (!isInPanGestureBounds(e1)) {
189 // The gesture of scrolling from edge to the center should be handle d by Android OS.
190 mInputState.setDetectedAction(InputState.DetectedAction.SCROLL_EDGE) ;
191 return false;
192 }
193
194 if (((mSwipeWithMoreFingers && e2.getPointerCount() >= 3) || e2.getPoint erCount() == 3)
195 && !mInputState.swipeCompleted()) {
196 if (distanceY > mSwipeThreshold || distanceY < -mSwipeThreshold) {
197 mInputState.setDetectedAction(DetectedAction.SWIPE);
198 mOnSwipe.raise(new TwoPointsEventParameter(e1, e2, distanceX, di stanceY));
199 return true;
200 }
201 return false;
202 }
203
204 if (e2.getPointerCount() == 2 && mSwipePinchDetector.isSwiping()) {
205 mInputState.setDetectedAction(DetectedAction.SCROLL);
206 mOnScroll.raise(new TwoPointsEventParameter(e1, e2, distanceX, dista nceY));
207 return true;
208 }
209
210 if (e2.getPointerCount() != 1 || mInputState.suppressCursorMovement()) {
211 return false;
212 }
213
214 mInputState.setDetectedAction(DetectedAction.MOVE);
215 mOnMove.raise(new TwoPointsEventParameter(e1, e2, distanceX, distanceY)) ;
216 return true;
217 }
218
219 /** Called by {@link GestureDetector}, does nothing. */
220 @Override
221 public void onShowPress(MotionEvent e) {}
222
223 /** Called by {@link GestureDetector}, returns false to continue following g esture detection. */
224 @Override
225 public boolean onSingleTapUp(MotionEvent e) {
226 return false;
227 }
228
229 // --------- Implementations of ScaleGestureDetector.OnScaleGestureListener -----------
230 /** Called when the user is in the process of pinch-zooming. */
231 @Override
232 public boolean onScale(ScaleGestureDetector detector) {
233 if (!mSwipePinchDetector.isPinching()) {
234 return false;
235 }
236
237 mInputState.setDetectedAction(DetectedAction.SCALE);
238 mOnScale.raise(new ScaleEventParameter(detector.getScaleFactor(),
239 detector.getFocusX(),
240 detector.getFocusY()));
241 return true;
242 }
243
244 /**
245 * Called when the user starts to zoom. Always accepts the zoom so that
246 * onScale() can decide whether to respond to it.
247 */
248 @Override
249 public boolean onScaleBegin(ScaleGestureDetector detector) {
250 return true;
251 }
252
253 /** Called when the user is done zooming. Defers to onScale()'s judgement. * /
254 @Override
255 public void onScaleEnd(ScaleGestureDetector detector) {
256 onScale(detector);
257 }
258
259 // -------------- Implementations of TapGestureDetector.OnTapListener ------ ----------
260 /** Called when the user taps the screen with one or more fingers. */
261 @Override
262 public boolean onTap(int pointerCount, float x, float y) {
263 TapEventParameter para = new TapEventParameter(pointerCount, x, y);
264 mOnTap.raise(para);
265 return para.handled;
266 }
267
268 /** Called when a long-press is triggered for one or more fingers. */
269 @Override
270 public void onLongPress(int pointerCount, float x, float y) {
271 TapEventParameter para = new TapEventParameter(pointerCount, x, y);
272 mOnPressAndHold.raise(para);
273 if (para.handled) {
274 mInputState.setStartAction(StartAction.LONG_PRESS);
275 }
276 }
277
278 /**
279 * Returns a boolean value to indicate whether the MotionEvent is in the ran ge of
280 * {@link mPanGestureBounds}
281 */
282 private boolean isInPanGestureBounds(MotionEvent e) {
283 Preconditions.notNull(e);
284 return mPanGestureBounds == null
285 || mPanGestureBounds.contains((int) e.getX(), (int) e.getY());
286 }
287
288 // ---------------------------- Event handlers ----------------------------- ----------
289 private void handleClientSizeChanged(SizeChangedEventParameter parameter) {
290 mPanGestureBounds = new Rect(mEdgeSlopInPx,
291 mEdgeSlopInPx,
292 parameter.width - mEdgeSlopInPx,
293 parameter.height - mEdgeSlopInPx);
294 }
295
296 private void handleTouch(TouchEventParameter parameter) {
297 mOnTouchEvent.raise(parameter.event);
298
299 boolean handled = mScroller.onTouchEvent(parameter.event);
300 handled |= mZoomer.onTouchEvent(parameter.event);
301 handled |= mTapDetector.onTouchEvent(parameter.event);
302 mSwipePinchDetector.onTouchEvent(parameter.event);
303
304 parameter.handled = handled;
305 }
306 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698