/RockLock/src/com/google/marvin/widget/GestureOverlay.java
Java | 186 lines | 117 code | 39 blank | 30 comment | 30 complexity | abdc6ceeb4e5ab88d296c70dee30d362 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 17package com.google.marvin.widget; 18 19import android.content.Context; 20import android.view.MotionEvent; 21import android.view.View; 22 23/** 24 * A transparent overlay which catches all touch events and uses a call back to 25 * return the gesture that the user performed. 26 * 27 * @author clchen@google.com (Charles L. Chen) 28 */ 29 30public class GestureOverlay extends View { 31 /** 32 * Constants for the types of stroke gestures 33 */ 34 public static class Gesture { 35 public static final int UPLEFT = 1; 36 37 public static final int UP = 2; 38 39 public static final int UPRIGHT = 3; 40 41 public static final int LEFT = 4; 42 43 public static final int CENTER = 5; 44 45 public static final int RIGHT = 6; 46 47 public static final int DOWNLEFT = 7; 48 49 public static final int DOWN = 8; 50 51 public static final int DOWNRIGHT = 9; 52 } 53 54 /** 55 * The callback interface to be used when a gesture is detected. 56 */ 57 public interface GestureListener { 58 public void onGestureStart(int g); 59 60 public void onGestureChange(int g); 61 62 public void onGestureFinish(int g); 63 } 64 65 private final double left = 0; 66 67 private final double upleft = Math.PI * .25; 68 69 private final double up = Math.PI * .5; 70 71 private final double upright = Math.PI * .75; 72 73 private final double downright = -Math.PI * .75; 74 75 private final double down = -Math.PI * .5; 76 77 private final double downleft = -Math.PI * .25; 78 79 private final double right = Math.PI; 80 81 private final double rightWrap = -Math.PI; 82 83 private GestureListener cb = null; 84 85 private double downX; 86 87 private double downY; 88 89 private int currentGesture; 90 91 private int radiusThreshold = 30; 92 93 public GestureOverlay(Context context, GestureListener callback) { 94 super(context); 95 cb = callback; 96 } 97 98 public GestureOverlay(Context context) { 99 super(context); 100 } 101 102 public void setGestureListener(GestureListener callback) { 103 cb = callback; 104 } 105 106 public void setMinimumRadius(int minRadius) { 107 radiusThreshold = minRadius; 108 } 109 110 @Override 111 public boolean onTouchEvent(MotionEvent event) { 112 int action = event.getAction(); 113 float x = event.getX(); 114 float y = event.getY(); 115 int prevGesture = -1; 116 switch (action) { 117 case MotionEvent.ACTION_DOWN: 118 downX = x; 119 downY = y; 120 currentGesture = Gesture.CENTER; 121 if (cb != null) { 122 cb.onGestureStart(currentGesture); 123 } 124 break; 125 case MotionEvent.ACTION_UP: 126 prevGesture = currentGesture; 127 currentGesture = evalMotion(x, y); 128 // Do some correction if the user lifts up on deadspace 129 if (currentGesture == -1) { 130 currentGesture = prevGesture; 131 } 132 if (cb != null) { 133 cb.onGestureFinish(currentGesture); 134 } 135 break; 136 default: 137 prevGesture = currentGesture; 138 currentGesture = evalMotion(x, y); 139 // Do some correction if the user lifts up on deadspace 140 if (currentGesture == -1) { 141 currentGesture = prevGesture; 142 break; 143 } 144 if (prevGesture != currentGesture) { 145 if (cb != null) { 146 cb.onGestureChange(currentGesture); 147 } 148 } 149 break; 150 } 151 return true; 152 } 153 154 public int evalMotion(double x, double y) { 155 float rTolerance = radiusThreshold; 156 double thetaTolerance = (Math.PI / 12); 157 158 double r = Math.sqrt(((downX - x) * (downX - x)) + ((downY - y) * (downY - y))); 159 160 if (r < rTolerance) { 161 return Gesture.CENTER; 162 } 163 164 double theta = Math.atan2(downY - y, downX - x); 165 if (Math.abs(theta - left) < thetaTolerance) { 166 return Gesture.LEFT; 167 } else if (Math.abs(theta - upleft) < thetaTolerance) { 168 return Gesture.UPLEFT; 169 } else if (Math.abs(theta - up) < thetaTolerance) { 170 return Gesture.UP; 171 } else if (Math.abs(theta - upright) < thetaTolerance) { 172 return Gesture.UPRIGHT; 173 } else if (Math.abs(theta - downright) < thetaTolerance) { 174 return Gesture.DOWNRIGHT; 175 } else if (Math.abs(theta - down) < thetaTolerance) { 176 return Gesture.DOWN; 177 } else if (Math.abs(theta - downleft) < thetaTolerance) { 178 return Gesture.DOWNLEFT; 179 } else if ((theta > right - thetaTolerance) || (theta < rightWrap + thetaTolerance)) { 180 return Gesture.RIGHT; 181 } 182 // Off by more than the threshold, so it doesn't count 183 return -1; 184 } 185 186}