From 7f6f7737b5d71ab6720c093702a99f77ddc0db02 Mon Sep 17 00:00:00 2001 From: Doris Liu Date: Tue, 14 May 2013 14:37:46 -0700 Subject: Improve gesture handling Change-Id: Ib1e18274480b6bb681bd06f3130f9b9ea198ea98 --- src/com/android/camera/NewPreviewGestures.java | 246 +++++++------------------ 1 file changed, 71 insertions(+), 175 deletions(-) (limited to 'src/com') diff --git a/src/com/android/camera/NewPreviewGestures.java b/src/com/android/camera/NewPreviewGestures.java index 2718e55ae..39c4be664 100644 --- a/src/com/android/camera/NewPreviewGestures.java +++ b/src/com/android/camera/NewPreviewGestures.java @@ -19,11 +19,13 @@ package com.android.camera; 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 com.android.gallery3d.R; 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 @@ public class NewPreviewGestures 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 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 class NewPreviewGestures 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 @@ public class NewPreviewGestures 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 class NewPreviewGestures 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(); - } - 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 @@ public class NewPreviewGestures } 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 @@ public class NewPreviewGestures 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 @@ public class NewPreviewGestures } 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 @@ public class NewPreviewGestures @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); } } -- cgit v1.2.3