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

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

Issue 19500017: Implement basic point-and-touch mouse input for Android client (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Bump version number to 0.01 Created 7 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 | Annotate | Revision Log
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.Bitmap; 8 import android.graphics.Bitmap;
9 import android.graphics.Canvas; 9 import android.graphics.Canvas;
10 import android.graphics.Color; 10 import android.graphics.Color;
(...skipping 14 matching lines...) Expand all
25 * The user interface for viewing and interacting with a specific remote host. 25 * The user interface for viewing and interacting with a specific remote host.
26 * It provides a canvas onto which the video feed is rendered, handles 26 * It provides a canvas onto which the video feed is rendered, handles
27 * multitouch pan and zoom gestures, and collects and forwards input events. 27 * multitouch pan and zoom gestures, and collects and forwards input events.
28 */ 28 */
29 /** GUI element that holds the drawing canvas. */ 29 /** GUI element that holds the drawing canvas. */
30 public class DesktopView extends SurfaceView implements Runnable, SurfaceHolder. Callback { 30 public class DesktopView extends SurfaceView implements Runnable, SurfaceHolder. Callback {
31 /** 31 /**
32 * *Square* of the minimum displacement (in pixels) to be recognized as a sc roll gesture. 32 * *Square* of the minimum displacement (in pixels) to be recognized as a sc roll gesture.
33 * Setting this to a lower value forces more frequent canvas redraws during scrolling. 33 * Setting this to a lower value forces more frequent canvas redraws during scrolling.
34 */ 34 */
35 private static int MIN_SCROLL_DISTANCE = 8 * 8; 35 private static final int MIN_SCROLL_DISTANCE = 8 * 8;
36 36
37 /** 37 /**
38 * Minimum change to the scaling factor to be recognized as a zoom gesture. Setting lower 38 * Minimum change to the scaling factor to be recognized as a zoom gesture. Setting lower
39 * values here will result in more frequent canvas redraws during zooming. 39 * values here will result in more frequent canvas redraws during zooming.
40 */ 40 */
41 private static double MIN_ZOOM_FACTOR = 0.05; 41 private static final double MIN_ZOOM_FACTOR = 0.05;
42
43 /*
44 * These constants must match those in the generated struct protoc::MouseEve nt_MouseButton.
45 */
46 private static final int BUTTON_UNDEFINED = 0;
47 private static final int BUTTON_LEFT = 1;
48 private static final int BUTTON_RIGHT = 3;
42 49
43 /** Specifies one dimension of an image. */ 50 /** Specifies one dimension of an image. */
44 private static enum Constraint { 51 private static enum Constraint {
45 UNDEFINED, WIDTH, HEIGHT 52 UNDEFINED, WIDTH, HEIGHT
46 } 53 }
47 54
48 private GestureDetector mScroller; 55 private GestureDetector mScroller;
49 private ScaleGestureDetector mZoomer; 56 private ScaleGestureDetector mZoomer;
50 57
51 /** Stores pan and zoom configuration and converts image coordinates to scre en coordinates. */ 58 /** Stores pan and zoom configuration and converts image coordinates to scre en coordinates. */
52 private Matrix mTransform; 59 private Matrix mTransform;
53 60
54 private int mScreenWidth; 61 private int mScreenWidth;
55 private int mScreenHeight; 62 private int mScreenHeight;
56 63
57 /** Specifies the dimension by which the zoom level is being lower-bounded. */ 64 /** Specifies the dimension by which the zoom level is being lower-bounded. */
58 private Constraint mConstraint; 65 private Constraint mConstraint;
59 66
60 /** Whether the right edge of the image was visible on-screen during the las t render. */ 67 /** Whether the right edge of the image was visible on-screen during the las t render. */
61 private boolean mRightUsedToBeOut; 68 private boolean mRightUsedToBeOut;
62 69
63 /** Whether the bottom edge of the image was visible on-screen during the la st render. */ 70 /** Whether the bottom edge of the image was visible on-screen during the la st render. */
64 private boolean mBottomUsedToBeOut; 71 private boolean mBottomUsedToBeOut;
65 72
73 private int mMouseButton;
74 private boolean mMousePressed;
75
66 /** Whether the device has just been rotated, necessitating a canvas redraw. */ 76 /** Whether the device has just been rotated, necessitating a canvas redraw. */
67 private boolean mJustRotated; 77 private boolean mJustRotated;
68 78
69 public DesktopView(Context context) { 79 public DesktopView(Context context) {
70 super(context); 80 super(context);
71 getHolder().addCallback(this); 81 getHolder().addCallback(this);
72 DesktopListener listener = new DesktopListener(); 82 DesktopListener listener = new DesktopListener();
73 mScroller = new GestureDetector(context, listener); 83 mScroller = new GestureDetector(context, listener);
74 mZoomer = new ScaleGestureDetector(context, listener); 84 mZoomer = new ScaleGestureDetector(context, listener);
75 85
76 mTransform = new Matrix(); 86 mTransform = new Matrix();
77 mScreenWidth = 0; 87 mScreenWidth = 0;
78 mScreenHeight = 0; 88 mScreenHeight = 0;
79 mConstraint = Constraint.UNDEFINED; 89 mConstraint = Constraint.UNDEFINED;
80 90
81 mRightUsedToBeOut = false; 91 mRightUsedToBeOut = false;
82 mBottomUsedToBeOut = false; 92 mBottomUsedToBeOut = false;
83 93
94 mMouseButton = BUTTON_UNDEFINED;
95 mMousePressed = false;
96
84 mJustRotated = false; 97 mJustRotated = false;
85 } 98 }
86 99
87 /** 100 /**
88 * Redraws the canvas. This should be done on a non-UI thread or it could 101 * Redraws the canvas. This should be done on a non-UI thread or it could
89 * cause the UI to lag. Specifically, it is currently invoked on the native 102 * cause the UI to lag. Specifically, it is currently invoked on the native
90 * graphics thread using a JNI. 103 * graphics thread using a JNI.
91 */ 104 */
92 @Override 105 @Override
93 public void run() { 106 public void run() {
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
144 // screen's edges, which indicates that the image is zoomed in t o far to see the 157 // screen's edges, which indicates that the image is zoomed in t o far to see the
145 // whole host screen. However, if only one of a pair of edges ha s entered the 158 // whole host screen. However, if only one of a pair of edges ha s entered the
146 // screen, the user is attempting to scroll into a blank area of the canvas. 159 // screen, the user is attempting to scroll into a blank area of the canvas.
147 160
148 // A value of true means the corresponding edge has entered the screen's borders. 161 // A value of true means the corresponding edge has entered the screen's borders.
149 boolean leftEdgeOutOfBounds = values[Matrix.MTRANS_X] > 0; 162 boolean leftEdgeOutOfBounds = values[Matrix.MTRANS_X] > 0;
150 boolean topEdgeOutOfBounds = values[Matrix.MTRANS_Y] > 0; 163 boolean topEdgeOutOfBounds = values[Matrix.MTRANS_Y] > 0;
151 boolean rightEdgeOutOfBounds = bottomright[0] < mScreenWidth; 164 boolean rightEdgeOutOfBounds = bottomright[0] < mScreenWidth;
152 boolean bottomEdgeOutOfBounds = bottomright[1] < mScreenHeight; 165 boolean bottomEdgeOutOfBounds = bottomright[1] < mScreenHeight;
153 166
167 // Prevent the user from scrolling past the left or right edge o f the image.
154 if (leftEdgeOutOfBounds != rightEdgeOutOfBounds) { 168 if (leftEdgeOutOfBounds != rightEdgeOutOfBounds) {
155 if (leftEdgeOutOfBounds != mRightUsedToBeOut) { 169 if (leftEdgeOutOfBounds != mRightUsedToBeOut) {
170 // Make the left edge of the image flush with the left s creen edge.
156 values[Matrix.MTRANS_X] = 0; 171 values[Matrix.MTRANS_X] = 0;
157 } 172 }
158 else { 173 else {
174 // Make the right edge of the image flush with the right screen edge.
159 values[Matrix.MTRANS_X] += mScreenWidth - bottomright[0] ; 175 values[Matrix.MTRANS_X] += mScreenWidth - bottomright[0] ;
160 } 176 }
161 } 177 }
162 else { // The view would oscillate if this were updated while s crolling off-screen. 178 else {
179 // The else prevents this from being updated during the repo sitioning process,
180 // in which case the view would begin to oscillate.
163 mRightUsedToBeOut = rightEdgeOutOfBounds; 181 mRightUsedToBeOut = rightEdgeOutOfBounds;
164 } 182 }
165 183
184 // Prevent the user from scrolling past the top or bottom edge o f the image.
166 if (topEdgeOutOfBounds != bottomEdgeOutOfBounds) { 185 if (topEdgeOutOfBounds != bottomEdgeOutOfBounds) {
167 if (topEdgeOutOfBounds != mBottomUsedToBeOut) { 186 if (topEdgeOutOfBounds != mBottomUsedToBeOut) {
187 // Make the top edge of the image flush with the top scr een edge.
168 values[Matrix.MTRANS_Y] = 0; 188 values[Matrix.MTRANS_Y] = 0;
169 } 189 }
170 else { 190 else {
191 // Make the bottom edge of the image flush with the bott om screen edge.
171 values[Matrix.MTRANS_Y] += mScreenHeight - bottomright[1 ]; 192 values[Matrix.MTRANS_Y] += mScreenHeight - bottomright[1 ];
172 } 193 }
173 } 194 }
174 else { // The view would oscillate if this were updated while s crolling off-screen. 195 else {
196 // The else prevents this from being updated during the repo sitioning process,
197 // in which case the view would begin to oscillate.
175 mBottomUsedToBeOut = bottomEdgeOutOfBounds; 198 mBottomUsedToBeOut = bottomEdgeOutOfBounds;
176 } 199 }
177 200
178 mTransform.setValues(values); 201 mTransform.setValues(values);
179 } 202 }
180 203
181 canvas.setMatrix(mTransform); 204 canvas.setMatrix(mTransform);
182 } 205 }
183 206
184 canvas.drawColor(Color.BLACK); 207 canvas.drawColor(Color.BLACK);
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
217 Log.i("deskview", "DesktopView.surfaceCreated(...)"); 240 Log.i("deskview", "DesktopView.surfaceCreated(...)");
218 JniInterface.provideRedrawCallback(this); 241 JniInterface.provideRedrawCallback(this);
219 } 242 }
220 243
221 /** Called when the canvas is finally destroyed. */ 244 /** Called when the canvas is finally destroyed. */
222 @Override 245 @Override
223 public void surfaceDestroyed(SurfaceHolder holder) { 246 public void surfaceDestroyed(SurfaceHolder holder) {
224 Log.i("deskview", "DesktopView.surfaceDestroyed(...)"); 247 Log.i("deskview", "DesktopView.surfaceDestroyed(...)");
225 } 248 }
226 249
250 /** Called when a mouse action is made. */
251 private void handleMouseMovement(float[] coordinates, int button, boolean pr essed) {
252 // Coordinates are relative to the canvas, but we need image coordinates .
253 Matrix canvasToImage = new Matrix();
254 mTransform.invert(canvasToImage);
255 canvasToImage.mapPoints(coordinates);
256
257 // Coordinates are now relative to the image, so transmit them to the ho st.
258 JniInterface.mouseAction((int)coordinates[0], (int)coordinates[1], butto n, pressed);
259 }
260
227 /** 261 /**
228 * Called whenever the user attempts to touch the canvas. Forwards such 262 * Called whenever the user attempts to touch the canvas. Forwards such
229 * events to the appropriate gesture detector until one accepts them. 263 * events to the appropriate gesture detector until one accepts them.
230 */ 264 */
231 @Override 265 @Override
232 public boolean onTouchEvent(MotionEvent event) { 266 public boolean onTouchEvent(MotionEvent event) {
233 return mScroller.onTouchEvent(event) || mZoomer.onTouchEvent(event); 267 boolean handled = mScroller.onTouchEvent(event) || mZoomer.onTouchEvent( event);
268
269 if (event.getPointerCount()==1) {
270 float[] coordinates = {event.getRawX(), event.getY()};
271
272 switch (event.getActionMasked()) {
273 case MotionEvent.ACTION_DOWN:
274 Log.i("mouse", "Found a finger");
275 mMouseButton = BUTTON_UNDEFINED;
276 mMousePressed = false;
277 break;
278
279 case MotionEvent.ACTION_MOVE:
280 Log.i("mouse", "Finger is dragging");
281 if (mMouseButton == BUTTON_UNDEFINED) {
282 Log.i("mouse", "\tStarting left click");
283 mMouseButton = BUTTON_LEFT;
284 mMousePressed = true;
285 }
286 break;
287
288 case MotionEvent.ACTION_UP:
289 Log.i("mouse", "Lost the finger");
290 if (mMouseButton == BUTTON_UNDEFINED) {
291 // The user pressed and released without moving: do left click and release.
292 Log.i("mouse", "\tStarting and finishing left click");
293 handleMouseMovement(coordinates, BUTTON_LEFT, true);
294 mMouseButton = BUTTON_LEFT;
295 mMousePressed = false;
296 }
297 else if (mMousePressed) {
298 Log.i("mouse", "\tReleasing the currently-pressed button ");
299 mMousePressed = false;
300 }
301 else {
302 Log.w("mouse", "Button already in released state before gesture ended");
303 }
304 break;
305
306 default:
307 return handled;
308 }
309 handleMouseMovement(coordinates, mMouseButton, mMousePressed);
310
311 return true;
312 }
313
314 return handled;
234 } 315 }
235 316
236 /** Responds to touch events filtered by the gesture detectors. */ 317 /** Responds to touch events filtered by the gesture detectors. */
237 private class DesktopListener extends GestureDetector.SimpleOnGestureListene r 318 private class DesktopListener extends GestureDetector.SimpleOnGestureListene r
238 implements ScaleGestureDetector.OnScaleGestureListener { 319 implements ScaleGestureDetector.OnScaleGestureListener {
239 /** 320 /**
240 * Called when the user is scrolling. We refuse to accept or process the event unless it 321 * Called when the user is scrolling. We refuse to accept or process the event unless it
241 * is being performed with 2 or more touch points, in order to reserve s ingle-point touch 322 * is being performed with 2 or more touch points, in order to reserve s ingle-point touch
242 * events for emulating mouse input. 323 * events for emulating mouse input.
243 */ 324 */
(...skipping 21 matching lines...) Expand all
265 346
266 synchronized (mTransform) { 347 synchronized (mTransform) {
267 float scaleFactor = detector.getScaleFactor(); 348 float scaleFactor = detector.getScaleFactor();
268 mTransform.postScale( 349 mTransform.postScale(
269 scaleFactor, scaleFactor, detector.getFocusX(), detector .getFocusY()); 350 scaleFactor, scaleFactor, detector.getFocusX(), detector .getFocusY());
270 } 351 }
271 JniInterface.redrawGraphics(); 352 JniInterface.redrawGraphics();
272 return true; 353 return true;
273 } 354 }
274 355
356 /** Called whenever a gesture starts. Always accepts the gesture so it i sn't ignored. */
357 @Override
358 public boolean onDown(MotionEvent e) {
359 return true;
360 }
361
275 /** 362 /**
276 * Called when the user starts to zoom. Always accepts the zoom so that 363 * Called when the user starts to zoom. Always accepts the zoom so that
277 * onScale() can decide whether to respond to it. 364 * onScale() can decide whether to respond to it.
278 */ 365 */
279 @Override 366 @Override
280 public boolean onScaleBegin(ScaleGestureDetector detector) { 367 public boolean onScaleBegin(ScaleGestureDetector detector) {
281 return true; 368 return true;
282 } 369 }
283 370
284 /** 371 /** Called when the user is done zooming. Defers to onScale()'s judgemen t. */
285 * Called when the user is done zooming. Defers to onScale()'s judgement .
286 */
287 @Override 372 @Override
288 public void onScaleEnd(ScaleGestureDetector detector) { 373 public void onScaleEnd(ScaleGestureDetector detector) {
289 onScale(detector); 374 onScale(detector);
290 } 375 }
376
377 /** Called when the user holds down on the screen. Starts a right-click. */
378 @Override
379 public void onLongPress(MotionEvent e) {
380 if (e.getPointerCount() > 1) {
381 return;
382 }
383
384 float[] coordinates = new float[] {e.getRawX(), e.getY()};
385
386 Log.i("mouse", "Finger held down");
387 if (mMousePressed) {
388 Log.i("mouse", "\tReleasing the currently-pressed button");
389 handleMouseMovement(coordinates, mMouseButton, false);
390 }
391
392 Log.i("mouse", "\tStarting right click");
393 mMouseButton = BUTTON_RIGHT;
394 mMousePressed = true;
395 handleMouseMovement(coordinates, mMouseButton, mMousePressed);
396 }
291 } 397 }
292 } 398 }
OLDNEW
« no previous file with comments | « remoting/android/java/AndroidManifest.xml ('k') | remoting/android/java/src/org/chromium/chromoting/jni/JniInterface.java » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698