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 //-------------------------------------------------------------------------------- 32 GestureDetector::GestureDetector() 33 { 34 dp_factor_ = 1.f; 35 } 36 37 void GestureDetector::SetConfiguration( AConfiguration* config ) 38 { 39 dp_factor_ = 160.f / AConfiguration_getDensity( config ); 40 } 41 42 //-------------------------------------------------------------------------------- 43 // TapDetector 44 //-------------------------------------------------------------------------------- 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 //-------------------------------------------------------------------------------- 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 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 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 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 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 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 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 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