PageRenderTime 26ms CodeModel.GetById 17ms app.highlight 6ms RepoModel.GetById 1ms app.codeStats 0ms

/utils/src/com/google/marvin/widget/TouchGestureControlOverlay.java

http://eyes-free.googlecode.com/
Java | 140 lines | 105 code | 19 blank | 16 comment | 30 complexity | be0ce1ba478aae1eb9e2ee1013a675a5 MD5 | raw file
  1package com.google.marvin.widget;
  2
  3
  4import android.content.Context;
  5import android.view.MotionEvent;
  6import android.view.View;
  7
  8/**
  9 * A transparent overlay which catches all touch events and uses a call back to
 10 * return the gesture that the user performed.
 11 * 
 12 * @author clchen@google.com (Charles L. Chen)
 13 * 
 14 */
 15
 16public class TouchGestureControlOverlay extends View {
 17
 18  /**
 19   * An enumeration of the possible gestures.
 20   */
 21  public enum Gesture {
 22    UPLEFT, UP, UPRIGHT, LEFT, CENTER, RIGHT, DOWNLEFT, DOWN, DOWNRIGHT
 23  }
 24
 25  /**
 26   * The callback interface to be used when a gesture is detected.
 27   */
 28  public interface GestureListener {
 29    public void onGestureStart(Gesture g);
 30
 31    public void onGestureChange(Gesture g);
 32
 33    public void onGestureFinish(Gesture g);
 34  }
 35
 36  private final double left = 0;
 37  private final double upleft = Math.PI * .25;
 38  private final double up = Math.PI * .5;
 39  private final double upright = Math.PI * .75;
 40  private final double downright = -Math.PI * .75;
 41  private final double down = -Math.PI * .5;
 42  private final double downleft = -Math.PI * .25;
 43  private final double right = Math.PI;
 44  private final double rightWrap = -Math.PI;
 45
 46  private GestureListener cb = null;
 47  private double downX;
 48  private double downY;
 49  private Gesture currentGesture;
 50
 51  public TouchGestureControlOverlay(Context context, GestureListener callback) {
 52    super(context);
 53    cb = callback;
 54  }
 55
 56  public TouchGestureControlOverlay(Context context) {
 57    super(context);
 58  }
 59
 60  public void setGestureListener(GestureListener callback) {
 61    cb = callback;
 62  }
 63
 64  @Override
 65  public boolean onTouchEvent(MotionEvent event) {
 66    int action = event.getAction();
 67    float x = event.getX();
 68    float y = event.getY();
 69    Gesture prevGesture = null;
 70    switch (action) {
 71      case MotionEvent.ACTION_DOWN:
 72        downX = x;
 73        downY = y;
 74        currentGesture = Gesture.CENTER;
 75        if (cb != null) {
 76          cb.onGestureStart(currentGesture);
 77        }
 78        break;
 79      case MotionEvent.ACTION_UP:
 80        prevGesture = currentGesture;
 81        currentGesture = evalMotion(x, y);
 82        // Do some correction if the user lifts up on deadspace
 83        if (currentGesture == null) {
 84          currentGesture = prevGesture;
 85        }
 86        if (cb != null) {
 87          cb.onGestureFinish(currentGesture);
 88        }
 89        break;
 90      default:
 91        prevGesture = currentGesture;
 92        currentGesture = evalMotion(x, y);
 93        // Do some correction if the user lifts up on deadspace
 94        if (currentGesture == null) {
 95          currentGesture = prevGesture;
 96          break;
 97        }
 98        if (prevGesture != currentGesture) {
 99          if (cb != null) {
100            cb.onGestureChange(currentGesture);
101          }
102        }
103        break;
104    }
105    return true;
106  }
107
108  public Gesture evalMotion(double x, double y) {
109    float rTolerance = 25;
110    double thetaTolerance = (Math.PI / 12);
111
112    double r = Math.sqrt(((downX - x) * (downX - x)) + ((downY - y) * (downY - y)));
113
114    if (r < rTolerance) {
115      return Gesture.CENTER;
116    }
117
118    double theta = Math.atan2(downY - y, downX - x);
119    if (Math.abs(theta - left) < thetaTolerance) {
120      return Gesture.LEFT;
121    } else if (Math.abs(theta - upleft) < thetaTolerance) {
122      return Gesture.UPLEFT;
123    } else if (Math.abs(theta - up) < thetaTolerance) {
124      return Gesture.UP;
125    } else if (Math.abs(theta - upright) < thetaTolerance) {
126      return Gesture.UPRIGHT;
127    } else if (Math.abs(theta - downright) < thetaTolerance) {
128      return Gesture.DOWNRIGHT;
129    } else if (Math.abs(theta - down) < thetaTolerance) {
130      return Gesture.DOWN;
131    } else if (Math.abs(theta - downleft) < thetaTolerance) {
132      return Gesture.DOWNLEFT;
133    } else if ((theta > right - thetaTolerance) || (theta < rightWrap + thetaTolerance)) {
134      return Gesture.RIGHT;
135    }
136    // Off by more than the threshold, so it doesn't count
137    return null;
138  }
139
140}