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

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

Issue 2441723004: [Android][Client] Updating the calculations used for image overpanning (Closed)
Patch Set: Pre-CR cleanup Created 4 years, 1 month 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
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2015 The Chromium Authors. All rights reserved. 1 // Copyright 2015 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.graphics.Matrix; 7 import android.graphics.Matrix;
8 import android.graphics.PointF; 8 import android.graphics.PointF;
9 import android.graphics.Rect; 9 import android.graphics.Rect;
10 import android.graphics.RectF; 10 import android.graphics.RectF;
11 11
12 /** 12 /**
13 * This class is responsible for transforming the desktop image matrix. 13 * This class is responsible for transforming the desktop image matrix.
14 */ 14 */
15 public class DesktopCanvas { 15 public class DesktopCanvas {
16 /** 16 private static final float EPSILON = 0.0001f;
Lambros 2016/10/24 22:20:33 Does this value need to be different from MINIMUM_
joedow 2016/10/25 02:28:18 This is used for floating point comparisons (speci
17 * Maximum allowed zoom level - see {@link #scaleAndRepositionImage()}. 17
18 */ 18 /** Maximum allowed zoom level - see {@link #scaleAndRepositionImage()}. */
19 private static final float MAX_ZOOM_FACTOR = 100.0f; 19 private static final float MAX_ZOOM_FACTOR = 100.0f;
20 20
21 /** 21 /** Used to smoothly reduce the viewport offset. */
22 * Used to smoothly reduce the amount of padding while the user is zooming. 22 private static final float OFFSET_REDUCTION_FACTOR = 0.85f;
23 */ 23
24 private static final float PADDING_REDUCTION_FACTOR = 0.85f; 24 /** Used to terminate the offset animation once a minimum offset(1 pixel) ha s been reached. */
25 private static final float MINIMUM_OFFSET_DISTANCE = 1;
Lambros 2016/10/24 22:20:33 This is in screen coordinates?
joedow 2016/10/25 02:28:18 It is in the same coordinates as mViewportOffset.
25 26
26 private final RenderStub mRenderStub; 27 private final RenderStub mRenderStub;
27 private final RenderData mRenderData; 28 private final RenderData mRenderData;
28 29
29 /** 30 /**
30 * Represents the actual center of the viewport in image space. This value needs to be a pair
31 * of floats so the desktop image can be positioned with sub-pixel accuracy for smoother panning
32 * animations at high zoom levels.
33 */
34 // TODO(joedow): See if we can collapse Viewport and Cursor position members . They were needed
35 // in the past due to how we calculated the center positions but may not be needed now.
36 private PointF mViewportPosition = new PointF();
37
38 /**
39 * Represents the desired center of the viewport in image space. This value may not represent 31 * Represents the desired center of the viewport in image space. This value may not represent
40 * the actual center of the viewport as adjustments are made to ensure as mu ch of the desktop is 32 * the actual center of the viewport as adjustments are made to ensure as mu ch of the desktop is
41 * visible as possible. This value needs to be a pair of floats so the desk top image can be 33 * visible as possible. This value needs to be a pair of floats so the desk top image can be
42 * positioned with sub-pixel accuracy for smoother panning animations at hig h zoom levels. 34 * positioned with sub-pixel accuracy for smoother panning animations at hig h zoom levels.
43 * Note: The internal cursor position may be placed outside of the image bou ndary, however the
44 * cursor position we inject on the host side is restricted to the actual im age dimensions.
45 */ 35 */
46 private PointF mCursorPosition = new PointF(); 36 private PointF mCursorPosition = new PointF();
47 37
48 /** 38 /**
49 * Represents the amount of space, in pixels, used by System UI on each edge of the screen. 39 * Represents the amount of space, in pixels, used by System UI on each edge of the screen.
50 */ 40 */
51 // TODO(joedow): Update usage of this member so it is a true Rect instead of a set of offsets.
52 private Rect mSystemUiScreenSize = new Rect(); 41 private Rect mSystemUiScreenSize = new Rect();
53 42
54 /** 43 /**
55 * Represents the amount of padding, in screen pixels, added to each edge of the desktop image. 44 * Represents the amount of space, in pixels, to shift the image under the v iewport. This value
56 * This extra space allows the user to reveal portions of the desktop image which are obscured 45 * is used to allow panning the image further than would be possible when us ing the normal
57 * by System UI. 46 * boundary values to account for System UI. This functionality ensures the user can view and
47 * interact with any area of the remote image, even when System UI might oth erwise obscure it.
58 */ 48 */
59 private RectF mVisibleImagePadding = new RectF(); 49 private PointF mViewportOffset = new PointF();
60 50
61 /** 51 /**
62 * Tracks whether to adjust the viewport to account for System UI. If false, the viewport 52 * Tracks whether to adjust the size of the viewport to account for System U I. If false, the
63 * center is the center of the screen. If true, then System UI offsets will be used to 53 * viewport center is mapped to the center of the screen. If true, then Sys tem UI sizes will be
64 * adjust the position of the viewport to ensure the cursor is visible. 54 * used to determine the center of the viewport.
65 */ 55 */
66 private boolean mAdjustViewportForSystemUi = false; 56 private boolean mAdjustViewportSizeForSystemUi = false;
67 57
68 /** 58 /* Used to perform per-frame rendering tasks. */
69 * Represents the amount of space, in pixels, to adjust the cursor center alo ng the y-axis. 59 private Event.ParameterCallback<Boolean, Void> mFrameRenderedCallback;
70 */
71 private float mCursorOffsetScreenY = 0.0f;
72 60
73 public DesktopCanvas(RenderStub renderStub, RenderData renderData) { 61 public DesktopCanvas(RenderStub renderStub, RenderData renderData) {
74 mRenderStub = renderStub; 62 mRenderStub = renderStub;
75 mRenderData = renderData; 63 mRenderData = renderData;
76 } 64 }
77 65
78 /** 66 /**
79 * Sets the desired center position of the viewport (a.k.a. the cursor posit ion) and ensures 67 * Sets the desired center position of the viewport (a.k.a. the cursor posit ion).
80 * the viewport is updated to include the cursor within it.
81 * 68 *
82 * @param newX The new x coordinate value for the desired center position. 69 * @param newX The new x coordinate value for the desired center position.
83 * @param newY The new y coordinate value for the desired center position. 70 * @param newY The new y coordinate value for the desired center position.
84 */ 71 */
85 public void setCursorPosition(float newX, float newY) { 72 public void setCursorPosition(float newX, float newY) {
86 // First set the cursor position since its potential values are a supers et of the viewport. 73 updateCursorPosition(newX, newY, getImageBounds());
87 mCursorPosition.set(newX, newY); 74 }
88 constrainPointToBounds(mCursorPosition, getImageBounds());
89 75
90 // Now set the viewport position based on the cursor. 76 /**
91 mViewportPosition.set(mCursorPosition); 77 * Sets the center of the viewport using an absolute position (in image coor dinates).
92 constrainPointToBounds(mViewportPosition, getViewportBounds()); 78 *
79 * @param newX The new x coordinate value for the center position of the vie wport.
80 * @param newY The new y coordinate value for the center position of the vie wport.
81 */
82 public void setViewportCenter(float newX, float newY) {
83 updateCursorPosition(newX, newY, getViewportBounds());
84 }
93 85
94 repositionImage(); 86 /**
87 * Shifts the cursor by the passed in values (in image coordinates).
88 *
89 * @param deltaX The distance (in image coordinates) to move the cursor alon g the x-axis.
90 * @param deltaY The distance (in image coordinates) to move the cursor alon g the y-axis.
91 * @return A point representing the new cursor position.
92 */
93 public PointF moveCursorPosition(float deltaX, float deltaY) {
94 updateCursorPosition(
95 mCursorPosition.x + deltaX, mCursorPosition.y + deltaY, getImage Bounds());
96 return new PointF(mCursorPosition.x, mCursorPosition.y);
95 } 97 }
96 98
97 /** 99 /**
98 * Shifts the viewport by the passed in values (in image coordinates). 100 * Shifts the viewport by the passed in values (in image coordinates).
99 * 101 *
100 * @param deltaX The distance (in image coordinates) to move the viewport al ong the x-axis. 102 * @param deltaX The distance (in image coordinates) to move the viewport al ong the x-axis.
101 * @param deltaY The distance (in image coordinates) to move the viewport al ong the y-axis. 103 * @param deltaY The distance (in image coordinates) to move the viewport al ong the y-axis.
102 */ 104 */
103 public void moveViewportCenter(float deltaX, float deltaY) { 105 public void moveViewportCenter(float deltaX, float deltaY) {
104 // Offset and adjust the viewport center position to fit the screen. 106 updateCursorPosition(
105 mViewportPosition.offset(deltaX, deltaY); 107 mCursorPosition.x + deltaX, mCursorPosition.y + deltaY, getViewp ortBounds());
106 constrainPointToBounds(mViewportPosition, getViewportBounds());
107
108 // We don't need to constrain the cursor position as the viewport positi on is always within
109 // the bounds of the potential cursor positions.
110 mCursorPosition.set(mViewportPosition);
111
112 repositionImage();
113 }
114
115 /**
116 * Shifts the cursor by the passed in values (in image coordinates) and adju sts the viewport.
117 *
118 * @param deltaX The distance (in image coordinates) to move the cursor alon g the x-axis.
119 * @param deltaY The distance (in image coordinates) to move the cursor alon g the y-axis.
120 * @return A point representing the new cursor position.
121 */
122 public PointF moveCursorPosition(float deltaX, float deltaY) {
123 setCursorPosition(mCursorPosition.x + deltaX, mCursorPosition.y + deltaY );
124 return new PointF(mCursorPosition.x, mCursorPosition.y);
125 } 108 }
126 109
127 /** 110 /**
128 * Handles System UI size and visibility changes. 111 * Handles System UI size and visibility changes.
129 * 112 *
130 * @param parameter The set of values defining the current System UI state. 113 * @param parameter The set of values defining the current System UI state.
131 */ 114 */
132 public void onSystemUiVisibilityChanged(SystemUiVisibilityChangedEventParame ter parameter) { 115 public void onSystemUiVisibilityChanged(SystemUiVisibilityChangedEventParame ter parameter) {
133 if (parameter.softInputMethodVisible) { 116 if (parameter.softInputMethodVisible) {
134 mSystemUiScreenSize.set(parameter.left, parameter.top, 117 mSystemUiScreenSize.set(
135 mRenderData.screenWidth - parameter.right, 118 parameter.left, parameter.top, parameter.right, parameter.bo ttom);
136 mRenderData.screenHeight - parameter.bottom);
137 119
138 if (mAdjustViewportForSystemUi) { 120 if (mFrameRenderedCallback != null) {
Lambros 2016/10/24 22:20:33 Please add a comment, or move this to a method cal
joedow 2016/10/25 02:28:19 Done!
139 // Adjust the cursor position to ensure it's visible when large System UI (1/3 or 121 mRenderStub.onCanvasRendered().remove(mFrameRenderedCallback);
140 // more of the total screen size) is displayed (typically the So ft Keyboard). 122 mFrameRenderedCallback = null;
141 // Without this change, it is difficult for users to enter text into edit controls
142 // which are located bottom of the screen and may not see the cu rsor at all.
143 if (mSystemUiScreenSize.bottom > (mRenderData.screenHeight / 3)) {
144 // Center the cursor within the viewable area (not obscured by System UI).
145 mCursorOffsetScreenY = (float) parameter.bottom / 2.0f;
146 } else {
147 mCursorOffsetScreenY = 0.0f;
148 }
149
150 // Apply the cursor offset.
151 setCursorPosition(mCursorPosition.x, mCursorPosition.y);
152 } 123 }
153 } else { 124 } else {
154 mCursorOffsetScreenY = 0.0f;
155 mSystemUiScreenSize.setEmpty(); 125 mSystemUiScreenSize.setEmpty();
126 startOffsetReductionAnimation();
156 } 127 }
128
129 repositionImage();
157 } 130 }
158 131
159 public void adjustViewportForSystemUi(boolean adjustViewportForSystemUi) { 132 public void adjustViewportForSystemUi(boolean adjustViewportForSystemUi) {
160 mAdjustViewportForSystemUi = adjustViewportForSystemUi; 133 mAdjustViewportSizeForSystemUi = adjustViewportForSystemUi;
134
135 // The viewport center may have changed so reposition the image to refle ct the new value.
136 repositionImage();
161 } 137 }
162 138
163 /** Resizes the image by zooming it such that the image is displayed without borders. */ 139 /** Resizes the image by zooming it such that the image is displayed without borders. */
164 public void resizeImageToFitScreen() { 140 public void resizeImageToFitScreen() {
165 // Protect against being called before the image has been initialized. 141 // Protect against being called before the image has been initialized.
166 if (mRenderData.imageWidth == 0 || mRenderData.imageHeight == 0) { 142 if (mRenderData.imageWidth == 0 || mRenderData.imageHeight == 0) {
167 return; 143 return;
168 } 144 }
169 145
170 float widthRatio = (float) mRenderData.screenWidth / mRenderData.imageWi dth; 146 float widthRatio = (float) mRenderData.screenWidth / mRenderData.imageWi dth;
171 float heightRatio = (float) mRenderData.screenHeight / mRenderData.image Height; 147 float heightRatio = (float) mRenderData.screenHeight / mRenderData.image Height;
172 float screenToImageScale = Math.max(widthRatio, heightRatio); 148 float screenToImageScale = Math.max(widthRatio, heightRatio);
173 149
174 // If the image is smaller than the screen in either dimension, then we want to scale it 150 // If the image is smaller than the screen in either dimension, then we want to scale it
175 // up to fit both and fill the screen with the image of the remote deskt op. 151 // up to fit both and fill the screen with the image of the remote deskt op.
176 if (screenToImageScale > 1.0f) { 152 if (screenToImageScale > 1.0f) {
177 mRenderData.transform.setScale(screenToImageScale, screenToImageScal e); 153 mRenderData.transform.setScale(screenToImageScale, screenToImageScal e);
178 } 154 }
179 } 155 }
180 156
181 /** 157 /**
182 * Repositions the image by translating and zooming it, to keep the zoom lev el within sensible 158 * Repositions the image by translating and zooming it, to keep the zoom lev el within sensible
183 * limits. The minimum zoom level is chosen to avoid black space around all 4 sides. The 159 * limits. The minimum zoom level is chosen to avoid letterboxing on all 4 s ides. The
184 * maximum zoom level is set arbitrarily, so that the user can zoom out agai n in a reasonable 160 * maximum zoom level is set arbitrarily, so that the user can zoom out agai n in a reasonable
185 * time, and to prevent arithmetic overflow problems from displaying the ima ge. 161 * time, and to prevent arithmetic overflow problems from displaying the ima ge.
186 * 162 *
187 * @param scaleFactor The factor used to zoom the canvas in or out. 163 * @param scaleFactor The factor used to zoom the canvas in or out.
188 * @param px The center x coordinate for the scale action. 164 * @param px The center x coordinate for the scale action.
189 * @param py The center y coordinate for the scale action. 165 * @param py The center y coordinate for the scale action.
190 * @param centerOnCursor Determines whether the viewport will be translated to the desired 166 * @param centerOnCursor Determines whether the viewport will be translated to the desired
191 * center position before being adjusted to fit the sc reen boundaries. 167 * center position before being adjusted to fit the sc reen boundaries.
192 */ 168 */
193 public void scaleAndRepositionImage( 169 public void scaleAndRepositionImage(
(...skipping 16 matching lines...) Expand all
210 mRenderData.transform.mapVectors(imageSize); 186 mRenderData.transform.mapVectors(imageSize);
211 187
212 if (imageSize[0] < mRenderData.screenWidth && imageSize[1] < mRenderData .screenHeight) { 188 if (imageSize[0] < mRenderData.screenWidth && imageSize[1] < mRenderData .screenHeight) {
213 // Displayed image is too small in both directions, so apply the min imum zoom 189 // Displayed image is too small in both directions, so apply the min imum zoom
214 // level needed to fit either the width or height. 190 // level needed to fit either the width or height.
215 float scale = Math.min((float) mRenderData.screenWidth / mRenderData .imageWidth, 191 float scale = Math.min((float) mRenderData.screenWidth / mRenderData .imageWidth,
216 (float) mRenderData.screenHeight / mRenderDat a.imageHeight); 192 (float) mRenderData.screenHeight / mRenderDat a.imageHeight);
217 mRenderData.transform.setScale(scale, scale); 193 mRenderData.transform.setScale(scale, scale);
218 } 194 }
219 195
220 // Trim the image padding if the user is zooming out. This prevents cas es where the image
221 // pops to the center when it reaches its minimum size. Note that we do not need to do
222 // anything when the user is zooming in as the canvas will expand and ab sorb the padding.
223 if (scaleFactor < 1.0f) {
224 mVisibleImagePadding.set(mVisibleImagePadding.left * PADDING_REDUCTI ON_FACTOR,
225 mVisibleImagePadding.top * PADDING_REDUCTION_FACTOR,
226 mVisibleImagePadding.right * PADDING_REDUCTION_FACTOR,
227 mVisibleImagePadding.bottom * PADDING_REDUCTION_FACTOR);
228 }
229
230 if (centerOnCursor) { 196 if (centerOnCursor) {
231 setCursorPosition(mCursorPosition.x, mCursorPosition.y); 197 setCursorPosition(mCursorPosition.x, mCursorPosition.y);
232 } else { 198 } else {
233 // Find the new screen center (it was probably changed during the zo om operation) and 199 // Find the new screen center (it probably changed during the zoom o peration) and update
234 // update the viewport and cursor. 200 // the viewport to smoothly track the zoom gesture.
235 float[] mappedPoints = { 201 float[] mappedPoints = {((float) mRenderData.screenWidth / 2) - mVie wportOffset.x,
236 ((float) mRenderData.screenWidth / 2), ((float) mRenderData. screenHeight / 2)}; 202 ((float) mRenderData.screenHeight / 2) - mViewportOffset.y};
237 Matrix screenToImage = new Matrix(); 203 Matrix screenToImage = new Matrix();
238 mRenderData.transform.invert(screenToImage); 204 mRenderData.transform.invert(screenToImage);
239 screenToImage.mapPoints(mappedPoints); 205 screenToImage.mapPoints(mappedPoints);
240 // The cursor is mapped to the center of the viewport in this case. 206 // The cursor is mapped to the center of the viewport in this case.
241 setCursorPosition(mappedPoints[0], mappedPoints[1]); 207 setViewportCenter(mappedPoints[0], mappedPoints[1]);
242 } 208 }
243 } 209 }
244 210
245 /** 211 /**
212 * Sets the new cursor position, bounded by the given rect, and updates the image transform to
213 * reflect the new position.
214 */
215 private void updateCursorPosition(float newX, float newY, RectF bounds) {
216 mCursorPosition.set(newX, newY);
217 constrainPointToBounds(mCursorPosition, bounds);
218
219 calculateViewportOffset(newX - mCursorPosition.x, newY - mCursorPosition .y);
220
221 repositionImage();
222 }
223
224 /**
225 * Returns the height of the screen (in screen coordinates) for use in calcu lations involving
226 * viewport positioning.
227 */
228 private float getAdjustedScreenHeight() {
229 float adjustedScreenHeight;
230 if (mAdjustViewportSizeForSystemUi && !mSystemUiScreenSize.isEmpty()) {
Lambros 2016/10/24 22:37:27 You're calling isEmpty() on something that isn't a
joedow 2016/10/25 02:28:18 It is an actual Rect (updated based on previous CR
231 // Find the center point of the viewport on the screen.
232 adjustedScreenHeight = mSystemUiScreenSize.bottom;
Lambros 2016/10/24 22:20:32 I don't follow this. For example, if the system ke
joedow 2016/10/25 02:28:19 Since this is a rect, given an example screen heig
233 } else {
234 adjustedScreenHeight = ((float) mRenderData.screenHeight);
235 }
236
237 return adjustedScreenHeight;
238 }
239
240 /**
241 * Returns the center position of the viewport (in screen coordinates) inclu ding adjustments.
242 */
243 private PointF getViewportCenter() {
244 return new PointF((float) mRenderData.screenWidth / 2, getAdjustedScreen Height() / 2);
245 }
246
247 /**
246 * Repositions the image by translating it (without affecting the zoom level ). 248 * Repositions the image by translating it (without affecting the zoom level ).
247 */ 249 */
248 private void repositionImage() { 250 private void repositionImage() {
249 // Map the current viewport position to screen coordinates and adjust th e image position. 251 PointF viewportPosition = new PointF(mCursorPosition.x, mCursorPosition. y);
250 float[] viewportPosition = {mViewportPosition.x, mViewportPosition.y}; 252 constrainPointToBounds(viewportPosition, getViewportBounds());
251 mRenderData.transform.mapPoints(viewportPosition); 253 float[] viewportAdjustment = {viewportPosition.x, viewportPosition.y};
254 mRenderData.transform.mapPoints(viewportAdjustment);
252 255
253 float viewportTransX = ((float) mRenderData.screenWidth / 2) - viewportP osition[0]; 256 // Adjust the viewport to include the overpan amount.
254 float viewportTransY = 257 viewportAdjustment[0] += mViewportOffset.x;
255 ((float) mRenderData.screenHeight / 2) - viewportPosition[1] - m CursorOffsetScreenY; 258 viewportAdjustment[1] += mViewportOffset.y;
256 259
257 // Translate the image to move the viewport to the expected screen locat ion. 260 // Translate the image to move the viewport to the expected screen locat ion.
258 mRenderData.transform.postTranslate(viewportTransX, viewportTransY); 261 PointF viewportCenter = getViewportCenter();
259 262 mRenderData.transform.postTranslate(
260 updateVisibleImagePadding(); 263 viewportCenter.x - viewportAdjustment[0], viewportCenter.y - vie wportAdjustment[1]);
261 264
262 mRenderStub.setTransformation(mRenderData.transform); 265 mRenderStub.setTransformation(mRenderData.transform);
263 } 266 }
264 267
265 /** 268 /**
266 * Updates the given point such that it refers to a coordinate within the bo unds provided. 269 * Updates the given point such that it refers to a coordinate within the bo unds provided.
267 * 270 *
268 * @param point The point to adjust, the original object is modified. 271 * @param point The point to adjust, the original object is modified.
269 * @param bounds The bounds used to constrain the point. 272 * @param bounds The bounds used to constrain the point.
270 */ 273 */
271 private void constrainPointToBounds(PointF point, RectF bounds) { 274 private void constrainPointToBounds(PointF point, RectF bounds) {
272 if (point.x < bounds.left) { 275 if (point.x < bounds.left) {
273 point.x = bounds.left; 276 point.x = bounds.left;
274 } else if (point.x > bounds.right) { 277 } else if (point.x > bounds.right) {
275 point.x = bounds.right; 278 point.x = bounds.right;
276 } 279 }
277 280
278 if (point.y < bounds.top) { 281 if (point.y < bounds.top) {
279 point.y = bounds.top; 282 point.y = bounds.top;
280 } else if (point.y > bounds.bottom) { 283 } else if (point.y > bounds.bottom) {
281 point.y = bounds.bottom; 284 point.y = bounds.bottom;
282 } 285 }
283 } 286 }
284 287
285 /** Returns a region which defines the set of valid cursor positions in imag e space. */ 288 /** Returns a region which defines the set of valid cursor positions in imag e space. */
286 private RectF getImageBounds() { 289 private RectF getImageBounds() {
287 // The set of valid cursor positions includes any point on the image as well as the padding. 290 return new RectF(0, 0, mRenderData.imageWidth, mRenderData.imageHeight);
288 // Padding is additional space added to the image which is the larger va lue of:
289 // - Potential overlap of the System UI and image content
290 // - Actual amount of padding already being used
291 //
292 // By expanding the area, we allow the user to move the cursor 'under' t he System UI which
293 // pulls the content out from under it and allows it to be visible. Onc e the System UI has
294 // been dismissed or changes size, we use the actual padding value inste ad which prevents
295 // the desktop image from 'snapping' back to pre-System UI state.
296 RectF systemUiOverlap = getSystemUiOverlap();
297 float[] padding = {Math.max(mVisibleImagePadding.left, systemUiOverlap.l eft),
298 Math.max(mVisibleImagePadding.top + mCursorOffsetScreenY, system UiOverlap.top),
299 Math.max(mVisibleImagePadding.right, systemUiOverlap.right),
300 Math.max(mVisibleImagePadding.bottom - mCursorOffsetScreenY,
301 systemUiOverlap.bottom)};
302 Matrix screenToImage = new Matrix();
303 mRenderData.transform.invert(screenToImage);
304 screenToImage.mapVectors(padding);
305
306 return new RectF(-padding[0], -padding[1], mRenderData.imageWidth + padd ing[2],
307 mRenderData.imageHeight + padding[3]);
308 } 291 }
309 292
310 /** Returns a region which defines the set of valid viewport center values i n image space. */ 293 /** Returns a region which defines the set of valid viewport center values i n image space. */
311 private RectF getViewportBounds() { 294 private RectF getViewportBounds() {
312 // The region of allowable viewport values is the imageBound rect, inset by the size of the 295 // The region of allowable viewport values is the imageBound rect, inset by the size of the
313 // viewport itself. This prevents over and under panning of the viewpor t while still 296 // viewport itself. This prevents over and under panning of the viewpor t while still
314 // allowing the user to see and interact with all pixels one the desktop image. 297 // allowing the user to see and interact with all pixels one the desktop image.
315 Matrix screenToImage = new Matrix(); 298 Matrix screenToImage = new Matrix();
316 mRenderData.transform.invert(screenToImage); 299 mRenderData.transform.invert(screenToImage);
317 300
318 float[] screenVectors = {(float) mRenderData.screenWidth, (float) mRende rData.screenHeight}; 301 PointF viewportCenter = getViewportCenter();
302 float[] screenVectors = {viewportCenter.x, viewportCenter.y};
319 screenToImage.mapVectors(screenVectors); 303 screenToImage.mapVectors(screenVectors);
320 304
321 PointF letterboxPadding = getLetterboxPadding(); 305 PointF letterboxPadding = getLetterboxPadding();
322 float[] letterboxPaddingVectors = {letterboxPadding.x, letterboxPadding. y}; 306 float[] letterboxPaddingVectors = {letterboxPadding.x, letterboxPadding. y};
323 screenToImage.mapVectors(letterboxPaddingVectors); 307 screenToImage.mapVectors(letterboxPaddingVectors);
324 308
325 // screenCenter values are 1/2 of a particular screen dimension mapped t o image space. 309 // screenCenter values are 1/2 of a particular screen dimension mapped t o image space.
326 float screenCenterX = (screenVectors[0] / 2.0f) - letterboxPaddingVector s[0]; 310 float screenCenterX = screenVectors[0] - letterboxPaddingVectors[0];
327 float screenCenterY = (screenVectors[1] / 2.0f) - letterboxPaddingVector s[1]; 311 float screenCenterY = screenVectors[1] - letterboxPaddingVectors[1];
328 RectF imageBounds = getImageBounds(); 312 RectF imageBounds = getImageBounds();
329 imageBounds.inset(screenCenterX, screenCenterY); 313 imageBounds.inset(screenCenterX, screenCenterY);
330 return imageBounds; 314 return imageBounds;
331 } 315 }
332 316
333 /** 317 /**
318 * Returns a region defining the maximum overpan distance required to view t he entire image
319 * given the current amount of System UI overlapping it.
320 */
321 private RectF getViewportOffsetBounds() {
322 // The allowable region is determined by:
323 // - Overlap of the System UI and image content
324 // - Current viewport offset
325 //
326 // The System UI overlap represents the maximum allowable offset, this i s used to bound the
327 // viewport movement in each direction. The current offset is used to p revent 'snapping'
328 // the image when the System UI overlap is reduced.
329 RectF overpanScreenRect =
330 new RectF(Math.min(mViewportOffset.x, 0.0f), Math.min(mViewportO ffset.y, 0.0f),
Lambros 2016/10/24 22:20:33 Would new RectF().union(mViewportOffset.x, mViewpo
joedow 2016/10/25 02:28:19 It does, union returns void though so I can't chai
331 Math.max(mViewportOffset.x, 0.0f), Math.max(mViewportOff set.y, 0.0f));
332
333 RectF systemUiOverlap = getSystemUiOverlap();
334 return new RectF(Math.min(overpanScreenRect.left, -systemUiOverlap.left) ,
335 Math.min(overpanScreenRect.top, -systemUiOverlap.top),
336 Math.max(overpanScreenRect.right, systemUiOverlap.right),
337 Math.max(overpanScreenRect.bottom, systemUiOverlap.bottom));
338 }
339
340 /**
334 * Provides the amount of padding needed to center the image content on the screen. 341 * Provides the amount of padding needed to center the image content on the screen.
335 */ 342 */
336 private PointF getLetterboxPadding() { 343 private PointF getLetterboxPadding() {
337 float[] imageVectors = {mRenderData.imageWidth, mRenderData.imageHeight} ; 344 float[] imageVectors = {mRenderData.imageWidth, mRenderData.imageHeight} ;
338 mRenderData.transform.mapVectors(imageVectors); 345 mRenderData.transform.mapVectors(imageVectors);
339 346
340 // We want to letterbox when the image is smaller than the screen in a s pecific dimension. 347 // We want to letterbox when the image is smaller than the screen in a s pecific dimension.
341 // Since we center the image, split the difference so it is equally dist ributed. 348 // Since we center the image, split the difference so it is equally dist ributed.
342 float widthAdjust = 349 float widthAdjust = Math.max(((float) mRenderData.screenWidth - imageVec tors[0]) / 2, 0);
343 Math.max(((float) mRenderData.screenWidth - imageVectors[0]) / 2 .0f, 0.0f); 350 float heightAdjust = Math.max((getAdjustedScreenHeight() - imageVectors[ 1]) / 2, 0);
344 float heightAdjust =
345 Math.max(((float) mRenderData.screenHeight - imageVectors[1]) / 2.0f, 0.0f);
346 351
347 return new PointF(widthAdjust, heightAdjust); 352 return new PointF(widthAdjust, heightAdjust);
348 } 353 }
349 354
350 /** 355 /**
351 * Returns the amount of System UI along each edge of the screen which could overlap the remote 356 * Returns the amount of System UI along each edge of the screen which could overlap the remote
352 * desktop image below it. This is the maximum amount that could overlap, n ot the actual value. 357 * desktop image below it. This is the maximum amount that could overlap, n ot the actual value.
353 */ 358 */
354 private RectF getSystemUiOverlap() { 359 private RectF getSystemUiOverlap() {
360 if (mSystemUiScreenSize.isEmpty()) {
361 return new RectF(mSystemUiScreenSize);
Lambros 2016/10/24 22:20:33 Just 'new RectF()', no need to pass in an empty Re
joedow 2016/10/25 02:28:18 Good point, I think this is left over from a previ
362 }
363
355 // letterBox padding represents the space added to the image to center i t on the screen. 364 // letterBox padding represents the space added to the image to center i t on the screen.
Lambros 2016/10/24 22:20:32 nit: Begin with capital letter, or enclose with ''
joedow 2016/10/25 02:28:18 Done.
356 // Since it does not contain any interactable UI, we ignore it when calc ulating the overlap 365 // Since it does not contain any interactable UI, we ignore it when calc ulating the overlap
357 // between the System UI and the remote desktop image. 366 // between the System UI and the remote desktop image.
358 // Note: Ignore negative padding (clamp to 0) since that means no overla p exists. 367 // Note: Ignore negative padding (clamp to 0) since that means no overla p exists.
368 float adjustedScreenHeight = getAdjustedScreenHeight();
359 PointF letterboxPadding = getLetterboxPadding(); 369 PointF letterboxPadding = getLetterboxPadding();
360 return new RectF(Math.max(mSystemUiScreenSize.left - letterboxPadding.x, 0.0f), 370 return new RectF(Math.max(mSystemUiScreenSize.left - letterboxPadding.x, 0.0f),
361 Math.max(mSystemUiScreenSize.top - letterboxPadding.y + mCursorO ffsetScreenY, 0.0f), 371 Math.max(mSystemUiScreenSize.top - letterboxPadding.y, 0.0f),
362 Math.max(mSystemUiScreenSize.right - letterboxPadding.x, 0.0f), 372 Math.max(mRenderData.screenWidth - mSystemUiScreenSize.right - l etterboxPadding.x,
363 Math.max(mSystemUiScreenSize.bottom - letterboxPadding.y - mCurs orOffsetScreenY, 373 0.0f),
374 Math.max(adjustedScreenHeight - mSystemUiScreenSize.bottom - let terboxPadding.y,
364 0.0f)); 375 0.0f));
365 } 376 }
366 377
367 /** 378 /**
368 * Calculates the amount of padding visible on each edge of the desktop imag e. 379 * Applies the given offset, as needed, to allow moving the image outside it s normal bounds.
369 */ 380 */
370 private void updateVisibleImagePadding() { 381 private void calculateViewportOffset(float offsetX, float offsetY) {
371 PointF letterboxPadding = getLetterboxPadding(); 382 if (mSystemUiScreenSize.isEmpty()) {
372 float[] imagePoints = {0.0f, 0.0f, mRenderData.imageWidth, mRenderData.i mageHeight}; 383 // We only want to change adjust the viewport offset when System UI is present.
Lambros 2016/10/24 22:20:33 Remove 'change' or 'adjust'.
joedow 2016/10/25 02:28:19 Done.
373 mRenderData.transform.mapPoints(imagePoints); 384 return;
385 }
374 386
375 mVisibleImagePadding.set(Math.max(imagePoints[0] - letterboxPadding.x, 0 .0f), 387 float[] offsets = {offsetX, offsetY};
376 Math.max(imagePoints[1] - letterboxPadding.y, 0.0f), 388 mRenderData.transform.mapVectors(offsets);
377 Math.max(mRenderData.screenWidth - imagePoints[2] - letterboxPad ding.x, 0.0f), 389
378 Math.max(mRenderData.screenHeight - imagePoints[3] - letterboxPa dding.y, 0.0f)); 390 // Use a temporary variable here as {@link #getViewportOffsetBounds()} u ses the current
391 // viewport offset as a maximum boundary. If we add the offset first, t he result ends up
392 // being unbounded. Thus we use a temporary object for the boundary cal culation.
393 PointF requestedOffset =
394 new PointF(mViewportOffset.x + offsets[0], mViewportOffset.y + o ffsets[1]);
395 constrainPointToBounds(requestedOffset, getViewportOffsetBounds());
396 mViewportOffset.set(requestedOffset);
397 }
398
399 /**
400 * Starts an animation to smoothly reduce the viewport offset. Does nothing if an animation is
401 * already running or the offset is already 0.
402 */
403 private void startOffsetReductionAnimation() {
404 if (mFrameRenderedCallback != null || Math.abs(mViewportOffset.length()) < EPSILON) {
405 return;
406 }
407
408 mFrameRenderedCallback = new Event.ParameterCallback<Boolean, Void>() {
409 @Override
410 public Boolean run(Void p) {
411 mViewportOffset.set(mViewportOffset.x * OFFSET_REDUCTION_FACTOR,
412 mViewportOffset.y * OFFSET_REDUCTION_FACTOR);
413
414 if (Math.abs(mViewportOffset.length()) < MINIMUM_OFFSET_DISTANCE ) {
415 mViewportOffset.set(0.0f, 0.0f);
416 mFrameRenderedCallback = null;
417 }
418
419 repositionImage();
420
421 return mFrameRenderedCallback != null;
422 }
423 };
424
425 mRenderStub.onCanvasRendered().addSelfRemovable(mFrameRenderedCallback);
379 } 426 }
380 } 427 }
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698