Add LCOV remarkers to increase line coverage rate
[platform/core/api/maps-service.git] / src / view / inertial_gesture.cpp
1 /* Copyright (c) 2010-2014 Samsung Electronics Co., Ltd. All rights reserved.
2  *
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 #include "inertial_gesture.h"
19 #include "maps_util.h"
20 #include <glib.h>
21 #include "gesture_detector_statemachine.h"
22 #include <unistd.h>
23 #include <time.h>
24
25 extern void _maps_view_set_idle_listener(maps_view_h view,
26                                         void (*callback)(void *user_data),
27                                         void *user_data);
28
29 extern void _maps_view_halt_inertial_camera(maps_view_h view);
30
31 //LCOV_EXCL_START
32 view::inertial_gesture::inertial_gesture(maps_view_h view)
33         : gesture_detector(view)
34           , _d(NULL)
35           , transiting(false)
36           , transiting_trajectory(false)
37 {
38         reset();
39
40         _d = new gesture_detector_statemachine(view);
41
42         //_maps_view_set_idle_listener(view, on_idle, this);
43 }
44
45 view::inertial_gesture::~inertial_gesture()
46 {
47         //_maps_view_set_idle_listener(_view, NULL, NULL);
48
49         if (_d)
50                 delete _d;
51         _d = NULL;
52 }
53
54 view::inertial_gesture::inertial_gesture(const inertial_gesture &src)
55         : gesture_detector(NULL)
56           , _d(NULL)
57           , transiting(false)
58           , transiting_trajectory(false)
59 {
60 }
61
62 view::inertial_gesture &view::inertial_gesture::operator=(const inertial_gesture &src)
63 {
64         return *this;
65 }
66
67 void view::inertial_gesture::tap(int finger_no, const touch_point &tp)
68 {
69         MAPS_LOGI("TRANSITION finger %d tap time: %d",
70                   finger_no, tp._timestamp);
71
72         _maps_view_halt_inertial_camera(_view);
73
74         if (transiting) { /* Halt the transition */
75                 for (int i = 0; i < MAX_FINGERS; i ++) {
76                         if (!transiting_part[i])
77                                 continue;
78
79                         unsigned int timestamp = _last[i]._timestamp + get_transition_time(i);
80
81                         const touch_point tp(_cur_x[i], _cur_y[i], timestamp);
82                         MAPS_LOGI("TRANSITION finger %d up FAKE BRAKE time: %d", i, tp._timestamp);
83                         _d->up(i, tp);
84                 }
85
86                 _d->halt_gesture();
87                 reset();
88         }
89
90         _down[finger_no] = tp;
91         _last[finger_no] = tp;
92         _prev[finger_no] = tp;
93         _cur_x[finger_no] = tp._x;
94         _cur_y[finger_no] = tp._y;
95         _inertial_start[finger_no] = tp;
96
97         if (_d)
98                 _d->tap(finger_no, tp);
99 }
100
101 void view::inertial_gesture::move(int finger_no, const touch_point &tp)
102 {
103         MAPS_LOGI("TRANSITION finger %d move", finger_no);
104
105         _maps_view_halt_inertial_camera(_view);
106         update_inertial_start_point(finger_no);
107
108         _prev[finger_no] = _last[finger_no];
109         _last[finger_no] = tp;
110         _cur_x[finger_no] = tp._x;
111         _cur_y[finger_no] = tp._y;
112
113         /* check if moved enough as much as effective length */
114         int trajectory = get_trajectory_effective_length(_down[finger_no], tp);
115         MAPS_LOGD("trajectory=%d", trajectory);
116         if (trajectory >= __CLICK_AREA)
117                 transiting_trajectory = true;
118
119         if (_d)
120                 _d->move(finger_no, tp);
121 }
122
123 void view::inertial_gesture::up(int finger_no, const touch_point &tp)
124 {
125         MAPS_LOGI("TRANSITION finger %d up time: %d", finger_no, tp._timestamp);
126
127         _last[finger_no] = tp;
128
129         const int delta_x = _last[finger_no]._x - _inertial_start[finger_no]._x;
130         const int delta_y = _last[finger_no]._y - _inertial_start[finger_no]._y;
131         unsigned int dt = _last[finger_no]._timestamp - _inertial_start[finger_no]._timestamp;
132
133         /* check if moved enough as much as effective length */
134         int trajectory_total = get_trajectory_effective_length(_down[finger_no], tp);
135         int trajectory_last  = get_trajectory_effective_length(_prev[finger_no], tp);
136
137         /* check minimal size of click-area to be recognized as a valid gesture */
138         if (trajectory_total >= __CLICK_AREA)
139                 transiting_trajectory = true;
140
141         /* to prevent inertial movement even by tapping gesture */
142         if (trajectory_last <= __CLICK_AREA / 3.)
143                 transiting_trajectory = false;
144
145         if (dt == 0 || !transiting_trajectory) {
146                 _derivative_x[finger_no] = .0;
147                 _derivative_y[finger_no] = .0;
148         } else {
149                 _derivative_x[finger_no] = 10. * (delta_x) / dt;
150                 _derivative_y[finger_no] = 10. * (delta_y) / dt;
151         }
152         _dt[finger_no] = MIN(1.*dt, 1.);
153
154         /* Continue "move" with negative acceleration */
155         transiting_part[finger_no] = true;
156         transiting_start[finger_no] = get_cur_time();
157         transiting = true;
158 }
159
160 bool view::inertial_gesture::next_transition_step()
161 {
162         MAPS_LOGI("TRANSITION get next transition step");
163         transiting = false;
164
165         //static const double dt = 1.;
166         for (int i = 0; i < MAX_FINGERS; i ++) {
167                 if (!transiting_part[i])
168                         continue;
169
170                 transiting_part[i] = false;
171
172                 if ((ABS(_derivative_x[i]) > __ACCURACY) || (ABS(_derivative_y[i]) > __ACCURACY)) {
173                         _cur_x[i] = get_next_point(_cur_x[i], _derivative_x[i], _dt[i]);
174                         _derivative_x[i] = get_next_derivative(_derivative_x[i], _dt[i]);
175                         transiting_part[i] |= ABS(_derivative_x[i]) > __ACCURACY;
176
177                         _cur_y[i] = get_next_point(_cur_y[i], _derivative_y[i], _dt[i]);
178                         _derivative_y[i] = get_next_derivative(_derivative_y[i], _dt[i]);
179                         transiting_part[i] |= ABS(_derivative_y[i]) > __ACCURACY;
180                 }
181
182                 unsigned int timestamp = _last[i]._timestamp + get_transition_time(i);
183
184                 const touch_point tp(_cur_x[i], _cur_y[i], timestamp);
185                 if (transiting_part[i]) {
186                         /* MAPS_LOGI("TRANSITION finger %d move FAKE time: %d", i, tp._timestamp); */
187                         _d->move(i, tp);
188                 } else {
189                         /* MAPS_LOGI("TRANSITION finger %d up FAKE time: %d", i, tp._timestamp); */
190                         _d->up(i, tp);
191                 }
192
193                 transiting = true; /* There were changes, so may be one more
194                                       step in transient is needed */
195         }
196
197         if (!transiting)
198                 reset();
199
200         return transiting;
201 }
202
203 double view::inertial_gesture::get_next_point(const double &start,
204                                               const double &derivative,
205                                               const double &dt)
206 {
207         /* Simple square parabola */
208         return (start + derivative * dt);
209 }
210
211 double view::inertial_gesture::get_next_derivative(const double &derivative,
212                                                    const double &dt)
213 {
214         /* Simple square parabola */
215         /*if (derivative > 0)
216                 return (derivative + __ACCEL * dt);
217         else
218                 return (derivative - __ACCEL * dt);*/
219
220         /* Exponential spped down */
221         if (_d->_info._fingers_pressed <= 1)
222                 return (derivative * .9);
223         else
224                 return (derivative * .5);
225 }
226
227 unsigned int view::inertial_gesture::get_cur_time()
228 {
229         struct timespec ts;
230         unsigned int theTick = 0U;
231         clock_gettime(CLOCK_REALTIME, &ts);
232         theTick  = ts.tv_nsec / 1000000;
233         theTick += ts.tv_sec * 1000;
234         return theTick;
235 }
236
237 unsigned int view::inertial_gesture::get_transition_time(int finger_no) const
238 {
239         return get_cur_time() - transiting_start[finger_no];
240 }
241
242 /*
243 void view::inertial_gesture::on_idle(void *data)
244 {
245         inertial_gesture *ig = (inertial_gesture *)data;
246         if (ig && ig->transiting) {
247                 MAPS_LOGI("TRANSITION on idle");
248                 ig->next_transition_step();
249                 g_usleep(5*1000);
250         }
251 }
252 */
253
254 void view::inertial_gesture::reset()
255 {
256         transiting = false;
257         transiting_trajectory = false;
258         for (int i = 0; i < MAX_FINGERS; i ++) {
259                 transiting_part[i] = false;
260                 transiting_start[i] = 0;
261         }
262 }
263
264 void view::inertial_gesture::update_inertial_start_point(int finger_no)
265 {
266         const int margin = 3;
267         if (((_last[finger_no]._x > _prev[finger_no]._x + margin) && (_last[finger_no]._x < _inertial_start[finger_no]._x - margin)) ||
268                 ((_last[finger_no]._x < _prev[finger_no]._x - margin) && (_last[finger_no]._x > _inertial_start[finger_no]._x + margin)) ||
269                 ((_last[finger_no]._y > _prev[finger_no]._y + margin) && (_last[finger_no]._y < _inertial_start[finger_no]._y - margin)) ||
270                 ((_last[finger_no]._y < _prev[finger_no]._y - margin) && (_last[finger_no]._y > _inertial_start[finger_no]._y + margin))) {
271                 _inertial_start[finger_no] = _last[finger_no];
272                 MAPS_LOGD("reset inertial start (%d,%d)", _inertial_start[finger_no]._x, _inertial_start[finger_no]._y);
273         }
274 }
275 //LCOV_EXCL_STOP