org.gearvrf.viewmanager.controls.gestures.TouchPadGesturesDetector.java Source code

Java tutorial

Introduction

Here is the source code for org.gearvrf.viewmanager.controls.gestures.TouchPadGesturesDetector.java

Source

/* Copyright 2015 Samsung Electronics Co., LTD
 *
 * 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.gearvrf.viewmanager.controls.gestures;

import android.content.Context;
import android.content.SharedPreferences;
import android.support.v4.view.GestureDetectorCompat;
import android.util.Log;
import android.view.GestureDetector;
import android.view.MotionEvent;

public class TouchPadGesturesDetector
        implements GestureDetector.OnGestureListener, GestureDetector.OnDoubleTapListener {

    private static final int MIN_MOVE_TIME = 250;
    public static final String DEBUG_TAG = "Gestures";
    private GestureDetectorCompat mDetector;
    private long downCurrentTimeMillis = 0;
    private SwipeDirection lastDirection = SwipeDirection.Ignore;

    private static final int SWIPE_MIN_DISTANCE = 80;
    private static final int ONTAP_MIN_DISTANCE = 0;

    public enum SwipeDirection {
        Backward, Forward, Down, Up, Ignore
    }

    OnTouchPadGestureListener gestureListener;
    OnTouchPadDoubleTapListener doubleTapListener;

    /**
     * The listener that is used to notify when gestures occur.
     */
    public interface OnTouchPadGestureListener {
        /**
         * Notified when a tap occurs with the up {@link MotionEvent} that
         * triggered it.
         * 
         * @param e The up motion event that completed the first tap
         * @return true if the event is consumed, else false
         */
        abstract boolean onSingleTap(MotionEvent e);

        /**
         * Notified when a long press occurs with the initial on down
         * {@link MotionEvent} that triggered it.
         * 
         * @param e The initial on down motion event that started the longpress.
         */
        abstract void onLongPress(MotionEvent e);

        /**
         * Notified when a swipe occurs.
         * 
         * @param e1 The first down motion event that started the fling.
         * @param swipeDirection The direction of swipe.
         * @param velocityX The velocity of this fling measured in pixels per
         *            second along the x axis.
         * @param velocityY The velocity of this fling measured in pixels per
         *            second along the y axis.
         * @return true if the event is consumed, else false
         */
        abstract boolean onSwipe(MotionEvent e, SwipeDirection swipeDirection, float velocityX, float velocityY);

        abstract void onSwiping(MotionEvent e, MotionEvent e2, float velocityX, float velocityY,
                SwipeDirection swipeDirection);

        abstract void onSwipeOppositeLastDirection();
    }

    /**
     * The listener that is used to notify when a double-tap or a confirmed
     * single-tap occur.
     */
    public interface OnTouchPadDoubleTapListener {
        /**
         * Notified when a single-tap occurs.
         * 
         * @param e The down motion event of the single-tap.
         * @return true if the event is consumed, else false
         */
        boolean onSingleTapConfirmed(MotionEvent e);

        /**
         * Notified when a double-tap occurs.
         * 
         * @param e The down motion event of the first tap of the double-tap.
         * @return true if the event is consumed, else false
         */
        boolean onDoubleTap(MotionEvent e);
    }

    SharedPreferences sharedPref;
    SharedPreferences.Editor editor;
    int countSwipe = 0;

    public TouchPadGesturesDetector(Context context, OnTouchPadGestureListener listener) {

        this.mDetector = new GestureDetectorCompat(context, this);
        this.mDetector.setIsLongpressEnabled(false);
        this.mDetector.setOnDoubleTapListener(this);
        this.gestureListener = listener;

        sharedPref = context.getSharedPreferences("VR", Context.MODE_PRIVATE);
        editor = sharedPref.edit();
    }

    public void setOnDoubleTapListener(OnTouchPadDoubleTapListener onDoubleTapListener) {
        doubleTapListener = onDoubleTapListener;
    }

    public boolean onTouchEvent(MotionEvent event) {
        return this.mDetector.onTouchEvent(event);
    }

    @Override
    public boolean onDown(MotionEvent event) {
        downCurrentTimeMillis = System.currentTimeMillis();
        return true;
    }

    @Override
    public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {

        long moveTime = System.currentTimeMillis();

        if ((moveTime - downCurrentTimeMillis) > MIN_MOVE_TIME) {

            SwipeDirection direction = getSwipeDirection(e1.getX(), e1.getY(), e2.getX(), e2.getY());

            if (direction != lastDirection) {
                gestureListener.onSwipeOppositeLastDirection();
            }

            lastDirection = direction;
        }

        gestureListener.onSwiping(e1, e2, distanceX, distanceY, lastDirection);

        return true;
    }

    private void saveSwipeDistanceValue(float value) {
        editor.putFloat("SWIPE_DISTANCE" + countSwipe, value);
        editor.commit();
        countSwipe++;
    }

    @Override
    public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {

        Log.d(TouchPadGesturesDetector.DEBUG_TAG, "onFling()");

        if (mDetector == null) {
            return false;
        }

        double distance = Math.sqrt(Math.pow(e2.getX() - e1.getX(), 2) + Math.pow(e2.getY() - e1.getY(), 2));

        saveSwipeDistanceValue((float) distance);

        if (distance > SWIPE_MIN_DISTANCE) {
            try {

                double deltaY = e2.getY() - e1.getY();
                double deltaX = e2.getX() - e1.getX();

                double angle = Math.toDegrees(Math.atan2(deltaY, deltaX)) + 180 + 45;

                if (angle > 360)
                    angle -= 360;

                if (angle < 90) {
                    return gestureListener.onSwipe(e1, SwipeDirection.Forward, velocityX, velocityY);
                } else if (angle < 180) {
                    return gestureListener.onSwipe(e1, SwipeDirection.Up, velocityX, velocityY);
                } else if (angle < 270) {
                    return gestureListener.onSwipe(e1, SwipeDirection.Backward, velocityX, velocityY);
                } else {
                    return gestureListener.onSwipe(e1, SwipeDirection.Down, velocityX, velocityY);
                }

            } catch (Exception e) {
                // Ignore
            }

        } else if (distance >= ONTAP_MIN_DISTANCE) {
            /*
             * The gesture listener filters out dirty taps that look like swipes
             * altogether. This reduces usability as it's hard to get a clean
             * tap on the tracker
             */
            gestureListener.onSingleTap(e1);
            return true;
        }

        return false;
    }

    @Override
    public void onLongPress(MotionEvent event) {
    }

    @Override
    public void onShowPress(MotionEvent event) {
    }

    @Override
    public boolean onSingleTapUp(MotionEvent event) {

        if (gestureListener != null) {
            return gestureListener.onSingleTap(event);
        }

        return false;
    }

    @Override
    public boolean onDoubleTap(MotionEvent event) {
        if (doubleTapListener != null) {
            return doubleTapListener.onDoubleTap(event);
        }
        return false;
    }

    @Override
    public boolean onDoubleTapEvent(MotionEvent event) {
        return true;
    }

    @Override
    public boolean onSingleTapConfirmed(MotionEvent event) {
        if (doubleTapListener != null) {
            return doubleTapListener.onSingleTapConfirmed(event);
        }
        return false;
    }

    private SwipeDirection getSwipeDirection(float x1, float y1, float x2, float y2) {

        Double angle = Math.toDegrees(Math.atan2(y1 - y2, x2 - x1));

        if (angle > 45 && angle <= 135) {
            return SwipeDirection.Up;
        } else if (angle >= 135 && angle < 180 || angle < -135 && angle > -180) {
            return SwipeDirection.Ignore; // left to right
        } else if (angle < -45 && angle >= -135) {
            return SwipeDirection.Down;
        } else if (angle > -45 && angle <= 45) {
            return SwipeDirection.Ignore; // right to left
        }

        return SwipeDirection.Ignore;
    }
}