Adaptor: Fix Klocwork issues
[platform/core/uifw/dali-adaptor.git] / adaptors / common / events / tap-gesture-detector.cpp
1 /*
2  * Copyright (c) 2014 Samsung Electronics Co., Ltd.
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
18 // CLASS HEADER
19 #include "tap-gesture-detector.h"
20
21 // EXTERNAL INCLUDES
22 #include <cmath>
23
24 #include <dali/public-api/events/touch-point.h>
25 #include <dali/public-api/math/vector2.h>
26
27 #include <dali/integration-api/events/gesture-requests.h>
28 #include <dali/integration-api/events/tap-gesture-event.h>
29 #include <dali/integration-api/events/touch-event-integ.h>
30 #include <base/core-event-interface.h>
31
32 // INTERNAL INCLUDES
33
34 namespace Dali
35 {
36
37 namespace Internal
38 {
39
40 namespace Adaptor
41 {
42
43 namespace
44 {
45 // TODO: Set these according to DPI
46 const float MAXIMUM_MOTION_ALLOWED = 20.0f;
47 const unsigned long MAXIMUM_TIME_ALLOWED = 300u;
48 } // unnamed namespace
49
50 TapGestureDetector::TapGestureDetector(CoreEventInterface& coreEventInterface, Vector2 screenSize, const Integration::TapGestureRequest& request)
51 : GestureDetector(screenSize, Gesture::Tap),
52   mCoreEventInterface(coreEventInterface),
53   mState(Clear),
54   mMinimumTapsRequired(request.minTaps),
55   mMaximumTapsRequired(request.maxTaps),
56   mTapsRegistered(0),
57   mTouchTime(0),
58   mTimerSlot( this )
59 {
60   mTimer = Dali::Timer::New(MAXIMUM_TIME_ALLOWED);
61   mTimer.TickSignal().Connect( mTimerSlot, &TapGestureDetector::TimerCallback );
62 }
63
64 TapGestureDetector::~TapGestureDetector()
65 {
66 }
67
68 void TapGestureDetector::SendEvent(const Integration::TouchEvent& event)
69 {
70   if (event.GetPointCount() == 1)
71   {
72     const TouchPoint& point = event.points[0];
73     TouchPoint::State pointState = point.state;
74
75     switch (mState)
76     {
77       case Clear:
78       {
79         if (pointState == TouchPoint::Down)
80         {
81           mTouchPosition.x = point.screen.x;
82           mTouchPosition.y = point.screen.y;
83           mTouchTime = event.time;
84           mTapsRegistered = 0;
85           mState = Touched;
86           EmitGesture( Gesture::Possible, mTouchTime );
87         }
88         break;
89       }
90
91       case Touched:
92       {
93         Vector2 distanceDelta(abs(mTouchPosition.x - point.screen.x),
94                               abs(mTouchPosition.y - point.screen.y));
95
96         unsigned long timeDelta = abs(event.time - mTouchTime);
97
98         if (distanceDelta.x > MAXIMUM_MOTION_ALLOWED ||
99             distanceDelta.y > MAXIMUM_MOTION_ALLOWED ||
100             timeDelta > MAXIMUM_TIME_ALLOWED)
101         {
102           // We may have already registered some taps so try emitting the gesture
103           EmitGesture( mTapsRegistered ? Gesture::Started : Gesture::Cancelled, event.time );
104           mState = (pointState == TouchPoint::Motion) ? Failed : Clear;
105           mTimer.Stop();
106         }
107
108         if (mState == Touched && pointState == TouchPoint::Up)
109         {
110           ++mTapsRegistered;
111
112           if (mTapsRegistered < mMaximumTapsRequired)
113           {
114             // Only emit gesture after timer expires if asked for multiple taps.
115             mState = Registered;
116             mTimer.Start();
117           }
118           else
119           {
120             EmitGesture(Gesture::Started, event.time);
121             mState = Clear;
122             mTimer.Stop();
123           }
124         }
125         break;
126       }
127
128       case Registered:
129       {
130         if (pointState == TouchPoint::Down)
131         {
132           mTimer.Stop();
133
134           Vector2 distanceDelta(abs(mTouchPosition.x - point.screen.x),
135                                 abs(mTouchPosition.y - point.screen.y));
136
137           // Check if subsequent tap is in a different position, if not then emit the previous tap
138           // count gesture (if required),
139           if (distanceDelta.x > MAXIMUM_MOTION_ALLOWED ||
140               distanceDelta.y > MAXIMUM_MOTION_ALLOWED)
141           {
142             EmitGesture(Gesture::Started, event.time);
143             mTouchPosition.x = point.screen.x;
144             mTouchPosition.y = point.screen.y;
145           }
146
147           mTouchTime = event.time;
148           mState = Touched;
149           mTimer.Start();
150         }
151         break;
152       }
153
154       case Failed:
155       {
156         if (pointState == TouchPoint::Up)
157         {
158           mState = Clear;
159         }
160         break;
161       }
162
163       default:
164         mState = Clear;
165         break;
166     }
167   }
168   else
169   {
170     mState = Failed;
171
172     // We have entered a multi-touch event so emit registered gestures if required.
173     EmitGesture(Gesture::Started, event.time);
174   }
175 }
176
177 void TapGestureDetector::Update(const Integration::GestureRequest& request)
178 {
179   const Integration::TapGestureRequest& tap = static_cast<const Integration::TapGestureRequest&>(request);
180
181   mMinimumTapsRequired = tap.minTaps;
182   mMaximumTapsRequired = tap.maxTaps;
183 }
184
185 bool TapGestureDetector::TimerCallback()
186 {
187   EmitGesture( ( mTapsRegistered >= mMinimumTapsRequired ? Gesture::Started : Gesture::Cancelled ), mTouchTime + MAXIMUM_TIME_ALLOWED);
188   mState = Clear;
189   return false;
190 }
191
192 void TapGestureDetector::EmitGesture( Gesture::State state, unsigned int time )
193 {
194   if ( (state == Gesture::Possible) ||
195        (state == Gesture::Cancelled) ||
196        (mTapsRegistered >= mMinimumTapsRequired && mTapsRegistered <= mMaximumTapsRequired) )
197   {
198     Integration::TapGestureEvent event( state );
199     event.numberOfTaps = mTapsRegistered;
200     event.point = mTouchPosition;
201     event.time = time;
202
203     mCoreEventInterface.QueueCoreEvent(event);
204   }
205   mTapsRegistered = 0;
206 }
207
208 } // namespace Adaptor
209
210 } // namespace Internal
211
212 } // namespace Dali