Android Open Source - BlueCtrl Touchpad View






From Project

Back to project page BlueCtrl.

License

The source code is released under:

GNU General Public License

If you think the Android project BlueCtrl listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.

Java Source Code

/*
 * Copyright (C) 2012/*from  w  w  w  .j  av a  2  s  . c om*/
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.ronsdev.bluectrl.widget;

import org.ronsdev.bluectrl.HidKeyboard;
import org.ronsdev.bluectrl.HidMouse;
import org.ronsdev.bluectrl.IntArrayList;
import org.ronsdev.bluectrl.OnMouseButtonClickListener;
import org.ronsdev.bluectrl.R;

import android.content.Context;
import android.content.res.Resources;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.HapticFeedbackConstants;
import android.view.MotionEvent;
import android.view.SoundEffectConstants;
import android.view.View;

/**
 * A touchpad that handles touch events and redirects them to a HID Mouse.
 */
public class TouchpadView extends View
        implements OnMouseButtonClickListener, OnScrollModeChangedListener {

    /** Indicates that a gesture from the top edge of the screen has been detected. */
    public static final int GESTURE_EDGE_TOP = 10;

    /** Indicates that a gesture from the right edge of the screen has been detected. */
    public static final int GESTURE_EDGE_RIGHT = 20;

    /** Indicates that a gesture from the bottom edge of the screen has been detected. */
    public static final int GESTURE_EDGE_BOTTOM = 30;

    /** Indicates that a gesture from the left edge of the screen has been detected. */
    public static final int GESTURE_EDGE_LEFT = 40;

    /** Indicates that a 2-finger gesture has been detected. */
    public static final int GESTURE_2FINGER = 200;

    /** Indicates that a 3-finger gesture has been detected. */
    public static final int GESTURE_3FINGER = 300;

    /** Indicates that a 4-finger gesture has been detected. */
    public static final int GESTURE_4FINGER = 400;


    /** Indicates that the gesture movement went to the top. */
    public static final int GESTURE_DIRECTION_UP = 0;

    /** Indicates that the gesture movement went to the right. */
    public static final int GESTURE_DIRECTION_RIGHT = 90;

    /** Indicates that the gesture movement went to the bottom. */
    public static final int GESTURE_DIRECTION_DOWN = 180;

    /** Indicates that the gesture movement went to the left. */
    public static final int GESTURE_DIRECTION_LEFT = 270;


    /** Indicates that no scroll mode is active. */
    public static final int SCROLL_MODE_NONE = 0;

    /** Indicates that the vertical scroll mode is active. */
    public static final int SCROLL_MODE_VERTICAL = 10;

    /** Indicates that the horizontal scroll mode is active. */
    public static final int SCROLL_MODE_HORIZONTAL = 20;

    /** Indicates that the vertical and horizontal scroll mode is active. */
    public static final int SCROLL_MODE_ALL = 30;


    private static final int DEFAULT_TOUCHPAD_AREA_PADDING_DP = 16;

    private static final int BUTTON_BAR_HEIGHT_DP = 48;
    private static final float BUTTON_BAR_STROKE_WIDTH_DP = 1.5f;
    private static final float BUTTON_SEP_STROKE_WIDTH_DP = 0.8f;
    private static final int BUTTON_SEP_MARGIN_DP = 12;
    private static final int MIDDLE_BUTTON_WIDTH_DP = 48;
    private static final int BUTTON_CLICK_DURATION = 100;

    private static final int BUTTON_INDEX_FIRST = 0;
    private static final int BUTTON_INDEX_SECOND = 1;
    private static final int BUTTON_INDEX_MIDDLE = 2;
    private static final int BUTTON_COUNT = 3;


    private Paint mButtonBarPaint = new Paint();

    private Drawable mBackgroundDrawable = null;
    private Drawable mButtonDrawable = null;
    private Drawable mScrollVerticalDrawable = null;
    private Drawable mScrollHorizontalDrawable = null;
    private Drawable mScrollAllDrawable = null;

    private TouchpadViewGestureListener mGestureListener = null;
    private MouseTouchListener mMouseTouchListener = null;

    private HidMouse mHidMouse = null;
    private HidKeyboard mHidKeyboard = null;

    private boolean mShowButtons = true;
    private boolean mShowInfoGraphics = true;

    private Rect mInnerRect = null;
    private Rect mTouchpadAreaRect = null;

    private int mDefaultTouchpadAreaPadding;
    private int mTouchpadAreaPadding;

    private int mButtonBarColor;
    private int mButtonBarHeight;
    private int mButtonBarStrokeWidth;
    private int mButtonSepStrokeWidth;
    private int mButtonSepMargin;
    private int mMiddleButtonWidth;

    /**
     * Array with the rectangles for the buttons (see 'BUTTON_INDEX_*' constants for index
     * mapping).
     */
    private Rect[] mButtonRects = new Rect[BUTTON_COUNT];

    /**
     * Array with Pointer ID Lists of every touched button (see 'BUTTON_INDEX_*' constants for
     * index mapping).
     */
    private IntArrayList[] mButtonPointerIds = new IntArrayList[BUTTON_COUNT];

    /**
     * Array with the pressed states of short clicked buttons (see 'BUTTON_INDEX_*' constants for
     * index mapping).
     */
    private boolean[] mClickedButtons = new boolean[BUTTON_COUNT];


    public TouchpadView(Context context) {
        super(context);

        initView();
    }

    public TouchpadView(Context context, AttributeSet attrs) {
        super(context, attrs);

        initView();
    }

    public TouchpadView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);

        initView();
    }


    private final void initView() {
        final Resources res = getResources();

        mBackgroundDrawable = res.getDrawable(R.drawable.touchpad_background);
        mButtonDrawable = res.getDrawable(R.drawable.btn_touchpad);
        mScrollVerticalDrawable = res.getDrawable(R.drawable.scroll_vertical);
        mScrollHorizontalDrawable = res.getDrawable(R.drawable.scroll_horizontal);
        mScrollAllDrawable = res.getDrawable(R.drawable.scroll_all);

        final float displayDensity = res.getDisplayMetrics().density;

        mDefaultTouchpadAreaPadding =
                (int)(DEFAULT_TOUCHPAD_AREA_PADDING_DP * displayDensity + 0.5f);
        mTouchpadAreaPadding = mDefaultTouchpadAreaPadding;

        mButtonBarColor = res.getColor(R.color.btn_touchpad_border);
        mButtonBarHeight = (int)(BUTTON_BAR_HEIGHT_DP * displayDensity + 0.5f);
        mButtonBarStrokeWidth = (int)(BUTTON_BAR_STROKE_WIDTH_DP * displayDensity + 0.5f);
        mButtonSepStrokeWidth = (int)(BUTTON_SEP_STROKE_WIDTH_DP * displayDensity + 0.5f);
        mButtonSepMargin = (int)(BUTTON_SEP_MARGIN_DP * displayDensity + 0.5f);
        mMiddleButtonWidth = (int)(MIDDLE_BUTTON_WIDTH_DP * displayDensity + 0.5f);

        mGestureListener = new TouchpadViewGestureListener(this);

        mMouseTouchListener = new MouseTouchListener(this);
        mMouseTouchListener.setOnTouchpadGestureListener(mGestureListener);
        mMouseTouchListener.setOnScrollModeChangedListener(this);

        recalculateRects();

        for (int i = 0; i < mButtonPointerIds.length; i++) {
            mButtonPointerIds[i] = new IntArrayList(5);
        }
    }

    private void recalculateRects() {
        final int innerLeft = getPaddingLeft();
        final int innerRight = getWidth() - getPaddingRight();
        final int innerTop = getPaddingTop();
        final int innerBottom = getHeight() - getPaddingBottom();
        final int buttonBarTop = innerBottom - getVisibleButtonBarHeight();
        final int buttonCenterX = innerLeft + ((innerRight - innerLeft) / 2);
        final int middleButtonLeft = buttonCenterX - (mMiddleButtonWidth / 2);
        final int middleButtonRight = middleButtonLeft + mMiddleButtonWidth;

        mInnerRect = new Rect(innerLeft, innerTop, innerRight, innerBottom);

        mTouchpadAreaRect = new Rect(innerLeft, innerTop, innerRight, buttonBarTop);
        mMouseTouchListener.setTouchpadAreaRect(mTouchpadAreaRect);

        mButtonRects[BUTTON_INDEX_FIRST] =
                new Rect(innerLeft, buttonBarTop, buttonCenterX, innerBottom);

        mButtonRects[BUTTON_INDEX_SECOND] =
                new Rect(buttonCenterX, buttonBarTop, innerRight, innerBottom);

        mButtonRects[BUTTON_INDEX_MIDDLE] =
                new Rect(middleButtonLeft, buttonBarTop, middleButtonRight, innerBottom);
    }

    public boolean isActive() {
        return ((mHidMouse != null) && mHidMouse.isConnected());
    }

    public HidMouse getHidMouse() {
        return mHidMouse;
    }
    public void setHidMouse(HidMouse hidMouse) {
        mHidMouse = hidMouse;
        mMouseTouchListener.setHidMouse(hidMouse);
    }

    public HidKeyboard getHidKeyboard() {
        return mHidKeyboard;
    }
    public void setHidKeyboard(HidKeyboard hidKeyboard) {
        mHidKeyboard = hidKeyboard;
        mMouseTouchListener.setHidKeyboard(hidKeyboard);
    }

    public boolean getShowButtons() {
        return mShowButtons;
    }
    public void setShowButtons(boolean value) {
        if (value != mShowButtons) {
            mShowButtons = value;
            recalculateRects();
            invalidate();
        }
    }

    public boolean getShowInfoGraphics() {
        return mShowInfoGraphics;
    }
    public void setShowInfoGraphics(boolean value) {
        if (value != mShowInfoGraphics) {
            mShowInfoGraphics = value;
            invalidate();
        }
    }

    public String getGestureMode() {
        return mGestureListener.getGestureMode();
    }
    public void setGestureMode(String value) {
        mGestureListener.setGestureMode(value);
    }

    public float getMouseSensitivity() {
        return mMouseTouchListener.getMouseSensitivity();
    }
    public void setMouseSensitivity(float value) {
        mMouseTouchListener.setMouseSensitivity(value);
    }

    public float getScrollSensitivity() {
        return mMouseTouchListener.getScrollSensitivity();
    }
    public void setScrollSensitivity(float value) {
        mMouseTouchListener.setScrollSensitivity(value);
    }

    public float getPinchZoomSensitivity() {
        return mMouseTouchListener.getPinchZoomSensitivity();
    }
    public void setPinchZoomSensitivity(float value) {
        mMouseTouchListener.setPinchZoomSensitivity(value);
    }

    public boolean getInvertScroll() {
        return mMouseTouchListener.getInvertScroll();
    }
    public void setInvertScroll(boolean value) {
        mMouseTouchListener.setInvertScroll(value);
    }

    public boolean getFlingScroll() {
        return mMouseTouchListener.getFlingScroll();
    }
    public void setFlingScroll(boolean value) {
        mMouseTouchListener.setFlingScroll(value);
    }

    public int getTouchpadAreaPadding() {
        return mTouchpadAreaPadding;
    }
    public void setTouchpadAreaPadding(int value) {
        mTouchpadAreaPadding = value;
    }
    public void resetTouchpadAreaPadding() {
        mTouchpadAreaPadding = mDefaultTouchpadAreaPadding;
    }

    public int getVisibleButtonBarHeight() {
        return (mShowButtons ? mButtonBarHeight : 0);
    }

    public void activatePointerMode() {
        mMouseTouchListener.activatePointerMode();
    }

    public void activateDragMode(int dragButton, boolean useFastEdgeMovement) {
        mMouseTouchListener.activateDragMode(dragButton, useFastEdgeMovement);
    }

    public void activateScrollMode(int scrollMode) {
        mMouseTouchListener.activateScrollMode(scrollMode);
    }

    public void performButtonPressFeedback() {
        performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
        playSoundEffect(SoundEffectConstants.CLICK);
    }

    public void performButtonReleaseFeedback() {
        performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
        playSoundEffect(SoundEffectConstants.CLICK);
    }

    public void performButtonClickFeedback() {
        performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP);
        playSoundEffect(SoundEffectConstants.CLICK);
    }

    public void performGestureDetectedFeedback() {
        performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
    }

    public void performModeChangedFeedback() {
        performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
    }

    @Override
    public void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);

        recalculateRects();
    }

    public void onMouseButtonClick(int clickType, int button) {
        if (clickType == HidMouse.CLICK_TYPE_CLICK) {
            final int buttonIndex = convertHidMouseBtToBtIndex(button);
            if (buttonIndex > -1) {
                mClickedButtons[buttonIndex] = true;
                postDelayed(new Runnable()
                {
                     @Override
                     public void run() {
                         mClickedButtons[buttonIndex] = false;
                         invalidate();
                     }
                }, BUTTON_CLICK_DURATION);
            }
        }

        invalidate();
    }

    public void onScrollModeChanged(int newMode, int oldMode) {
        invalidate();
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (mShowButtons && handleButtonsTouchEvent(event)) {
            return true;
        }

        return mMouseTouchListener.onTouch(this, event);
    }

    private boolean handleButtonsTouchEvent(MotionEvent event) {
        if (!isActive() || (event.getActionMasked() == MotionEvent.ACTION_CANCEL)) {
            releaseAllButtons();
            return false;
        }

        switch (event.getActionMasked()) {
        case MotionEvent.ACTION_DOWN:
        case MotionEvent.ACTION_POINTER_DOWN:
            final int downPointerIndex = event.getActionIndex();
            final int downPointerId = event.getPointerId(downPointerIndex);
            final int downX = (int)event.getX(downPointerIndex);
            final int downY = (int)event.getY(downPointerIndex);

            for (int i = (mButtonRects.length - 1); i >= 0; i--) {
                if (mButtonRects[i].contains(downX, downY)) {
                    if (mButtonPointerIds[i].isEmpty()) {
                        mHidMouse.pressButton(convertBtIndexToHidMouseBt(i));
                        performButtonPressFeedback();
                    }
                    if (!mButtonPointerIds[i].containsValue(downPointerId)) {
                        mButtonPointerIds[i].addValue(downPointerId);
                    }
                    return true;
                }
            }
            break;
        case MotionEvent.ACTION_POINTER_UP:
            final int upPointerIndex = event.getActionIndex();
            final int upPointerId = event.getPointerId(upPointerIndex);

            for (int i = 0; i < mButtonPointerIds.length; i++) {
                if (mButtonPointerIds[i].containsValue(upPointerId)) {
                    mButtonPointerIds[i].removeValue(upPointerId);
                    if (mButtonPointerIds[i].isEmpty()) {
                        mHidMouse.releaseButton(convertBtIndexToHidMouseBt(i));
                        performButtonReleaseFeedback();
                    }
                    return true;
                }
            }
            break;
        case MotionEvent.ACTION_UP:
            releaseAllButtons();
            break;
        }

        return false;
    }

    private int convertBtIndexToHidMouseBt(int buttonIndex) {
        switch (buttonIndex) {
        case BUTTON_INDEX_FIRST:
            return HidMouse.BUTTON_FIRST;
        case BUTTON_INDEX_SECOND:
            return HidMouse.BUTTON_SECOND;
        case BUTTON_INDEX_MIDDLE:
            return HidMouse.BUTTON_MIDDLE;
        default:
            return 0;
        }
    }

    private int convertHidMouseBtToBtIndex(int hidMouseButton) {
        switch (hidMouseButton) {
        case HidMouse.BUTTON_FIRST:
            return BUTTON_INDEX_FIRST;
        case HidMouse.BUTTON_SECOND:
            return BUTTON_INDEX_SECOND;
        case HidMouse.BUTTON_MIDDLE:
            return BUTTON_INDEX_MIDDLE;
        default:
            return -1;
        }
    }

    private boolean isButtonPressed(int btIndex) {
        final int hidMouseBt = convertBtIndexToHidMouseBt(btIndex);
        return (mClickedButtons[btIndex] ||
                ((mHidMouse != null) && mHidMouse.isButtonPressed(hidMouseBt)));
    }

    private void releaseAllButtons() {
        for (int i = 0; i < mButtonPointerIds.length; i++) {
            if (!mButtonPointerIds[i].isEmpty()) {
                if (mHidMouse != null) {
                    mHidMouse.releaseButton(convertBtIndexToHidMouseBt(i));
                    performButtonReleaseFeedback();
                }
                mButtonPointerIds[i].clear();
            }
        }
    }

    @Override
    public void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        mBackgroundDrawable.setBounds(mInnerRect);
        mBackgroundDrawable.draw(canvas);

        if (mShowInfoGraphics) {
            switch (mMouseTouchListener.getScrollMode()) {
            case SCROLL_MODE_VERTICAL:
                drawInfoDrawable(canvas, mScrollVerticalDrawable);
                break;
            case SCROLL_MODE_HORIZONTAL:
                drawInfoDrawable(canvas, mScrollHorizontalDrawable);
                break;
            case SCROLL_MODE_ALL:
                drawInfoDrawable(canvas, mScrollAllDrawable);
                break;
            }
        }

        if (mShowButtons) {
            drawButtons(canvas);
        }
    }

    private void drawInfoDrawable(Canvas canvas, Drawable drawable) {
        final int maxWidth = mTouchpadAreaRect.width() - (mTouchpadAreaPadding * 2);
        final int maxHeight = mTouchpadAreaRect.height() - (mTouchpadAreaPadding * 2);

        int drawableWidth = drawable.getIntrinsicWidth();
        int drawableHeight = drawable.getIntrinsicHeight();
        if ((drawableWidth > maxWidth) || (drawableHeight > maxHeight)) {
            if (maxWidth < maxHeight) {
                drawableWidth = maxWidth;
                drawableHeight = maxWidth;
            } else {
                drawableWidth = maxHeight;
                drawableHeight = maxHeight;
            }
        }

        final int touchpadCenterX = mTouchpadAreaRect.left + (mTouchpadAreaRect.width() / 2);
        final int touchpadCenterY = mTouchpadAreaRect.top + (mTouchpadAreaRect.height() / 2);
        final int left = touchpadCenterX - (drawableWidth / 2);
        final int top = touchpadCenterY - (drawableHeight / 2);

        drawable.setBounds(left, top, left + drawableWidth, top + drawableHeight);
        drawable.draw(canvas);
    }

    private void drawButtons(Canvas canvas) {
        final Rect firstButtonRect = mButtonRects[BUTTON_INDEX_FIRST];
        final Rect secondButtonRect = mButtonRects[BUTTON_INDEX_SECOND];

        mButtonDrawable.setBounds(firstButtonRect);
        if (isButtonPressed(BUTTON_INDEX_FIRST) || isButtonPressed(BUTTON_INDEX_MIDDLE)) {
            mButtonDrawable.setState(PRESSED_ENABLED_STATE_SET);
        } else {
            mButtonDrawable.setState(EMPTY_STATE_SET);
        }
        mButtonDrawable.draw(canvas);

        mButtonDrawable.setBounds(secondButtonRect);
        if (isButtonPressed(BUTTON_INDEX_SECOND) || isButtonPressed(BUTTON_INDEX_MIDDLE)) {
            mButtonDrawable.setState(PRESSED_ENABLED_STATE_SET);
        } else {
            mButtonDrawable.setState(EMPTY_STATE_SET);
        }
        mButtonDrawable.draw(canvas);


        final int buttonBarY = firstButtonRect.top - (mButtonBarStrokeWidth / 2);
        mButtonBarPaint.setColor(mButtonBarColor);
        mButtonBarPaint.setStrokeWidth(mButtonBarStrokeWidth);
        canvas.drawLine(firstButtonRect.left,
                buttonBarY,
                secondButtonRect.right,
                buttonBarY,
                mButtonBarPaint);

        final int buttonSepX = firstButtonRect.right - (mButtonSepStrokeWidth / 2);
        mButtonBarPaint.setColor(mButtonBarColor);
        mButtonBarPaint.setStrokeWidth(mButtonSepStrokeWidth);
        canvas.drawLine(buttonSepX,
                firstButtonRect.top + mButtonSepMargin,
                buttonSepX,
                firstButtonRect.bottom - mButtonSepMargin,
                mButtonBarPaint);
    }
}




