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