1 package com.android.camera;
4 * Copyright (C) 2013 The Android Open Source Project
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
19 import android.os.Handler;
20 import android.os.Message;
21 import android.util.Log;
22 import android.view.GestureDetector;
23 import android.view.MotionEvent;
24 import android.view.ScaleGestureDetector;
25 import android.view.View;
26 import android.view.ViewConfiguration;
28 import com.android.camera.PreviewGestures.SingleTapListener;
29 import com.android.camera.PreviewGestures.SwipeListener;
30 import com.android.camera.ui.PieRenderer;
31 import com.android.camera.ui.RenderOverlay;
32 import com.android.camera.ui.ZoomRenderer;
33 import com.android.gallery3d.R;
35 import java.util.ArrayList;
36 import java.util.List;
38 /* NewPreviewGestures disambiguates touch events received on RenderOverlay
39 * and dispatch them to the proper recipient (i.e. zoom renderer or pie renderer).
40 * Touch events on CameraControls will be handled by framework.
42 public class NewPreviewGestures
43 implements ScaleGestureDetector.OnScaleGestureListener {
45 private static final String TAG = "CAM_gestures";
47 private static final long TIMEOUT_PIE = 200;
48 private static final int MSG_PIE = 1;
49 private static final int MODE_NONE = 0;
50 private static final int MODE_PIE = 1;
51 private static final int MODE_ZOOM = 2;
52 private static final int MODE_MODULE = 3;
53 private static final int MODE_ALL = 4;
54 private static final int MODE_SWIPE = 5;
56 public static final int DIR_UP = 0;
57 public static final int DIR_DOWN = 1;
58 public static final int DIR_LEFT = 2;
59 public static final int DIR_RIGHT = 3;
61 private NewCameraActivity mActivity;
62 private SingleTapListener mTapListener;
63 private RenderOverlay mOverlay;
64 private PieRenderer mPie;
65 private ZoomRenderer mZoom;
66 private MotionEvent mDown;
67 private MotionEvent mCurrent;
68 private ScaleGestureDetector mScale;
71 private int mTapTimeout;
72 private boolean mZoomEnabled;
73 private boolean mEnabled;
74 private boolean mZoomOnly;
75 private int mOrientation;
76 private GestureDetector mGestureDetector;
78 private GestureDetector.SimpleOnGestureListener mGestureListener = new GestureDetector.SimpleOnGestureListener() {
80 public void onLongPress (MotionEvent e) {
82 if (mPie != null && !mPie.showsItems()) {
88 public boolean onSingleTapUp (MotionEvent e) {
89 // Tap to focus when pie is not open
90 if (mPie == null || !mPie.showsItems()) {
91 mTapListener.onSingleTapUp(null, (int) e.getX(), (int) e.getY());
98 public boolean onScroll (MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
99 if (mMode == MODE_ZOOM) return false;
100 int deltaX = (int) (e1.getX() - e2.getX());
101 int deltaY = (int) (e1.getY() - e2.getY());
102 if (deltaY > 2 * deltaX && deltaY > -2 * deltaX) {
103 // Open pie on swipe up
104 if (mPie != null && !mPie.showsItems()) {
113 private Handler mHandler = new Handler() {
114 public void handleMessage(Message msg) {
115 if (msg.what == MSG_PIE) {
122 public interface SingleTapListener {
123 public void onSingleTapUp(View v, int x, int y);
126 public NewPreviewGestures(NewCameraActivity ctx, SingleTapListener tapListener,
127 ZoomRenderer zoom, PieRenderer pie) {
129 mTapListener = tapListener;
133 mScale = new ScaleGestureDetector(ctx, this);
134 mSlop = (int) ctx.getResources().getDimension(R.dimen.pie_touch_slop);
135 mTapTimeout = ViewConfiguration.getTapTimeout();
137 mGestureDetector = new GestureDetector(mGestureListener);
140 public void setRenderOverlay(RenderOverlay overlay) {
144 public void setOrientation(int orientation) {
145 mOrientation = orientation;
148 public void setEnabled(boolean enabled) {
152 public void setZoomEnabled(boolean enable) {
153 mZoomEnabled = enable;
156 public void setZoomOnly(boolean zoom) {
160 public boolean isEnabled() {
164 public boolean dispatchTouch(MotionEvent m) {
169 if (MotionEvent.ACTION_DOWN == m.getActionMasked()) {
171 mDown = MotionEvent.obtain(m);
174 // If pie is open, redirects all the touch events to pie.
175 if (mPie != null && mPie.isOpen()) {
179 // If pie is not open, send touch events to gesture detector and scale
180 // listener to recognize the gesture.
181 mGestureDetector.onTouchEvent(m);
183 mScale.onTouchEvent(m);
184 if (MotionEvent.ACTION_POINTER_DOWN == m.getActionMasked()) {
187 // Start showing zoom UI as soon as there is a second finger down
188 mZoom.onScaleBegin(mScale);
190 } else if (MotionEvent.ACTION_POINTER_UP == m.getActionMasked()) {
191 mZoom.onScaleEnd(mScale);
197 // left tests for finger moving right to left
198 private int getSwipeDirection(MotionEvent m) {
201 switch (mOrientation) {
203 dx = m.getX() - mDown.getX();
204 dy = m.getY() - mDown.getY();
207 dx = - (m.getY() - mDown.getY());
208 dy = m.getX() - mDown.getX();
211 dx = -(m.getX() - mDown.getX());
212 dy = m.getY() - mDown.getY();
215 dx = m.getY() - mDown.getY();
216 dy = m.getX() - mDown.getX();
219 if (dx < 0 && (Math.abs(dy) / -dx < 2)) return DIR_LEFT;
220 if (dx > 0 && (Math.abs(dy) / dx < 2)) return DIR_RIGHT;
221 if (dy > 0) return DIR_DOWN;
225 private MotionEvent makeCancelEvent(MotionEvent m) {
226 MotionEvent c = MotionEvent.obtain(m);
227 c.setAction(MotionEvent.ACTION_CANCEL);
231 private void openPie() {
232 mGestureDetector.onTouchEvent(makeCancelEvent(mDown));
233 mScale.onTouchEvent(makeCancelEvent(mDown));
234 mOverlay.directDispatchTouch(mDown, mPie);
237 private boolean sendToPie(MotionEvent m) {
238 return mOverlay.directDispatchTouch(m, mPie);
241 // OnScaleGestureListener implementation
243 public boolean onScale(ScaleGestureDetector detector) {
244 return mZoom.onScale(detector);
248 public boolean onScaleBegin(ScaleGestureDetector detector) {
249 if (mPie == null || !mPie.isOpen()) {
251 mGestureDetector.onTouchEvent(makeCancelEvent(mCurrent));
252 if (!mZoomEnabled) return false;
253 return mZoom.onScaleBegin(detector);
259 public void onScaleEnd(ScaleGestureDetector detector) {
260 mZoom.onScaleEnd(detector);