| 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.content.Context; |
| 8 import android.graphics.Matrix; | 8 import android.graphics.Matrix; |
| 9 import android.graphics.PointF; | 9 import android.graphics.PointF; |
| 10 import android.graphics.Rect; |
| 11 import android.graphics.RectF; |
| 10 import android.view.GestureDetector; | 12 import android.view.GestureDetector; |
| 11 import android.view.MotionEvent; | 13 import android.view.MotionEvent; |
| 12 import android.view.ScaleGestureDetector; | 14 import android.view.ScaleGestureDetector; |
| 13 import android.widget.Scroller; | 15 import android.widget.Scroller; |
| 14 | 16 |
| 15 /** | 17 /** |
| 16 * This class implements the cursor-tracking behavior and gestures. | 18 * This class implements the cursor-tracking behavior and gestures. |
| 17 */ | 19 */ |
| 18 public class TrackingInputHandler implements TouchInputHandler { | 20 public class TrackingInputHandler implements TouchInputHandler { |
| 19 /** | 21 /** |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 72 * dragging whilst a button is held down. | 74 * dragging whilst a button is held down. |
| 73 */ | 75 */ |
| 74 private boolean mSuppressFling = false; | 76 private boolean mSuppressFling = false; |
| 75 | 77 |
| 76 /** | 78 /** |
| 77 * Set to true when 3-finger swipe gesture is complete, so that further move
ment doesn't | 79 * Set to true when 3-finger swipe gesture is complete, so that further move
ment doesn't |
| 78 * trigger more swipe actions. | 80 * trigger more swipe actions. |
| 79 */ | 81 */ |
| 80 private boolean mSwipeCompleted = false; | 82 private boolean mSwipeCompleted = false; |
| 81 | 83 |
| 82 public TrackingInputHandler(DesktopViewInterface viewer, Context context, | 84 /** |
| 83 RenderData renderData) { | 85 * Represents the amount of vertical space in pixels used by the soft input
device and |
| 86 * accompanying system UI. |
| 87 */ |
| 88 private int mInputMethodOffsetY = 0; |
| 89 |
| 90 /** |
| 91 * Represents the amount of horizontal space in pixels used by the soft inpu
t device and |
| 92 * accompanying system UI. |
| 93 */ |
| 94 private int mInputMethodOffsetX = 0; |
| 95 |
| 96 public TrackingInputHandler( |
| 97 DesktopViewInterface viewer, Context context, RenderData renderData)
{ |
| 84 mViewer = viewer; | 98 mViewer = viewer; |
| 85 mRenderData = renderData; | 99 mRenderData = renderData; |
| 86 | 100 |
| 87 GestureListener listener = new GestureListener(); | 101 GestureListener listener = new GestureListener(); |
| 88 mScroller = new GestureDetector(context, listener, null, false); | 102 mScroller = new GestureDetector(context, listener, null, false); |
| 89 | 103 |
| 90 // If long-press is enabled, the gesture-detector will not emit any furt
her onScroll | 104 // If long-press is enabled, the gesture-detector will not emit any furt
her onScroll |
| 91 // notifications after the onLongPress notification. Since onScroll is b
eing used for | 105 // notifications after the onLongPress notification. Since onScroll is b
eing used for |
| 92 // moving the cursor, it means that the cursor would become stuck if the
finger were held | 106 // moving the cursor, it means that the cursor would become stuck if the
finger were held |
| 93 // down too long. | 107 // down too long. |
| (...skipping 29 matching lines...) Expand all Loading... |
| 123 | 137 |
| 124 mViewer.injectMouseEvent((int) newX, (int) newY, BUTTON_UNDEFINED, false
); | 138 mViewer.injectMouseEvent((int) newX, (int) newY, BUTTON_UNDEFINED, false
); |
| 125 } | 139 } |
| 126 | 140 |
| 127 /** | 141 /** |
| 128 * Repositions the image by translating it (without affecting the zoom level
) to place the | 142 * Repositions the image by translating it (without affecting the zoom level
) to place the |
| 129 * cursor close to the center of the screen. | 143 * cursor close to the center of the screen. |
| 130 */ | 144 */ |
| 131 private void repositionImage() { | 145 private void repositionImage() { |
| 132 synchronized (mRenderData) { | 146 synchronized (mRenderData) { |
| 147 float adjustedScreenWidth = mRenderData.screenWidth - mInputMethodOf
fsetX; |
| 148 float adjustedScreenHeight = mRenderData.screenHeight - mInputMethod
OffsetY; |
| 149 |
| 133 // Get the current cursor position in screen coordinates. | 150 // Get the current cursor position in screen coordinates. |
| 134 float[] cursorScreen = {mCursorPosition.x, mCursorPosition.y}; | 151 float[] cursorScreen = {mCursorPosition.x, mCursorPosition.y}; |
| 135 mRenderData.transform.mapPoints(cursorScreen); | 152 mRenderData.transform.mapPoints(cursorScreen); |
| 136 | 153 |
| 137 // Translate so the cursor is displayed in the middle of the screen. | 154 // Translate so the cursor is displayed in the middle of the screen. |
| 138 mRenderData.transform.postTranslate( | 155 mRenderData.transform.postTranslate((float) adjustedScreenWidth / 2
- cursorScreen[0], |
| 139 (float) mRenderData.screenWidth / 2 - cursorScreen[0], | 156 (float) adjustedScreenHeight / 2 - cursorScreen[1]); |
| 140 (float) mRenderData.screenHeight / 2 - cursorScreen[1]); | |
| 141 | 157 |
| 142 // Now the cursor is displayed in the middle of the screen, see if t
he image can be | 158 // Now the cursor is displayed in the middle of the screen, see if t
he image can be |
| 143 // panned so that more of it is visible. The primary goal is to show
as much of the | 159 // panned so that more of it is visible. The primary goal is to show
as much of the |
| 144 // image as possible. The secondary goal is to keep the cursor in th
e middle. | 160 // image as possible. The secondary goal is to keep the cursor in th
e middle. |
| 145 | 161 |
| 146 // Get the coordinates of the desktop rectangle (top-left/bottom-rig
ht corners) in | 162 // Get the coordinates of the desktop rectangle (top-left/bottom-rig
ht corners) in |
| 147 // screen coordinates. Order is: left, top, right, bottom. | 163 // screen coordinates. Order is: left, top, right, bottom. |
| 148 float[] rectScreen = {0, 0, mRenderData.imageWidth, mRenderData.imag
eHeight}; | 164 RectF rectScreen = new RectF(0, 0, mRenderData.imageWidth, mRenderDa
ta.imageHeight); |
| 149 mRenderData.transform.mapPoints(rectScreen); | 165 mRenderData.transform.mapRect(rectScreen); |
| 150 | 166 |
| 151 float leftDelta = rectScreen[0]; | 167 float leftDelta = rectScreen.left; |
| 152 float rightDelta = rectScreen[2] - mRenderData.screenWidth; | 168 float rightDelta = rectScreen.right - mRenderData.screenWidth + mInp
utMethodOffsetX; |
| 153 float topDelta = rectScreen[1]; | 169 float topDelta = rectScreen.top; |
| 154 float bottomDelta = rectScreen[3] - mRenderData.screenHeight; | 170 float bottomDelta = rectScreen.bottom - mRenderData.screenHeight + m
InputMethodOffsetY; |
| 155 float xAdjust = 0; | 171 float xAdjust = 0; |
| 156 float yAdjust = 0; | 172 float yAdjust = 0; |
| 157 | 173 |
| 158 if (rectScreen[2] - rectScreen[0] < mRenderData.screenWidth) { | 174 if (rectScreen.right - rectScreen.left < adjustedScreenWidth) { |
| 159 // Image is narrower than the screen, so center it. | 175 // Image is narrower than the screen, so center it. |
| 160 xAdjust = -(rightDelta + leftDelta) / 2; | 176 xAdjust = -(rightDelta + leftDelta) / 2; |
| 161 } else if (leftDelta > 0 && rightDelta > 0) { | 177 } else if (leftDelta > 0 && rightDelta > 0) { |
| 162 // Panning the image left will show more of it. | 178 // Panning the image left will show more of it. |
| 163 xAdjust = -Math.min(leftDelta, rightDelta); | 179 xAdjust = -Math.min(leftDelta, rightDelta); |
| 164 } else if (leftDelta < 0 && rightDelta < 0) { | 180 } else if (leftDelta < 0 && rightDelta < 0) { |
| 165 // Pan the image right. | 181 // Pan the image right. |
| 166 xAdjust = Math.min(-leftDelta, -rightDelta); | 182 xAdjust = Math.min(-leftDelta, -rightDelta); |
| 167 } | 183 } |
| 168 | 184 |
| 169 // Apply similar logic for yAdjust. | 185 // Apply similar logic for yAdjust. |
| 170 if (rectScreen[3] - rectScreen[1] < mRenderData.screenHeight) { | 186 if (rectScreen.bottom - rectScreen.top < adjustedScreenHeight) { |
| 171 yAdjust = -(bottomDelta + topDelta) / 2; | 187 yAdjust = -(bottomDelta + topDelta) / 2; |
| 172 } else if (topDelta > 0 && bottomDelta > 0) { | 188 } else if (topDelta > 0 && bottomDelta > 0) { |
| 173 yAdjust = -Math.min(topDelta, bottomDelta); | 189 yAdjust = -Math.min(topDelta, bottomDelta); |
| 174 } else if (topDelta < 0 && bottomDelta < 0) { | 190 } else if (topDelta < 0 && bottomDelta < 0) { |
| 175 yAdjust = Math.min(-topDelta, -bottomDelta); | 191 yAdjust = Math.min(-topDelta, -bottomDelta); |
| 176 } | 192 } |
| 177 | 193 |
| 178 mRenderData.transform.postTranslate(xAdjust, yAdjust); | 194 mRenderData.transform.postTranslate(xAdjust, yAdjust); |
| 179 } | 195 } |
| 180 mViewer.transformationChanged(); | 196 mViewer.transformationChanged(); |
| (...skipping 19 matching lines...) Expand all Loading... |
| 200 } | 216 } |
| 201 | 217 |
| 202 // Get image size scaled to screen coordinates. | 218 // Get image size scaled to screen coordinates. |
| 203 float[] imageSize = {mRenderData.imageWidth, mRenderData.imageHeight
}; | 219 float[] imageSize = {mRenderData.imageWidth, mRenderData.imageHeight
}; |
| 204 mRenderData.transform.mapVectors(imageSize); | 220 mRenderData.transform.mapVectors(imageSize); |
| 205 | 221 |
| 206 if (imageSize[0] < mRenderData.screenWidth && imageSize[1] < mRender
Data.screenHeight) { | 222 if (imageSize[0] < mRenderData.screenWidth && imageSize[1] < mRender
Data.screenHeight) { |
| 207 // Displayed image is too small in both directions, so apply the
minimum zoom | 223 // Displayed image is too small in both directions, so apply the
minimum zoom |
| 208 // level needed to fit either the width or height. | 224 // level needed to fit either the width or height. |
| 209 float scale = Math.min((float) mRenderData.screenWidth / mRender
Data.imageWidth, | 225 float scale = Math.min((float) mRenderData.screenWidth / mRender
Data.imageWidth, |
| 210 (float) mRenderData.screenHeight / mRende
rData.imageHeight); | 226 (float) mRenderData.screenHeight / mRenderData.imageHeig
ht); |
| 211 mRenderData.transform.setScale(scale, scale); | 227 mRenderData.transform.setScale(scale, scale); |
| 212 } | 228 } |
| 213 | 229 |
| 214 repositionImage(); | 230 repositionImage(); |
| 215 } | 231 } |
| 216 } | 232 } |
| 217 | 233 |
| 218 /** Injects a button event using the current cursor location. */ | 234 /** Injects a button event using the current cursor location. */ |
| 219 private void injectButtonEvent(int button, boolean pressed) { | 235 private void injectButtonEvent(int button, boolean pressed) { |
| 220 mViewer.injectMouseEvent((int) mCursorPosition.x, (int) mCursorPosition.
y, button, pressed); | 236 mViewer.injectMouseEvent((int) mCursorPosition.x, (int) mCursorPosition.
y, button, pressed); |
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 282 repositionImageWithZoom(); | 298 repositionImageWithZoom(); |
| 283 } | 299 } |
| 284 | 300 |
| 285 @Override | 301 @Override |
| 286 public void onHostSizeChanged(int width, int height) { | 302 public void onHostSizeChanged(int width, int height) { |
| 287 moveCursor((float) width / 2, (float) height / 2); | 303 moveCursor((float) width / 2, (float) height / 2); |
| 288 repositionImageWithZoom(); | 304 repositionImageWithZoom(); |
| 289 } | 305 } |
| 290 | 306 |
| 291 @Override | 307 @Override |
| 308 public void onSoftInputMethodVisibilityChanged(boolean inputMethodVisible, R
ect bounds) { |
| 309 if (inputMethodVisible) { |
| 310 mInputMethodOffsetY = mRenderData.screenHeight - bounds.bottom; |
| 311 mInputMethodOffsetX = mRenderData.screenWidth - bounds.right; |
| 312 } else { |
| 313 mInputMethodOffsetY = 0; |
| 314 mInputMethodOffsetX = 0; |
| 315 } |
| 316 |
| 317 repositionImageWithZoom(); |
| 318 } |
| 319 |
| 320 @Override |
| 292 public void processAnimation() { | 321 public void processAnimation() { |
| 293 int previousX = mFlingScroller.getCurrX(); | 322 int previousX = mFlingScroller.getCurrX(); |
| 294 int previousY = mFlingScroller.getCurrY(); | 323 int previousY = mFlingScroller.getCurrY(); |
| 295 if (!mFlingScroller.computeScrollOffset()) { | 324 if (!mFlingScroller.computeScrollOffset()) { |
| 296 mViewer.setAnimationEnabled(false); | 325 mViewer.setAnimationEnabled(false); |
| 297 return; | 326 return; |
| 298 } | 327 } |
| 299 int deltaX = mFlingScroller.getCurrX() - previousX; | 328 int deltaX = mFlingScroller.getCurrX() - previousX; |
| 300 int deltaY = mFlingScroller.getCurrY() - previousY; | 329 int deltaY = mFlingScroller.getCurrY() - previousY; |
| 301 float[] delta = {deltaX, deltaY}; | 330 float[] delta = {deltaX, deltaY}; |
| (...skipping 149 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 451 public void onLongPress(int pointerCount) { | 480 public void onLongPress(int pointerCount) { |
| 452 mHeldButton = mouseButtonFromPointerCount(pointerCount); | 481 mHeldButton = mouseButtonFromPointerCount(pointerCount); |
| 453 if (mHeldButton != BUTTON_UNDEFINED) { | 482 if (mHeldButton != BUTTON_UNDEFINED) { |
| 454 injectButtonEvent(mHeldButton, true); | 483 injectButtonEvent(mHeldButton, true); |
| 455 mViewer.showLongPressFeedback(); | 484 mViewer.showLongPressFeedback(); |
| 456 mSuppressFling = true; | 485 mSuppressFling = true; |
| 457 } | 486 } |
| 458 } | 487 } |
| 459 } | 488 } |
| 460 } | 489 } |
| OLD | NEW |