2 * Copyright (C) 2013 The Android Open Source Project
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 package com.android.camera;
19 import android.view.GestureDetector;
20 import android.view.MotionEvent;
21 import android.view.ScaleGestureDetector;
22 import android.view.View;
24 import com.android.camera.debug.Log;
25 import com.android.camera.ui.PieRenderer;
26 import com.android.camera.ui.RenderOverlay;
27 import com.android.camera.ui.ZoomRenderer;
29 /* PreviewGestures disambiguates touch events received on RenderOverlay
30 * and dispatch them to the proper recipient (i.e. zoom renderer or pie renderer).
31 * Touch events on CameraControls will be handled by framework.
33 public class PreviewGestures
34 implements ScaleGestureDetector.OnScaleGestureListener {
36 private static final Log.Tag TAG = new Log.Tag("PreviewGestures");
38 private static final int MODE_NONE = 0;
39 private static final int MODE_ZOOM = 2;
41 public static final int DIR_UP = 0;
42 public static final int DIR_DOWN = 1;
43 public static final int DIR_LEFT = 2;
44 public static final int DIR_RIGHT = 3;
46 private final SingleTapListener mTapListener;
47 private RenderOverlay mOverlay;
48 private final PieRenderer mPie;
49 private final ZoomRenderer mZoom;
50 private MotionEvent mDown;
51 private MotionEvent mCurrent;
52 private final ScaleGestureDetector mScale;
54 private boolean mZoomEnabled;
55 private boolean mEnabled;
56 private boolean mZoomOnly;
57 private final GestureDetector mGestureDetector;
59 private final GestureDetector.SimpleOnGestureListener mGestureListener = new GestureDetector.SimpleOnGestureListener() {
61 public void onLongPress (MotionEvent e) {
63 if (!mZoomOnly && mPie != null && !mPie.showsItems()) {
69 public boolean onSingleTapUp (MotionEvent e) {
70 // Tap to focus when pie is not open
71 if (mPie == null || !mPie.showsItems()) {
72 mTapListener.onSingleTapUp(null, (int) e.getX(), (int) e.getY());
79 public boolean onScroll (MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
81 // e1 can be null if for some cases.
84 if (mZoomOnly || mMode == MODE_ZOOM) return false;
85 int deltaX = (int) (e1.getX() - e2.getX());
86 int deltaY = (int) (e1.getY() - e2.getY());
87 if (deltaY > 2 * deltaX && deltaY > -2 * deltaX) {
88 // Open pie on swipe up
89 if (mPie != null && !mPie.showsItems()) {
98 public interface SingleTapListener {
99 public void onSingleTapUp(View v, int x, int y);
102 public PreviewGestures(CameraActivity ctx, SingleTapListener tapListener,
103 ZoomRenderer zoom, PieRenderer pie) {
104 mTapListener = tapListener;
108 mScale = new ScaleGestureDetector(ctx, this);
110 mGestureDetector = new GestureDetector(mGestureListener);
113 public void setRenderOverlay(RenderOverlay overlay) {
117 public void setEnabled(boolean enabled) {
121 public void setZoomEnabled(boolean enable) {
122 mZoomEnabled = enable;
125 public void setZoomOnly(boolean zoom) {
129 public boolean isEnabled() {
133 public boolean dispatchTouch(MotionEvent m) {
138 if (MotionEvent.ACTION_DOWN == m.getActionMasked()) {
140 mDown = MotionEvent.obtain(m);
143 // If pie is open, redirects all the touch events to pie.
144 if (mPie != null && mPie.isOpen()) {
148 // If pie is not open, send touch events to gesture detector and scale
149 // listener to recognize the gesture.
150 mGestureDetector.onTouchEvent(m);
152 mScale.onTouchEvent(m);
153 if (MotionEvent.ACTION_POINTER_DOWN == m.getActionMasked()) {
156 // Start showing zoom UI as soon as there is a second finger down
157 mZoom.onScaleBegin(mScale);
159 } else if (MotionEvent.ACTION_POINTER_UP == m.getActionMasked()) {
160 mZoom.onScaleEnd(mScale);
166 private MotionEvent makeCancelEvent(MotionEvent m) {
167 MotionEvent c = MotionEvent.obtain(m);
168 c.setAction(MotionEvent.ACTION_CANCEL);
172 private void openPie() {
173 mGestureDetector.onTouchEvent(makeCancelEvent(mDown));
174 mScale.onTouchEvent(makeCancelEvent(mDown));
175 mOverlay.directDispatchTouch(mDown, mPie);
178 private boolean sendToPie(MotionEvent m) {
179 return mOverlay.directDispatchTouch(m, mPie);
182 // OnScaleGestureListener implementation
184 public boolean onScale(ScaleGestureDetector detector) {
185 return mZoom.onScale(detector);
189 public boolean onScaleBegin(ScaleGestureDetector detector) {
190 if (mPie == null || !mPie.isOpen()) {
192 mGestureDetector.onTouchEvent(makeCancelEvent(mCurrent));
193 if (!mZoomEnabled) return false;
194 return mZoom.onScaleBegin(detector);
200 public void onScaleEnd(ScaleGestureDetector detector) {
201 mZoom.onScaleEnd(detector);