/utils/src/com/google/marvin/widget/TouchGestureControlOverlay.java
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}