13a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang/*
23a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang * Copyright (C) 2012 The Android Open Source Project
33a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang *
43a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang * Licensed under the Apache License, Version 2.0 (the "License");
53a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang * you may not use this file except in compliance with the License.
63a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang * You may obtain a copy of the License at
73a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang *
83a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang *      http://www.apache.org/licenses/LICENSE-2.0
93a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang *
103a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang * Unless required by applicable law or agreed to in writing, software
113a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang * distributed under the License is distributed on an "AS IS" BASIS,
123a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
133a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang * See the License for the specific language governing permissions and
143a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang * limitations under the License.
153a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang */
163a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang
173a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Changpackage com.android.gallery3d.ui;
183a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang
193a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Changimport android.content.Context;
20534b12fd804610dd67b8109bc08ba76f31afb33eChih-Chung Changimport android.os.SystemClock;
213a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Changimport android.view.GestureDetector;
223a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Changimport android.view.MotionEvent;
233a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Changimport android.view.ScaleGestureDetector;
243a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang
253a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang// This class aggregates three gesture detectors: GestureDetector,
263a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang// ScaleGestureDetector, and DownUpDetector.
273a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Changpublic class GestureRecognizer {
287817979db0c52ffeacb951625b1e821eba303285Ahbong Chang    @SuppressWarnings("unused")
293a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang    private static final String TAG = "GestureRecognizer";
303a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang
313a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang    public interface Listener {
323a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang        boolean onSingleTapUp(float x, float y);
333a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang        boolean onDoubleTap(float x, float y);
346b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang        boolean onScroll(float dx, float dy, float totalX, float totalY);
35137c6d060f9710f1a460326f27459e89b49820c2Bobby Georgescu        boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY);
363a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang        boolean onScaleBegin(float focusX, float focusY);
373a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang        boolean onScale(float focusX, float focusY, float scale);
383a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang        void onScaleEnd();
396b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang        void onDown(float x, float y);
403a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang        void onUp();
413a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang    }
423a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang
433a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang    private final GestureDetector mGestureDetector;
443a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang    private final ScaleGestureDetector mScaleDetector;
453a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang    private final DownUpDetector mDownUpDetector;
463a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang    private final Listener mListener;
473a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang
483a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang    public GestureRecognizer(Context context, Listener listener) {
493a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang        mListener = listener;
503a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang        mGestureDetector = new GestureDetector(context, new MyGestureListener(),
513a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang                null, true /* ignoreMultitouch */);
523a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang        mScaleDetector = new ScaleGestureDetector(
533a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang                context, new MyScaleListener());
543a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang        mDownUpDetector = new DownUpDetector(new MyDownUpListener());
553a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang    }
563a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang
573a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang    public void onTouchEvent(MotionEvent event) {
583a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang        mGestureDetector.onTouchEvent(event);
593a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang        mScaleDetector.onTouchEvent(event);
603a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang        mDownUpDetector.onTouchEvent(event);
613a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang    }
623a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang
633a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang    public boolean isDown() {
643a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang        return mDownUpDetector.isDown();
653a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang    }
663a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang
67534b12fd804610dd67b8109bc08ba76f31afb33eChih-Chung Chang    public void cancelScale() {
68534b12fd804610dd67b8109bc08ba76f31afb33eChih-Chung Chang        long now = SystemClock.uptimeMillis();
69534b12fd804610dd67b8109bc08ba76f31afb33eChih-Chung Chang        MotionEvent cancelEvent = MotionEvent.obtain(
70534b12fd804610dd67b8109bc08ba76f31afb33eChih-Chung Chang                now, now, MotionEvent.ACTION_CANCEL, 0, 0, 0);
71534b12fd804610dd67b8109bc08ba76f31afb33eChih-Chung Chang        mScaleDetector.onTouchEvent(cancelEvent);
72534b12fd804610dd67b8109bc08ba76f31afb33eChih-Chung Chang        cancelEvent.recycle();
73534b12fd804610dd67b8109bc08ba76f31afb33eChih-Chung Chang    }
74534b12fd804610dd67b8109bc08ba76f31afb33eChih-Chung Chang
753a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang    private class MyGestureListener
763a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang                extends GestureDetector.SimpleOnGestureListener {
773a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang        @Override
783a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang        public boolean onSingleTapUp(MotionEvent e) {
793a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang            return mListener.onSingleTapUp(e.getX(), e.getY());
803a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang        }
813a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang
823a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang        @Override
833a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang        public boolean onDoubleTap(MotionEvent e) {
843a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang            return mListener.onDoubleTap(e.getX(), e.getY());
853a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang        }
863a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang
873a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang        @Override
883a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang        public boolean onScroll(
893a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang                MotionEvent e1, MotionEvent e2, float dx, float dy) {
906b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang            return mListener.onScroll(
916b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang                    dx, dy, e2.getX() - e1.getX(), e2.getY() - e1.getY());
923a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang        }
933a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang
943a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang        @Override
953a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang        public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
963a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang                float velocityY) {
97137c6d060f9710f1a460326f27459e89b49820c2Bobby Georgescu            return mListener.onFling(e1, e2, velocityX, velocityY);
983a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang        }
993a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang    }
1003a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang
1013a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang    private class MyScaleListener
1023a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang            extends ScaleGestureDetector.SimpleOnScaleGestureListener {
1033a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang        @Override
1043a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang        public boolean onScaleBegin(ScaleGestureDetector detector) {
1053a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang            return mListener.onScaleBegin(
1063a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang                    detector.getFocusX(), detector.getFocusY());
1073a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang        }
1083a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang
1093a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang        @Override
1103a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang        public boolean onScale(ScaleGestureDetector detector) {
1113a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang            return mListener.onScale(detector.getFocusX(),
1123a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang                    detector.getFocusY(), detector.getScaleFactor());
1133a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang        }
1143a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang
1153a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang        @Override
1163a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang        public void onScaleEnd(ScaleGestureDetector detector) {
1173a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang            mListener.onScaleEnd();
1183a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang        }
1193a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang    }
1203a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang
1213a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang    private class MyDownUpListener implements DownUpDetector.DownUpListener {
1223a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang        @Override
1233a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang        public void onDown(MotionEvent e) {
1246b891c6a3739f8c49d42f9db6fc76cb92c7c5f25Chih-Chung Chang            mListener.onDown(e.getX(), e.getY());
1253a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang        }
1263a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang
1273a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang        @Override
1283a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang        public void onUp(MotionEvent e) {
1293a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang            mListener.onUp();
1303a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang        }
1313a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang    }
1323a02809c97669a157cf45bfd61d45272110d4091Chih-Chung Chang}
133