diff options
author | joedow <joedow@chromium.org> | 2015-12-09 08:23:21 -0800 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2015-12-09 16:24:27 +0000 |
commit | c6c60dd07b7351381b4e65dd2c85a93a064b70dd (patch) | |
tree | 2da9bfaf68c6292842435d3e52a570cf32a415ec /remoting/android/java | |
parent | 2c9be589e5244cedb5c85f09004e88ae3ad8a29c (diff) | |
download | chromium_src-c6c60dd07b7351381b4e65dd2c85a93a064b70dd.zip chromium_src-c6c60dd07b7351381b4e65dd2c85a93a064b70dd.tar.gz chromium_src-c6c60dd07b7351381b4e65dd2c85a93a064b70dd.tar.bz2 |
Update InputStrategyInterface to support new input strategies.
Updated the InputStrategyInterface to be less imperative. The interface
now has method names which are used to notify the InputStrategy instead
of methods which are used to tell it to perform a certain action.
Input strategies can now maintain their own internal state as needed
and can react, or not, to the events as they occur.
This flexibility allows the majority of the input logic to remain in the
containing class (of the input strategy) and forward gesture data to the
input strategy to allow it to react and inject the appropriate events on
the remote OS.
As a result of the change in the interface, some logic which was driven
by old interface properties/methods was updated. These changes were
part of a larger CL and were broken out to make the CL simpler.
BUG=454549
Review URL: https://codereview.chromium.org/1512753002
Cr-Commit-Position: refs/heads/master@{#364075}
Diffstat (limited to 'remoting/android/java')
5 files changed, 145 insertions, 94 deletions
diff --git a/remoting/android/java/src/org/chromium/chromoting/DesktopCanvas.java b/remoting/android/java/src/org/chromium/chromoting/DesktopCanvas.java index b9edf31..a0149cf 100644 --- a/remoting/android/java/src/org/chromium/chromoting/DesktopCanvas.java +++ b/remoting/android/java/src/org/chromium/chromoting/DesktopCanvas.java @@ -37,26 +37,36 @@ public class DesktopCanvas { */ private int mInputMethodOffsetX = 0; - /** Used to determine whether the view should be locked to the cursor. */ - private boolean mCenterCursorInView = true; - public DesktopCanvas(DesktopViewInterface viewer, RenderData renderData) { mViewer = viewer; mRenderData = renderData; } - public void setCenterCursorInView(boolean centerCursor) { - mCenterCursorInView = centerCursor; - } - + /** + * Returns the position of the cursor. + * + * @return A point representing the position of the cursor. + */ public PointF getCursorPosition() { return new PointF(mCursorPosition.x, mCursorPosition.y); } + /** + * Sets the position of the cursor which is used for rendering. + * + * @param newX The new value of the x coordinate. + * @param newY The new value of the y coordinate + */ public void setCursorPosition(float newX, float newY) { mCursorPosition.set(newX, newY); } + /** + * Sets the offset values used to calculate the space used by the current soft input method. + * + * @param offsetX The space used by the soft input method UI on the right edge of the screen. + * @param offsetY The space used by the soft input method UI on the bottom edge of the screen. + */ public void setInputMethodOffsetValues(int offsetX, int offsetY) { mInputMethodOffsetX = offsetX; mInputMethodOffsetY = offsetY; @@ -106,20 +116,14 @@ public class DesktopCanvas { float adjustedScreenWidth = mRenderData.screenWidth - mInputMethodOffsetX; float adjustedScreenHeight = mRenderData.screenHeight - mInputMethodOffsetY; - if (mCenterCursorInView) { - // For indirect input modes such as Trackpad emulation, we want to try to position - // the view so the cursor is centered. We move it here and then make adjustments - // below as needed to keep as much of the image on screen as possible. + // Get the current cursor position in screen coordinates. + float[] cursorScreen = {mCursorPosition.x, mCursorPosition.y}; + mRenderData.transform.mapPoints(cursorScreen); - // Get the current cursor position in screen coordinates. - float[] cursorScreen = {mCursorPosition.x, mCursorPosition.y}; - mRenderData.transform.mapPoints(cursorScreen); - - // Translate so the cursor is displayed in the middle of the screen. - mRenderData.transform.postTranslate( - (float) adjustedScreenWidth / 2 - cursorScreen[0], - (float) adjustedScreenHeight / 2 - cursorScreen[1]); - } + // Translate so the cursor is displayed in the middle of the screen. + mRenderData.transform.postTranslate( + (float) adjustedScreenWidth / 2 - cursorScreen[0], + (float) adjustedScreenHeight / 2 - cursorScreen[1]); // Get the coordinates of the desktop rectangle (top-left/bottom-right corners) in // screen coordinates. Order is: left, top, right, bottom. diff --git a/remoting/android/java/src/org/chromium/chromoting/DesktopView.java b/remoting/android/java/src/org/chromium/chromoting/DesktopView.java index ec63fee..5d015e5 100644 --- a/remoting/android/java/src/org/chromium/chromoting/DesktopView.java +++ b/remoting/android/java/src/org/chromium/chromoting/DesktopView.java @@ -412,7 +412,7 @@ public class DesktopView extends SurfaceView implements DesktopViewInterface, switch (inputMode) { case TRACKPAD: - mInputHandler.setInputStrategy(new TrackpadInputStrategy(this, mRenderData)); + mInputHandler.setInputStrategy(new TrackpadInputStrategy(mRenderData)); break; case TOUCH: diff --git a/remoting/android/java/src/org/chromium/chromoting/InputStrategyInterface.java b/remoting/android/java/src/org/chromium/chromoting/InputStrategyInterface.java index 1048f51..4f39962 100644 --- a/remoting/android/java/src/org/chromium/chromoting/InputStrategyInterface.java +++ b/remoting/android/java/src/org/chromium/chromoting/InputStrategyInterface.java @@ -4,33 +4,74 @@ package org.chromium.chromoting; +import android.view.MotionEvent; + /** * This interface defines the methods used to customize input handling for * a particular strategy. The implementing class is responsible for sending * remote input events and defining implementation specific behavior. */ public interface InputStrategyInterface { - /** Sends a pointer move event to the remote host. */ - void injectRemoteMoveEvent(int x, int y); + /** + * Called when a user tap has been detected. + * + * @param button The button value for the tap event. + * @return A boolean representing whether the event was handled. + */ + boolean onTap(int button); + + /** + * Called when the user has put one or more fingers down on the screen for a period of time. + * + * @param button The button value for the tap event. + * @return A boolean representing whether the event was handled. + */ + boolean onPressAndHold(int button); + + /** + * Called when a MotionEvent is received. This method allows the input strategy to store or + * react to specific MotionEvents as needed. + * + * @param event The original event for the current touch motion. + */ + void onMotionEvent(MotionEvent event); - /** Sends a pointer button event to the remote host. */ - void injectRemoteButtonEvent(int button, boolean pressed); + /** + * Called when the user is attempting to scroll/pan the remote UI. + * + * @param distanceX The distance moved along the x-axis. + * @param distanceY The distance moved along the y-axis. + */ + void onScroll(float distanceX, float distanceY); - /** Sends a scroll/pan event to the remote host. */ - void injectRemoteScrollEvent(int deltaX, int deltaY); + /** + * Called to update the remote cursor position. + * + * @param x The new x coordinate of the cursor. + * @param y The new y coordinate of the cursor. + */ + void injectCursorMoveEvent(int x, int y); - /** Returns the feedback animation type to use for a short press. */ + /** + * Returns the feedback animation type to use for a short press. + * + * @return The feedback to display when a short press occurs. + */ DesktopView.InputFeedbackType getShortPressFeedbackType(); - /** Returns the feedback animation type to use for a long press. */ + /** + * Returns the feedback animation type to use for a long press. + * + * @return The feedback to display when a long press occurs. + */ DesktopView.InputFeedbackType getLongPressFeedbackType(); /** - * Indicates whether the view should be manipulated to keep the cursor in the center or if the - * view and cursor are not linked. + * Indicates whether this input mode is an indirect input mode. Indirect input modes manipulate + * the cursor in a detached fashion (such as a trackpad) and direct input modes will update the + * cursor/screen position to match the location of the touch point. + * + * @return A boolean representing whether this input mode is indirect (true) or direct (false). */ - boolean centerCursorInView(); - - /** Indicates whether to invert cursor movement for panning/scrolling. */ - boolean invertCursorMovement(); + boolean isIndirectInputMode(); } diff --git a/remoting/android/java/src/org/chromium/chromoting/TouchInputHandler.java b/remoting/android/java/src/org/chromium/chromoting/TouchInputHandler.java index 71c3be0..e71abcd 100644 --- a/remoting/android/java/src/org/chromium/chromoting/TouchInputHandler.java +++ b/remoting/android/java/src/org/chromium/chromoting/TouchInputHandler.java @@ -52,9 +52,6 @@ public class TouchInputHandler implements TouchInputHandlerInterface { */ private float mSwipeThreshold; - /** Mouse-button currently held down, or BUTTON_UNDEFINED otherwise. */ - private int mHeldButton = BUTTON_UNDEFINED; - /** * Set to true to prevent any further movement of the cursor, for example, when showing the * keyboard to prevent the cursor wandering from the area where keystrokes should be sent. @@ -73,6 +70,12 @@ public class TouchInputHandler implements TouchInputHandlerInterface { */ private boolean mSwipeCompleted = false; + /** + * Set to true when a 1 finger pan gesture originates with a longpress. This means the user + * is performing a drag operation. + */ + private boolean mIsDragging = false; + public TouchInputHandler(DesktopViewInterface viewer, Context context, RenderData renderData) { mViewer = viewer; mRenderData = renderData; @@ -101,6 +104,11 @@ public class TouchInputHandler implements TouchInputHandlerInterface { @Override public boolean onTouchEvent(MotionEvent event) { + // Give the underlying input strategy a chance to observe the current motion event before + // passing it to the gesture detectors. This allows the input strategy to react to the + // event or save the payload for use in recreating the gesture remotely. + mInputStrategy.onMotionEvent(event); + // Avoid short-circuit logic evaluation - ensure all gesture detectors see all events so // that they generate correct notifications. boolean handled = mScroller.onTouchEvent(event); @@ -114,16 +122,13 @@ public class TouchInputHandler implements TouchInputHandlerInterface { mSuppressCursorMovement = false; mSuppressFling = false; mSwipeCompleted = false; + mIsDragging = false; break; case MotionEvent.ACTION_POINTER_DOWN: mTotalMotionY = 0; break; - case MotionEvent.ACTION_UP: - releaseAnyHeldButton(); - break; - default: break; } @@ -178,12 +183,11 @@ public class TouchInputHandler implements TouchInputHandlerInterface { @Override public void setInputStrategy(InputStrategyInterface inputStrategy) { mInputStrategy = inputStrategy; - mDesktopCanvas.setCenterCursorInView(mInputStrategy.centerCursorInView()); } /** Moves the mouse-cursor relative to the current position. */ private void moveCursorRelative(float deltaX, float deltaY) { - if (mInputStrategy.invertCursorMovement()) { + if (mInputStrategy.isIndirectInputMode() || mIsDragging) { deltaX = -deltaX; deltaY = -deltaY; } @@ -208,12 +212,17 @@ public class TouchInputHandler implements TouchInputHandlerInterface { newY = mRenderData.imageHeight; } + // Test if the cursor actually moved, which requires repainting the cursor and updating + // the position on the remote machine. + boolean cursorMoved = mRenderData.setCursorPosition((int) newX, (int) newY); + if (cursorMoved) { + mInputStrategy.injectCursorMoveEvent((int) newX, (int) newY); + } + mDesktopCanvas.setCursorPosition(newX, newY); } mDesktopCanvas.repositionImage(); - - mInputStrategy.injectRemoteMoveEvent((int) newX, (int) newY); } /** Processes a (multi-finger) swipe gesture. */ @@ -234,14 +243,6 @@ public class TouchInputHandler implements TouchInputHandlerInterface { return true; } - /** Injects a button-up event if the button is currently held down (during a drag event). */ - private void releaseAnyHeldButton() { - if (mHeldButton != BUTTON_UNDEFINED) { - mInputStrategy.injectRemoteButtonEvent(mHeldButton, false); - mHeldButton = BUTTON_UNDEFINED; - } - } - /** Responds to touch events filtered by the gesture detectors. */ private class GestureListener extends GestureDetector.SimpleOnGestureListener implements ScaleGestureDetector.OnScaleGestureListener, @@ -261,7 +262,7 @@ public class TouchInputHandler implements TouchInputHandlerInterface { } if (pointerCount == 2 && mSwipePinchDetector.isSwiping()) { - mInputStrategy.injectRemoteScrollEvent(-(int) distanceX, -(int) distanceY); + mInputStrategy.onScroll(distanceX, distanceY); // Prevent the cursor being moved or flung by the gesture. mSuppressCursorMovement = true; @@ -360,22 +361,26 @@ public class TouchInputHandler implements TouchInputHandlerInterface { int button = mouseButtonFromPointerCount(pointerCount); if (button == BUTTON_UNDEFINED) { return false; - } else { - mInputStrategy.injectRemoteButtonEvent(button, true); - mInputStrategy.injectRemoteButtonEvent(button, false); + } + + if (mInputStrategy.onTap(button)) { mViewer.showInputFeedback(mInputStrategy.getShortPressFeedbackType()); - return true; } + return true; } /** Called when a long-press is triggered for one or more fingers. */ @Override public void onLongPress(int pointerCount, float x, float y) { - mHeldButton = mouseButtonFromPointerCount(pointerCount); - if (mHeldButton != BUTTON_UNDEFINED) { - mInputStrategy.injectRemoteButtonEvent(mHeldButton, true); + int button = mouseButtonFromPointerCount(pointerCount); + if (button == BUTTON_UNDEFINED) { + return; + } + + if (mInputStrategy.onPressAndHold(button)) { mViewer.showInputFeedback(mInputStrategy.getLongPressFeedbackType()); mSuppressFling = true; + mIsDragging = true; } } diff --git a/remoting/android/java/src/org/chromium/chromoting/TrackpadInputStrategy.java b/remoting/android/java/src/org/chromium/chromoting/TrackpadInputStrategy.java index 93b1f22..b992124 100644 --- a/remoting/android/java/src/org/chromium/chromoting/TrackpadInputStrategy.java +++ b/remoting/android/java/src/org/chromium/chromoting/TrackpadInputStrategy.java @@ -5,6 +5,7 @@ package org.chromium.chromoting; import android.graphics.Point; +import android.view.MotionEvent; import org.chromium.chromoting.jni.JniInterface; @@ -15,31 +16,45 @@ import org.chromium.chromoting.jni.JniInterface; */ public class TrackpadInputStrategy implements InputStrategyInterface { private final RenderData mRenderData; - private final DesktopViewInterface mViewer; - public TrackpadInputStrategy(DesktopViewInterface viewer, RenderData renderData) { - mViewer = viewer; + /** Mouse-button currently held down, or BUTTON_UNDEFINED otherwise. */ + private int mHeldButton = TouchInputHandlerInterface.BUTTON_UNDEFINED; + + public TrackpadInputStrategy(RenderData renderData) { mRenderData = renderData; } @Override - public void injectRemoteMoveEvent(int x, int y) { - injectRemoteButtonEvent(x, y, TouchInputHandlerInterface.BUTTON_UNDEFINED, false); + public boolean onTap(int button) { + injectMouseButtonEvent(button, true); + injectMouseButtonEvent(button, false); + return true; } @Override - public void injectRemoteButtonEvent(int button, boolean pressed) { - Point cursorPosition; - synchronized (mRenderData) { - cursorPosition = mRenderData.getCursorPosition(); - } + public boolean onPressAndHold(int button) { + injectMouseButtonEvent(button, true); + mHeldButton = button; + return true; + } - injectRemoteButtonEvent(cursorPosition.x, cursorPosition.y, button, pressed); + @Override + public void onScroll(float distanceX, float distanceY) { + JniInterface.sendMouseWheelEvent((int) -distanceX, (int) -distanceY); } @Override - public void injectRemoteScrollEvent(int deltaX, int deltaY) { - JniInterface.sendMouseWheelEvent(deltaX, deltaY); + public void onMotionEvent(MotionEvent event) { + if (event.getActionMasked() == MotionEvent.ACTION_UP + && mHeldButton != TouchInputHandlerInterface.BUTTON_UNDEFINED) { + injectMouseButtonEvent(mHeldButton, false); + mHeldButton = TouchInputHandlerInterface.BUTTON_UNDEFINED; + } + } + + @Override + public void injectCursorMoveEvent(int x, int y) { + JniInterface.sendMouseEvent(x, y, TouchInputHandlerInterface.BUTTON_UNDEFINED, false); } @Override @@ -53,29 +68,15 @@ public class TrackpadInputStrategy implements InputStrategyInterface { } @Override - public boolean centerCursorInView() { - return true; - } - - @Override - public boolean invertCursorMovement() { + public boolean isIndirectInputMode() { return true; } - private void injectRemoteButtonEvent(int x, int y, int button, boolean pressed) { - boolean cursorMoved; + private void injectMouseButtonEvent(int button, boolean pressed) { + Point cursorPosition; synchronized (mRenderData) { - cursorMoved = mRenderData.setCursorPosition(x, y); - } - - if (button == TouchInputHandlerInterface.BUTTON_UNDEFINED && !cursorMoved) { - // No need to inject anything or repaint. - return; - } - - JniInterface.sendMouseEvent(x, y, button, pressed); - if (cursorMoved) { - mViewer.transformationChanged(); + cursorPosition = mRenderData.getCursorPosition(); } + JniInterface.sendMouseEvent(cursorPosition.x, cursorPosition.y, button, pressed); } } |