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