/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

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