Update package version to 0.1.171031
[platform/core/uifw/inputdelegator.git] / src / MicEffector.cpp
1 /*
2  * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
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 #define EFL_BETA_API_SUPPORT 1
18 #define EFL_EO_API_SUPPORT 1
19
20 #include <Eo.h>
21
22 #include <string.h>
23 #include "MicEffector.h"
24
25 #include <Elementary.h>
26 #include <Evas.h>
27 #include <dlog.h>
28 #undef LOG_TAG
29 #define LOG_TAG "INPUT_DELEGATOR"
30
31
32 using namespace is::ui;
33
34 /**
35  * animation configuration values
36  *
37  */
38 static size_t start_stop_anim_count = 28;
39 static size_t spectrum_count = SAMPLE_COUNT;
40 static float spectrum_posx = 40.0f;
41
42 static float timeout_s = 1.0f / 60.0f;
43
44 #define MATH_PI (3.141592)
45
46 double cubic_easy_in_out(double index, double start, double end, double duration)
47 {
48     index /= duration/2;
49     if (index < 1)
50         return end/2*index*index*index + start;
51
52     index -= 2;
53     return end/2*(index*index*index + 2) + start;
54 }
55
56 double cubic_easy_in(double index, double start, double end, double duration)
57 {
58     index /= duration;
59     return end*index*index*index*index*index + start;
60 }
61
62 double cubic_easy_out(double index, double start, double end, double duration)
63 {
64     index /= duration;
65     index--;
66     return end*(index*index*index + 1) + start;
67 }
68
69 /**
70  * Constructor
71  *
72  * #1. Create ea_vector handle for drawing effect.
73  *     ( 1 canvas, 1 paint and 45 paths )
74  * #2. Drawing empty frame to avoid broken screen.
75  *
76  */
77 MicEffector::MicEffector(Evas_Object *canvas, Evas_Object *layout, IMicEffector& effect)
78     : drawcount(0)
79     , forcestop(false)
80     , started(false)
81     , fake(false)
82     , timer(NULL)
83     , layout(layout)
84     , ieffect(effect)
85 {
86     vg = evas_object_vg_add(evas_object_evas_get(canvas));
87     evas_object_show(vg);
88
89     root = evas_object_vg_root_node_get(vg);
90     shape = evas_vg_shape_add(root);
91     evas_vg_node_color_set(shape, 80, 80, 80, 80);
92
93     elm_object_part_content_set(layout, "EFFECT_BG", vg);
94
95     evas_vg_shape_stroke_cap_set(shape, EFL_GFX_CAP_BUTT);
96     evas_vg_shape_stroke_join_set(shape, EFL_GFX_JOIN_MITER);
97
98     evas_vg_shape_stroke_width_set(shape, 3.0);
99     evas_vg_shape_stroke_color_set(shape, 255, 255, 255, 255);
100
101     DrawDummyFrame();
102 };
103
104 /**
105  * Destructor
106  *
107  * #1. Destroy ea_vector handle
108  *
109  */
110 MicEffector::~MicEffector()
111 {
112     if (timer) {
113         ecore_timer_del(timer);
114         timer = NULL;
115     }
116     if (vg)
117         evas_object_del(vg);
118
119     if (root)
120         evas_object_del(root);
121
122     if (shape)
123         evas_object_del(shape);
124 }
125
126 /**
127  * Draw empty frame to remove or initiate screen
128  *
129  */
130 void MicEffector::DrawDummyFrame()
131 {
132     evas_vg_shape_reset(shape);
133     evas_vg_shape_append_move_to(shape, 0, 0);
134     evas_vg_shape_append_line_to(shape, 0, 0);
135
136     evas_object_show(vg);
137 }
138
139 /**
140  * Draw Que animation
141  *
142  * In case of start, it shows 2 more dots per one time.
143  * In case of stop, it remove 2 dots per one time.
144  *
145  * it works during 22 times.
146  *
147  */
148 void MicEffector::DrawQue(int idx, bool is_start)
149 {
150     float margin = spectrum_posx;
151     float posx = 0.0;
152
153     double speed = cubic_easy_out(idx + 1.0, 0.0, 23.0, 23);
154
155     unsigned int start = start_stop_anim_count - (int) speed;
156     unsigned int end = start_stop_anim_count + (int) speed;
157
158     double opacity = 0.0;;
159
160     if (is_start) {
161         opacity = cubic_easy_out(idx, 0.0, 1.0, 26.0);
162     } else {
163         opacity = cubic_easy_out(idx, 0, 1.0, 26.0);
164     }
165
166     evas_vg_shape_reset(shape);
167
168     for (unsigned int i = start; i < end; i++)
169     {
170         posx = margin + (i * 5);
171
172         evas_vg_shape_append_move_to(shape, posx, 37);
173         evas_vg_shape_append_line_to(shape, posx, 38);
174         evas_vg_shape_stroke_color_set(shape, 255, 255, 255, opacity);
175     }
176
177     evas_object_show(vg);
178 }
179
180 float MicEffector::GetAmplifyValue(unsigned int idx)
181 {
182     float amplify = 0.0;
183
184     int max[SAMPLE_COUNT] = {
185         /**
186          * dot "A" (9)
187          *
188          */
189         1, 1, 1, 1,
190
191
192         1, 1, 1, 1, 1, 1, 1, 1, 1,
193
194         /**
195          * dot "B" (9)
196          *
197          */
198         10, 8, 2, 3, 10, 11, 6, 12, 4,
199
200         /**
201          * dot "C" (15)
202          *
203          */
204          3, 5, 9, 12, 11, 8, 14, 15, 13, 11, 12, 6, 8, 3, 2,
205
206         /**
207          * reverse dot "B" (9)
208          *
209          */
210          4, 12, 6, 11, 10, 3, 2, 8, 10,
211
212         /**
213          * dot "A" (9)
214          *
215          */
216         1, 1, 1, 1, 1, 1, 1, 1, 1,
217
218         1, 1, 1, 1
219     };
220
221     amplify = (float) max[idx] / 10.0f * 1.9f;
222
223     return amplify;
224 }
225
226 /**
227  * Draw effect animation
228  *
229  * It draws volume effect. during 5 times.
230  * Center of effect area, it applies amplified value.
231  *
232  */
233 void MicEffector::DrawWave(unsigned int idx, int amount, int prev_amount, double opacity, bool is_lastcmd)
234 {
235     float ratio = GetAmplifyValue(idx);
236
237     float am = ((float) amount) * ratio;
238     float pam = ((float) prev_amount) * ratio;
239     float cnt = (float) drawcount;
240
241     float posx = spectrum_posx;
242
243     float height = pam > am?
244         pam - cubic_easy_in_out(cnt + 1.0, am, pam, 7):
245         cubic_easy_in_out(cnt + 1.0, pam, am, 7);
246
247     posx += idx * 8;
248
249     evas_vg_shape_append_move_to(shape, posx, (37.0f - (height / 2.0)));
250     evas_vg_shape_append_line_to(shape, posx, (38.0f + (height / 2.0)));
251     evas_vg_shape_stroke_color_set(shape, 255, 255, 255, opacity);
252 }
253
254 /**
255  * Effect Start
256  *
257  */
258 void MicEffector::Start()
259 {
260     if (timer) {
261         ecore_timer_del(timer);
262         timer = NULL;
263     }
264
265     drawcount = 0;
266
267     prev.clear();
268     current.clear();
269
270     for (size_t i = 0; i < spectrum_count; i++)
271     {
272         prev.push_back(0);
273         current.push_back(0);
274     }
275
276     Listening();
277
278     /**
279      * Que animation
280      *
281      */
282     timer = ecore_timer_add(timeout_s,
283                 [](void *data)->Eina_Bool
284                 {
285                     MicEffector *effector = static_cast<MicEffector*>(data);
286
287                     effector->DrawQue(effector->drawcount);
288
289                     if (effector->drawcount < (int) start_stop_anim_count) {
290                         effector->drawcount += 2;
291                         return ECORE_CALLBACK_RENEW;
292                     } else {
293                         for (unsigned int i = 0; i < spectrum_count; i++)
294                             effector->DrawWave(i, 0, 0);
295
296                         evas_object_show(effector->vg);
297
298                         effector->drawcount = 0;
299                         effector->timer = NULL;
300                         effector->VolumeCheck(true);
301                         effector->Effect();
302                         return ECORE_CALLBACK_CANCEL;
303                     }
304                 },
305                 this);
306 }
307
308 /**
309  * Volume effect
310  *
311  */
312 void MicEffector::Effect(bool fake)
313 {
314     /**
315      * Volume effect animation
316      *
317      */
318     if ( timer ) {
319             ecore_timer_del(timer);
320             timer = NULL;
321     }
322
323     timer = ecore_timer_add(timeout_s,
324                 [](void *data)->Eina_Bool
325                 {
326                     MicEffector *effector = static_cast<MicEffector *>(data);
327
328                     bool is_empty_prev = effector->prev.empty();
329
330                     evas_vg_shape_reset(effector->shape);
331
332                     for (unsigned int i = 0; i < effector->current.size(); i++)
333                     {
334                         if (is_empty_prev) {
335                             effector->DrawWave(i, effector->current.at(i), 0);
336                         } else {
337                             effector->DrawWave(i, effector->current.at(i), effector->prev.at(i));
338                         }
339                     }
340                     evas_object_show(effector->vg);
341
342                     if (effector->drawcount < 7)    {
343                         effector->drawcount++;
344                         effector->VolumeCheck(true);
345                     } else {
346                         effector->drawcount = 0;
347                         effector->VolumeCheck(true);
348                     }
349
350                     return ECORE_CALLBACK_RENEW;
351                 }, this);
352 }
353
354 /**
355  * Stop volume animation effect
356  *
357  */
358 void MicEffector::Stop(bool forced)
359 {
360     if (timer)
361     {
362         ecore_timer_del(timer);
363         timer = NULL;
364     }
365
366     if (!started)
367     {
368         Idle();
369         return;
370     }
371
372     forcestop = forced;
373
374     timer = ecore_timer_add(timeout_s,
375         [](void *data)->Eina_Bool
376         {
377             MicEffector *effector = static_cast<MicEffector*>(data);
378
379             effector->DrawQue(start_stop_anim_count - effector->drawcount, false);
380
381             if (effector->drawcount < (int) start_stop_anim_count) {
382                 effector->drawcount += 2;
383                 return ECORE_CALLBACK_RENEW;
384             } else {
385                 effector->forcestop = false;
386                 effector->drawcount = 0;
387                 effector->timer = NULL;
388                 return ECORE_CALLBACK_CANCEL;
389             }
390         }, this);
391 }
392
393 /**
394  * Signal. Refresh volume effect
395  *
396  */
397 void MicEffector::VolumeCheck(bool fake)
398 {
399     std::vector<int> volumes;
400
401     this->fake = fake;
402
403     if (!fake) {
404         volumes = ieffect.GetVolume();
405     } else {
406         for (unsigned int i = 0; i < spectrum_count; i++) {
407             unsigned int seed = time(NULL);
408             volumes.push_back(rand_r(&seed) % 6);
409         }
410     }
411
412     prev.clear();
413     prev.assign(current.begin(), current.end());
414
415     current.clear();
416     current.assign(volumes.begin(), volumes.end());
417 }
418
419 /**
420  * Signal. Listening effect
421  *
422  */
423 void MicEffector::Listening()
424 {
425     started = true;
426
427     elm_object_signal_emit(layout, "elm,state,listening", "elm");
428     elm_object_signal_emit(layout, "elm,state,eq,show", "eq");
429 }
430
431 /**
432  * Signal. Processing effect
433  *
434  */
435 void MicEffector::Processing()
436 {
437     started = false;
438
439     elm_object_signal_emit(layout, "elm,state,eq,hide", "eq");
440     elm_object_signal_emit(layout, "elm,state,processing", "elm");
441
442     ieffect.ProcessingAnimationStart();
443 }
444
445 /**
446  * Signal. Idle effect
447  *
448  */
449 void MicEffector::Idle()
450 {
451     const char *text;
452     const char *state;
453     double val;
454
455     started = false;
456
457     elm_object_signal_emit(layout, "elm,state,eq,hide", "eq");
458
459     text = elm_object_part_text_get(layout, "elm.text");
460     state = edje_object_part_state_get(elm_layout_edje_get(layout), "guide_text_block", &val);
461
462     if ((text && strlen(text) > 0) && (state && !strcmp(state, "bottom")))
463         elm_object_signal_emit(layout, "elm,state,init_message", "elm");
464     else
465         elm_object_signal_emit(layout, "elm,state,init", "elm");
466
467     ieffect.ProcessingAnimationStop();
468 }