11 package com.freerdp.freerdpcore.presentation;
13 import android.content.Context;
14 import android.graphics.Bitmap;
15 import android.graphics.Canvas;
16 import android.graphics.Color;
17 import android.graphics.Matrix;
18 import android.graphics.Rect;
19 import android.graphics.RectF;
20 import android.graphics.drawable.BitmapDrawable;
21 import android.text.InputType;
22 import android.util.AttributeSet;
23 import android.util.Log;
24 import android.view.KeyEvent;
25 import android.view.MotionEvent;
26 import android.view.ScaleGestureDetector;
27 import android.view.View;
28 import android.view.inputmethod.EditorInfo;
29 import android.view.inputmethod.InputConnection;
31 import com.freerdp.freerdpcore.application.SessionState;
32 import com.freerdp.freerdpcore.services.LibFreeRDP;
33 import com.freerdp.freerdpcore.utils.DoubleGestureDetector;
34 import com.freerdp.freerdpcore.utils.GestureDetector;
35 import com.freerdp.freerdpcore.utils.Mouse;
37 import java.util.Stack;
41 public static final float MAX_SCALE_FACTOR = 3.0f;
42 public static final float MIN_SCALE_FACTOR = 1.0f;
43 private static final String TAG =
"SessionView";
44 private static final float SCALE_FACTOR_DELTA = 0.0001f;
45 private static final float TOUCH_SCROLL_DELTA = 10.0f;
48 private BitmapDrawable surface;
49 private Stack<Rect> invalidRegions;
50 private int touchPointerPaddingWidth = 0;
51 private int touchPointerPaddingHeight = 0;
54 private float scaleFactor = 1.0f;
55 private Matrix scaleMatrix;
56 private Matrix invScaleMatrix;
57 private RectF invalidRegionF;
66 initSessionView(context);
69 public SessionView(Context context, AttributeSet attrs)
71 super(context, attrs);
72 initSessionView(context);
75 public SessionView(Context context, AttributeSet attrs,
int defStyle)
77 super(context, attrs, defStyle);
78 initSessionView(context);
81 private void initSessionView(Context context)
83 invalidRegions =
new Stack<>();
84 gestureDetector =
new GestureDetector(context,
new SessionGestureListener(),
null,
true);
85 doubleGestureDetector =
89 scaleMatrix =
new Matrix();
90 invScaleMatrix =
new Matrix();
91 invalidRegionF =
new RectF();
93 setSystemUiVisibility(View.SYSTEM_UI_FLAG_HIDE_NAVIGATION |
94 View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);
98 @Override
public boolean onHoverEvent(MotionEvent event)
100 if (event.getAction() == MotionEvent.ACTION_HOVER_MOVE)
103 float x =
event.getX();
104 float y =
event.getY();
106 MotionEvent mappedEvent = mapTouchEvent(event);
107 LibFreeRDP.sendCursorEvent(currentSession.getInstance(), (
int)mappedEvent.getX(),
108 (
int)mappedEvent.getY(),
Mouse.getMoveEvent());
114 public void setScaleGestureDetector(ScaleGestureDetector scaleGestureDetector)
121 this.sessionViewListener = sessionViewListener;
124 public void addInvalidRegion(Rect invalidRegion)
127 invalidRegionF.set(invalidRegion);
128 scaleMatrix.mapRect(invalidRegionF);
129 invalidRegionF.roundOut(invalidRegion);
131 invalidRegions.add(invalidRegion);
134 public void invalidateRegion()
136 invalidate(invalidRegions.pop());
141 surface = session.getSurface();
142 Bitmap bitmap = surface.getBitmap();
143 width = bitmap.getWidth();
144 height = bitmap.getHeight();
145 surface.setBounds(0, 0, width, height);
147 setMinimumWidth(width);
148 setMinimumHeight(height);
151 currentSession = session;
154 public float getZoom()
159 public void setZoom(
float factor)
163 scaleFactor = factor;
164 scaleMatrix.setScale(scaleFactor, scaleFactor);
165 invScaleMatrix.setScale(1.0f / scaleFactor, 1.0f / scaleFactor);
171 public boolean isAtMaxZoom()
173 return (scaleFactor > (MAX_SCALE_FACTOR - SCALE_FACTOR_DELTA));
176 public boolean isAtMinZoom()
178 return (scaleFactor < (MIN_SCALE_FACTOR + SCALE_FACTOR_DELTA));
181 public boolean zoomIn(
float factor)
184 scaleFactor += factor;
185 if (scaleFactor > (MAX_SCALE_FACTOR - SCALE_FACTOR_DELTA))
187 scaleFactor = MAX_SCALE_FACTOR;
190 setZoom(scaleFactor);
194 public boolean zoomOut(
float factor)
197 scaleFactor -= factor;
198 if (scaleFactor < (MIN_SCALE_FACTOR + SCALE_FACTOR_DELTA))
200 scaleFactor = MIN_SCALE_FACTOR;
203 setZoom(scaleFactor);
207 public void setTouchPointerPadding(
int width,
int height)
209 touchPointerPaddingWidth = width;
210 touchPointerPaddingHeight = height;
214 public int getTouchPointerPaddingWidth()
216 return touchPointerPaddingWidth;
219 public int getTouchPointerPaddingHeight()
221 return touchPointerPaddingHeight;
224 @Override
public void onMeasure(
int widthMeasureSpec,
int heightMeasureSpec)
226 Log.v(TAG, width +
"x" + height);
227 this.setMeasuredDimension((
int)(width * scaleFactor) + touchPointerPaddingWidth,
228 (
int)(height * scaleFactor) + touchPointerPaddingHeight);
231 @Override
public void onDraw(Canvas canvas)
233 super.onDraw(canvas);
236 canvas.concat(scaleMatrix);
237 canvas.drawColor(Color.BLACK);
238 surface.draw(canvas);
244 @Override
public boolean dispatchKeyEventPreIme(KeyEvent event)
246 if (event.getKeyCode() == KeyEvent.KEYCODE_BACK &&
247 event.getAction() == KeyEvent.ACTION_DOWN)
249 return super.dispatchKeyEventPreIme(event);
253 private MotionEvent mapTouchEvent(MotionEvent event)
255 MotionEvent mappedEvent = MotionEvent.obtain(event);
256 float[] coordinates = { mappedEvent.getX(), mappedEvent.getY() };
257 invScaleMatrix.mapPoints(coordinates);
258 mappedEvent.setLocation(coordinates[0], coordinates[1]);
263 private MotionEvent mapDoubleTouchEvent(MotionEvent event)
265 MotionEvent mappedEvent = MotionEvent.obtain(event);
266 float[] coordinates = { (mappedEvent.getX(0) + mappedEvent.getX(1)) / 2,
267 (mappedEvent.getY(0) + mappedEvent.getY(1)) / 2 };
268 invScaleMatrix.mapPoints(coordinates);
269 mappedEvent.setLocation(coordinates[0], coordinates[1]);
273 @Override
public boolean onTouchEvent(MotionEvent event)
281 abstract void onSessionViewBeginTouch();
283 abstract void onSessionViewEndTouch();
285 abstract void onSessionViewLeftTouch(
int x,
int y,
boolean down);
287 abstract void onSessionViewRightTouch(
int x,
int y,
boolean down);
289 abstract void onSessionViewMove(
int x,
int y);
291 abstract void onSessionViewScroll(
boolean down);
294 private class SessionGestureListener
extends GestureDetector.SimpleOnGestureListener
296 boolean longPressInProgress =
false;
298 public boolean onDown(MotionEvent e)
303 public boolean onUp(MotionEvent e)
305 sessionViewListener.onSessionViewEndTouch();
309 public void onLongPress(MotionEvent e)
311 MotionEvent mappedEvent = mapTouchEvent(e);
312 sessionViewListener.onSessionViewBeginTouch();
313 sessionViewListener.onSessionViewLeftTouch((
int)mappedEvent.getX(),
314 (
int)mappedEvent.getY(),
true);
315 longPressInProgress =
true;
318 public void onLongPressUp(MotionEvent e)
320 MotionEvent mappedEvent = mapTouchEvent(e);
321 sessionViewListener.onSessionViewLeftTouch((
int)mappedEvent.getX(),
322 (
int)mappedEvent.getY(),
false);
323 longPressInProgress =
false;
324 sessionViewListener.onSessionViewEndTouch();
327 public boolean onScroll(MotionEvent e1, MotionEvent e2,
float distanceX,
float distanceY)
329 if (longPressInProgress)
331 MotionEvent mappedEvent = mapTouchEvent(e2);
332 sessionViewListener.onSessionViewMove((
int)mappedEvent.getX(),
333 (
int)mappedEvent.getY());
340 public boolean onDoubleTap(MotionEvent e)
343 MotionEvent mappedEvent = mapTouchEvent(e);
344 sessionViewListener.onSessionViewLeftTouch((
int)mappedEvent.getX(),
345 (
int)mappedEvent.getY(),
true);
346 sessionViewListener.onSessionViewLeftTouch((
int)mappedEvent.getX(),
347 (
int)mappedEvent.getY(),
false);
351 public boolean onSingleTapUp(MotionEvent e)
354 MotionEvent mappedEvent = mapTouchEvent(e);
355 sessionViewListener.onSessionViewBeginTouch();
356 switch (e.getButtonState())
358 case MotionEvent.BUTTON_PRIMARY:
359 sessionViewListener.onSessionViewLeftTouch((
int)mappedEvent.getX(),
360 (
int)mappedEvent.getY(),
true);
361 sessionViewListener.onSessionViewLeftTouch((
int)mappedEvent.getX(),
362 (
int)mappedEvent.getY(),
false);
364 case MotionEvent.BUTTON_SECONDARY:
365 sessionViewListener.onSessionViewRightTouch((
int)mappedEvent.getX(),
366 (
int)mappedEvent.getY(),
true);
367 sessionViewListener.onSessionViewRightTouch((
int)mappedEvent.getX(),
368 (
int)mappedEvent.getY(),
false);
369 sessionViewListener.onSessionViewLeftTouch((
int)mappedEvent.getX(),
370 (
int)mappedEvent.getY(),
true);
371 sessionViewListener.onSessionViewLeftTouch((
int)mappedEvent.getX(),
372 (
int)mappedEvent.getY(),
false);
375 sessionViewListener.onSessionViewEndTouch();
380 private class SessionDoubleGestureListener
381 implements DoubleGestureDetector.OnDoubleGestureListener
383 private MotionEvent prevEvent =
null;
385 public boolean onDoubleTouchDown(MotionEvent e)
387 sessionViewListener.onSessionViewBeginTouch();
388 prevEvent = MotionEvent.obtain(e);
392 public boolean onDoubleTouchUp(MotionEvent e)
394 if (prevEvent !=
null)
399 sessionViewListener.onSessionViewEndTouch();
403 public boolean onDoubleTouchScroll(MotionEvent e1, MotionEvent e2)
406 float deltaY = e2.getY() - prevEvent.getY();
407 if (deltaY > TOUCH_SCROLL_DELTA)
409 sessionViewListener.onSessionViewScroll(
true);
411 prevEvent = MotionEvent.obtain(e2);
413 else if (deltaY < -TOUCH_SCROLL_DELTA)
415 sessionViewListener.onSessionViewScroll(
false);
417 prevEvent = MotionEvent.obtain(e2);
422 public boolean onDoubleTouchSingleTap(MotionEvent e)
425 MotionEvent mappedEvent = mapDoubleTouchEvent(e);
426 sessionViewListener.onSessionViewRightTouch((
int)mappedEvent.getX(),
427 (
int)mappedEvent.getY(),
true);
428 sessionViewListener.onSessionViewRightTouch((
int)mappedEvent.getX(),
429 (
int)mappedEvent.getY(),
false);
434 @Override
public InputConnection onCreateInputConnection(EditorInfo outAttrs)
436 super.onCreateInputConnection(outAttrs);
437 outAttrs.inputType = InputType.TYPE_CLASS_TEXT;
void setScaleGestureDetector(ScaleGestureDetector scaleGestureDetector)
boolean onTouchEvent(MotionEvent ev)
boolean onTouchEvent(MotionEvent ev)