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.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 Loading... | |
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; |
66 | 69 |
70 /** Why the screen dimensions are changing. */ | |
garykac
2013/07/30 17:45:26
I don't understand this comment. What does TRUE me
solb
2013/07/30 18:17:39
Oops! That was left over from a more complicated i
| |
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 Loading... | |
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() > |
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 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
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; | |
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) { |
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 Loading... | |
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 } |
OLD | NEW |