43 public static final float MAX_SCALE_FACTOR = 3.0f;
44 public static final float MIN_SCALE_FACTOR = 1.0f;
45 private static final String TAG =
"SessionView";
46 private static final float SCALE_FACTOR_DELTA = 0.0001f;
47 private static final float TOUCH_SCROLL_DELTA = 10.0f;
50 private BitmapDrawable surface;
51 private Stack<Rect> invalidRegions;
52 private int touchPointerPaddingWidth = 0;
53 private int touchPointerPaddingHeight = 0;
56 private float scaleFactor = 1.0f;
57 private Matrix scaleMatrix;
58 private Matrix invScaleMatrix;
59 private RectF invalidRegionF;
60 private GestureDetector gestureDetector;
61 private SessionState currentSession;
64 private DoubleGestureDetector doubleGestureDetector;
68 initSessionView(context);
71 public SessionView(Context context, AttributeSet attrs)
73 super(context, attrs);
74 initSessionView(context);
77 public SessionView(Context context, AttributeSet attrs,
int defStyle)
79 super(context, attrs, defStyle);
80 initSessionView(context);
83 private void initSessionView(Context context)
85 invalidRegions =
new Stack<>();
86 gestureDetector =
new GestureDetector(context,
new SessionGestureListener(),
null,
true);
87 doubleGestureDetector =
88 new DoubleGestureDetector(context,
null,
new SessionDoubleGestureListener());
91 scaleMatrix =
new Matrix();
92 invScaleMatrix =
new Matrix();
93 invalidRegionF =
new RectF();
95 setSystemUiVisibility(View.SYSTEM_UI_FLAG_HIDE_NAVIGATION |
96 View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);
100 @Override
public boolean onHoverEvent(MotionEvent event)
102 if (event.getAction() == MotionEvent.ACTION_HOVER_MOVE)
105 float x =
event.getX();
106 float y =
event.getY();
108 MotionEvent mappedEvent = mapTouchEvent(event);
109 LibFreeRDP.sendCursorEvent(currentSession.getInstance(), (
int)mappedEvent.getX(),
110 (
int)mappedEvent.getY(), Mouse.getMoveEvent());
116 public void setScaleGestureDetector(ScaleGestureDetector scaleGestureDetector)
118 doubleGestureDetector.setScaleGestureDetector(scaleGestureDetector);
123 this.sessionViewListener = sessionViewListener;
126 public void addInvalidRegion(Rect invalidRegion)
129 invalidRegionF.set(invalidRegion);
130 scaleMatrix.mapRect(invalidRegionF);
131 invalidRegionF.roundOut(invalidRegion);
133 invalidRegions.add(invalidRegion);
136 public void invalidateRegion()
138 invalidate(invalidRegions.pop());
141 public void onSurfaceChange(SessionState session)
143 surface = session.getSurface();
144 Bitmap bitmap = surface.getBitmap();
145 width = bitmap.getWidth();
146 height = bitmap.getHeight();
147 surface.setBounds(0, 0, width, height);
149 setMinimumWidth(width);
150 setMinimumHeight(height);
153 currentSession = session;
156 public float getZoom()
161 public void setZoom(
float factor)
165 scaleFactor = factor;
166 scaleMatrix.setScale(scaleFactor, scaleFactor);
167 invScaleMatrix.setScale(1.0f / scaleFactor, 1.0f / scaleFactor);
173 public boolean isAtMaxZoom()
175 return (scaleFactor > (MAX_SCALE_FACTOR - SCALE_FACTOR_DELTA));
178 public boolean isAtMinZoom()
180 return (scaleFactor < (MIN_SCALE_FACTOR + SCALE_FACTOR_DELTA));
183 public boolean zoomIn(
float factor)
186 scaleFactor += factor;
187 if (scaleFactor > (MAX_SCALE_FACTOR - SCALE_FACTOR_DELTA))
189 scaleFactor = MAX_SCALE_FACTOR;
192 setZoom(scaleFactor);
196 public boolean zoomOut(
float factor)
199 scaleFactor -= factor;
200 if (scaleFactor < (MIN_SCALE_FACTOR + SCALE_FACTOR_DELTA))
202 scaleFactor = MIN_SCALE_FACTOR;
205 setZoom(scaleFactor);
209 public void setTouchPointerPadding(
int width,
int height)
211 touchPointerPaddingWidth = width;
212 touchPointerPaddingHeight = height;
216 public int getTouchPointerPaddingWidth()
218 return touchPointerPaddingWidth;
221 public int getTouchPointerPaddingHeight()
223 return touchPointerPaddingHeight;
226 @Override
public void onMeasure(
int widthMeasureSpec,
int heightMeasureSpec)
228 Log.v(TAG, width +
"x" + height);
229 this.setMeasuredDimension((
int)(width * scaleFactor) + touchPointerPaddingWidth,
230 (
int)(height * scaleFactor) + touchPointerPaddingHeight);
233 @Override
public void onDraw(@NonNull Canvas canvas)
235 super.onDraw(canvas);
238 canvas.concat(scaleMatrix);
239 canvas.drawColor(Color.BLACK);
242 surface.draw(canvas);
249 @Override
public boolean dispatchKeyEventPreIme(KeyEvent event)
251 if (event.getKeyCode() == KeyEvent.KEYCODE_BACK &&
252 event.getAction() == KeyEvent.ACTION_DOWN)
254 return super.dispatchKeyEventPreIme(event);
258 private MotionEvent mapTouchEvent(MotionEvent event)
260 MotionEvent mappedEvent = MotionEvent.obtain(event);
261 float[] coordinates = { mappedEvent.getX(), mappedEvent.getY() };
262 invScaleMatrix.mapPoints(coordinates);
263 mappedEvent.setLocation(coordinates[0], coordinates[1]);
268 private MotionEvent mapDoubleTouchEvent(MotionEvent event)
270 MotionEvent mappedEvent = MotionEvent.obtain(event);
271 float[] coordinates = { (mappedEvent.getX(0) + mappedEvent.getX(1)) / 2,
272 (mappedEvent.getY(0) + mappedEvent.getY(1)) / 2 };
273 invScaleMatrix.mapPoints(coordinates);
274 mappedEvent.setLocation(coordinates[0], coordinates[1]);
278 @Override
public boolean onTouchEvent(MotionEvent event)
280 boolean res = gestureDetector.onTouchEvent(event);
281 res |= doubleGestureDetector.onTouchEvent(event);
286 void onSessionViewBeginTouch();
288 void onSessionViewEndTouch();
290 void onSessionViewLeftTouch(
int x,
int y,
boolean down);
292 void onSessionViewRightTouch(
int x,
int y,
boolean down);
294 void onSessionViewMove(
int x,
int y);
296 void onSessionViewScroll(
boolean down);
299 private class SessionGestureListener
extends GestureDetector.SimpleOnGestureListener
301 boolean longPressInProgress =
false;
303 public boolean onDown(MotionEvent e)
308 public boolean onUp(MotionEvent e)
310 sessionViewListener.onSessionViewEndTouch();
314 public void onLongPress(MotionEvent e)
316 MotionEvent mappedEvent = mapTouchEvent(e);
317 sessionViewListener.onSessionViewBeginTouch();
318 sessionViewListener.onSessionViewLeftTouch((
int)mappedEvent.getX(),
319 (
int)mappedEvent.getY(),
true);
320 longPressInProgress =
true;
323 public void onLongPressUp(MotionEvent e)
325 MotionEvent mappedEvent = mapTouchEvent(e);
326 sessionViewListener.onSessionViewLeftTouch((
int)mappedEvent.getX(),
327 (
int)mappedEvent.getY(),
false);
328 longPressInProgress =
false;
329 sessionViewListener.onSessionViewEndTouch();
332 public boolean onScroll(MotionEvent e1, MotionEvent e2,
float distanceX,
float distanceY)
334 if (longPressInProgress)
336 MotionEvent mappedEvent = mapTouchEvent(e2);
337 sessionViewListener.onSessionViewMove((
int)mappedEvent.getX(),
338 (
int)mappedEvent.getY());
345 public boolean onDoubleTap(MotionEvent e)
348 MotionEvent mappedEvent = mapTouchEvent(e);
349 sessionViewListener.onSessionViewLeftTouch((
int)mappedEvent.getX(),
350 (
int)mappedEvent.getY(),
true);
351 sessionViewListener.onSessionViewLeftTouch((
int)mappedEvent.getX(),
352 (
int)mappedEvent.getY(),
false);
356 public boolean onSingleTapUp(MotionEvent e)
359 MotionEvent mappedEvent = mapTouchEvent(e);
360 sessionViewListener.onSessionViewBeginTouch();
361 switch (e.getButtonState())
363 case MotionEvent.BUTTON_PRIMARY:
364 sessionViewListener.onSessionViewLeftTouch((
int)mappedEvent.getX(),
365 (
int)mappedEvent.getY(),
true);
366 sessionViewListener.onSessionViewLeftTouch((
int)mappedEvent.getX(),
367 (
int)mappedEvent.getY(),
false);
369 case MotionEvent.BUTTON_SECONDARY:
370 sessionViewListener.onSessionViewRightTouch((
int)mappedEvent.getX(),
371 (
int)mappedEvent.getY(),
true);
372 sessionViewListener.onSessionViewRightTouch((
int)mappedEvent.getX(),
373 (
int)mappedEvent.getY(),
false);
374 sessionViewListener.onSessionViewLeftTouch((
int)mappedEvent.getX(),
375 (
int)mappedEvent.getY(),
true);
376 sessionViewListener.onSessionViewLeftTouch((
int)mappedEvent.getX(),
377 (
int)mappedEvent.getY(),
false);
380 sessionViewListener.onSessionViewEndTouch();
385 private class SessionDoubleGestureListener
386 implements DoubleGestureDetector.OnDoubleGestureListener
388 private MotionEvent prevEvent =
null;
390 public boolean onDoubleTouchDown(MotionEvent e)
392 sessionViewListener.onSessionViewBeginTouch();
393 prevEvent = MotionEvent.obtain(e);
397 public boolean onDoubleTouchUp(MotionEvent e)
399 if (prevEvent !=
null)
404 sessionViewListener.onSessionViewEndTouch();
408 public boolean onDoubleTouchScroll(MotionEvent e1, MotionEvent e2)
411 float deltaY = e2.getY() - prevEvent.getY();
412 if (deltaY > TOUCH_SCROLL_DELTA)
414 sessionViewListener.onSessionViewScroll(
true);
416 prevEvent = MotionEvent.obtain(e2);
418 else if (deltaY < -TOUCH_SCROLL_DELTA)
420 sessionViewListener.onSessionViewScroll(
false);
422 prevEvent = MotionEvent.obtain(e2);
427 public boolean onDoubleTouchSingleTap(MotionEvent e)
430 MotionEvent mappedEvent = mapDoubleTouchEvent(e);
431 sessionViewListener.onSessionViewRightTouch((
int)mappedEvent.getX(),
432 (
int)mappedEvent.getY(),
true);
433 sessionViewListener.onSessionViewRightTouch((
int)mappedEvent.getX(),
434 (
int)mappedEvent.getY(),
false);
439 @Override
public InputConnection onCreateInputConnection(EditorInfo outAttrs)
441 super.onCreateInputConnection(outAttrs);
442 outAttrs.inputType = InputType.TYPE_CLASS_TEXT;