Chromium Code Reviews| OLD | NEW |
|---|---|
| 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.view.GestureDetector; | 11 import android.view.GestureDetector; |
| 12 import android.view.MotionEvent; | 12 import android.view.MotionEvent; |
| 13 import android.view.ScaleGestureDetector; | 13 import android.view.ScaleGestureDetector; |
| 14 import android.view.ViewConfiguration; | 14 import android.view.ViewConfiguration; |
| 15 | 15 |
| 16 /** | 16 /** |
| 17 * This class is responsible for handling Touch input from the user. Touch even ts which manipulate | 17 * 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 | 18 * 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. | 19 * are passed to the InputStrategyInterface implementation set by the DesktopVie w. |
| 20 */ | 20 */ |
| 21 public class TouchInputHandler { | 21 public class TouchInputHandler { |
| 22 private static final float EPSILON = 0.001f; | 22 private static final float EPSILON = 0.001f; |
| 23 | 23 |
| 24 private final DesktopView mViewer; | 24 private final DesktopView mViewer; |
| 25 private final Context mContext; | 25 private final Context mContext; |
| 26 private final RenderData mRenderData; | 26 private final RenderData mRenderData; |
| 27 private final DesktopCanvas mDesktopCanvas; | 27 private DesktopCanvas mDesktopCanvas; |
|
Hzj_jie
2016/09/08 21:37:33
Once init function has been removed, these fields
Yuwei
2016/09/08 23:09:15
Done. Made everything final-able final.
| |
| 28 private InputStrategyInterface mInputStrategy; | 28 private InputStrategyInterface mInputStrategy; |
| 29 private RenderStub mRenderStub; | |
| 29 | 30 |
| 30 private GestureDetector mScroller; | 31 private GestureDetector mScroller; |
| 31 private ScaleGestureDetector mZoomer; | 32 private ScaleGestureDetector mZoomer; |
| 32 private TapGestureDetector mTapDetector; | 33 private TapGestureDetector mTapDetector; |
| 33 | 34 |
| 34 /** Used to disambiguate a 2-finger gesture as a swipe or a pinch. */ | 35 /** Used to disambiguate a 2-finger gesture as a swipe or a pinch. */ |
| 35 private SwipePinchDetector mSwipePinchDetector; | 36 private SwipePinchDetector mSwipePinchDetector; |
| 36 | 37 |
| 37 // Used for processing cursor & scroller fling animations. | 38 // 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 | 39 // May consider using a List of AnimationJob if we have more than two animat ion jobs in |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 86 * trigger more swipe actions. | 87 * trigger more swipe actions. |
| 87 */ | 88 */ |
| 88 private boolean mSwipeCompleted = false; | 89 private boolean mSwipeCompleted = false; |
| 89 | 90 |
| 90 /** | 91 /** |
| 91 * Set to true when a 1 finger pan gesture originates with a longpress. Thi s means the user | 92 * Set to true when a 1 finger pan gesture originates with a longpress. Thi s means the user |
| 92 * is performing a drag operation. | 93 * is performing a drag operation. |
| 93 */ | 94 */ |
| 94 private boolean mIsDragging = false; | 95 private boolean mIsDragging = false; |
| 95 | 96 |
| 97 private boolean mValid = false; | |
| 98 | |
| 96 private Event.ParameterCallback<Boolean, Void> mProcessAnimationCallback; | 99 private Event.ParameterCallback<Boolean, Void> mProcessAnimationCallback; |
| 97 | 100 |
| 98 /** | 101 /** |
| 99 * This class implements fling animation for cursor | 102 * This class implements fling animation for cursor |
| 100 */ | 103 */ |
| 101 private class CursorAnimationJob extends FlingAnimationJob { | 104 private class CursorAnimationJob extends FlingAnimationJob { |
| 102 public CursorAnimationJob(Context context) { | 105 public CursorAnimationJob(Context context) { |
| 103 super(context); | 106 super(context); |
| 104 } | 107 } |
| 105 | 108 |
| (...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 177 @Override | 180 @Override |
| 178 public boolean isIndirectInputMode() { | 181 public boolean isIndirectInputMode() { |
| 179 return false; | 182 return false; |
| 180 } | 183 } |
| 181 } | 184 } |
| 182 | 185 |
| 183 public TouchInputHandler(DesktopView viewer, Context context) { | 186 public TouchInputHandler(DesktopView viewer, Context context) { |
| 184 mViewer = viewer; | 187 mViewer = viewer; |
| 185 mContext = context; | 188 mContext = context; |
| 186 mRenderData = new RenderData(); | 189 mRenderData = new RenderData(); |
| 187 mDesktopCanvas = new DesktopCanvas(mViewer, mRenderData); | |
| 188 | 190 |
| 189 GestureListener listener = new GestureListener(); | 191 GestureListener listener = new GestureListener(); |
| 190 mScroller = new GestureDetector(context, listener, null, false); | 192 mScroller = new GestureDetector(context, listener, null, false); |
| 191 | 193 |
| 192 // If long-press is enabled, the gesture-detector will not emit any furt her onScroll | 194 // 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 | 195 // 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 | 196 // moving the cursor, it means that the cursor would become stuck if the finger were held |
| 195 // down too long. | 197 // down too long. |
| 196 mScroller.setIsLongpressEnabled(false); | 198 mScroller.setIsLongpressEnabled(false); |
| 197 | 199 |
| (...skipping 13 matching lines...) Expand all Loading... | |
| 211 | 213 |
| 212 mCursorAnimationJob = new CursorAnimationJob(context); | 214 mCursorAnimationJob = new CursorAnimationJob(context); |
| 213 mScrollAnimationJob = new ScrollAnimationJob(context); | 215 mScrollAnimationJob = new ScrollAnimationJob(context); |
| 214 | 216 |
| 215 mProcessAnimationCallback = new Event.ParameterCallback<Boolean, Void>() { | 217 mProcessAnimationCallback = new Event.ParameterCallback<Boolean, Void>() { |
| 216 @Override | 218 @Override |
| 217 public Boolean run(Void p) { | 219 public Boolean run(Void p) { |
| 218 return processAnimation(); | 220 return processAnimation(); |
| 219 } | 221 } |
| 220 }; | 222 }; |
| 221 | |
| 222 attachViewEvents(viewer); | |
| 223 } | 223 } |
| 224 | 224 |
| 225 /** | 225 /** |
| 226 * Steps forward the animation. | 226 * Steps forward the animation. |
| 227 * @return true if the animation is not finished yet. | 227 * @return true if the animation is not finished yet. |
| 228 */ | 228 */ |
| 229 private boolean processAnimation() { | 229 private boolean processAnimation() { |
| 230 return mCursorAnimationJob.processAnimation() || mScrollAnimationJob.pro cessAnimation(); | 230 return mCursorAnimationJob.processAnimation() || mScrollAnimationJob.pro cessAnimation(); |
| 231 } | 231 } |
| 232 | 232 |
| 233 /** | 233 /** |
| 234 * Start stepping animation when onCanvasRendered is triggered. | 234 * Start stepping animation when onCanvasRendered is triggered. |
| 235 */ | 235 */ |
| 236 private void startAnimation() { | 236 private void startAnimation() { |
| 237 mViewer.onCanvasRendered().addSelfRemovable(mProcessAnimationCallback); | 237 mRenderStub.onCanvasRendered().addSelfRemovable(mProcessAnimationCallbac k); |
| 238 } | 238 } |
| 239 | 239 |
| 240 /** | 240 /** |
| 241 * Abort all animations. | 241 * Abort all animations. |
| 242 */ | 242 */ |
| 243 private void abortAnimation() { | 243 private void abortAnimation() { |
| 244 mCursorAnimationJob.abortAnimation(); | 244 mCursorAnimationJob.abortAnimation(); |
| 245 mScrollAnimationJob.abortAnimation(); | 245 mScrollAnimationJob.abortAnimation(); |
| 246 } | 246 } |
| 247 | 247 |
| 248 public void init(Desktop desktop, final InputEventSender injector) { | 248 public void init(Desktop desktop, RenderStub renderStub, final InputEventSen der injector) { |
| 249 Preconditions.notNull(injector); | 249 Preconditions.notNull(injector); |
| 250 desktop.onInputModeChanged().add( | 250 Preconditions.notNull(renderStub); |
| 251 new Event.ParameterRunnable<InputModeChangedEventParameter>() { | 251 mRenderStub = renderStub; |
| 252 mDesktopCanvas = new DesktopCanvas(renderStub, mRenderData); | |
| 253 | |
| 254 mValid = true; | |
|
joedow
2016/09/08 18:32:47
Can't you just detach the event handlers / remove
Yuwei
2016/09/08 19:12:16
The reason was that I didn't want to have a lot of
Hzj_jie
2016/09/08 21:37:33
Emmm ... Seems you are writing more codes by using
Yuwei
2016/09/08 23:09:15
s/HashMap/list of listener-event pairs/
Yuwei
2016/09/08 23:09:15
Simplified.
| |
| 255 | |
| 256 mViewer.onTouch().addSelfRemovable( | |
| 257 new Event.ParameterCallback<Boolean, TouchEventParameter>() { | |
| 252 @Override | 258 @Override |
| 253 public void run(InputModeChangedEventParameter parameter) { | 259 public Boolean run(TouchEventParameter parameter) { |
| 254 handleInputModeChanged(parameter, injector); | 260 if (!mValid) { |
| 261 return false; | |
| 262 } | |
| 263 parameter.handled = handleTouchEvent(parameter.event); | |
| 264 return true; | |
| 255 } | 265 } |
| 256 }); | 266 }); |
| 257 | 267 |
| 258 desktop.onSystemUiVisibilityChanged().add( | 268 desktop.onInputModeChanged().addSelfRemovable( |
| 259 new Event.ParameterRunnable<SystemUiVisibilityChangedEventParame ter>() { | 269 new Event.ParameterCallback<Boolean, InputModeChangedEventParame ter>() { |
| 260 @Override | 270 @Override |
| 261 public void run(SystemUiVisibilityChangedEventParameter para meter) { | 271 public Boolean run(InputModeChangedEventParameter parameter) { |
| 272 if (!mValid) { | |
| 273 return false; | |
| 274 } | |
| 275 handleInputModeChanged(parameter, injector); | |
| 276 return true; | |
| 277 } | |
| 278 }); | |
| 279 | |
| 280 desktop.onSystemUiVisibilityChanged().addSelfRemovable( | |
| 281 new Event.ParameterCallback<Boolean, SystemUiVisibilityChangedEv entParameter>() { | |
| 282 @Override | |
| 283 public Boolean run(SystemUiVisibilityChangedEventParameter p arameter) { | |
| 284 if (!mValid) { | |
| 285 return false; | |
| 286 } | |
| 262 handleSystemUiVisibilityChanged(parameter); | 287 handleSystemUiVisibilityChanged(parameter); |
| 288 return true; | |
| 289 } | |
| 290 }); | |
| 291 | |
| 292 renderStub.onClientSizeChanged().addSelfRemovable( | |
| 293 new Event.ParameterCallback<Boolean, SizeChangedEventParameter>( ) { | |
| 294 @Override | |
| 295 public Boolean run(SizeChangedEventParameter parameter) { | |
| 296 if (!mValid) { | |
| 297 return false; | |
| 298 } | |
| 299 handleClientSizeChanged(parameter.width, parameter.heigh t); | |
| 300 return true; | |
| 301 } | |
| 302 }); | |
| 303 | |
| 304 renderStub.onHostSizeChanged().addSelfRemovable( | |
| 305 new Event.ParameterCallback<Boolean, SizeChangedEventParameter>( ) { | |
| 306 @Override | |
| 307 public Boolean run(SizeChangedEventParameter parameter) { | |
| 308 if (!mValid) { | |
| 309 return false; | |
| 310 } | |
| 311 handleHostSizeChanged(parameter.width, parameter.height) ; | |
| 312 return true; | |
| 263 } | 313 } |
| 264 }); | 314 }); |
| 265 } | 315 } |
| 266 | 316 |
| 267 private void attachViewEvents(DesktopView viewer) { | 317 public void invalidate() { |
| 268 viewer.onTouch().add(new Event.ParameterRunnable<TouchEventParameter>() { | 318 mValid = false; |
| 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 } | 319 } |
| 287 | 320 |
| 288 private void handleInputModeChanged( | 321 private void handleInputModeChanged( |
| 289 InputModeChangedEventParameter parameter, InputEventSender injector) { | 322 InputModeChangedEventParameter parameter, InputEventSender injector) { |
| 290 final Desktop.InputMode inputMode = parameter.inputMode; | 323 final Desktop.InputMode inputMode = parameter.inputMode; |
| 291 final CapabilityManager.HostCapability hostTouchCapability = | 324 final CapabilityManager.HostCapability hostTouchCapability = |
| 292 parameter.hostCapability; | 325 parameter.hostCapability; |
| 293 // We need both input mode and host input capabilities to select the inp ut | 326 // We need both input mode and host input capabilities to select the inp ut |
| 294 // strategy. | 327 // strategy. |
| 295 if (!inputMode.isSet() || !hostTouchCapability.isSet()) { | 328 if (!inputMode.isSet() || !hostTouchCapability.isSet()) { |
| (...skipping 13 matching lines...) Expand all Loading... | |
| 309 new SimulatedTouchInputStrategy(mRenderData, injecto r, mContext)); | 342 new SimulatedTouchInputStrategy(mRenderData, injecto r, mContext)); |
| 310 } | 343 } |
| 311 break; | 344 break; |
| 312 | 345 |
| 313 default: | 346 default: |
| 314 // Unreachable, but required by Google Java style and findbugs. | 347 // Unreachable, but required by Google Java style and findbugs. |
| 315 assert false : "Unreached"; | 348 assert false : "Unreached"; |
| 316 } | 349 } |
| 317 | 350 |
| 318 // Ensure the cursor state is updated appropriately. | 351 // Ensure the cursor state is updated appropriately. |
| 319 mViewer.cursorVisibilityChanged(mRenderData.drawCursor); | 352 mRenderStub.setCursorVisibility(mRenderData.drawCursor); |
| 320 } | 353 } |
| 321 | 354 |
| 322 private void handleSystemUiVisibilityChanged( | 355 private void handleSystemUiVisibilityChanged( |
| 323 SystemUiVisibilityChangedEventParameter parameter) { | 356 SystemUiVisibilityChangedEventParameter parameter) { |
| 324 if (parameter.softInputMethodVisible) { | 357 if (parameter.softInputMethodVisible) { |
| 325 mDesktopCanvas.setSystemUiOffsetValues(parameter.left, parameter.top , | 358 mDesktopCanvas.setSystemUiOffsetValues(parameter.left, parameter.top , |
| 326 mRenderData.screenWidth - parameter.right, | 359 mRenderData.screenWidth - parameter.right, |
| 327 mRenderData.screenHeight - parameter.bottom); | 360 mRenderData.screenHeight - parameter.bottom); |
| 328 } else { | 361 } else { |
| 329 mDesktopCanvas.setSystemUiOffsetValues(0, 0, 0, 0); | 362 mDesktopCanvas.setSystemUiOffsetValues(0, 0, 0, 0); |
| (...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 430 moveCursor(imagePoint[0], imagePoint[1]); | 463 moveCursor(imagePoint[0], imagePoint[1]); |
| 431 } | 464 } |
| 432 | 465 |
| 433 /** Moves the cursor to the specified position on the remote host. */ | 466 /** Moves the cursor to the specified position on the remote host. */ |
| 434 private void moveCursor(float newX, float newY) { | 467 private void moveCursor(float newX, float newY) { |
| 435 boolean cursorMoved = mRenderData.setCursorPosition(newX, newY); | 468 boolean cursorMoved = mRenderData.setCursorPosition(newX, newY); |
| 436 if (cursorMoved) { | 469 if (cursorMoved) { |
| 437 mInputStrategy.injectCursorMoveEvent((int) newX, (int) newY); | 470 mInputStrategy.injectCursorMoveEvent((int) newX, (int) newY); |
| 438 } | 471 } |
| 439 | 472 |
| 440 mViewer.cursorMoved(mRenderData.getCursorPosition()); | 473 mRenderStub.moveCursor(mRenderData.getCursorPosition()); |
| 441 } | 474 } |
| 442 | 475 |
| 443 /** Processes a (multi-finger) swipe gesture. */ | 476 /** Processes a (multi-finger) swipe gesture. */ |
| 444 private boolean onSwipe() { | 477 private boolean onSwipe() { |
| 445 if (mTotalMotionY > mSwipeThreshold) { | 478 if (mTotalMotionY > mSwipeThreshold) { |
| 446 // Swipe down occurred. | 479 // Swipe down occurred. |
| 447 mViewer.showActionBar(); | 480 mViewer.showActionBar(); |
| 448 } else if (mTotalMotionY < -mSwipeThreshold) { | 481 } else if (mTotalMotionY < -mSwipeThreshold) { |
| 449 // Swipe up occurred. | 482 // Swipe up occurred. |
| 450 mViewer.showKeyboard(); | 483 mViewer.showKeyboard(); |
| (...skipping 158 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 609 if (!mInputStrategy.isIndirectInputMode()) { | 642 if (!mInputStrategy.isIndirectInputMode()) { |
| 610 if (screenPointLiesOutsideImageBoundary(x, y)) { | 643 if (screenPointLiesOutsideImageBoundary(x, y)) { |
| 611 return false; | 644 return false; |
| 612 } | 645 } |
| 613 moveCursorToScreenPoint(x, y); | 646 moveCursorToScreenPoint(x, y); |
| 614 } | 647 } |
| 615 | 648 |
| 616 if (mInputStrategy.onTap(button)) { | 649 if (mInputStrategy.onTap(button)) { |
| 617 PointF pos = mRenderData.getCursorPosition(); | 650 PointF pos = mRenderData.getCursorPosition(); |
| 618 | 651 |
| 619 mViewer.showInputFeedback(mInputStrategy.getShortPressFeedbackTy pe(), pos); | 652 mRenderStub.showInputFeedback(mInputStrategy.getShortPressFeedba ckType(), pos); |
| 620 } | 653 } |
| 621 return true; | 654 return true; |
| 622 } | 655 } |
| 623 | 656 |
| 624 /** Called when a long-press is triggered for one or more fingers. */ | 657 /** Called when a long-press is triggered for one or more fingers. */ |
| 625 @Override | 658 @Override |
| 626 public void onLongPress(int pointerCount, float x, float y) { | 659 public void onLongPress(int pointerCount, float x, float y) { |
| 627 int button = mouseButtonFromPointerCount(pointerCount); | 660 int button = mouseButtonFromPointerCount(pointerCount); |
| 628 if (button == InputStub.BUTTON_UNDEFINED) { | 661 if (button == InputStub.BUTTON_UNDEFINED) { |
| 629 return; | 662 return; |
| 630 } | 663 } |
| 631 | 664 |
| 632 if (!mInputStrategy.isIndirectInputMode()) { | 665 if (!mInputStrategy.isIndirectInputMode()) { |
| 633 if (screenPointLiesOutsideImageBoundary(x, y)) { | 666 if (screenPointLiesOutsideImageBoundary(x, y)) { |
| 634 return; | 667 return; |
| 635 } | 668 } |
| 636 moveCursorToScreenPoint(x, y); | 669 moveCursorToScreenPoint(x, y); |
| 637 } | 670 } |
| 638 | 671 |
| 639 if (mInputStrategy.onPressAndHold(button)) { | 672 if (mInputStrategy.onPressAndHold(button)) { |
| 640 PointF pos = mRenderData.getCursorPosition(); | 673 PointF pos = mRenderData.getCursorPosition(); |
| 641 | 674 |
| 642 mViewer.showInputFeedback(mInputStrategy.getLongPressFeedbackTyp e(), pos); | 675 mRenderStub.showInputFeedback(mInputStrategy.getLongPressFeedbac kType(), pos); |
| 643 mSuppressFling = true; | 676 mSuppressFling = true; |
| 644 mIsDragging = true; | 677 mIsDragging = true; |
| 645 } | 678 } |
| 646 } | 679 } |
| 647 | 680 |
| 648 /** Maps the number of fingers in a tap or long-press gesture to a mouse -button. */ | 681 /** Maps the number of fingers in a tap or long-press gesture to a mouse -button. */ |
| 649 private int mouseButtonFromPointerCount(int pointerCount) { | 682 private int mouseButtonFromPointerCount(int pointerCount) { |
| 650 switch (pointerCount) { | 683 switch (pointerCount) { |
| 651 case 1: | 684 case 1: |
| 652 return InputStub.BUTTON_LEFT; | 685 return InputStub.BUTTON_LEFT; |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 664 float[] mappedPoints = mapScreenPointToImagePoint(screenX, screenY); | 697 float[] mappedPoints = mapScreenPointToImagePoint(screenX, screenY); |
| 665 | 698 |
| 666 float imageWidth = (float) mRenderData.imageWidth + EPSILON; | 699 float imageWidth = (float) mRenderData.imageWidth + EPSILON; |
| 667 float imageHeight = (float) mRenderData.imageHeight + EPSILON; | 700 float imageHeight = (float) mRenderData.imageHeight + EPSILON; |
| 668 | 701 |
| 669 return mappedPoints[0] < -EPSILON || mappedPoints[0] > imageWidth | 702 return mappedPoints[0] < -EPSILON || mappedPoints[0] > imageWidth |
| 670 || mappedPoints[1] < -EPSILON || mappedPoints[1] > imageHeig ht; | 703 || mappedPoints[1] < -EPSILON || mappedPoints[1] > imageHeig ht; |
| 671 } | 704 } |
| 672 } | 705 } |
| 673 } | 706 } |
| OLD | NEW |