Java Source Code List

org.ronsdev.bluectrl.ChangelogDialog.java
org.ronsdev.bluectrl.CharKeyReportMap.java
org.ronsdev.bluectrl.DeviceManager.java
org.ronsdev.bluectrl.DevicePreferenceActivity.java
org.ronsdev.bluectrl.DeviceSettings.java
org.ronsdev.bluectrl.HidKeyboard.java
org.ronsdev.bluectrl.HidMouse.java
org.ronsdev.bluectrl.IntArrayList.java
org.ronsdev.bluectrl.KeyEventFuture.java
org.ronsdev.bluectrl.MainActivity.java
org.ronsdev.bluectrl.OnMouseButtonClickListener.java
org.ronsdev.bluectrl.PairedDevice.java
org.ronsdev.bluectrl.PairingActivity.java
org.ronsdev.bluectrl.TouchpadActivity.java
org.ronsdev.bluectrl.TouchpadTutorialActivity.java
org.ronsdev.bluectrl.daemon.DaemonActivity.java
org.ronsdev.bluectrl.daemon.DaemonCallbackReceiver.java
org.ronsdev.bluectrl.daemon.DaemonListActivity.java
org.ronsdev.bluectrl.daemon.DaemonService.java
org.ronsdev.bluectrl.widget.ComposeTextLayout.java
org.ronsdev.bluectrl.widget.FloatSliderPreference.java
org.ronsdev.bluectrl.widget.KeyboardInputView.java
org.ronsdev.bluectrl.widget.MouseTouchListener.java
org.ronsdev.bluectrl.widget.OnKeyboardComposingTextListener.java
org.ronsdev.bluectrl.widget.OnScrollModeChangedListener.java
org.ronsdev.bluectrl.widget.OnSendComposeTextListener.java
org.ronsdev.bluectrl.widget.OnTouchpadGestureListener.java
org.ronsdev.bluectrl.widget.SummaryListPreference.java
org.ronsdev.bluectrl.widget.TouchpadViewGestureListener.java
org.ronsdev.bluectrl.widget.TouchpadView.java