1/*
2 * Copyright (C) 2013 The Android Open Source Project
3 *
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
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
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.
15 */
16
17package com.android.camera.ui;
18
19import android.content.Context;
20import android.view.GestureDetector;
21import android.view.InputDevice;
22import android.view.KeyEvent;
23import android.view.MotionEvent;
24import android.view.ScaleGestureDetector;
25
26import com.android.camera.debug.Log;
27
28// This class aggregates two gesture detectors: GestureDetector,
29// ScaleGestureDetector.
30public class FilmstripGestureRecognizer {
31    @SuppressWarnings("unused")
32    private static final Log.Tag TAG = new Log.Tag("FStripGestureRecog");
33
34    public interface Listener {
35        boolean onSingleTapUp(float x, float y);
36        boolean onDoubleTap(float x, float y);
37        boolean onScroll(float x, float y, float dx, float dy);
38        boolean onMouseScroll(float hscroll, float vscroll);
39        boolean onFling(float velocityX, float velocityY);
40        boolean onScaleBegin(float focusX, float focusY);
41        boolean onScale(float focusX, float focusY, float scale);
42        boolean onDown(float x, float y);
43        boolean onUp(float x, float y);
44        void onLongPress(float x, float y);
45        void onScaleEnd();
46    }
47
48    private final GestureDetector mGestureDetector;
49    private final ScaleGestureDetector mScaleDetector;
50    private final Listener mListener;
51
52    public FilmstripGestureRecognizer(Context context, Listener listener) {
53        mListener = listener;
54        mGestureDetector = new GestureDetector(context, new MyGestureListener(),
55                null, true /* ignoreMultitouch */);
56        mGestureDetector.setOnDoubleTapListener(new MyDoubleTapListener());
57        mScaleDetector = new ScaleGestureDetector(
58                context, new MyScaleListener());
59    }
60
61    public boolean onTouchEvent(MotionEvent event) {
62        final boolean gestureProcessed = mGestureDetector.onTouchEvent(event);
63        final boolean scaleProcessed = mScaleDetector.onTouchEvent(event);
64        if (event.getAction() == MotionEvent.ACTION_UP) {
65            mListener.onUp(event.getX(), event.getY());
66        }
67        return (gestureProcessed | scaleProcessed);
68    }
69
70    public boolean onGenericMotionEvent(MotionEvent event) {
71        if ((event.getSource() & InputDevice.SOURCE_CLASS_POINTER) != 0) {
72            switch (event.getAction()) {
73                case MotionEvent.ACTION_SCROLL: {
74                    final float hscroll = event.getAxisValue(MotionEvent.AXIS_HSCROLL);
75                    final float vscroll = -event.getAxisValue(MotionEvent.AXIS_VSCROLL);
76
77                    if (hscroll != 0.0f || vscroll != 0.0f) {
78                        mListener.onMouseScroll(hscroll, vscroll);
79                    }
80                }
81            }
82        }
83
84        return true;
85    }
86
87    private class MyGestureListener
88                extends GestureDetector.SimpleOnGestureListener {
89        @Override
90        public void onLongPress(MotionEvent e) {
91            mListener.onLongPress(e.getX(), e.getY());
92        }
93
94        @Override
95        public boolean onScroll(
96                MotionEvent e1, MotionEvent e2, float dx, float dy) {
97            return mListener.onScroll(e2.getX(), e2.getY(), dx, dy);
98        }
99
100        @Override
101        public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
102                float velocityY) {
103            return mListener.onFling(velocityX, velocityY);
104        }
105
106        @Override
107        public boolean onDown(MotionEvent e) {
108            mListener.onDown(e.getX(), e.getY());
109            return super.onDown(e);
110        }
111    }
112
113    /**
114     * The listener that is used to notify when a double-tap or a confirmed
115     * single-tap occur.
116     */
117    private class MyDoubleTapListener implements GestureDetector.OnDoubleTapListener {
118
119        @Override
120        public boolean onSingleTapConfirmed(MotionEvent e) {
121            return mListener.onSingleTapUp(e.getX(), e.getY());
122        }
123
124        @Override
125        public boolean onDoubleTap(MotionEvent e) {
126            return mListener.onDoubleTap(e.getX(), e.getY());
127        }
128
129        @Override
130        public boolean onDoubleTapEvent(MotionEvent e) {
131            return true;
132        }
133    }
134
135    private class MyScaleListener
136            extends ScaleGestureDetector.SimpleOnScaleGestureListener {
137        @Override
138        public boolean onScaleBegin(ScaleGestureDetector detector) {
139            return mListener.onScaleBegin(
140                    detector.getFocusX(), detector.getFocusY());
141        }
142
143        @Override
144        public boolean onScale(ScaleGestureDetector detector) {
145            return mListener.onScale(detector.getFocusX(),
146                    detector.getFocusY(), detector.getScaleFactor());
147        }
148
149        @Override
150        public void onScaleEnd(ScaleGestureDetector detector) {
151            mListener.onScaleEnd();
152        }
153    }
154}
155