45 public static final float MAX_SCALE_FACTOR = 3.0f;
46 public static final float MIN_SCALE_FACTOR = 1.0f;
47 private static final String TAG =
"SessionView";
48 private static final float SCALE_FACTOR_DELTA = 0.0001f;
49 private static final float TOUCH_SCROLL_DELTA = 10.0f;
52 private BitmapDrawable surface;
53 private Stack<Rect> invalidRegions;
54 private int touchPointerPaddingWidth = 0;
55 private int touchPointerPaddingHeight = 0;
58 private float scaleFactor = 1.0f;
59 private Matrix scaleMatrix;
60 private Matrix invScaleMatrix;
61 private RectF invalidRegionF;
62 private GestureDetector gestureDetector;
63 private SessionState currentSession;
66 private DoubleGestureDetector doubleGestureDetector;
70 initSessionView(context);
73 public SessionView(Context context, AttributeSet attrs)
75 super(context, attrs);
76 initSessionView(context);
79 public SessionView(Context context, AttributeSet attrs,
int defStyle)
81 super(context, attrs, defStyle);
82 initSessionView(context);
85 private void initSessionView(Context context)
89 setFocusableInTouchMode(
true);
91 invalidRegions =
new Stack<>();
92 gestureDetector =
new GestureDetector(context,
new SessionGestureListener(),
null,
true);
93 doubleGestureDetector =
94 new DoubleGestureDetector(context,
null,
new SessionDoubleGestureListener());
97 scaleMatrix =
new Matrix();
98 invScaleMatrix =
new Matrix();
99 invalidRegionF =
new RectF();
103 @Override
public boolean onHoverEvent(MotionEvent event)
105 if (event.getAction() == MotionEvent.ACTION_HOVER_MOVE)
108 float x =
event.getX();
109 float y =
event.getY();
111 MotionEvent mappedEvent = mapTouchEvent(event);
112 sessionViewListener.onSessionViewMouseMove((
int)mappedEvent.getX(),
113 (
int)mappedEvent.getY());
114 mappedEvent.recycle();
120 public void setScaleGestureDetector(ScaleGestureDetector scaleGestureDetector)
122 doubleGestureDetector.setScaleGestureDetector(scaleGestureDetector);
127 this.sessionViewListener = sessionViewListener;
130 public void addInvalidRegion(Rect invalidRegion)
133 invalidRegionF.set(invalidRegion);
134 scaleMatrix.mapRect(invalidRegionF);
135 invalidRegionF.roundOut(invalidRegion);
137 invalidRegions.add(invalidRegion);
140 public void invalidateRegion()
142 invalidate(invalidRegions.pop());
145 public void onSurfaceChange(SessionState session)
147 surface = session.getSurface();
148 Bitmap bitmap = surface.getBitmap();
149 width = bitmap.getWidth();
150 height = bitmap.getHeight();
151 surface.setBounds(0, 0, width, height);
153 setMinimumWidth(width);
154 setMinimumHeight(height);
157 currentSession = session;
160 public float getZoom()
165 public void setZoom(
float factor)
169 scaleFactor = factor;
170 scaleMatrix.setScale(scaleFactor, scaleFactor);
171 invScaleMatrix.setScale(1.0f / scaleFactor, 1.0f / scaleFactor);
177 public boolean isAtMaxZoom()
179 return (scaleFactor > (MAX_SCALE_FACTOR - SCALE_FACTOR_DELTA));
182 public boolean isAtMinZoom()
184 return (scaleFactor < (MIN_SCALE_FACTOR + SCALE_FACTOR_DELTA));
187 public boolean zoomIn(
float factor)
190 scaleFactor += factor;
191 if (scaleFactor > (MAX_SCALE_FACTOR - SCALE_FACTOR_DELTA))
193 scaleFactor = MAX_SCALE_FACTOR;
196 setZoom(scaleFactor);
200 public boolean zoomOut(
float factor)
203 scaleFactor -= factor;
204 if (scaleFactor < (MIN_SCALE_FACTOR + SCALE_FACTOR_DELTA))
206 scaleFactor = MIN_SCALE_FACTOR;
209 setZoom(scaleFactor);
213 public void setTouchPointerPadding(
int width,
int height)
215 touchPointerPaddingWidth = width;
216 touchPointerPaddingHeight = height;
220 public int getTouchPointerPaddingWidth()
222 return touchPointerPaddingWidth;
225 public int getTouchPointerPaddingHeight()
227 return touchPointerPaddingHeight;
230 @Override
public void onMeasure(
int widthMeasureSpec,
int heightMeasureSpec)
232 Log.v(TAG, width +
"x" + height);
233 this.setMeasuredDimension((
int)(width * scaleFactor) + touchPointerPaddingWidth,
234 (
int)(height * scaleFactor) + touchPointerPaddingHeight);
237 @Override
public void onDraw(@NonNull Canvas canvas)
239 super.onDraw(canvas);
242 canvas.concat(scaleMatrix);
243 canvas.drawColor(Color.BLACK);
246 surface.draw(canvas);
252 private MotionEvent mapTouchEvent(MotionEvent event)
254 MotionEvent mappedEvent = MotionEvent.obtain(event);
255 float[] coordinates = { mappedEvent.getX(), mappedEvent.getY() };
256 invScaleMatrix.mapPoints(coordinates);
257 mappedEvent.setLocation(coordinates[0], coordinates[1]);
262 private MotionEvent mapDoubleTouchEvent(MotionEvent event)
264 MotionEvent mappedEvent = MotionEvent.obtain(event);
265 float[] coordinates = { (mappedEvent.getX(0) + mappedEvent.getX(1)) / 2,
266 (mappedEvent.getY(0) + mappedEvent.getY(1)) / 2 };
267 invScaleMatrix.mapPoints(coordinates);
268 mappedEvent.setLocation(coordinates[0], coordinates[1]);
272 @Override
public boolean onTouchEvent(MotionEvent event)
277 if (event.isFromSource(InputDevice.SOURCE_MOUSE))
279 int action =
event.getActionMasked();
280 if (action == MotionEvent.ACTION_MOVE && event.getButtonState() != 0)
282 MotionEvent mapped = mapTouchEvent(event);
283 sessionViewListener.onSessionViewMouseMove((
int)mapped.getX(), (
int)mapped.getY());
290 boolean res = gestureDetector.onTouchEvent(event);
291 res |= doubleGestureDetector.onTouchEvent(event);
296 @Override
public boolean onGenericMotionEvent(MotionEvent event)
298 if (!event.isFromSource(InputDevice.SOURCE_MOUSE))
301 int action =
event.getActionMasked();
303 if (action == MotionEvent.ACTION_BUTTON_PRESS ||
304 action == MotionEvent.ACTION_BUTTON_RELEASE)
306 boolean down = action == MotionEvent.ACTION_BUTTON_PRESS;
307 MotionEvent mapped = mapTouchEvent(event);
308 int x = (int)mapped.getX();
309 int y = (int)mapped.getY();
312 switch (event.getActionButton())
314 case MotionEvent.BUTTON_PRIMARY:
316 sessionViewListener.onSessionViewBeginTouch();
317 sessionViewListener.onSessionViewLeftTouch(x, y, down);
319 sessionViewListener.onSessionViewEndTouch();
321 case MotionEvent.BUTTON_SECONDARY:
323 sessionViewListener.onSessionViewBeginTouch();
324 sessionViewListener.onSessionViewRightTouch(x, y, down);
326 case MotionEvent.BUTTON_TERTIARY:
327 sessionViewListener.onSessionViewMiddleTouch(x, y, down);
334 if (action == MotionEvent.ACTION_SCROLL)
336 float vScroll =
event.getAxisValue(MotionEvent.AXIS_VSCROLL);
337 float hScroll =
event.getAxisValue(MotionEvent.AXIS_HSCROLL);
339 sessionViewListener.onSessionViewScroll(vScroll > 0);
341 sessionViewListener.onSessionViewHScroll(hScroll > 0);
350 void onSessionViewBeginTouch();
352 void onSessionViewEndTouch();
354 void onSessionViewLeftTouch(
int x,
int y,
boolean down);
356 void onSessionViewMiddleTouch(
int x,
int y,
boolean down);
358 void onSessionViewRightTouch(
int x,
int y,
boolean down);
360 void onSessionViewMove(
int x,
int y);
362 void onSessionViewMouseMove(
int x,
int y);
364 void onSessionViewScroll(
boolean down);
366 void onSessionViewHScroll(
boolean right);
369 private class SessionGestureListener
extends GestureDetector.SimpleOnGestureListener
371 boolean longPressInProgress =
false;
373 public boolean onDown(MotionEvent e)
378 public boolean onUp(MotionEvent e)
380 sessionViewListener.onSessionViewEndTouch();
384 public void onLongPress(MotionEvent e)
386 MotionEvent mappedEvent = mapTouchEvent(e);
387 sessionViewListener.onSessionViewBeginTouch();
388 sessionViewListener.onSessionViewLeftTouch((
int)mappedEvent.getX(),
389 (
int)mappedEvent.getY(),
true);
390 longPressInProgress =
true;
393 public void onLongPressUp(MotionEvent e)
395 MotionEvent mappedEvent = mapTouchEvent(e);
396 sessionViewListener.onSessionViewLeftTouch((
int)mappedEvent.getX(),
397 (
int)mappedEvent.getY(),
false);
398 longPressInProgress =
false;
399 sessionViewListener.onSessionViewEndTouch();
402 public boolean onScroll(MotionEvent e1, MotionEvent e2,
float distanceX,
float distanceY)
404 if (longPressInProgress)
406 MotionEvent mappedEvent = mapTouchEvent(e2);
407 sessionViewListener.onSessionViewMove((
int)mappedEvent.getX(),
408 (
int)mappedEvent.getY());
415 public boolean onDoubleTap(MotionEvent e)
418 MotionEvent mappedEvent = mapTouchEvent(e);
419 sessionViewListener.onSessionViewLeftTouch((
int)mappedEvent.getX(),
420 (
int)mappedEvent.getY(),
true);
421 sessionViewListener.onSessionViewLeftTouch((
int)mappedEvent.getX(),
422 (
int)mappedEvent.getY(),
false);
426 public boolean onSingleTapUp(MotionEvent e)
430 if (e.getButtonState() != 0)
434 MotionEvent mappedEvent = mapTouchEvent(e);
435 sessionViewListener.onSessionViewBeginTouch();
436 sessionViewListener.onSessionViewLeftTouch((
int)mappedEvent.getX(),
437 (
int)mappedEvent.getY(),
true);
438 sessionViewListener.onSessionViewLeftTouch((
int)mappedEvent.getX(),
439 (
int)mappedEvent.getY(),
false);
440 sessionViewListener.onSessionViewEndTouch();
445 private class SessionDoubleGestureListener
446 implements DoubleGestureDetector.OnDoubleGestureListener
448 private MotionEvent prevEvent =
null;
450 public boolean onDoubleTouchDown(MotionEvent e)
452 sessionViewListener.onSessionViewBeginTouch();
453 prevEvent = MotionEvent.obtain(e);
457 public boolean onDoubleTouchUp(MotionEvent e)
459 if (prevEvent !=
null)
464 sessionViewListener.onSessionViewEndTouch();
468 public boolean onDoubleTouchScroll(MotionEvent e1, MotionEvent e2)
471 float deltaY = e2.getY() - prevEvent.getY();
472 if (deltaY > TOUCH_SCROLL_DELTA)
474 sessionViewListener.onSessionViewScroll(
true);
476 prevEvent = MotionEvent.obtain(e2);
478 else if (deltaY < -TOUCH_SCROLL_DELTA)
480 sessionViewListener.onSessionViewScroll(
false);
482 prevEvent = MotionEvent.obtain(e2);
487 public boolean onDoubleTouchSingleTap(MotionEvent e)
490 MotionEvent mappedEvent = mapDoubleTouchEvent(e);
491 sessionViewListener.onSessionViewRightTouch((
int)mappedEvent.getX(),
492 (
int)mappedEvent.getY(),
true);
493 sessionViewListener.onSessionViewRightTouch((
int)mappedEvent.getX(),
494 (
int)mappedEvent.getY(),
false);
499 @Override
public InputConnection onCreateInputConnection(EditorInfo outAttrs)
501 outAttrs.actionLabel =
null;
502 outAttrs.inputType = InputType.TYPE_NULL;
503 outAttrs.imeOptions = EditorInfo.IME_ACTION_NONE | EditorInfo.IME_FLAG_NO_EXTRACT_UI |
504 EditorInfo.IME_FLAG_NO_FULLSCREEN;
505 return new BaseInputConnection(
this,
false);