PageRenderTime 27ms CodeModel.GetById 13ms app.highlight 11ms RepoModel.GetById 1ms app.codeStats 1ms

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

http://eyes-free.googlecode.com/
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}