This source file includes following definitions.
- moveCursor
- repositionImage
- repositionImageWithZoom
- injectButtonEvent
- onSwipe
- releaseAnyHeldButton
- onTouchEvent
- onScreenConfigurationChanged
- onClientSizeChanged
- onHostSizeChanged
- processAnimation
- onScroll
- onFling
- onScale
- onDown
- onScaleBegin
- onScaleEnd
- mouseButtonFromPointerCount
- onTap
- onLongPress
package org.chromium.chromoting;
import android.content.Context;
import android.graphics.Matrix;
import android.graphics.PointF;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.widget.Scroller;
public class TrackingInputHandler implements TouchInputHandler {
private static final double MIN_ZOOM_DELTA = 0.05;
private static final float MAX_ZOOM_FACTOR = 100.0f;
private DesktopViewInterface mViewer;
private RenderData mRenderData;
private GestureDetector mScroller;
private ScaleGestureDetector mZoomer;
private TapGestureDetector mTapDetector;
private Scroller mFlingScroller;
private SwipePinchDetector mSwipePinchDetector;
private PointF mCursorPosition;
private float mTotalMotionY = 0;
private float mSwipeThreshold;
private int mHeldButton = BUTTON_UNDEFINED;
private boolean mSuppressCursorMovement = false;
private boolean mSuppressFling = false;
private boolean mSwipeCompleted = false;
public TrackingInputHandler(DesktopViewInterface viewer, Context context,
RenderData renderData) {
mViewer = viewer;
mRenderData = renderData;
GestureListener listener = new GestureListener();
mScroller = new GestureDetector(context, listener, null, false);
mScroller.setIsLongpressEnabled(false);
mZoomer = new ScaleGestureDetector(context, listener);
mTapDetector = new TapGestureDetector(context, listener);
mFlingScroller = new Scroller(context);
mSwipePinchDetector = new SwipePinchDetector(context);
mCursorPosition = new PointF();
float density = context.getResources().getDisplayMetrics().density;
mSwipeThreshold = 40 * density;
}
private void moveCursor(float newX, float newY) {
synchronized (mRenderData) {
if (newX < 0) newX = 0;
if (newY < 0) newY = 0;
if (newX > mRenderData.imageWidth) newX = mRenderData.imageWidth;
if (newY > mRenderData.imageHeight) newY = mRenderData.imageHeight;
mCursorPosition.set(newX, newY);
repositionImage();
}
mViewer.injectMouseEvent((int)newX, (int)newY, BUTTON_UNDEFINED, false);
}
private void repositionImage() {
synchronized (mRenderData) {
float[] cursorScreen = {mCursorPosition.x, mCursorPosition.y};
mRenderData.transform.mapPoints(cursorScreen);
mRenderData.transform.postTranslate(
(float)mRenderData.screenWidth / 2 - cursorScreen[0],
(float)mRenderData.screenHeight / 2 - cursorScreen[1]);
float[] rectScreen = {0, 0, mRenderData.imageWidth, mRenderData.imageHeight};
mRenderData.transform.mapPoints(rectScreen);
float leftDelta = rectScreen[0];
float rightDelta = rectScreen[2] - mRenderData.screenWidth;
float topDelta = rectScreen[1];
float bottomDelta = rectScreen[3] - mRenderData.screenHeight;
float xAdjust = 0;
float yAdjust = 0;
if (rectScreen[2] - rectScreen[0] < mRenderData.screenWidth) {
xAdjust = -(rightDelta + leftDelta) / 2;
} else if (leftDelta > 0 && rightDelta > 0) {
xAdjust = -Math.min(leftDelta, rightDelta);
} else if (leftDelta < 0 && rightDelta < 0) {
xAdjust = Math.min(-leftDelta, -rightDelta);
}
if (rectScreen[3] - rectScreen[1] < mRenderData.screenHeight) {
yAdjust = -(bottomDelta + topDelta) / 2;
} else if (topDelta > 0 && bottomDelta > 0) {
yAdjust = -Math.min(topDelta, bottomDelta);
} else if (topDelta < 0 && bottomDelta < 0) {
yAdjust = Math.min(-topDelta, -bottomDelta);
}
mRenderData.transform.postTranslate(xAdjust, yAdjust);
}
mViewer.transformationChanged();
}
private void repositionImageWithZoom() {
synchronized (mRenderData) {
if (mRenderData.imageWidth == 0 || mRenderData.imageHeight == 0) {
return;
}
float currentZoomLevel = mRenderData.transform.mapRadius(1.0f);
if (currentZoomLevel > MAX_ZOOM_FACTOR) {
mRenderData.transform.setScale(MAX_ZOOM_FACTOR, MAX_ZOOM_FACTOR);
}
float[] imageSize = {(float)mRenderData.imageWidth, (float)mRenderData.imageHeight};
mRenderData.transform.mapVectors(imageSize);
if (imageSize[0] < mRenderData.screenWidth && imageSize[1] < mRenderData.screenHeight) {
float scale = Math.min((float)mRenderData.screenWidth / mRenderData.imageWidth,
(float)mRenderData.screenHeight / mRenderData.imageHeight);
mRenderData.transform.setScale(scale, scale);
}
repositionImage();
}
}
private void injectButtonEvent(int button, boolean pressed) {
mViewer.injectMouseEvent((int)mCursorPosition.x, (int)mCursorPosition.y, button, pressed);
}
private boolean onSwipe() {
if (mTotalMotionY > mSwipeThreshold) {
mViewer.showActionBar();
} else if (mTotalMotionY < -mSwipeThreshold) {
mViewer.showKeyboard();
} else {
return false;
}
mSuppressCursorMovement = true;
mSuppressFling = true;
mSwipeCompleted = true;
return true;
}
private void releaseAnyHeldButton() {
if (mHeldButton != BUTTON_UNDEFINED) {
injectButtonEvent(mHeldButton, false);
mHeldButton = BUTTON_UNDEFINED;
}
}
@Override
public boolean onTouchEvent(MotionEvent event) {
boolean handled = mScroller.onTouchEvent(event);
handled |= mZoomer.onTouchEvent(event);
handled |= mTapDetector.onTouchEvent(event);
mSwipePinchDetector.onTouchEvent(event);
switch (event.getActionMasked()) {
case MotionEvent.ACTION_DOWN:
mViewer.setAnimationEnabled(false);
mSuppressCursorMovement = false;
mSuppressFling = false;
mSwipeCompleted = false;
break;
case MotionEvent.ACTION_POINTER_DOWN:
mTotalMotionY = 0;
break;
case MotionEvent.ACTION_UP:
releaseAnyHeldButton();
break;
default:
break;
}
return handled;
}
@Override
public void onScreenConfigurationChanged() {
}
@Override
public void onClientSizeChanged(int width, int height) {
repositionImageWithZoom();
}
@Override
public void onHostSizeChanged(int width, int height) {
moveCursor((float)width / 2, (float)height / 2);
repositionImageWithZoom();
}
@Override
public void processAnimation() {
int previousX = mFlingScroller.getCurrX();
int previousY = mFlingScroller.getCurrY();
if (!mFlingScroller.computeScrollOffset()) {
mViewer.setAnimationEnabled(false);
return;
}
int deltaX = mFlingScroller.getCurrX() - previousX;
int deltaY = mFlingScroller.getCurrY() - previousY;
float[] delta = {(float)deltaX, (float)deltaY};
synchronized (mRenderData) {
Matrix canvasToImage = new Matrix();
mRenderData.transform.invert(canvasToImage);
canvasToImage.mapVectors(delta);
}
moveCursor(mCursorPosition.x + delta[0], mCursorPosition.y + delta[1]);
}
private class GestureListener extends GestureDetector.SimpleOnGestureListener
implements ScaleGestureDetector.OnScaleGestureListener,
TapGestureDetector.OnTapListener {
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
int pointerCount = e2.getPointerCount();
if (pointerCount == 3 && !mSwipeCompleted) {
mTotalMotionY -= distanceY;
return onSwipe();
}
if (pointerCount == 2 && mSwipePinchDetector.isSwiping()) {
mViewer.injectMouseWheelDeltaEvent(-(int)distanceX, -(int)distanceY);
mSuppressCursorMovement = true;
return true;
}
if (pointerCount != 1 || mSuppressCursorMovement) {
return false;
}
float[] delta = {distanceX, distanceY};
synchronized (mRenderData) {
Matrix canvasToImage = new Matrix();
mRenderData.transform.invert(canvasToImage);
canvasToImage.mapVectors(delta);
}
moveCursor(mCursorPosition.x - delta[0], mCursorPosition.y - delta[1]);
return true;
}
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
if (mSuppressCursorMovement || mSuppressFling) {
return false;
}
mFlingScroller.fling(0, 0, (int)velocityX, (int)velocityY, Integer.MIN_VALUE,
Integer.MAX_VALUE, Integer.MIN_VALUE, Integer.MAX_VALUE);
mFlingScroller.computeScrollOffset();
mViewer.setAnimationEnabled(true);
return true;
}
@Override
public boolean onScale(ScaleGestureDetector detector) {
if (!mSwipePinchDetector.isPinching()) {
return false;
}
if (Math.abs(detector.getScaleFactor() - 1) < MIN_ZOOM_DELTA) {
return false;
}
float scaleFactor = detector.getScaleFactor();
synchronized (mRenderData) {
mRenderData.transform.postScale(
scaleFactor, scaleFactor, detector.getFocusX(), detector.getFocusY());
}
repositionImageWithZoom();
return true;
}
@Override
public boolean onDown(MotionEvent e) {
return true;
}
@Override
public boolean onScaleBegin(ScaleGestureDetector detector) {
return true;
}
@Override
public void onScaleEnd(ScaleGestureDetector detector) {
onScale(detector);
}
private int mouseButtonFromPointerCount(int pointerCount) {
switch (pointerCount) {
case 1:
return BUTTON_LEFT;
case 2:
return BUTTON_RIGHT;
case 3:
return BUTTON_MIDDLE;
default:
return BUTTON_UNDEFINED;
}
}
@Override
public boolean onTap(int pointerCount) {
int button = mouseButtonFromPointerCount(pointerCount);
if (button == BUTTON_UNDEFINED) {
return false;
} else {
injectButtonEvent(button, true);
injectButtonEvent(button, false);
return true;
}
}
@Override
public void onLongPress(int pointerCount) {
mHeldButton = mouseButtonFromPointerCount(pointerCount);
if (mHeldButton != BUTTON_UNDEFINED) {
injectButtonEvent(mHeldButton, true);
mViewer.showLongPressFeedback();
mSuppressFling = true;
}
}
}
}