/MusicLockTutorial/src/com/google/marvin/widget/GestureOverlay.java

http://eyes-free.googlecode.com/ · Java · 183 lines · 117 code · 39 blank · 27 comment · 30 complexity · 75633b1b9f7e456cb2c80a5a33538d62 MD5 · raw file

  1. /*
  2. * Copyright (C) 2010 Google Inc.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License"); you may not
  5. * use this file except in compliance with the License. You may obtain a copy of
  6. * the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  12. * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  13. * License for the specific language governing permissions and limitations under
  14. * the License.
  15. */
  16. package com.google.marvin.widget;
  17. import android.content.Context;
  18. import android.view.MotionEvent;
  19. import android.view.View;
  20. /**
  21. * A transparent overlay which catches all touch events and uses a call back to
  22. * return the gesture that the user performed.
  23. *
  24. * @author clchen@google.com (Charles L. Chen)
  25. */
  26. public class GestureOverlay extends View {
  27. public static class Gesture {
  28. public static final int UPLEFT = 1;
  29. public static final int UP = 2;
  30. public static final int UPRIGHT = 3;
  31. public static final int LEFT = 4;
  32. public static final int CENTER = 5;
  33. public static final int RIGHT = 6;
  34. public static final int DOWNLEFT = 7;
  35. public static final int DOWN = 8;
  36. public static final int DOWNRIGHT = 9;
  37. }
  38. /**
  39. * The callback interface to be used when a gesture is detected.
  40. */
  41. public interface GestureListener {
  42. public void onGestureStart(int g);
  43. public void onGestureChange(int g);
  44. public void onGestureFinish(int g);
  45. }
  46. private final double left = 0;
  47. private final double upleft = Math.PI * .25;
  48. private final double up = Math.PI * .5;
  49. private final double upright = Math.PI * .75;
  50. private final double downright = -Math.PI * .75;
  51. private final double down = -Math.PI * .5;
  52. private final double downleft = -Math.PI * .25;
  53. private final double right = Math.PI;
  54. private final double rightWrap = -Math.PI;
  55. private GestureListener cb = null;
  56. private double downX;
  57. private double downY;
  58. private int currentGesture;
  59. private int radiusThreshold = 30;
  60. public GestureOverlay(Context context, GestureListener callback) {
  61. super(context);
  62. cb = callback;
  63. }
  64. public GestureOverlay(Context context) {
  65. super(context);
  66. }
  67. public void setGestureListener(GestureListener callback) {
  68. cb = callback;
  69. }
  70. public void setMinimumRadius(int minRadius) {
  71. radiusThreshold = minRadius;
  72. }
  73. @Override
  74. public boolean onTouchEvent(MotionEvent event) {
  75. int action = event.getAction();
  76. float x = event.getX();
  77. float y = event.getY();
  78. int prevGesture = -1;
  79. switch (action) {
  80. case MotionEvent.ACTION_DOWN:
  81. downX = x;
  82. downY = y;
  83. currentGesture = Gesture.CENTER;
  84. if (cb != null) {
  85. cb.onGestureStart(currentGesture);
  86. }
  87. break;
  88. case MotionEvent.ACTION_UP:
  89. prevGesture = currentGesture;
  90. currentGesture = evalMotion(x, y);
  91. // Do some correction if the user lifts up on deadspace
  92. if (currentGesture == -1) {
  93. currentGesture = prevGesture;
  94. }
  95. if (cb != null) {
  96. cb.onGestureFinish(currentGesture);
  97. }
  98. break;
  99. default:
  100. prevGesture = currentGesture;
  101. currentGesture = evalMotion(x, y);
  102. // Do some correction if the user lifts up on deadspace
  103. if (currentGesture == -1) {
  104. currentGesture = prevGesture;
  105. break;
  106. }
  107. if (prevGesture != currentGesture) {
  108. if (cb != null) {
  109. cb.onGestureChange(currentGesture);
  110. }
  111. }
  112. break;
  113. }
  114. return true;
  115. }
  116. public int evalMotion(double x, double y) {
  117. float rTolerance = radiusThreshold;
  118. double thetaTolerance = (Math.PI / 12);
  119. double r = Math.sqrt(((downX - x) * (downX - x)) + ((downY - y) * (downY - y)));
  120. if (r < rTolerance) {
  121. return Gesture.CENTER;
  122. }
  123. double theta = Math.atan2(downY - y, downX - x);
  124. if (Math.abs(theta - left) < thetaTolerance) {
  125. return Gesture.LEFT;
  126. } else if (Math.abs(theta - upleft) < thetaTolerance) {
  127. return Gesture.UPLEFT;
  128. } else if (Math.abs(theta - up) < thetaTolerance) {
  129. return Gesture.UP;
  130. } else if (Math.abs(theta - upright) < thetaTolerance) {
  131. return Gesture.UPRIGHT;
  132. } else if (Math.abs(theta - downright) < thetaTolerance) {
  133. return Gesture.DOWNRIGHT;
  134. } else if (Math.abs(theta - down) < thetaTolerance) {
  135. return Gesture.DOWN;
  136. } else if (Math.abs(theta - downleft) < thetaTolerance) {
  137. return Gesture.DOWNLEFT;
  138. } else if ((theta > right - thetaTolerance) || (theta < rightWrap + thetaTolerance)) {
  139. return Gesture.RIGHT;
  140. }
  141. // Off by more than the threshold, so it doesn't count
  142. return -1;
  143. }
  144. }