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

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

Issue 21120005: Add Android Chromoting client keyboard input (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Improve related comments Created 7 years, 4 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.app.ActionBar;
8 import android.app.Activity;
8 import android.graphics.Bitmap; 9 import android.graphics.Bitmap;
9 import android.graphics.Canvas; 10 import android.graphics.Canvas;
10 import android.graphics.Color; 11 import android.graphics.Color;
11 import android.graphics.Matrix; 12 import android.graphics.Matrix;
12 import android.graphics.Paint; 13 import android.graphics.Paint;
13 import android.os.Bundle; 14 import android.os.Bundle;
14 import android.os.Looper; 15 import android.os.Looper;
15 import android.util.Log; 16 import android.util.Log;
16 import android.view.GestureDetector; 17 import android.view.GestureDetector;
17 import android.view.MotionEvent; 18 import android.view.MotionEvent;
(...skipping 27 matching lines...) Expand all
45 */ 46 */
46 private static final int BUTTON_UNDEFINED = 0; 47 private static final int BUTTON_UNDEFINED = 0;
47 private static final int BUTTON_LEFT = 1; 48 private static final int BUTTON_LEFT = 1;
48 private static final int BUTTON_RIGHT = 3; 49 private static final int BUTTON_RIGHT = 3;
49 50
50 /** Specifies one dimension of an image. */ 51 /** Specifies one dimension of an image. */
51 private static enum Constraint { 52 private static enum Constraint {
52 UNDEFINED, WIDTH, HEIGHT 53 UNDEFINED, WIDTH, HEIGHT
53 } 54 }
54 55
56 private ActionBar mActionBar;
57
55 private GestureDetector mScroller; 58 private GestureDetector mScroller;
56 private ScaleGestureDetector mZoomer; 59 private ScaleGestureDetector mZoomer;
57 60
58 /** Stores pan and zoom configuration and converts image coordinates to scre en coordinates. */ 61 /** Stores pan and zoom configuration and converts image coordinates to scre en coordinates. */
59 private Matrix mTransform; 62 private Matrix mTransform;
60 63
61 private int mScreenWidth; 64 private int mScreenWidth;
62 private int mScreenHeight; 65 private int mScreenHeight;
63 66
64 /** Specifies the dimension by which the zoom level is being lower-bounded. */ 67 /** Specifies the dimension by which the zoom level is being lower-bounded. */
65 private Constraint mConstraint; 68 private Constraint mConstraint;
Sergey Ulanov 2013/07/30 19:19:27 Should this be called mZoomConstraint?
solb 2013/07/30 21:30:54 Not really, since it also affects panning behavior
66 69
70 /** Whether the dimension of constraint should be reckecked on the next aspe ct ratio change. */
71 private boolean mRecheckConstraint;
72
67 /** Whether the right edge of the image was visible on-screen during the las t render. */ 73 /** Whether the right edge of the image was visible on-screen during the las t render. */
68 private boolean mRightUsedToBeOut; 74 private boolean mRightUsedToBeOut;
69 75
70 /** Whether the bottom edge of the image was visible on-screen during the la st render. */ 76 /** Whether the bottom edge of the image was visible on-screen during the la st render. */
71 private boolean mBottomUsedToBeOut; 77 private boolean mBottomUsedToBeOut;
72 78
73 private int mMouseButton; 79 private int mMouseButton;
74 private boolean mMousePressed; 80 private boolean mMousePressed;
75 81
76 /** Whether the canvas needs to be redrawn. The update occurs when its size is next updated. */ 82 public DesktopView(Activity context) {
77 private boolean mCanvasNeedsRedraw; 83 super(context);
84 mActionBar = context.getActionBar();
78 85
79 public DesktopView(Context context) {
80 super(context);
81 getHolder().addCallback(this); 86 getHolder().addCallback(this);
82 DesktopListener listener = new DesktopListener(); 87 DesktopListener listener = new DesktopListener();
83 mScroller = new GestureDetector(context, listener); 88 mScroller = new GestureDetector(context, listener);
84 mZoomer = new ScaleGestureDetector(context, listener); 89 mZoomer = new ScaleGestureDetector(context, listener);
85 90
86 mTransform = new Matrix(); 91 mTransform = new Matrix();
87 mScreenWidth = 0; 92 mScreenWidth = 0;
88 mScreenHeight = 0; 93 mScreenHeight = 0;
94
89 mConstraint = Constraint.UNDEFINED; 95 mConstraint = Constraint.UNDEFINED;
96 mRecheckConstraint = false;
90 97
91 mRightUsedToBeOut = false; 98 mRightUsedToBeOut = false;
92 mBottomUsedToBeOut = false; 99 mBottomUsedToBeOut = false;
93 100
94 mMouseButton = BUTTON_UNDEFINED; 101 mMouseButton = BUTTON_UNDEFINED;
95 mMousePressed = false; 102 mMousePressed = false;
96
97 mCanvasNeedsRedraw = false;
98 } 103 }
99 104
100 /** 105 /**
101 * Redraws the canvas. This should be done on a non-UI thread or it could 106 * Redraws the canvas. This should be done on a non-UI thread or it could
102 * cause the UI to lag. Specifically, it is currently invoked on the native 107 * cause the UI to lag. Specifically, it is currently invoked on the native
103 * graphics thread using a JNI. 108 * graphics thread using a JNI.
104 */ 109 */
105 @Override 110 @Override
106 public void run() { 111 public void run() {
107 if (Looper.myLooper() == Looper.getMainLooper()) { 112 if (Looper.myLooper() == Looper.getMainLooper()) {
(...skipping 12 matching lines...) Expand all
120 // Screen coordinates of two defining points of the image. 125 // Screen coordinates of two defining points of the image.
121 float[] topleft = {0, 0}; 126 float[] topleft = {0, 0};
122 mTransform.mapPoints(topleft); 127 mTransform.mapPoints(topleft);
123 float[] bottomright = {image.getWidth(), image.getHeight()}; 128 float[] bottomright = {image.getWidth(), image.getHeight()};
124 mTransform.mapPoints(bottomright); 129 mTransform.mapPoints(bottomright);
125 130
126 // Whether to rescale and recenter the view. 131 // Whether to rescale and recenter the view.
127 boolean recenter = false; 132 boolean recenter = false;
128 133
129 if (mConstraint == Constraint.UNDEFINED) { 134 if (mConstraint == Constraint.UNDEFINED) {
130 mConstraint = image.getWidth()/image.getHeight() > mScreenWidth/ mScreenHeight ? 135 mConstraint = (double)image.getWidth()/image.getHeight() >
Sergey Ulanov 2013/07/30 19:19:27 mConstraint is calculated and used in the same met
solb 2013/07/30 21:30:54 Sometimes we need to keep the old value between re
131 Constraint.WIDTH : Constraint.HEIGHT; 136 (double)mScreenWidth/mScreenHeight ? Constraint.WIDTH : Constraint.HEIGHT;
132 recenter = true; // We always rescale and recenter after a rota tion. 137 recenter = true; // We always rescale and recenter after a rota tion.
133 } 138 }
134 139
135 if (mConstraint == Constraint.WIDTH && 140 if (mConstraint == Constraint.WIDTH &&
136 ((int)(bottomright[0] - topleft[0] + 0.5) < mScreenWidth || recenter)) { 141 ((int)(bottomright[0] - topleft[0] + 0.5) < mScreenWidth || recenter)) {
137 // The vertical edges of the image are flush against the device' s screen edges 142 // The vertical edges of the image are flush against the device' s screen edges
138 // when the entire host screen is visible, and the user has zoom ed out too far. 143 // when the entire host screen is visible, and the user has zoom ed out too far.
139 float imageMiddle = (float)image.getHeight() / 2; 144 float imageMiddle = (float)image.getHeight() / 2;
140 float screenMiddle = (float)mScreenHeight / 2; 145 float screenMiddle = (float)mScreenHeight / 2;
141 mTransform.setPolyToPoly( 146 mTransform.setPolyToPoly(
(...skipping 26 matching lines...) Expand all
168 if (leftEdgeOutOfBounds != rightEdgeOutOfBounds) { 173 if (leftEdgeOutOfBounds != rightEdgeOutOfBounds) {
169 if (leftEdgeOutOfBounds != mRightUsedToBeOut) { 174 if (leftEdgeOutOfBounds != mRightUsedToBeOut) {
170 // Make the left edge of the image flush with the left s creen edge. 175 // Make the left edge of the image flush with the left s creen edge.
171 values[Matrix.MTRANS_X] = 0; 176 values[Matrix.MTRANS_X] = 0;
172 } 177 }
173 else { 178 else {
174 // Make the right edge of the image flush with the right screen edge. 179 // Make the right edge of the image flush with the right screen edge.
175 values[Matrix.MTRANS_X] += mScreenWidth - bottomright[0] ; 180 values[Matrix.MTRANS_X] += mScreenWidth - bottomright[0] ;
176 } 181 }
177 } 182 }
178 else { 183 else {
Sergey Ulanov 2013/07/30 19:19:27 nit: else goes to the previous line.
solb 2013/07/30 21:30:54 Handling in https://codereview.chromium.org/212360
179 // The else prevents this from being updated during the repo sitioning process, 184 // The else prevents this from being updated during the repo sitioning process,
180 // in which case the view would begin to oscillate. 185 // in which case the view would begin to oscillate.
181 mRightUsedToBeOut = rightEdgeOutOfBounds; 186 mRightUsedToBeOut = rightEdgeOutOfBounds;
182 } 187 }
183 188
184 // Prevent the user from scrolling past the top or bottom edge o f the image. 189 // Prevent the user from scrolling past the top or bottom edge o f the image.
185 if (topEdgeOutOfBounds != bottomEdgeOutOfBounds) { 190 if (topEdgeOutOfBounds != bottomEdgeOutOfBounds) {
186 if (topEdgeOutOfBounds != mBottomUsedToBeOut) { 191 if (topEdgeOutOfBounds != mBottomUsedToBeOut) {
187 // Make the top edge of the image flush with the top scr een edge. 192 // Make the top edge of the image flush with the top scr een edge.
188 values[Matrix.MTRANS_Y] = 0; 193 values[Matrix.MTRANS_Y] = 0;
189 } 194 }
190 else { 195 else {
191 // Make the bottom edge of the image flush with the bott om screen edge. 196 // Make the bottom edge of the image flush with the bott om screen edge.
192 values[Matrix.MTRANS_Y] += mScreenHeight - bottomright[1 ]; 197 values[Matrix.MTRANS_Y] += mScreenHeight - bottomright[1 ];
193 } 198 }
194 } 199 }
195 else { 200 else {
Sergey Ulanov 2013/07/30 19:19:27 same here.
solb 2013/07/30 21:30:54 https://codereview.chromium.org/21236002
196 // The else prevents this from being updated during the repo sitioning process, 201 // The else prevents this from being updated during the repo sitioning process,
197 // in which case the view would begin to oscillate. 202 // in which case the view would begin to oscillate.
198 mBottomUsedToBeOut = bottomEdgeOutOfBounds; 203 mBottomUsedToBeOut = bottomEdgeOutOfBounds;
199 } 204 }
200 205
201 mTransform.setValues(values); 206 mTransform.setValues(values);
202 } 207 }
203 208
204 canvas.setMatrix(mTransform); 209 canvas.setMatrix(mTransform);
205 } 210 }
206 211
207 canvas.drawColor(Color.BLACK); 212 canvas.drawColor(Color.BLACK);
208 canvas.drawBitmap(image, 0, 0, new Paint()); 213 canvas.drawBitmap(image, 0, 0, new Paint());
209 getHolder().unlockCanvasAndPost(canvas); 214 getHolder().unlockCanvasAndPost(canvas);
210 } 215 }
211 216
212 /** Causes the canvas to be redrawn the next time our surface changes. */ 217 /**
213 public void requestCanvasRedraw() { 218 * Causes the next canvas redraw to perform a check for which screen dimensi on more tightly
214 mCanvasNeedsRedraw = true; 219 * constrains the view of the image. This should be called between the time that a screen size
220 * change is requested and the time it actually occurs. If it is not called in such a case, the
221 * screen will not be rearranged as aggressively (which is desirable when th e software keyboard
222 * appears in order to allow it to cover the image without forcing a resize) .
223 */
224 public void requestRecheckConstrainingDimension() {
225 mRecheckConstraint = true;
Sergey Ulanov 2013/07/30 19:19:27 Can we reset mContraint here?
solb 2013/07/30 21:30:54 No, because we won't know the screen size until on
215 } 226 }
216 227
217 /** 228 /**
218 * Called after the canvas is initially created, then after every 229 * Called after the canvas is initially created, then after every
219 * subsequent resize, as when the display is rotated. 230 * subsequent resize, as when the display is rotated.
220 */ 231 */
221 @Override 232 @Override
222 public void surfaceChanged( 233 public void surfaceChanged(
223 SurfaceHolder holder, int format, int width, int height) { 234 SurfaceHolder holder, int format, int width, int height) {
235 mActionBar.hide();
236
224 synchronized (mTransform) { 237 synchronized (mTransform) {
225 mScreenWidth = width; 238 mScreenWidth = width;
226 mScreenHeight = height; 239 mScreenHeight = height;
227 mConstraint = Constraint.UNDEFINED; 240
241 if (mRecheckConstraint) {
242 mConstraint = Constraint.UNDEFINED;
243 mRecheckConstraint = false;
244 }
228 } 245 }
229 246
230 if (mCanvasNeedsRedraw) { 247 if (!JniInterface.redrawGraphics()) {
231 JniInterface.redrawGraphics(); 248 JniInterface.provideRedrawCallback(this);
232 mCanvasNeedsRedraw = false;
233 } 249 }
234 } 250 }
235 251
236 /** Called when the canvas is first created. */ 252 /** Called when the canvas is first created. */
237 @Override 253 @Override
238 public void surfaceCreated(SurfaceHolder holder) { 254 public void surfaceCreated(SurfaceHolder holder) {
239 Log.i("deskview", "DesktopView.surfaceCreated(...)"); 255 Log.i("deskview", "DesktopView.surfaceCreated(...)");
240 JniInterface.provideRedrawCallback(this);
241 } 256 }
242 257
243 /** 258 /**
244 * Called when the canvas is finally destroyed. Marks the canvas as needing a redraw so that it 259 * Called when the canvas is finally destroyed. Marks the canvas as needing a redraw so that it
245 * will not be blank if the user later switches back to our window. 260 * will not be blank if the user later switches back to our window.
246 */ 261 */
247 @Override 262 @Override
248 public void surfaceDestroyed(SurfaceHolder holder) { 263 public void surfaceDestroyed(SurfaceHolder holder) {
249 Log.i("deskview", "DesktopView.surfaceDestroyed(...)"); 264 Log.i("deskview", "DesktopView.surfaceDestroyed(...)");
265
266 // Stop this canvas from being redrawn.
250 JniInterface.provideRedrawCallback(null); 267 JniInterface.provideRedrawCallback(null);
251
252 // Redraw the desktop as soon as the user switches back to this window.
253 mCanvasNeedsRedraw = true;
254 } 268 }
255 269
256 /** Called when a mouse action is made. */ 270 /** Called when a mouse action is made. */
257 private void handleMouseMovement(float[] coordinates, int button, boolean pr essed) { 271 private void handleMouseMovement(float[] coordinates, int button, boolean pr essed) {
258 // Coordinates are relative to the canvas, but we need image coordinates . 272 // Coordinates are relative to the canvas, but we need image coordinates .
259 Matrix canvasToImage = new Matrix(); 273 Matrix canvasToImage = new Matrix();
260 mTransform.invert(canvasToImage); 274 mTransform.invert(canvasToImage);
261 canvasToImage.mapPoints(coordinates); 275 canvasToImage.mapPoints(coordinates);
262 276
263 // Coordinates are now relative to the image, so transmit them to the ho st. 277 // Coordinates are now relative to the image, so transmit them to the ho st.
264 JniInterface.mouseAction((int)coordinates[0], (int)coordinates[1], butto n, pressed); 278 JniInterface.mouseAction((int)coordinates[0], (int)coordinates[1], butto n, pressed);
265 } 279 }
266 280
267 /** 281 /**
268 * Called whenever the user attempts to touch the canvas. Forwards such 282 * Called whenever the user attempts to touch the canvas. Forwards such
269 * events to the appropriate gesture detector until one accepts them. 283 * events to the appropriate gesture detector until one accepts them.
270 */ 284 */
271 @Override 285 @Override
272 public boolean onTouchEvent(MotionEvent event) { 286 public boolean onTouchEvent(MotionEvent event) {
287 if (event.getPointerCount() == 3) {
288 mActionBar.show();
289 }
290
273 boolean handled = mScroller.onTouchEvent(event) || mZoomer.onTouchEvent( event); 291 boolean handled = mScroller.onTouchEvent(event) || mZoomer.onTouchEvent( event);
274 292
275 if (event.getPointerCount()==1) { 293 if (event.getPointerCount() == 1) {
Sergey Ulanov 2013/07/30 19:19:27 Do we still need to handle the event here when han
solb 2013/07/30 21:30:54 Unfortunately, in order to ensure the gesture dete
276 float[] coordinates = {event.getRawX(), event.getY()}; 294 float[] coordinates = {event.getRawX(), event.getY()};
277 295
278 switch (event.getActionMasked()) { 296 switch (event.getActionMasked()) {
279 case MotionEvent.ACTION_DOWN: 297 case MotionEvent.ACTION_DOWN:
280 Log.i("mouse", "Found a finger"); 298 Log.i("mouse", "Found a finger");
281 mMouseButton = BUTTON_UNDEFINED; 299 mMouseButton = BUTTON_UNDEFINED;
282 mMousePressed = false; 300 mMousePressed = false;
283 break; 301 break;
284 302
285 case MotionEvent.ACTION_MOVE: 303 case MotionEvent.ACTION_MOVE:
(...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after
395 handleMouseMovement(coordinates, mMouseButton, false); 413 handleMouseMovement(coordinates, mMouseButton, false);
396 } 414 }
397 415
398 Log.i("mouse", "\tStarting right click"); 416 Log.i("mouse", "\tStarting right click");
399 mMouseButton = BUTTON_RIGHT; 417 mMouseButton = BUTTON_RIGHT;
400 mMousePressed = true; 418 mMousePressed = true;
401 handleMouseMovement(coordinates, mMouseButton, mMousePressed); 419 handleMouseMovement(coordinates, mMouseButton, mMousePressed);
402 } 420 }
403 } 421 }
404 } 422 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698