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

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

Issue 2322623002: [Remoting Android] Refactor GlDesktopView (Closed)
Patch Set: Reviewer's Feedback Created 4 years, 3 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
1 // Copyright 2013 The Chromium Authors. All rights reserved. 1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 package org.chromium.chromoting; 5 package org.chromium.chromoting;
6 6
7 import android.content.Context; 7 import android.content.Context;
8 import android.graphics.Matrix; 8 import android.graphics.Matrix;
9 import android.graphics.PointF; 9 import android.graphics.PointF;
10 import android.graphics.Rect; 10 import android.graphics.Rect;
11 import android.util.Pair;
11 import android.view.GestureDetector; 12 import android.view.GestureDetector;
12 import android.view.MotionEvent; 13 import android.view.MotionEvent;
13 import android.view.ScaleGestureDetector; 14 import android.view.ScaleGestureDetector;
14 import android.view.ViewConfiguration; 15 import android.view.ViewConfiguration;
15 16
17 import java.util.ArrayList;
18 import java.util.List;
19
16 /** 20 /**
17 * This class is responsible for handling Touch input from the user. Touch even ts which manipulate 21 * This class is responsible for handling Touch input from the user. Touch even ts which manipulate
18 * the local canvas are handled in this class and any input which should be sent to the remote host 22 * the local canvas are handled in this class and any input which should be sent to the remote host
19 * are passed to the InputStrategyInterface implementation set by the DesktopVie w. 23 * are passed to the InputStrategyInterface implementation set by the DesktopVie w.
20 */ 24 */
21 public class TouchInputHandler { 25 public class TouchInputHandler {
22 private static final float EPSILON = 0.001f; 26 private static final float EPSILON = 0.001f;
23 27
28 private final List<Pair<Object, Event<?>>> mAttachedEvents = new ArrayList<> ();
24 private final DesktopView mViewer; 29 private final DesktopView mViewer;
25 private final Context mContext; 30 private final Context mContext;
26 private final RenderData mRenderData; 31 private final RenderData mRenderData;
27 private final DesktopCanvas mDesktopCanvas; 32 private final DesktopCanvas mDesktopCanvas;
28 private InputStrategyInterface mInputStrategy; 33 private final RenderStub mRenderStub;
29 34 private final GestureDetector mScroller;
30 private GestureDetector mScroller; 35 private final ScaleGestureDetector mZoomer;
31 private ScaleGestureDetector mZoomer; 36 private final TapGestureDetector mTapDetector;
32 private TapGestureDetector mTapDetector;
33 37
34 /** Used to disambiguate a 2-finger gesture as a swipe or a pinch. */ 38 /** Used to disambiguate a 2-finger gesture as a swipe or a pinch. */
35 private SwipePinchDetector mSwipePinchDetector; 39 private final SwipePinchDetector mSwipePinchDetector;
36 40
37 // Used for processing cursor & scroller fling animations. 41 // Used for processing cursor & scroller fling animations.
38 // May consider using a List of AnimationJob if we have more than two animat ion jobs in 42 // May consider using a List of AnimationJob if we have more than two animat ion jobs in
39 // the future. 43 // the future.
40 private FlingAnimationJob mCursorAnimationJob, mScrollAnimationJob; 44 private final FlingAnimationJob mCursorAnimationJob;
45 private final FlingAnimationJob mScrollAnimationJob;
46
47 private InputStrategyInterface mInputStrategy;
41 48
42 /** 49 /**
43 * Used for tracking swipe gestures. Only the Y-direction is needed for resp onding to swipe-up 50 * Used for tracking swipe gestures. Only the Y-direction is needed for resp onding to swipe-up
44 * or swipe-down. 51 * or swipe-down.
45 */ 52 */
46 private float mTotalMotionY = 0; 53 private float mTotalMotionY = 0;
47 54
48 /** 55 /**
49 * Distance in pixels beyond which a motion gesture is considered to be a sw ipe. This is 56 * Distance in pixels beyond which a motion gesture is considered to be a sw ipe. This is
50 * initialized using the Context passed into the ctor. 57 * initialized using the Context passed into the ctor.
(...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after
173 public RenderStub.InputFeedbackType getLongPressFeedbackType() { 180 public RenderStub.InputFeedbackType getLongPressFeedbackType() {
174 return RenderStub.InputFeedbackType.NONE; 181 return RenderStub.InputFeedbackType.NONE;
175 } 182 }
176 183
177 @Override 184 @Override
178 public boolean isIndirectInputMode() { 185 public boolean isIndirectInputMode() {
179 return false; 186 return false;
180 } 187 }
181 } 188 }
182 189
183 public TouchInputHandler(DesktopView viewer, Context context) { 190 public TouchInputHandler(DesktopView viewer, Desktop desktop, RenderStub ren derStub,
191 final InputEventSender injector) {
192 Preconditions.notNull(viewer);
193 Preconditions.notNull(desktop);
194 Preconditions.notNull(renderStub);
195 Preconditions.notNull(injector);
196
184 mViewer = viewer; 197 mViewer = viewer;
185 mContext = context; 198 mContext = desktop;
199 mRenderStub = renderStub;
186 mRenderData = new RenderData(); 200 mRenderData = new RenderData();
187 mDesktopCanvas = new DesktopCanvas(mViewer, mRenderData); 201 mDesktopCanvas = new DesktopCanvas(renderStub, mRenderData);
188 202
189 GestureListener listener = new GestureListener(); 203 GestureListener listener = new GestureListener();
190 mScroller = new GestureDetector(context, listener, null, false); 204 mScroller = new GestureDetector(desktop, listener, null, false);
191 205
192 // If long-press is enabled, the gesture-detector will not emit any furt her onScroll 206 // If long-press is enabled, the gesture-detector will not emit any furt her onScroll
193 // notifications after the onLongPress notification. Since onScroll is b eing used for 207 // notifications after the onLongPress notification. Since onScroll is b eing used for
194 // moving the cursor, it means that the cursor would become stuck if the finger were held 208 // moving the cursor, it means that the cursor would become stuck if the finger were held
195 // down too long. 209 // down too long.
196 mScroller.setIsLongpressEnabled(false); 210 mScroller.setIsLongpressEnabled(false);
197 211
198 mZoomer = new ScaleGestureDetector(context, listener); 212 mZoomer = new ScaleGestureDetector(desktop, listener);
199 mTapDetector = new TapGestureDetector(context, listener); 213 mTapDetector = new TapGestureDetector(desktop, listener);
200 mSwipePinchDetector = new SwipePinchDetector(context); 214 mSwipePinchDetector = new SwipePinchDetector(desktop);
201 215
202 // The threshold needs to be bigger than the ScaledTouchSlop used by the gesture-detectors, 216 // The threshold needs to be bigger than the ScaledTouchSlop used by the gesture-detectors,
203 // so that a gesture cannot be both a tap and a swipe. It also needs to be small enough so 217 // so that a gesture cannot be both a tap and a swipe. It also needs to be small enough so
204 // that intentional swipes are usually detected. 218 // that intentional swipes are usually detected.
205 float density = context.getResources().getDisplayMetrics().density; 219 float density = desktop.getResources().getDisplayMetrics().density;
206 mSwipeThreshold = 40 * density; 220 mSwipeThreshold = 40 * density;
207 221
208 mEdgeSlopInPx = ViewConfiguration.get(context).getScaledEdgeSlop(); 222 mEdgeSlopInPx = ViewConfiguration.get(desktop).getScaledEdgeSlop();
209 223
210 mInputStrategy = new NullInputStrategy(); 224 mInputStrategy = new NullInputStrategy();
211 225
212 mCursorAnimationJob = new CursorAnimationJob(context); 226 mCursorAnimationJob = new CursorAnimationJob(desktop);
213 mScrollAnimationJob = new ScrollAnimationJob(context); 227 mScrollAnimationJob = new ScrollAnimationJob(desktop);
214 228
215 mProcessAnimationCallback = new Event.ParameterCallback<Boolean, Void>() { 229 mProcessAnimationCallback = new Event.ParameterCallback<Boolean, Void>() {
216 @Override 230 @Override
217 public Boolean run(Void p) { 231 public Boolean run(Void p) {
218 return processAnimation(); 232 return processAnimation();
219 } 233 }
220 }; 234 };
221 235
222 attachViewEvents(viewer); 236 attachEvent(mViewer.onTouch(), new Event.ParameterRunnable<TouchEventPar ameter>() {
237 @Override
238 public void run(TouchEventParameter parameter) {
239 parameter.handled = handleTouchEvent(parameter.event);
240 }
241 });
242
243 attachEvent(desktop.onInputModeChanged(),
244 new Event.ParameterRunnable<InputModeChangedEventParameter>() {
245 @Override
246 public void run(InputModeChangedEventParameter parameter) {
247 handleInputModeChanged(parameter, injector);
248 }
249 });
250
251 attachEvent(desktop.onSystemUiVisibilityChanged(),
252 new Event.ParameterRunnable<SystemUiVisibilityChangedEventParame ter>() {
253 @Override
254 public void run(SystemUiVisibilityChangedEventParameter para meter) {
255 handleSystemUiVisibilityChanged(parameter);
256 }
257 });
258
259 attachEvent(renderStub.onClientSizeChanged(),
260 new Event.ParameterRunnable<SizeChangedEventParameter>() {
261 @Override
262 public void run(SizeChangedEventParameter parameter) {
263 handleClientSizeChanged(parameter.width, parameter.heigh t);
264 }
265 });
266
267 attachEvent(renderStub.onHostSizeChanged(),
268 new Event.ParameterRunnable<SizeChangedEventParameter>() {
269 @Override
270 public void run(SizeChangedEventParameter parameter) {
271 handleHostSizeChanged(parameter.width, parameter.height) ;
272 }
273 });
274 }
275
276 private <ParamT> void attachEvent(Event<ParamT> event,
277 Event.ParameterRunnable<ParamT> runnable) {
278 mAttachedEvents.add(new Pair<Object, Event<?>>(event.add(runnable), even t));
223 } 279 }
224 280
225 /** 281 /**
282 * Detaches all registered event listeners. This function should be called e xactly once.
283 */
284 public void detachEventListeners() {
285 Preconditions.isTrue(!mAttachedEvents.isEmpty());
286 abortAnimation();
287 for (Pair<Object, Event<?>> pair : mAttachedEvents) {
288 pair.second.remove(pair.first);
289 }
290 mAttachedEvents.clear();
291 }
292
293 /**
226 * Steps forward the animation. 294 * Steps forward the animation.
227 * @return true if the animation is not finished yet. 295 * @return true if the animation is not finished yet.
228 */ 296 */
229 private boolean processAnimation() { 297 private boolean processAnimation() {
230 return mCursorAnimationJob.processAnimation() || mScrollAnimationJob.pro cessAnimation(); 298 return mCursorAnimationJob.processAnimation() || mScrollAnimationJob.pro cessAnimation();
231 } 299 }
232 300
233 /** 301 /**
234 * Start stepping animation when onCanvasRendered is triggered. 302 * Start stepping animation when onCanvasRendered is triggered.
235 */ 303 */
236 private void startAnimation() { 304 private void startAnimation() {
237 mViewer.onCanvasRendered().addSelfRemovable(mProcessAnimationCallback); 305 mRenderStub.onCanvasRendered().addSelfRemovable(mProcessAnimationCallbac k);
238 } 306 }
239 307
240 /** 308 /**
241 * Abort all animations. 309 * Abort all animations.
242 */ 310 */
243 private void abortAnimation() { 311 private void abortAnimation() {
244 mCursorAnimationJob.abortAnimation(); 312 mCursorAnimationJob.abortAnimation();
245 mScrollAnimationJob.abortAnimation(); 313 mScrollAnimationJob.abortAnimation();
246 } 314 }
247 315
248 public void init(Desktop desktop, final InputEventSender injector) {
249 Preconditions.notNull(injector);
250 desktop.onInputModeChanged().add(
251 new Event.ParameterRunnable<InputModeChangedEventParameter>() {
252 @Override
253 public void run(InputModeChangedEventParameter parameter) {
254 handleInputModeChanged(parameter, injector);
255 }
256 });
257
258 desktop.onSystemUiVisibilityChanged().add(
259 new Event.ParameterRunnable<SystemUiVisibilityChangedEventParame ter>() {
260 @Override
261 public void run(SystemUiVisibilityChangedEventParameter para meter) {
262 handleSystemUiVisibilityChanged(parameter);
263 }
264 });
265 }
266
267 private void attachViewEvents(DesktopView viewer) {
268 viewer.onTouch().add(new Event.ParameterRunnable<TouchEventParameter>() {
269 @Override
270 public void run(TouchEventParameter parameter) {
271 parameter.handled = handleTouchEvent(parameter.event);
272 }
273 });
274 viewer.onClientSizeChanged().add(new Event.ParameterRunnable<SizeChanged EventParameter>() {
275 @Override
276 public void run(SizeChangedEventParameter parameter) {
277 handleClientSizeChanged(parameter.width, parameter.height);
278 }
279 });
280 viewer.onHostSizeChanged().add(new Event.ParameterRunnable<SizeChangedEv entParameter>() {
281 @Override
282 public void run(SizeChangedEventParameter parameter) {
283 handleHostSizeChanged(parameter.width, parameter.height);
284 }
285 });
286 }
287
288 private void handleInputModeChanged( 316 private void handleInputModeChanged(
289 InputModeChangedEventParameter parameter, InputEventSender injector) { 317 InputModeChangedEventParameter parameter, InputEventSender injector) {
290 final Desktop.InputMode inputMode = parameter.inputMode; 318 final Desktop.InputMode inputMode = parameter.inputMode;
291 final CapabilityManager.HostCapability hostTouchCapability = 319 final CapabilityManager.HostCapability hostTouchCapability =
292 parameter.hostCapability; 320 parameter.hostCapability;
293 // We need both input mode and host input capabilities to select the inp ut 321 // We need both input mode and host input capabilities to select the inp ut
294 // strategy. 322 // strategy.
295 if (!inputMode.isSet() || !hostTouchCapability.isSet()) { 323 if (!inputMode.isSet() || !hostTouchCapability.isSet()) {
296 return; 324 return;
297 } 325 }
(...skipping 11 matching lines...) Expand all
309 new SimulatedTouchInputStrategy(mRenderData, injecto r, mContext)); 337 new SimulatedTouchInputStrategy(mRenderData, injecto r, mContext));
310 } 338 }
311 break; 339 break;
312 340
313 default: 341 default:
314 // Unreachable, but required by Google Java style and findbugs. 342 // Unreachable, but required by Google Java style and findbugs.
315 assert false : "Unreached"; 343 assert false : "Unreached";
316 } 344 }
317 345
318 // Ensure the cursor state is updated appropriately. 346 // Ensure the cursor state is updated appropriately.
319 mViewer.cursorVisibilityChanged(mRenderData.drawCursor); 347 mRenderStub.setCursorVisibility(mRenderData.drawCursor);
320 } 348 }
321 349
322 private void handleSystemUiVisibilityChanged( 350 private void handleSystemUiVisibilityChanged(
323 SystemUiVisibilityChangedEventParameter parameter) { 351 SystemUiVisibilityChangedEventParameter parameter) {
324 if (parameter.softInputMethodVisible) { 352 if (parameter.softInputMethodVisible) {
325 mDesktopCanvas.setSystemUiOffsetValues(parameter.left, parameter.top , 353 mDesktopCanvas.setSystemUiOffsetValues(parameter.left, parameter.top ,
326 mRenderData.screenWidth - parameter.right, 354 mRenderData.screenWidth - parameter.right,
327 mRenderData.screenHeight - parameter.bottom); 355 mRenderData.screenHeight - parameter.bottom);
328 } else { 356 } else {
329 mDesktopCanvas.setSystemUiOffsetValues(0, 0, 0, 0); 357 mDesktopCanvas.setSystemUiOffsetValues(0, 0, 0, 0);
(...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after
430 moveCursor(imagePoint[0], imagePoint[1]); 458 moveCursor(imagePoint[0], imagePoint[1]);
431 } 459 }
432 460
433 /** Moves the cursor to the specified position on the remote host. */ 461 /** Moves the cursor to the specified position on the remote host. */
434 private void moveCursor(float newX, float newY) { 462 private void moveCursor(float newX, float newY) {
435 boolean cursorMoved = mRenderData.setCursorPosition(newX, newY); 463 boolean cursorMoved = mRenderData.setCursorPosition(newX, newY);
436 if (cursorMoved) { 464 if (cursorMoved) {
437 mInputStrategy.injectCursorMoveEvent((int) newX, (int) newY); 465 mInputStrategy.injectCursorMoveEvent((int) newX, (int) newY);
438 } 466 }
439 467
440 mViewer.cursorMoved(mRenderData.getCursorPosition()); 468 mRenderStub.moveCursor(mRenderData.getCursorPosition());
441 } 469 }
442 470
443 /** Processes a (multi-finger) swipe gesture. */ 471 /** Processes a (multi-finger) swipe gesture. */
444 private boolean onSwipe() { 472 private boolean onSwipe() {
445 if (mTotalMotionY > mSwipeThreshold) { 473 if (mTotalMotionY > mSwipeThreshold) {
446 // Swipe down occurred. 474 // Swipe down occurred.
447 mViewer.showActionBar(); 475 mViewer.showActionBar();
448 } else if (mTotalMotionY < -mSwipeThreshold) { 476 } else if (mTotalMotionY < -mSwipeThreshold) {
449 // Swipe up occurred. 477 // Swipe up occurred.
450 mViewer.showKeyboard(); 478 mViewer.showKeyboard();
(...skipping 158 matching lines...) Expand 10 before | Expand all | Expand 10 after
609 if (!mInputStrategy.isIndirectInputMode()) { 637 if (!mInputStrategy.isIndirectInputMode()) {
610 if (screenPointLiesOutsideImageBoundary(x, y)) { 638 if (screenPointLiesOutsideImageBoundary(x, y)) {
611 return false; 639 return false;
612 } 640 }
613 moveCursorToScreenPoint(x, y); 641 moveCursorToScreenPoint(x, y);
614 } 642 }
615 643
616 if (mInputStrategy.onTap(button)) { 644 if (mInputStrategy.onTap(button)) {
617 PointF pos = mRenderData.getCursorPosition(); 645 PointF pos = mRenderData.getCursorPosition();
618 646
619 mViewer.showInputFeedback(mInputStrategy.getShortPressFeedbackTy pe(), pos); 647 mRenderStub.showInputFeedback(mInputStrategy.getShortPressFeedba ckType(), pos);
620 } 648 }
621 return true; 649 return true;
622 } 650 }
623 651
624 /** Called when a long-press is triggered for one or more fingers. */ 652 /** Called when a long-press is triggered for one or more fingers. */
625 @Override 653 @Override
626 public void onLongPress(int pointerCount, float x, float y) { 654 public void onLongPress(int pointerCount, float x, float y) {
627 int button = mouseButtonFromPointerCount(pointerCount); 655 int button = mouseButtonFromPointerCount(pointerCount);
628 if (button == InputStub.BUTTON_UNDEFINED) { 656 if (button == InputStub.BUTTON_UNDEFINED) {
629 return; 657 return;
630 } 658 }
631 659
632 if (!mInputStrategy.isIndirectInputMode()) { 660 if (!mInputStrategy.isIndirectInputMode()) {
633 if (screenPointLiesOutsideImageBoundary(x, y)) { 661 if (screenPointLiesOutsideImageBoundary(x, y)) {
634 return; 662 return;
635 } 663 }
636 moveCursorToScreenPoint(x, y); 664 moveCursorToScreenPoint(x, y);
637 } 665 }
638 666
639 if (mInputStrategy.onPressAndHold(button)) { 667 if (mInputStrategy.onPressAndHold(button)) {
640 PointF pos = mRenderData.getCursorPosition(); 668 PointF pos = mRenderData.getCursorPosition();
641 669
642 mViewer.showInputFeedback(mInputStrategy.getLongPressFeedbackTyp e(), pos); 670 mRenderStub.showInputFeedback(mInputStrategy.getLongPressFeedbac kType(), pos);
643 mSuppressFling = true; 671 mSuppressFling = true;
644 mIsDragging = true; 672 mIsDragging = true;
645 } 673 }
646 } 674 }
647 675
648 /** Maps the number of fingers in a tap or long-press gesture to a mouse -button. */ 676 /** Maps the number of fingers in a tap or long-press gesture to a mouse -button. */
649 private int mouseButtonFromPointerCount(int pointerCount) { 677 private int mouseButtonFromPointerCount(int pointerCount) {
650 switch (pointerCount) { 678 switch (pointerCount) {
651 case 1: 679 case 1:
652 return InputStub.BUTTON_LEFT; 680 return InputStub.BUTTON_LEFT;
(...skipping 11 matching lines...) Expand all
664 float[] mappedPoints = mapScreenPointToImagePoint(screenX, screenY); 692 float[] mappedPoints = mapScreenPointToImagePoint(screenX, screenY);
665 693
666 float imageWidth = (float) mRenderData.imageWidth + EPSILON; 694 float imageWidth = (float) mRenderData.imageWidth + EPSILON;
667 float imageHeight = (float) mRenderData.imageHeight + EPSILON; 695 float imageHeight = (float) mRenderData.imageHeight + EPSILON;
668 696
669 return mappedPoints[0] < -EPSILON || mappedPoints[0] > imageWidth 697 return mappedPoints[0] < -EPSILON || mappedPoints[0] > imageWidth
670 || mappedPoints[1] < -EPSILON || mappedPoints[1] > imageHeig ht; 698 || mappedPoints[1] < -EPSILON || mappedPoints[1] > imageHeig ht;
671 } 699 }
672 } 700 }
673 } 701 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698