summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--remoting/android/java/src/org/chromium/chromoting/DesktopView.java58
-rw-r--r--remoting/android/java/src/org/chromium/chromoting/DesktopViewInterface.java6
-rw-r--r--remoting/android/java/src/org/chromium/chromoting/TouchInputHandler.java8
-rw-r--r--remoting/android/java/src/org/chromium/chromoting/TrackingInputHandler.java53
4 files changed, 111 insertions, 14 deletions
diff --git a/remoting/android/java/src/org/chromium/chromoting/DesktopView.java b/remoting/android/java/src/org/chromium/chromoting/DesktopView.java
index 3a4f30c..5e04f23 100644
--- a/remoting/android/java/src/org/chromium/chromoting/DesktopView.java
+++ b/remoting/android/java/src/org/chromium/chromoting/DesktopView.java
@@ -106,6 +106,14 @@ public class DesktopView extends SurfaceView implements DesktopViewInterface, Ru
private FeedbackAnimator mFeedbackAnimator = new FeedbackAnimator();
+ // Variables to control animation by the TouchInputHandler.
+
+ /** Protects mInputAnimationRunning. */
+ private Object mAnimationLock = new Object();
+
+ /** Whether the TouchInputHandler has requested animation to be performed. */
+ private boolean mInputAnimationRunning = false;
+
public DesktopView(Activity context) {
super(context);
@@ -120,9 +128,7 @@ public class DesktopView extends SurfaceView implements DesktopViewInterface, Ru
getHolder().addCallback(this);
}
- /**
- * Request repainting of the desktop view.
- */
+ /** Request repainting of the desktop view. */
void requestRepaint() {
synchronized (mRenderData) {
if (mRepaintPending) {
@@ -187,20 +193,13 @@ public class DesktopView extends SurfaceView implements DesktopViewInterface, Ru
canvas.drawColor(Color.BLACK);
canvas.drawBitmap(image, 0, 0, new Paint());
- if (mFeedbackAnimator.isAnimationRunning()) {
+ boolean feedbackAnimationRunning = mFeedbackAnimator.isAnimationRunning();
+ if (feedbackAnimationRunning) {
float scaleFactor;
synchronized (mRenderData) {
scaleFactor = mRenderData.transform.mapRadius(1);
}
mFeedbackAnimator.render(canvas, x, y, 40 / scaleFactor);
-
- // Trigger a repaint request for the next frame of the animation.
- getHandler().postAtTime(new Runnable() {
- @Override
- public void run() {
- requestRepaint();
- }
- }, startTimeMs + 30);
}
Bitmap cursorBitmap = JniInterface.getCursorBitmap();
@@ -210,6 +209,31 @@ public class DesktopView extends SurfaceView implements DesktopViewInterface, Ru
}
getHolder().unlockCanvasAndPost(canvas);
+
+ synchronized (mAnimationLock) {
+ if (mInputAnimationRunning || feedbackAnimationRunning) {
+ getHandler().postAtTime(new Runnable() {
+ @Override
+ public void run() {
+ processAnimation();
+ }
+ }, startTimeMs + 30);
+ }
+ };
+ }
+
+ private void processAnimation() {
+ boolean running;
+ synchronized (mAnimationLock) {
+ running = mInputAnimationRunning;
+ }
+ if (running) {
+ mInputHandler.processAnimation();
+ }
+ running |= mFeedbackAnimator.isAnimationRunning();
+ if (running) {
+ requestRepaint();
+ }
}
/**
@@ -323,4 +347,14 @@ public class DesktopView extends SurfaceView implements DesktopViewInterface, Ru
public void transformationChanged() {
requestRepaint();
}
+
+ @Override
+ public void setAnimationEnabled(boolean enabled) {
+ synchronized (mAnimationLock) {
+ if (enabled && !mInputAnimationRunning) {
+ requestRepaint();
+ }
+ mInputAnimationRunning = enabled;
+ }
+ }
}
diff --git a/remoting/android/java/src/org/chromium/chromoting/DesktopViewInterface.java b/remoting/android/java/src/org/chromium/chromoting/DesktopViewInterface.java
index 18995f3..c0d50a0 100644
--- a/remoting/android/java/src/org/chromium/chromoting/DesktopViewInterface.java
+++ b/remoting/android/java/src/org/chromium/chromoting/DesktopViewInterface.java
@@ -25,4 +25,10 @@ public interface DesktopViewInterface {
* has been changed by the TouchInputHandler, which requires repainting.
*/
void transformationChanged();
+
+ /**
+ * Starts or stops an animation. Whilst the animation is running, the DesktopView will
+ * periodically call TouchInputHandler.processAnimation() and repaint itself.
+ */
+ void setAnimationEnabled(boolean enabled);
}
diff --git a/remoting/android/java/src/org/chromium/chromoting/TouchInputHandler.java b/remoting/android/java/src/org/chromium/chromoting/TouchInputHandler.java
index d546b47..bbbf4a6 100644
--- a/remoting/android/java/src/org/chromium/chromoting/TouchInputHandler.java
+++ b/remoting/android/java/src/org/chromium/chromoting/TouchInputHandler.java
@@ -11,7 +11,7 @@ import android.view.MotionEvent;
* switched. The DesktopView passes the low-level touchscreen events and other events via this
* interface. The implementation recognizes and processes the touchscreen gestures, and then
* performs actions on the DesktopView (such as panning/zooming the display, injecting input, or
- * showing/hiding UI elements).
+ * showing/hiding UI elements). All methods are called on the main UI thread.
*/
public interface TouchInputHandler {
// These constants must match those in the generated struct protoc::MouseEvent_MouseButton.
@@ -46,4 +46,10 @@ public interface TouchInputHandler {
* method returns.
*/
void onHostSizeChanged(int width, int height);
+
+ /**
+ * Whilst an animation is in progress, this method is called repeatedly until the animation is
+ * cancelled. After this method returns, the DesktopView will schedule a repaint.
+ */
+ void processAnimation();
}
diff --git a/remoting/android/java/src/org/chromium/chromoting/TrackingInputHandler.java b/remoting/android/java/src/org/chromium/chromoting/TrackingInputHandler.java
index 05e22db..daa4eb5 100644
--- a/remoting/android/java/src/org/chromium/chromoting/TrackingInputHandler.java
+++ b/remoting/android/java/src/org/chromium/chromoting/TrackingInputHandler.java
@@ -11,6 +11,7 @@ import android.util.Log;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
+import android.widget.Scroller;
/**
* This class implements the cursor-tracking behavior and gestures.
@@ -34,6 +35,9 @@ public class TrackingInputHandler implements TouchInputHandler {
private ScaleGestureDetector mZoomer;
private TapGestureDetector mTapDetector;
+ /** Used to calculate the physics for flinging the cursor. */
+ private Scroller mFlingScroller;
+
/**
* The current cursor position is stored here as floats, so that the desktop image can be
* positioned with sub-pixel accuracy, to give a smoother panning animation at high zoom levels.
@@ -78,6 +82,8 @@ public class TrackingInputHandler implements TouchInputHandler {
mZoomer = new ScaleGestureDetector(context, listener);
mTapDetector = new TapGestureDetector(context, listener);
+ mFlingScroller = new Scroller(context);
+
mCursorPosition = new PointF();
// The threshold needs to be bigger than the ScaledTouchSlop used by the gesture-detectors,
@@ -214,7 +220,6 @@ public class TrackingInputHandler implements TouchInputHandler {
return false;
}
-
/** Injects a button-up event if the button is currently held down (during a drag event). */
private void releaseAnyHeldButton() {
if (mHeldButton != BUTTON_UNDEFINED) {
@@ -232,6 +237,10 @@ public class TrackingInputHandler implements TouchInputHandler {
handled |= mTapDetector.onTouchEvent(event);
switch (event.getActionMasked()) {
+ case MotionEvent.ACTION_DOWN:
+ mViewer.setAnimationEnabled(false);
+ break;
+
case MotionEvent.ACTION_POINTER_DOWN:
mTotalMotionY = 0;
mSwipeCompleted = false;
@@ -262,6 +271,26 @@ public class TrackingInputHandler implements TouchInputHandler {
repositionImageWithZoom();
}
+ @Override
+ public void processAnimation() {
+ int previousX = mFlingScroller.getCurrX();
+ int previousY = mFlingScroller.getCurrY();
+ if (!mFlingScroller.computeScrollOffset()) {
+ mViewer.setAnimationEnabled(false);
+ return;
+ }
+ int deltaX = mFlingScroller.getCurrX() - previousX;
+ int deltaY = mFlingScroller.getCurrY() - previousY;
+ float delta[] = {(float)deltaX, (float)deltaY};
+ synchronized (mRenderData) {
+ Matrix canvasToImage = new Matrix();
+ mRenderData.transform.invert(canvasToImage);
+ canvasToImage.mapVectors(delta);
+ }
+
+ moveCursor(mCursorPosition.x + delta[0], mCursorPosition.y + delta[1]);
+ }
+
/** Responds to touch events filtered by the gesture detectors. */
private class GestureListener extends GestureDetector.SimpleOnGestureListener
implements ScaleGestureDetector.OnScaleGestureListener,
@@ -297,6 +326,28 @@ public class TrackingInputHandler implements TouchInputHandler {
return true;
}
+ /**
+ * Called when a fling gesture is recognized.
+ */
+ @Override
+ public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
+ // The fling physics calculation is based on screen coordinates, so that it will
+ // behave consistently at different zoom levels (and will work nicely at high zoom
+ // levels, since |mFlingScroller| outputs integer coordinates). However, the desktop
+ // will usually be panned as the cursor is moved across the desktop, which means the
+ // transformation mapping from screen to desktop coordinates will change. To deal with
+ // this, the cursor movement is computed from relative coordinate changes from
+ // |mFlingScroller|. This means the fling can be started at (0, 0) with no bounding
+ // constraints - the cursor is already constrained by the desktop size.
+ mFlingScroller.fling(0, 0, (int)velocityX, (int)velocityY, Integer.MIN_VALUE,
+ Integer.MAX_VALUE, Integer.MIN_VALUE, Integer.MAX_VALUE);
+ // Initialize the scroller's current offset coordinates, since they are used for
+ // calculating the delta values.
+ mFlingScroller.computeScrollOffset();
+ mViewer.setAnimationEnabled(true);
+ return true;
+ }
+
/** Called when the user is in the process of pinch-zooming. */
@Override
public boolean onScale(ScaleGestureDetector detector) {