Improve gesture handling

Change-Id: Ib1e18274480b6bb681bd06f3130f9b9ea198ea98
diff --git a/res/layout-land/camera_controls.xml b/res/layout-land/camera_controls.xml
index 96f593a..432ae9e 100644
--- a/res/layout-land/camera_controls.xml
+++ b/res/layout-land/camera_controls.xml
@@ -21,6 +21,7 @@
 
         <View
             android:id="@+id/blocker"
+            android:clickable="true"
             android:layout_height="match_parent"
             android:layout_width="@dimen/switcher_size"
             android:layout_gravity="right" />
diff --git a/res/layout-port/camera_controls.xml b/res/layout-port/camera_controls.xml
index ebbdf26..7dd66e4 100644
--- a/res/layout-port/camera_controls.xml
+++ b/res/layout-port/camera_controls.xml
@@ -21,6 +21,7 @@
 
         <View
             android:id="@+id/blocker"
+            android:clickable="true"
             android:layout_width="match_parent"
             android:layout_height="@dimen/switcher_size"
             android:layout_gravity="bottom" />
diff --git a/src/com/android/camera/NewPhotoModule.java b/src/com/android/camera/NewPhotoModule.java
index 3cb9733..e5d922a 100644
--- a/src/com/android/camera/NewPhotoModule.java
+++ b/src/com/android/camera/NewPhotoModule.java
@@ -906,7 +906,6 @@
         switch (state) {
         case PhotoController.PREVIEW_STOPPED:
         case PhotoController.SNAPSHOT_IN_PROGRESS:
-        case PhotoController.FOCUSING:
         case PhotoController.SWITCHING_CAMERA:
             mUI.enableGestures(false);
             break;
diff --git a/src/com/android/camera/NewPhotoUI.java b/src/com/android/camera/NewPhotoUI.java
index 1a14cf5..caf3d5a 100644
--- a/src/com/android/camera/NewPhotoUI.java
+++ b/src/com/android/camera/NewPhotoUI.java
@@ -61,11 +61,9 @@
 
 public class NewPhotoUI implements PieListener,
     NewPreviewGestures.SingleTapListener,
-    NewPreviewGestures.CancelEventListener,
     FocusUI, TextureView.SurfaceTextureListener,
     LocationManager.Listener,
-    FaceDetectionListener,
-    NewPreviewGestures.SwipeListener {
+    FaceDetectionListener {
 
     private static final String TAG = "CAM_UI";
     private static final int UPDATE_TRANSFORM_MATRIX = 1;
@@ -290,23 +288,10 @@
 
         if (mGestures == null) {
             // this will handle gesture disambiguation and dispatching
-            mGestures = new NewPreviewGestures(mActivity, this, mZoomRenderer, mPieRenderer,
-                    this);
-            mGestures.setCancelEventListener(this);
+            mGestures = new NewPreviewGestures(mActivity, this, mZoomRenderer, mPieRenderer);
+            mRenderOverlay.setGestures(mGestures);
         }
-        mGestures.clearTouchReceivers();
         mGestures.setRenderOverlay(mRenderOverlay);
-        mGestures.addTouchReceiver(mMenuButton);
-        mGestures.addTouchReceiver(mBlocker);
-        // make sure to add touch targets for image capture
-        if (mController.isImageCaptureIntent()) {
-            if (mReviewCancelButton != null) {
-                mGestures.addTouchReceiver(mReviewCancelButton);
-            }
-            if (mReviewDoneButton != null) {
-                mGestures.addTouchReceiver(mReviewDoneButton);
-            }
-        }
         mRenderOverlay.requestLayout();
 
         initializeZoom(params);
@@ -468,11 +453,6 @@
         return true;
     }
 
-    @Override
-    public void onTouchEventCancelled(MotionEvent cancelEvent) {
-        mRootView.dispatchTouchEvent(cancelEvent);
-    }
-
     public void enableGestures(boolean enable) {
         if (mGestures != null) {
             mGestures.setEnabled(enable);
@@ -797,10 +777,4 @@
         mFaceView.setFaces(faces);
     }
 
-    @Override
-    public void onSwipe(int direction) {
-        if (direction == PreviewGestures.DIR_UP) {
-            openMenu();
-        }
-    }
 }
diff --git a/src/com/android/camera/NewPreviewGestures.java b/src/com/android/camera/NewPreviewGestures.java
index 2718e55..39c4be6 100644
--- a/src/com/android/camera/NewPreviewGestures.java
+++ b/src/com/android/camera/NewPreviewGestures.java
@@ -19,11 +19,13 @@
 import android.os.Handler;
 import android.os.Message;
 import android.util.Log;
+import android.view.GestureDetector;
 import android.view.MotionEvent;
 import android.view.ScaleGestureDetector;
 import android.view.View;
 import android.view.ViewConfiguration;
 
+import com.android.camera.PreviewGestures.SingleTapListener;
 import com.android.camera.PreviewGestures.SwipeListener;
 import com.android.camera.ui.PieRenderer;
 import com.android.camera.ui.RenderOverlay;
@@ -33,6 +35,10 @@
 import java.util.ArrayList;
 import java.util.List;
 
+/* NewPreviewGestures disambiguates touch events received on RenderOverlay
+ * and dispatch them to the proper recipient (i.e. zoom renderer or pie renderer).
+ * Touch events on CameraControls will be handled by framework.
+ * */
 public class NewPreviewGestures
         implements ScaleGestureDetector.OnScaleGestureListener {
 
@@ -54,29 +60,60 @@
 
     private NewCameraActivity mActivity;
     private SingleTapListener mTapListener;
-    private CancelEventListener mCancelEventListener;
     private RenderOverlay mOverlay;
     private PieRenderer mPie;
     private ZoomRenderer mZoom;
     private MotionEvent mDown;
     private MotionEvent mCurrent;
     private ScaleGestureDetector mScale;
-    private List<View> mReceivers;
     private int mMode;
     private int mSlop;
     private int mTapTimeout;
     private boolean mEnabled;
     private boolean mZoomOnly;
     private int mOrientation;
-    private int[] mLocation;
-    private SwipeListener mSwipeListener;
+    private GestureDetector mGestureDetector;
+
+    private GestureDetector.SimpleOnGestureListener mGestureListener = new GestureDetector.SimpleOnGestureListener() {
+        @Override
+        public void onLongPress (MotionEvent e) {
+            // Open pie
+            if (mPie != null && !mPie.showsItems()) {
+                openPie();
+            }
+        }
+
+        @Override
+        public boolean onSingleTapUp (MotionEvent e) {
+            // Tap to focus when pie is not open
+            if (mPie == null || !mPie.showsItems()) {
+                mTapListener.onSingleTapUp(null, (int) e.getX(), (int) e.getY());
+                return true;
+            }
+            return false;
+        }
+
+        @Override
+        public boolean onScroll (MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
+            if (mMode == MODE_ZOOM) return false;
+            int deltaX = (int) (e1.getX() - e2.getX());
+            int deltaY = (int) (e1.getY() - e2.getY());
+            if (deltaY > 2 * deltaX && deltaY > -2 * deltaX) {
+                // Open pie on swipe up
+                if (mPie != null && !mPie.showsItems()) {
+                    openPie();
+                    return true;
+                }
+            }
+            return false;
+        }
+    };
 
     private Handler mHandler = new Handler() {
         public void handleMessage(Message msg) {
             if (msg.what == MSG_PIE) {
                 mMode = MODE_PIE;
                 openPie();
-                cancelActivityTouchHandling(mDown);
             }
         }
     };
@@ -85,16 +122,8 @@
         public void onSingleTapUp(View v, int x, int y);
     }
 
-    public interface CancelEventListener {
-        public void onTouchEventCancelled(MotionEvent cancelEvent);
-    }
-
-    interface SwipeListener {
-        public void onSwipe(int direction);
-    }
-
     public NewPreviewGestures(NewCameraActivity ctx, SingleTapListener tapListener,
-            ZoomRenderer zoom, PieRenderer pie, SwipeListener swipe) {
+            ZoomRenderer zoom, PieRenderer pie) {
         mActivity = ctx;
         mTapListener = tapListener;
         mPie = pie;
@@ -104,12 +133,7 @@
         mSlop = (int) ctx.getResources().getDimension(R.dimen.pie_touch_slop);
         mTapTimeout = ViewConfiguration.getTapTimeout();
         mEnabled = true;
-        mLocation = new int[2];
-        mSwipeListener = swipe;
-    }
-
-    public void setCancelEventListener(CancelEventListener listener) {
-        mCancelEventListener = listener;
+        mGestureDetector = new GestureDetector(mGestureListener);
     }
 
     public void setRenderOverlay(RenderOverlay overlay) {
@@ -122,26 +146,14 @@
 
     public void setEnabled(boolean enabled) {
         mEnabled = enabled;
-        if (!enabled) {
-            cancelPie();
-        }
     }
 
     public void setZoomOnly(boolean zoom) {
         mZoomOnly = zoom;
     }
 
-    public void addTouchReceiver(View v) {
-        if (mReceivers == null) {
-            mReceivers = new ArrayList<View>();
-        }
-        mReceivers.add(v);
-    }
-
-    public void clearTouchReceivers() {
-        if (mReceivers != null) {
-            mReceivers.clear();
-        }
+    public boolean isEnabled() {
+        return mEnabled;
     }
 
     public boolean dispatchTouch(MotionEvent m) {
@@ -150,121 +162,28 @@
         }
         mCurrent = m;
         if (MotionEvent.ACTION_DOWN == m.getActionMasked()) {
-            if (checkReceivers(m)) {
-                mMode = MODE_MODULE;
-                return false;
-            } else {
-                mMode = MODE_ALL;
-                mDown = MotionEvent.obtain(m);
-                if (mPie != null && mPie.showsItems()) {
-                    mMode = MODE_PIE;
-                    return sendToPie(m);
-                }
-                if (mPie != null && !mZoomOnly) {
-                    mHandler.sendEmptyMessageDelayed(MSG_PIE, TIMEOUT_PIE);
-                }
-                if (mZoom != null) {
-                    mScale.onTouchEvent(m);
-                }
-                // make sure this is ok
-                return false;
-            }
-        } else if (mMode == MODE_NONE) {
-            return false;
-        } else if (mMode == MODE_SWIPE) {
-            if (MotionEvent.ACTION_UP == m.getActionMasked()) {
-                mSwipeListener.onSwipe(getSwipeDirection(m));
-            }
-            return true;
-        } else if (mMode == MODE_PIE) {
-            if (MotionEvent.ACTION_POINTER_DOWN == m.getActionMasked()) {
-                sendToPie(makeCancelEvent(m));
-                if (mZoom != null) {
-                    onScaleBegin(mScale);
-                }
-            } else {
-                return sendToPie(m);
-            }
-            return true;
-        } else if (mMode == MODE_ZOOM) {
-            mScale.onTouchEvent(m);
-            if (!mScale.isInProgress() && MotionEvent.ACTION_POINTER_UP == m.getActionMasked()) {
-                mMode = MODE_NONE;
-                onScaleEnd(mScale);
-            }
-            return true;
-        } else if (mMode == MODE_MODULE) {
-            return false;
-        } else {
-            // didn't receive down event previously;
-            // assume module wasn't initialzed and ignore this event.
-            if (mDown == null) {
-                return true;
-            }
-            if (MotionEvent.ACTION_POINTER_DOWN == m.getActionMasked()) {
-                if (!mZoomOnly) {
-                    cancelPie();
-                    sendToPie(makeCancelEvent(m));
-                }
-                if (mZoom != null) {
-                    mScale.onTouchEvent(m);
-                    onScaleBegin(mScale);
-                }
-            } else if ((mMode == MODE_ZOOM) && !mScale.isInProgress()
-                    && MotionEvent.ACTION_POINTER_UP == m.getActionMasked()) {
-                // user initiated and stopped zoom gesture without zooming
-                mScale.onTouchEvent(m);
-                onScaleEnd(mScale);
-            }
-            // not zoom or pie mode and no timeout yet
-            if (mZoom != null) {
-                boolean res = mScale.onTouchEvent(m);
-                if (mScale.isInProgress()) {
-                    cancelPie();
-                    cancelActivityTouchHandling(m);
-                    return res;
-                }
-            }
-            if (MotionEvent.ACTION_UP == m.getActionMasked()) {
-                cancelPie();
-                cancelActivityTouchHandling(m);
-                // must have been tap
-                if (m.getEventTime() - mDown.getEventTime() < mTapTimeout) {
-                    mTapListener.onSingleTapUp(null,
-                            (int) mDown.getX() - mOverlay.getWindowPositionX(),
-                            (int) mDown.getY() - mOverlay.getWindowPositionY());
-                    return true;
-                } else {
-                    return false;
-                }
-            } else if (MotionEvent.ACTION_MOVE == m.getActionMasked()) {
-                if ((Math.abs(m.getX() - mDown.getX()) > mSlop)
-                        || Math.abs(m.getY() - mDown.getY()) > mSlop) {
-                    // moved too far and no timeout yet, no focus or pie
-                    cancelPie();
-                    int dir = getSwipeDirection(m);
-                    if (dir == DIR_LEFT) {
-                        mMode = MODE_MODULE;
-                        return false;
-                    } else {
-                        cancelActivityTouchHandling(m);
-                        mMode = MODE_NONE;
-                    }
-                }
-            }
-            return false;
+            mMode = MODE_NONE;
+            mDown = MotionEvent.obtain(m);
         }
-    }
 
-    private boolean checkReceivers(MotionEvent m) {
-        if (mReceivers != null) {
-            for (View receiver : mReceivers) {
-                if (isInside(m, receiver)) {
-                    return true;
-                }
+        // If pie is open, redirects all the touch events to pie.
+        if (mPie != null && mPie.isOpen()) {
+            return sendToPie(m);
+        }
+
+        // If pie is not open, send touch events to gesture detector and scale
+        // listener to recognize the gesture.
+        mGestureDetector.onTouchEvent(m);
+        if (mZoom != null) {
+            mScale.onTouchEvent(m);
+            if (MotionEvent.ACTION_POINTER_DOWN == m.getActionMasked()) {
+                mMode = MODE_ZOOM;
+                mZoom.onScaleBegin(mScale);
+            } else if (MotionEvent.ACTION_POINTER_UP == m.getActionMasked()) {
+                mZoom.onScaleEnd(mScale);
             }
         }
-        return false;
+        return true;
     }
 
     // left tests for finger moving right to left
@@ -295,19 +214,6 @@
         return DIR_UP;
     }
 
-    private boolean isInside(MotionEvent evt, View v) {
-        v.getLocationInWindow(mLocation);
-        return (v.getVisibility() == View.VISIBLE
-                && evt.getX() >= mLocation[0] && evt.getX() < mLocation[0] + v.getWidth()
-                && evt.getY() >= mLocation[1] && evt.getY() < mLocation[1] + v.getHeight());
-    }
-
-    public void cancelActivityTouchHandling(MotionEvent m) {
-        if (mCancelEventListener != null) {
-            mCancelEventListener.onTouchEventCancelled(makeCancelEvent(m));
-        }
-    }
-
     private MotionEvent makeCancelEvent(MotionEvent m) {
         MotionEvent c = MotionEvent.obtain(m);
         c.setAction(MotionEvent.ACTION_CANCEL);
@@ -315,21 +221,16 @@
     }
 
     private void openPie() {
-        mDown.offsetLocation(-mOverlay.getWindowPositionX(),
-                -mOverlay.getWindowPositionY());
+        mGestureDetector.onTouchEvent(makeCancelEvent(mDown));
+        mScale.onTouchEvent(makeCancelEvent(mDown));
         mOverlay.directDispatchTouch(mDown, mPie);
     }
 
-    private void cancelPie() {
-        mHandler.removeMessages(MSG_PIE);
-    }
-
     private boolean sendToPie(MotionEvent m) {
-        m.offsetLocation(-mOverlay.getWindowPositionX(),
-                -mOverlay.getWindowPositionY());
         return mOverlay.directDispatchTouch(m, mPie);
     }
 
+    // OnScaleGestureListener implementation
     @Override
     public boolean onScale(ScaleGestureDetector detector) {
         return mZoom.onScale(detector);
@@ -337,22 +238,17 @@
 
     @Override
     public boolean onScaleBegin(ScaleGestureDetector detector) {
-        if (mMode != MODE_ZOOM) {
+        if (mPie == null || !mPie.isOpen()) {
             mMode = MODE_ZOOM;
-            cancelActivityTouchHandling(mCurrent);
-        }
-        if (mCurrent.getActionMasked() != MotionEvent.ACTION_MOVE) {
+            mGestureDetector.onTouchEvent(makeCancelEvent(mCurrent));
             return mZoom.onScaleBegin(detector);
-        } else {
-            return true;
         }
+        return false;
     }
 
     @Override
     public void onScaleEnd(ScaleGestureDetector detector) {
-        if (mCurrent.getActionMasked() != MotionEvent.ACTION_MOVE) {
-            mZoom.onScaleEnd(detector);
-        }
+        mZoom.onScaleEnd(detector);
     }
 }
 
diff --git a/src/com/android/camera/NewVideoUI.java b/src/com/android/camera/NewVideoUI.java
index a14dae3..71ab669 100644
--- a/src/com/android/camera/NewVideoUI.java
+++ b/src/com/android/camera/NewVideoUI.java
@@ -55,8 +55,7 @@
 
 public class NewVideoUI implements PieRenderer.PieListener,
         NewPreviewGestures.SingleTapListener,
-        NewPreviewGestures.SwipeListener, SurfaceTextureListener,
-        SurfaceHolder.Callback {
+        SurfaceTextureListener, SurfaceHolder.Callback {
     private final static String TAG = "CAM_VideoUI";
     private static final int UPDATE_TRANSFORM_MATRIX = 1;
     // module fields
@@ -359,23 +358,10 @@
         }
         mRenderOverlay.addRenderer(mZoomRenderer);
         if (mGestures == null) {
-            mGestures = new NewPreviewGestures(mActivity, this, mZoomRenderer, mPieRenderer, this);
+            mGestures = new NewPreviewGestures(mActivity, this, mZoomRenderer, mPieRenderer);
+            mRenderOverlay.setGestures(mGestures);
         }
         mGestures.setRenderOverlay(mRenderOverlay);
-        mGestures.clearTouchReceivers();
-        mGestures.addTouchReceiver(mMenuButton);
-        mGestures.addTouchReceiver(mBlocker);
-        if (mController.isVideoCaptureIntent()) {
-            if (mReviewCancelButton != null) {
-                mGestures.addTouchReceiver(mReviewCancelButton);
-            }
-            if (mReviewDoneButton != null) {
-                mGestures.addTouchReceiver(mReviewDoneButton);
-            }
-            if (mReviewPlayButton != null) {
-                mGestures.addTouchReceiver(mReviewPlayButton);
-            }
-        }
     }
 
     public void setPrefChangedListener(OnPreferenceChangedListener listener) {
@@ -660,13 +646,6 @@
         }
     }
 
-    @Override
-    public void onSwipe(int direction) {
-        if (direction == PreviewGestures.DIR_UP) {
-            openMenu();
-        }
-    }
-
     public SurfaceTexture getSurfaceTexture() {
         synchronized (mLock) {
             if (mSurfaceTexture == null) {
diff --git a/src/com/android/camera/ui/FilmStripView.java b/src/com/android/camera/ui/FilmStripView.java
index 286d6e3..f6b7589 100644
--- a/src/com/android/camera/ui/FilmStripView.java
+++ b/src/com/android/camera/ui/FilmStripView.java
@@ -16,6 +16,8 @@
 
 package com.android.camera.ui;
 
+import com.android.gallery3d.R;
+
 import android.animation.Animator;
 import android.animation.TimeInterpolator;
 import android.animation.ValueAnimator;
@@ -41,6 +43,8 @@
     private static final int DURATION_GEOMETRY_ADJUST = 200;
     private static final float FILM_STRIP_SCALE = 0.6f;
     private static final float MAX_SCALE = 1f;
+    // Only check for intercepting touch events within first 500ms
+    private static final int SWIPE_TIME_OUT = 500;
 
     private Context mContext;
     private FilmStripGestureRecognizer mGestureRecognizer;
@@ -56,9 +60,11 @@
 
     private Listener mListener;
 
+    private MotionEvent mDown;
+    private boolean mCheckToIntercept = true;
     private View mCameraView;
     private ImageData mCameraData;
-
+    private int mSlop;
     private TimeInterpolator mViewAnimInterpolator;
 
     // This is used to resolve the misalignment problem when the device
@@ -253,6 +259,7 @@
         mViewAnimInterpolator = new LinearInterpolator();
         mGestureRecognizer =
                 new FilmStripGestureRecognizer(context, new MyGestureReceiver());
+        mSlop = (int) getContext().getResources().getDimension(R.dimen.pie_touch_slop);
     }
 
     public Controller getController() {
@@ -750,8 +757,28 @@
 
     @Override
     public boolean onInterceptTouchEvent(MotionEvent ev) {
-        if (isInCameraFullscreen()) return false;
-        return true;
+        if (ev.getActionMasked() == MotionEvent.ACTION_DOWN) {
+            mCheckToIntercept = true;
+            mDown = MotionEvent.obtain(ev);
+            return false;
+        } else if (ev.getActionMasked() == MotionEvent.ACTION_POINTER_DOWN) {
+            // Do not intercept touch once child is in zoom mode
+            mCheckToIntercept = false;
+            return false;
+        } else {
+            if (!mCheckToIntercept) return false;
+            if (ev.getEventTime() - ev.getDownTime() > SWIPE_TIME_OUT) return false;
+            int deltaX = (int) (ev.getX() - mDown.getX());
+            int deltaY = (int) (ev.getY() - mDown.getY());
+            if (ev.getActionMasked() == MotionEvent.ACTION_MOVE
+                    && deltaX < mSlop * (-1)) {
+                // intercept left swipe
+                if (Math.abs(deltaX) >= Math.abs(deltaY) * 2) {
+                    return true;
+                }
+            }
+        }
+        return false;
     }
 
     @Override
diff --git a/src/com/android/camera/ui/NewCameraRootView.java b/src/com/android/camera/ui/NewCameraRootView.java
index a50e41a..abb77b8 100644
--- a/src/com/android/camera/ui/NewCameraRootView.java
+++ b/src/com/android/camera/ui/NewCameraRootView.java
@@ -23,6 +23,7 @@
 import android.os.Debug;
 import android.util.AttributeSet;
 import android.view.Gravity;
+import android.view.MotionEvent;
 import android.view.View;
 import android.widget.FrameLayout;
 
@@ -131,4 +132,15 @@
             }
         }
     }
+
+    @Override
+    public boolean dispatchTouchEvent(MotionEvent ev) {
+        //TODO: This scale check is temporary, should be removed once full screen notification
+        // is implemented
+        if (((View) getParent()).getScaleX() == 1.0f) {
+            return super.dispatchTouchEvent(ev);
+        } else {
+            return false;
+        }
+    }
 }
diff --git a/src/com/android/camera/ui/PieMenuButton.java b/src/com/android/camera/ui/PieMenuButton.java
index e571931..0e23226 100644
--- a/src/com/android/camera/ui/PieMenuButton.java
+++ b/src/com/android/camera/ui/PieMenuButton.java
@@ -36,6 +36,7 @@
 
     @Override
     public boolean onTouchEvent(MotionEvent event) {
+        boolean handled = super.onTouchEvent(event);
         if (MotionEvent.ACTION_UP == event.getAction() && mPressed) {
             // Perform a customized click as soon as the ACTION_UP event
             // is received. The reason for doing this is that Framework
@@ -45,7 +46,7 @@
             mReadyToClick = true;
             performClick();
         }
-        return super.onTouchEvent(event);
+        return handled;
     }
 
     @Override
diff --git a/src/com/android/camera/ui/PieRenderer.java b/src/com/android/camera/ui/PieRenderer.java
index edae2be..834dc4b 100644
--- a/src/com/android/camera/ui/PieRenderer.java
+++ b/src/com/android/camera/ui/PieRenderer.java
@@ -303,6 +303,10 @@
         mHandler.sendEmptyMessage(show ? MSG_OPEN : MSG_CLOSE);
     }
 
+    public boolean isOpen() {
+        return mState == STATE_PIE && isVisible();
+    }
+
     private void fadeIn() {
         mFadeIn = new LinearAnimation(0, 1);
         mFadeIn.setDuration(PIE_FADE_IN_DURATION);
diff --git a/src/com/android/camera/ui/RenderOverlay.java b/src/com/android/camera/ui/RenderOverlay.java
index ba25915..0bda10a 100644
--- a/src/com/android/camera/ui/RenderOverlay.java
+++ b/src/com/android/camera/ui/RenderOverlay.java
@@ -23,6 +23,8 @@
 import android.view.View;
 import android.widget.FrameLayout;
 
+import com.android.camera.NewPreviewGestures;
+
 import java.util.ArrayList;
 import java.util.List;
 
@@ -42,7 +44,7 @@
 
     private RenderView mRenderView;
     private List<Renderer> mClients;
-
+    private NewPreviewGestures mGestures;
     // reverse list of touch clients
     private List<Renderer> mTouchClients;
     private int[] mPosition = new int[2];
@@ -57,6 +59,10 @@
         setWillNotDraw(false);
     }
 
+    public void setGestures(NewPreviewGestures gestures) {
+        mGestures = gestures;
+    }
+
     public void addRenderer(Renderer renderer) {
         mClients.add(renderer);
         renderer.setOverlay(this);
@@ -83,12 +89,13 @@
 
     @Override
     public boolean dispatchTouchEvent(MotionEvent m) {
-        return false;
+        if (mGestures != null) mGestures.dispatchTouch(m);
+        return true;
     }
 
     public boolean directDispatchTouch(MotionEvent m, Renderer target) {
         mRenderView.setTouchTarget(target);
-        boolean res = super.dispatchTouchEvent(m);
+        boolean res = mRenderView.dispatchTouchEvent(m);
         mRenderView.setTouchTarget(null);
         return res;
     }
@@ -123,7 +130,8 @@
         }
 
         @Override
-        public boolean onTouchEvent(MotionEvent evt) {
+        public boolean dispatchTouchEvent(MotionEvent evt) {
+
             if (mTouchTarget != null) {
                 return mTouchTarget.onTouchEvent(evt);
             }