Blame client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/presentation/TouchPointerView.java

Packit 1fb8d4
/*
Packit 1fb8d4
   Android Touch Pointer view
Packit 1fb8d4
Packit 1fb8d4
   Copyright 2013 Thincast Technologies GmbH, Author: Martin Fleisz
Packit 1fb8d4
Packit Service 5a9772
   This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
Packit Service 5a9772
   If a copy of the MPL was not distributed with this file, You can obtain one at
Packit Service 5a9772
   http://mozilla.org/MPL/2.0/.
Packit 1fb8d4
*/
Packit 1fb8d4
Packit 1fb8d4
package com.freerdp.freerdpcore.presentation;
Packit 1fb8d4
Packit 1fb8d4
import android.content.Context;
Packit 1fb8d4
import android.graphics.Matrix;
Packit 1fb8d4
import android.graphics.RectF;
Packit 1fb8d4
import android.os.Handler;
Packit 1fb8d4
import android.os.Message;
Packit 1fb8d4
import android.util.AttributeSet;
Packit 1fb8d4
import android.view.MotionEvent;
Packit 1fb8d4
import android.widget.ImageView;
Packit 1fb8d4
Packit 1fb8d4
import com.freerdp.freerdpcore.R;
Packit 1fb8d4
import com.freerdp.freerdpcore.utils.GestureDetector;
Packit 1fb8d4
Packit Service 5a9772
public class TouchPointerView extends ImageView
Packit Service 5a9772
{
Packit Service 5a9772
Packit Service 5a9772
	private static final int POINTER_ACTION_CURSOR = 0;
Packit Service 5a9772
	private static final int POINTER_ACTION_CLOSE = 3;
Packit Service 5a9772
Packit Service 5a9772
	// the touch pointer consists of 9 quadrants with the following functionality:
Packit Service 5a9772
	//
Packit Service 5a9772
	// -------------
Packit Service 5a9772
	// | 0 | 1 | 2 |
Packit Service 5a9772
	// -------------
Packit Service 5a9772
	// | 3 | 4 | 5 |
Packit Service 5a9772
	// -------------
Packit Service 5a9772
	// | 6 | 7 | 8 |
Packit Service 5a9772
	// -------------
Packit Service 5a9772
	//
Packit Service 5a9772
	// 0 ... contains the actual pointer (the tip must be centered in the quadrant)
Packit Service 5a9772
	// 1 ... is left empty
Packit Service 5a9772
	// 2, 3, 5, 6, 7, 8 ... function quadrants that issue a callback
Packit Service 5a9772
	// 4 ... pointer center used for left clicks and to drag the pointer
Packit Service 5a9772
	private static final int POINTER_ACTION_RCLICK = 2;
Packit Service 5a9772
	private static final int POINTER_ACTION_LCLICK = 4;
Packit Service 5a9772
	private static final int POINTER_ACTION_MOVE = 4;
Packit Service 5a9772
	private static final int POINTER_ACTION_SCROLL = 5;
Packit Service 5a9772
	private static final int POINTER_ACTION_RESET = 6;
Packit Service 5a9772
	private static final int POINTER_ACTION_KEYBOARD = 7;
Packit Service 5a9772
	private static final int POINTER_ACTION_EXTKEYBOARD = 8;
Packit Service 5a9772
	private static final float SCROLL_DELTA = 10.0f;
Packit Service 5a9772
	private static final int DEFAULT_TOUCH_POINTER_RESTORE_DELAY = 150;
Packit Service 5a9772
	private RectF pointerRect;
Packit Service 5a9772
	private RectF pointerAreaRects[] = new RectF[9];
Packit Service 5a9772
	private Matrix translationMatrix;
Packit Service 5a9772
	private boolean pointerMoving = false;
Packit Service 5a9772
	private boolean pointerScrolling = false;
Packit Service 5a9772
	private TouchPointerListener listener = null;
Packit Service 5a9772
	private UIHandler uiHandler = new UIHandler();
Packit Service 5a9772
	// gesture detection
Packit Service 5a9772
	private GestureDetector gestureDetector;
Packit Service 5a9772
	public TouchPointerView(Context context)
Packit Service 5a9772
	{
Packit Service 5a9772
		super(context);
Packit Service 5a9772
		initTouchPointer(context);
Packit Service 5a9772
	}
Packit Service 5a9772
Packit Service 5a9772
	public TouchPointerView(Context context, AttributeSet attrs)
Packit Service 5a9772
	{
Packit Service 5a9772
		super(context, attrs);
Packit Service 5a9772
		initTouchPointer(context);
Packit Service 5a9772
	}
Packit Service 5a9772
Packit Service 5a9772
	public TouchPointerView(Context context, AttributeSet attrs, int defStyle)
Packit Service 5a9772
	{
Packit Service 5a9772
		super(context, attrs, defStyle);
Packit Service 5a9772
		initTouchPointer(context);
Packit Service 5a9772
	}
Packit Service 5a9772
Packit Service 5a9772
	private void initTouchPointer(Context context)
Packit Service 5a9772
	{
Packit Service 5a9772
		gestureDetector =
Packit Service 5a9772
		    new GestureDetector(context, new TouchPointerGestureListener(), null, true);
Packit Service 5a9772
		gestureDetector.setLongPressTimeout(500);
Packit Service 5a9772
		translationMatrix = new Matrix();
Packit Service 5a9772
		setScaleType(ScaleType.MATRIX);
Packit Service 5a9772
		setImageMatrix(translationMatrix);
Packit Service 5a9772
Packit Service 5a9772
		// init rects
Packit Service 5a9772
		final float rectSizeWidth = (float)getDrawable().getIntrinsicWidth() / 3.0f;
Packit Service 5a9772
		final float rectSizeHeight = (float)getDrawable().getIntrinsicWidth() / 3.0f;
Packit Service 5a9772
		for (int i = 0; i < 3; i++)
Packit Service 5a9772
		{
Packit Service 5a9772
			for (int j = 0; j < 3; j++)
Packit Service 5a9772
			{
Packit Service 5a9772
				int left = (int)(j * rectSizeWidth);
Packit Service 5a9772
				int top = (int)(i * rectSizeHeight);
Packit Service 5a9772
				int right = left + (int)rectSizeWidth;
Packit Service 5a9772
				int bottom = top + (int)rectSizeHeight;
Packit Service 5a9772
				pointerAreaRects[i * 3 + j] = new RectF(left, top, right, bottom);
Packit Service 5a9772
			}
Packit Service 5a9772
		}
Packit Service 5a9772
		pointerRect =
Packit Service 5a9772
		    new RectF(0, 0, getDrawable().getIntrinsicWidth(), getDrawable().getIntrinsicHeight());
Packit Service 5a9772
	}
Packit Service 5a9772
Packit Service 5a9772
	public void setTouchPointerListener(TouchPointerListener listener)
Packit Service 5a9772
	{
Packit Service 5a9772
		this.listener = listener;
Packit Service 5a9772
	}
Packit Service 5a9772
Packit Service 5a9772
	public int getPointerWidth()
Packit Service 5a9772
	{
Packit Service 5a9772
		return getDrawable().getIntrinsicWidth();
Packit Service 5a9772
	}
Packit Service 5a9772
Packit Service 5a9772
	public int getPointerHeight()
Packit Service 5a9772
	{
Packit Service 5a9772
		return getDrawable().getIntrinsicHeight();
Packit Service 5a9772
	}
Packit Service 5a9772
Packit Service 5a9772
	public float[] getPointerPosition()
Packit Service 5a9772
	{
Packit Service 5a9772
		float[] curPos = new float[2];
Packit Service 5a9772
		translationMatrix.mapPoints(curPos);
Packit Service 5a9772
		return curPos;
Packit Service 5a9772
	}
Packit Service 5a9772
Packit Service 5a9772
	private void movePointer(float deltaX, float deltaY)
Packit Service 5a9772
	{
Packit Service 5a9772
		translationMatrix.postTranslate(deltaX, deltaY);
Packit Service 5a9772
		setImageMatrix(translationMatrix);
Packit Service 5a9772
	}
Packit Service 5a9772
Packit Service 5a9772
	private void ensureVisibility(int screen_width, int screen_height)
Packit Service 5a9772
	{
Packit Service 5a9772
		float[] curPos = new float[2];
Packit Service 5a9772
		translationMatrix.mapPoints(curPos);
Packit Service 5a9772
Packit Service 5a9772
		if (curPos[0] > (screen_width - pointerRect.width()))
Packit Service 5a9772
			curPos[0] = screen_width - pointerRect.width();
Packit Service 5a9772
		if (curPos[0] < 0)
Packit Service 5a9772
			curPos[0] = 0;
Packit Service 5a9772
		if (curPos[1] > (screen_height - pointerRect.height()))
Packit Service 5a9772
			curPos[1] = screen_height - pointerRect.height();
Packit Service 5a9772
		if (curPos[1] < 0)
Packit Service 5a9772
			curPos[1] = 0;
Packit Service 5a9772
Packit Service 5a9772
		translationMatrix.setTranslate(curPos[0], curPos[1]);
Packit Service 5a9772
		setImageMatrix(translationMatrix);
Packit Service 5a9772
	}
Packit Service 5a9772
Packit Service 5a9772
	private void displayPointerImageAction(int resId)
Packit Service 5a9772
	{
Packit Service 5a9772
		setPointerImage(resId);
Packit Service 5a9772
		uiHandler.sendEmptyMessageDelayed(0, DEFAULT_TOUCH_POINTER_RESTORE_DELAY);
Packit Service 5a9772
	}
Packit Service 5a9772
Packit Service 5a9772
	private void setPointerImage(int resId)
Packit Service 5a9772
	{
Packit Service 5a9772
		setImageResource(resId);
Packit Service 5a9772
	}
Packit Service 5a9772
Packit Service 5a9772
	// returns the pointer area with the current translation matrix applied
Packit Service 5a9772
	private RectF getCurrentPointerArea(int area)
Packit Service 5a9772
	{
Packit Service 5a9772
		RectF transRect = new RectF(pointerAreaRects[area]);
Packit Service 5a9772
		translationMatrix.mapRect(transRect);
Packit Service 5a9772
		return transRect;
Packit Service 5a9772
	}
Packit Service 5a9772
Packit Service 5a9772
	private boolean pointerAreaTouched(MotionEvent event, int area)
Packit Service 5a9772
	{
Packit Service 5a9772
		RectF transRect = new RectF(pointerAreaRects[area]);
Packit Service 5a9772
		translationMatrix.mapRect(transRect);
Packit Service 5a9772
		if (transRect.contains(event.getX(), event.getY()))
Packit Service 5a9772
			return true;
Packit Service 5a9772
		return false;
Packit Service 5a9772
	}
Packit Service 5a9772
Packit Service 5a9772
	private boolean pointerTouched(MotionEvent event)
Packit Service 5a9772
	{
Packit Service 5a9772
		RectF transRect = new RectF(pointerRect);
Packit Service 5a9772
		translationMatrix.mapRect(transRect);
Packit Service 5a9772
		if (transRect.contains(event.getX(), event.getY()))
Packit Service 5a9772
			return true;
Packit Service 5a9772
		return false;
Packit Service 5a9772
	}
Packit Service 5a9772
Packit Service 5a9772
	@Override public boolean onTouchEvent(MotionEvent event)
Packit Service 5a9772
	{
Packit Service 5a9772
		// check if pointer is being moved or if we are in scroll mode or if the pointer is touched
Packit Service 5a9772
		if (!pointerMoving && !pointerScrolling && !pointerTouched(event))
Packit Service 5a9772
			return false;
Packit Service 5a9772
		return gestureDetector.onTouchEvent(event);
Packit Service 5a9772
	}
Packit Service 5a9772
Packit Service 5a9772
	@Override protected void onLayout(boolean changed, int left, int top, int right, int bottom)
Packit Service 5a9772
	{
Packit Service 5a9772
		// ensure touch pointer is visible
Packit Service 5a9772
		if (changed)
Packit Service 5a9772
			ensureVisibility(right - left, bottom - top);
Packit Service 5a9772
	}
Packit Service 5a9772
Packit Service 5a9772
	// touch pointer listener - is triggered if an action field is
Packit Service 5a9772
	public interface TouchPointerListener {
Packit Service 5a9772
		abstract void onTouchPointerClose();
Packit Service 5a9772
Packit Service 5a9772
		abstract void onTouchPointerLeftClick(int x, int y, boolean down);
Packit Service 5a9772
Packit Service 5a9772
		abstract void onTouchPointerRightClick(int x, int y, boolean down);
Packit Service 5a9772
Packit Service 5a9772
		abstract void onTouchPointerMove(int x, int y);
Packit Service 5a9772
Packit Service 5a9772
		abstract void onTouchPointerScroll(boolean down);
Packit Service 5a9772
Packit Service 5a9772
		abstract void onTouchPointerToggleKeyboard();
Packit Service 5a9772
Packit Service 5a9772
		abstract void onTouchPointerToggleExtKeyboard();
Packit Service 5a9772
Packit Service 5a9772
		abstract void onTouchPointerResetScrollZoom();
Packit Service 5a9772
	}
Packit Service 5a9772
Packit Service 5a9772
	private class UIHandler extends Handler
Packit Service 5a9772
	{
Packit Service 5a9772
Packit Service 5a9772
		UIHandler()
Packit Service 5a9772
		{
Packit Service 5a9772
			super();
Packit Service 5a9772
		}
Packit Service 5a9772
Packit Service 5a9772
		@Override public void handleMessage(Message msg)
Packit Service 5a9772
		{
Packit Service 5a9772
			setPointerImage(R.drawable.touch_pointer_default);
Packit Service 5a9772
		}
Packit Service 5a9772
	}
Packit Service 5a9772
Packit Service 5a9772
	private class TouchPointerGestureListener extends GestureDetector.SimpleOnGestureListener
Packit Service 5a9772
	{
Packit Service 5a9772
Packit Service 5a9772
		private MotionEvent prevEvent = null;
Packit Service 5a9772
Packit Service 5a9772
		public boolean onDown(MotionEvent e)
Packit Service 5a9772
		{
Packit Service 5a9772
			if (pointerAreaTouched(e, POINTER_ACTION_MOVE))
Packit Service 5a9772
			{
Packit Service 5a9772
				prevEvent = MotionEvent.obtain(e);
Packit Service 5a9772
				pointerMoving = true;
Packit Service 5a9772
			}
Packit Service 5a9772
			else if (pointerAreaTouched(e, POINTER_ACTION_SCROLL))
Packit Service 5a9772
			{
Packit Service 5a9772
				prevEvent = MotionEvent.obtain(e);
Packit Service 5a9772
				pointerScrolling = true;
Packit Service 5a9772
				setPointerImage(R.drawable.touch_pointer_scroll);
Packit Service 5a9772
			}
Packit Service 5a9772
Packit Service 5a9772
			return true;
Packit Service 5a9772
		}
Packit Service 5a9772
Packit Service 5a9772
		public boolean onUp(MotionEvent e)
Packit Service 5a9772
		{
Packit Service 5a9772
			if (prevEvent != null)
Packit Service 5a9772
			{
Packit Service 5a9772
				prevEvent.recycle();
Packit Service 5a9772
				prevEvent = null;
Packit Service 5a9772
			}
Packit Service 5a9772
Packit Service 5a9772
			if (pointerScrolling)
Packit Service 5a9772
				setPointerImage(R.drawable.touch_pointer_default);
Packit Service 5a9772
Packit Service 5a9772
			pointerMoving = false;
Packit Service 5a9772
			pointerScrolling = false;
Packit Service 5a9772
			return true;
Packit Service 5a9772
		}
Packit Service 5a9772
Packit Service 5a9772
		public void onLongPress(MotionEvent e)
Packit Service 5a9772
		{
Packit Service 5a9772
			if (pointerAreaTouched(e, POINTER_ACTION_LCLICK))
Packit Service 5a9772
			{
Packit Service 5a9772
				setPointerImage(R.drawable.touch_pointer_active);
Packit Service 5a9772
				pointerMoving = true;
Packit Service 5a9772
				RectF rect = getCurrentPointerArea(POINTER_ACTION_CURSOR);
Packit Service 5a9772
				listener.onTouchPointerLeftClick((int)rect.centerX(), (int)rect.centerY(), true);
Packit Service 5a9772
			}
Packit Service 5a9772
		}
Packit Service 5a9772
Packit Service 5a9772
		public void onLongPressUp(MotionEvent e)
Packit Service 5a9772
		{
Packit Service 5a9772
			if (pointerMoving)
Packit Service 5a9772
			{
Packit Service 5a9772
				setPointerImage(R.drawable.touch_pointer_default);
Packit Service 5a9772
				pointerMoving = false;
Packit Service 5a9772
				RectF rect = getCurrentPointerArea(POINTER_ACTION_CURSOR);
Packit Service 5a9772
				listener.onTouchPointerLeftClick((int)rect.centerX(), (int)rect.centerY(), false);
Packit Service 5a9772
			}
Packit Service 5a9772
		}
Packit Service 5a9772
Packit Service 5a9772
		public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY)
Packit Service 5a9772
		{
Packit Service 5a9772
			if (pointerMoving)
Packit Service 5a9772
			{
Packit Service 5a9772
				// move pointer graphics
Packit Service 5a9772
				movePointer((int)(e2.getX() - prevEvent.getX()),
Packit Service 5a9772
				            (int)(e2.getY() - prevEvent.getY()));
Packit Service 5a9772
				prevEvent.recycle();
Packit Service 5a9772
				prevEvent = MotionEvent.obtain(e2);
Packit Service 5a9772
Packit Service 5a9772
				// send move notification
Packit Service 5a9772
				RectF rect = getCurrentPointerArea(POINTER_ACTION_CURSOR);
Packit Service 5a9772
				listener.onTouchPointerMove((int)rect.centerX(), (int)rect.centerY());
Packit Service 5a9772
				return true;
Packit Service 5a9772
			}
Packit Service 5a9772
			else if (pointerScrolling)
Packit Service 5a9772
			{
Packit Service 5a9772
				// calc if user scrolled up or down (or if any scrolling happened at all)
Packit Service 5a9772
				float deltaY = e2.getY() - prevEvent.getY();
Packit Service 5a9772
				if (deltaY > SCROLL_DELTA)
Packit Service 5a9772
				{
Packit Service 5a9772
					listener.onTouchPointerScroll(true);
Packit Service 5a9772
					prevEvent.recycle();
Packit Service 5a9772
					prevEvent = MotionEvent.obtain(e2);
Packit Service 5a9772
				}
Packit Service 5a9772
				else if (deltaY < -SCROLL_DELTA)
Packit Service 5a9772
				{
Packit Service 5a9772
					listener.onTouchPointerScroll(false);
Packit Service 5a9772
					prevEvent.recycle();
Packit Service 5a9772
					prevEvent = MotionEvent.obtain(e2);
Packit Service 5a9772
				}
Packit Service 5a9772
				return true;
Packit Service 5a9772
			}
Packit Service 5a9772
			return false;
Packit Service 5a9772
		}
Packit Service 5a9772
Packit Service 5a9772
		public boolean onSingleTapUp(MotionEvent e)
Packit Service 5a9772
		{
Packit Service 5a9772
			// look what area got touched and fire actions accordingly
Packit Service 5a9772
			if (pointerAreaTouched(e, POINTER_ACTION_CLOSE))
Packit Service 5a9772
				listener.onTouchPointerClose();
Packit Service 5a9772
			else if (pointerAreaTouched(e, POINTER_ACTION_LCLICK))
Packit Service 5a9772
			{
Packit Service 5a9772
				displayPointerImageAction(R.drawable.touch_pointer_lclick);
Packit Service 5a9772
				RectF rect = getCurrentPointerArea(POINTER_ACTION_CURSOR);
Packit Service 5a9772
				listener.onTouchPointerLeftClick((int)rect.centerX(), (int)rect.centerY(), true);
Packit Service 5a9772
				listener.onTouchPointerLeftClick((int)rect.centerX(), (int)rect.centerY(), false);
Packit Service 5a9772
			}
Packit Service 5a9772
			else if (pointerAreaTouched(e, POINTER_ACTION_RCLICK))
Packit Service 5a9772
			{
Packit Service 5a9772
				displayPointerImageAction(R.drawable.touch_pointer_rclick);
Packit Service 5a9772
				RectF rect = getCurrentPointerArea(POINTER_ACTION_CURSOR);
Packit Service 5a9772
				listener.onTouchPointerRightClick((int)rect.centerX(), (int)rect.centerY(), true);
Packit Service 5a9772
				listener.onTouchPointerRightClick((int)rect.centerX(), (int)rect.centerY(), false);
Packit Service 5a9772
			}
Packit Service 5a9772
			else if (pointerAreaTouched(e, POINTER_ACTION_KEYBOARD))
Packit Service 5a9772
			{
Packit Service 5a9772
				displayPointerImageAction(R.drawable.touch_pointer_keyboard);
Packit Service 5a9772
				listener.onTouchPointerToggleKeyboard();
Packit Service 5a9772
			}
Packit Service 5a9772
			else if (pointerAreaTouched(e, POINTER_ACTION_EXTKEYBOARD))
Packit Service 5a9772
			{
Packit Service 5a9772
				displayPointerImageAction(R.drawable.touch_pointer_extkeyboard);
Packit Service 5a9772
				listener.onTouchPointerToggleExtKeyboard();
Packit Service 5a9772
			}
Packit Service 5a9772
			else if (pointerAreaTouched(e, POINTER_ACTION_RESET))
Packit Service 5a9772
			{
Packit Service 5a9772
				displayPointerImageAction(R.drawable.touch_pointer_reset);
Packit Service 5a9772
				listener.onTouchPointerResetScrollZoom();
Packit Service 5a9772
			}
Packit Service 5a9772
Packit Service 5a9772
			return true;
Packit Service 5a9772
		}
Packit Service 5a9772
Packit Service 5a9772
		public boolean onDoubleTap(MotionEvent e)
Packit Service 5a9772
		{
Packit Service 5a9772
			// issue a double click notification if performed in center quadrant
Packit Service 5a9772
			if (pointerAreaTouched(e, POINTER_ACTION_LCLICK))
Packit Service 5a9772
			{
Packit Service 5a9772
				RectF rect = getCurrentPointerArea(POINTER_ACTION_CURSOR);
Packit Service 5a9772
				listener.onTouchPointerLeftClick((int)rect.centerX(), (int)rect.centerY(), true);
Packit Service 5a9772
				listener.onTouchPointerLeftClick((int)rect.centerX(), (int)rect.centerY(), false);
Packit Service 5a9772
			}
Packit Service 5a9772
			return true;
Packit Service 5a9772
		}
Packit Service 5a9772
	}
Packit 1fb8d4
}