1 /*
2  * Copyright 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 
17 #include "gestureDetector.h"
18 
19 //--------------------------------------------------------------------------------
20 // gestureDetector.cpp
21 //--------------------------------------------------------------------------------
22 namespace ndk_helper
23 {
24 
25 //--------------------------------------------------------------------------------
26 // includes
27 //--------------------------------------------------------------------------------
28 
29 //--------------------------------------------------------------------------------
30 // GestureDetector
31 //--------------------------------------------------------------------------------
GestureDetector()32 GestureDetector::GestureDetector()
33 {
34     dp_factor_ = 1.f;
35 }
36 
SetConfiguration(AConfiguration * config)37 void GestureDetector::SetConfiguration( AConfiguration* config )
38 {
39     dp_factor_ = 160.f / AConfiguration_getDensity( config );
40 }
41 
42 //--------------------------------------------------------------------------------
43 // TapDetector
44 //--------------------------------------------------------------------------------
Detect(const AInputEvent * motion_event)45 GESTURE_STATE TapDetector::Detect( const AInputEvent* motion_event )
46 {
47     if( AMotionEvent_getPointerCount( motion_event ) > 1 )
48     {
49         //Only support single touch
50         return false;
51     }
52 
53     int32_t action = AMotionEvent_getAction( motion_event );
54     unsigned int flags = action & AMOTION_EVENT_ACTION_MASK;
55     switch( flags )
56     {
57     case AMOTION_EVENT_ACTION_DOWN:
58         down_pointer_id_ = AMotionEvent_getPointerId( motion_event, 0 );
59         down_x_ = AMotionEvent_getX( motion_event, 0 );
60         down_y_ = AMotionEvent_getY( motion_event, 0 );
61         break;
62     case AMOTION_EVENT_ACTION_UP:
63     {
64         int64_t eventTime = AMotionEvent_getEventTime( motion_event );
65         int64_t downTime = AMotionEvent_getDownTime( motion_event );
66         if( eventTime - downTime <= TAP_TIMEOUT )
67         {
68             if( down_pointer_id_ == AMotionEvent_getPointerId( motion_event, 0 ) )
69             {
70                 float x = AMotionEvent_getX( motion_event, 0 ) - down_x_;
71                 float y = AMotionEvent_getY( motion_event, 0 ) - down_y_;
72                 if( x * x + y * y < TOUCH_SLOP * TOUCH_SLOP * dp_factor_ )
73                 {
74                     LOGI( "TapDetector: Tap detected" );
75                     return GESTURE_STATE_ACTION;
76                 }
77             }
78         }
79         break;
80     }
81     }
82     return GESTURE_STATE_NONE;
83 }
84 
85 //--------------------------------------------------------------------------------
86 // DoubletapDetector
87 //--------------------------------------------------------------------------------
Detect(const AInputEvent * motion_event)88 GESTURE_STATE DoubletapDetector::Detect( const AInputEvent* motion_event )
89 {
90     if( AMotionEvent_getPointerCount( motion_event ) > 1 )
91     {
92         //Only support single double tap
93         return false;
94     }
95 
96     bool tap_detected = tap_detector_.Detect( motion_event );
97 
98     int32_t action = AMotionEvent_getAction( motion_event );
99     unsigned int flags = action & AMOTION_EVENT_ACTION_MASK;
100     switch( flags )
101     {
102     case AMOTION_EVENT_ACTION_DOWN:
103     {
104         int64_t eventTime = AMotionEvent_getEventTime( motion_event );
105         if( eventTime - last_tap_time_ <= DOUBLE_TAP_TIMEOUT )
106         {
107             float x = AMotionEvent_getX( motion_event, 0 ) - last_tap_x_;
108             float y = AMotionEvent_getY( motion_event, 0 ) - last_tap_y_;
109             if( x * x + y * y < DOUBLE_TAP_SLOP * DOUBLE_TAP_SLOP * dp_factor_ )
110             {
111                 LOGI( "DoubletapDetector: Doubletap detected" );
112                 return GESTURE_STATE_ACTION;
113             }
114         }
115         break;
116     }
117     case AMOTION_EVENT_ACTION_UP:
118         if( tap_detected )
119         {
120             last_tap_time_ = AMotionEvent_getEventTime( motion_event );
121             last_tap_x_ = AMotionEvent_getX( motion_event, 0 );
122             last_tap_y_ = AMotionEvent_getY( motion_event, 0 );
123         }
124         break;
125     }
126     return GESTURE_STATE_NONE;
127 }
128 
SetConfiguration(AConfiguration * config)129 void DoubletapDetector::SetConfiguration( AConfiguration* config )
130 {
131     dp_factor_ = 160.f / AConfiguration_getDensity( config );
132     tap_detector_.SetConfiguration( config );
133 }
134 
135 //--------------------------------------------------------------------------------
136 // PinchDetector
137 //--------------------------------------------------------------------------------
138 
FindIndex(const AInputEvent * event,int32_t id)139 int32_t PinchDetector::FindIndex( const AInputEvent* event, int32_t id )
140 {
141     int32_t count = AMotionEvent_getPointerCount( event );
142     for( uint32_t i = 0; i < count; ++i )
143     {
144         if( id == AMotionEvent_getPointerId( event, i ) )
145             return i;
146     }
147     return -1;
148 }
149 
Detect(const AInputEvent * event)150 GESTURE_STATE PinchDetector::Detect( const AInputEvent* event )
151 {
152     GESTURE_STATE ret = GESTURE_STATE_NONE;
153     int32_t action = AMotionEvent_getAction( event );
154     uint32_t flags = action & AMOTION_EVENT_ACTION_MASK;
155     event_ = event;
156 
157     int32_t count = AMotionEvent_getPointerCount( event );
158     switch( flags )
159     {
160     case AMOTION_EVENT_ACTION_DOWN:
161         vec_pointers_.push_back( AMotionEvent_getPointerId( event, 0 ) );
162         break;
163     case AMOTION_EVENT_ACTION_POINTER_DOWN:
164     {
165         int32_t iIndex = (action & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK)
166                 >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
167         vec_pointers_.push_back( AMotionEvent_getPointerId( event, iIndex ) );
168         if( count == 2 )
169         {
170             //Start new pinch
171             ret = GESTURE_STATE_START;
172         }
173     }
174         break;
175     case AMOTION_EVENT_ACTION_UP:
176         vec_pointers_.pop_back();
177         break;
178     case AMOTION_EVENT_ACTION_POINTER_UP:
179     {
180         int32_t index = (action & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK)
181                 >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
182         int32_t released_pointer_id = AMotionEvent_getPointerId( event, index );
183 
184         std::vector<int32_t>::iterator it = vec_pointers_.begin();
185         std::vector<int32_t>::iterator it_end = vec_pointers_.end();
186         int32_t i = 0;
187         for( ; it != it_end; ++it, ++i )
188         {
189             if( *it == released_pointer_id )
190             {
191                 vec_pointers_.erase( it );
192                 break;
193             }
194         }
195 
196         if( i <= 1 )
197         {
198             //Reset pinch or drag
199             if( count != 2 )
200             {
201                 //Start new pinch
202                 ret = GESTURE_STATE_START | GESTURE_STATE_END;
203             }
204         }
205     }
206         break;
207     case AMOTION_EVENT_ACTION_MOVE:
208         switch( count )
209         {
210         case 1:
211             break;
212         default:
213             //Multi touch
214             ret = GESTURE_STATE_MOVE;
215             break;
216         }
217         break;
218     case AMOTION_EVENT_ACTION_CANCEL:
219         break;
220     }
221 
222     return ret;
223 }
224 
GetPointers(Vec2 & v1,Vec2 & v2)225 bool PinchDetector::GetPointers( Vec2& v1, Vec2& v2 )
226 {
227     if( vec_pointers_.size() < 2 )
228         return false;
229 
230     int32_t index = FindIndex( event_, vec_pointers_[0] );
231     if( index == -1 )
232         return false;
233 
234     float x = AMotionEvent_getX( event_, index );
235     float y = AMotionEvent_getY( event_, index );
236 
237     index = FindIndex( event_, vec_pointers_[1] );
238     if( index == -1 )
239         return false;
240 
241     float x2 = AMotionEvent_getX( event_, index );
242     float y2 = AMotionEvent_getY( event_, index );
243 
244     v1 = Vec2( x, y );
245     v2 = Vec2( x2, y2 );
246 
247     return true;
248 }
249 
250 //--------------------------------------------------------------------------------
251 // DragDetector
252 //--------------------------------------------------------------------------------
253 
FindIndex(const AInputEvent * event,int32_t id)254 int32_t DragDetector::FindIndex( const AInputEvent* event, int32_t id )
255 {
256     int32_t count = AMotionEvent_getPointerCount( event );
257     for( uint32_t i = 0; i < count; ++i )
258     {
259         if( id == AMotionEvent_getPointerId( event, i ) )
260             return i;
261     }
262     return -1;
263 }
264 
Detect(const AInputEvent * event)265 GESTURE_STATE DragDetector::Detect( const AInputEvent* event )
266 {
267     GESTURE_STATE ret = GESTURE_STATE_NONE;
268     int32_t action = AMotionEvent_getAction( event );
269     int32_t index = (action & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK)
270             >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
271     uint32_t flags = action & AMOTION_EVENT_ACTION_MASK;
272     event_ = event;
273 
274     int32_t count = AMotionEvent_getPointerCount( event );
275     switch( flags )
276     {
277     case AMOTION_EVENT_ACTION_DOWN:
278         vec_pointers_.push_back( AMotionEvent_getPointerId( event, 0 ) );
279         ret = GESTURE_STATE_START;
280         break;
281     case AMOTION_EVENT_ACTION_POINTER_DOWN:
282         vec_pointers_.push_back( AMotionEvent_getPointerId( event, index ) );
283         break;
284     case AMOTION_EVENT_ACTION_UP:
285         vec_pointers_.pop_back();
286         ret = GESTURE_STATE_END;
287         break;
288     case AMOTION_EVENT_ACTION_POINTER_UP:
289     {
290         int32_t released_pointer_id = AMotionEvent_getPointerId( event, index );
291 
292         std::vector<int32_t>::iterator it = vec_pointers_.begin();
293         std::vector<int32_t>::iterator it_end = vec_pointers_.end();
294         int32_t i = 0;
295         for( ; it != it_end; ++it, ++i )
296         {
297             if( *it == released_pointer_id )
298             {
299                 vec_pointers_.erase( it );
300                 break;
301             }
302         }
303 
304         if( i <= 1 )
305         {
306             //Reset pinch or drag
307             if( count == 2 )
308             {
309                 ret = GESTURE_STATE_START;
310             }
311         }
312         break;
313     }
314     case AMOTION_EVENT_ACTION_MOVE:
315         switch( count )
316         {
317         case 1:
318             //Drag
319             ret = GESTURE_STATE_MOVE;
320             break;
321         default:
322             break;
323         }
324         break;
325     case AMOTION_EVENT_ACTION_CANCEL:
326         break;
327     }
328 
329     return ret;
330 }
331 
GetPointer(Vec2 & v)332 bool DragDetector::GetPointer( Vec2& v )
333 {
334     if( vec_pointers_.size() < 1 )
335         return false;
336 
337     int32_t iIndex = FindIndex( event_, vec_pointers_[0] );
338     if( iIndex == -1 )
339         return false;
340 
341     float x = AMotionEvent_getX( event_, iIndex );
342     float y = AMotionEvent_getY( event_, iIndex );
343 
344     v = Vec2( x, y );
345 
346     return true;
347 }
348 
349 }   //namespace ndkHelper
350 
351