Update package version to 1.10.13
[platform/core/uifw/ise-default.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 "ISE_DEFAULT"
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     : startcount(0)
79     , drawcount(0)
80     , forcestop(false)
81     , started(false)
82     , fake(false)
83     , root(NULL)
84     , shape(NULL)
85     , timer(NULL)
86     , layout(layout)
87     , ieffect(effect)
88 {
89     vg = evas_object_vg_add(evas_object_evas_get(canvas));
90     /* temporary code to avoid crash when evas_vg_shape_add is crash sometimes */
91     if (!vg) {
92         LOGW("vg is null");
93         return;
94     }
95     evas_object_show(vg);
96
97     root = evas_object_vg_root_node_get(vg);
98     /* temporary code to avoid crash when evas_vg_shape_add is crash sometimes */
99     if (!root) {
100         LOGW("root is null");
101         return;
102     }
103
104     shape = evas_vg_shape_add(root);
105     evas_vg_node_color_set(shape, 80, 80, 80, 80);
106
107     elm_object_part_content_set(layout, "EFFECT_BG", vg);
108
109     evas_vg_shape_stroke_cap_set(shape, EVAS_VG_CAP_BUTT);
110     evas_vg_shape_stroke_join_set(shape, EVAS_VG_JOIN_MITER);
111
112     evas_vg_shape_stroke_width_set(shape, 3.0);
113 #ifdef _WEARABLE
114     evas_vg_shape_stroke_color_set(shape, 255, 255, 255, 255);
115 #else
116     evas_vg_shape_stroke_color_set(shape, 51, 204, 255, 255);
117 #endif
118     DrawDummyFrame();
119 };
120
121 /**
122  * Destructor
123  *
124  * #1. Destroy ea_vector handle
125  *
126  */
127 MicEffector::~MicEffector()
128 {
129     if (timer) {
130         ecore_timer_del(timer);
131         timer = NULL;
132     }
133     if (vg)
134         evas_object_del(vg);
135
136     if (root)
137         evas_object_del(root);
138
139     if (shape)
140         evas_object_del(shape);
141 }
142
143 /**
144  * Draw empty frame to remove or initiate screen
145  *
146  */
147 void MicEffector::DrawDummyFrame()
148 {
149     evas_vg_shape_reset(shape);
150     evas_vg_shape_append_move_to(shape, 0, 0);
151     evas_vg_shape_append_line_to(shape, 0, 0);
152
153     evas_object_show(vg);
154 }
155
156 /**
157  * Draw Que animation
158  *
159  * In case of start, it shows 2 more dots per one time.
160  * In case of stop, it remove 2 dots per one time.
161  *
162  * it works during 22 times.
163  *
164  */
165 void MicEffector::DrawQue(int idx, bool is_start)
166 {
167     float margin = spectrum_posx;
168     float posx = 0.0;
169
170     double speed = cubic_easy_out(idx + 1.0, 0.0, 23.0, 23);
171
172     unsigned int start = start_stop_anim_count - (int) speed;
173     unsigned int end = start_stop_anim_count + (int) speed;
174
175 #ifdef _WEARABLE
176     double opacity;
177
178     if (is_start) {
179         opacity = cubic_easy_out(idx, 0.0, 1.0, 26.0);
180     } else {
181         opacity = cubic_easy_out(idx, 0, 1.0, 26.0);
182     }
183 #endif
184
185     evas_vg_shape_reset(shape);
186
187     for (unsigned int i = start; i < end; i++)
188     {
189         posx = margin + (i * 5);
190
191         evas_vg_shape_append_move_to(shape, posx, 37);
192         evas_vg_shape_append_line_to(shape, posx, 38);
193 #ifdef _WEARABLE
194         evas_vg_shape_stroke_color_set(shape, 255, 255, 255, opacity);
195 #else
196         evas_vg_shape_stroke_color_set(shape, 51, 204, 255, 255);
197 #endif
198     }
199
200     evas_object_show(vg);
201 }
202
203 float MicEffector::GetAmplifyValue(unsigned int idx)
204 {
205     float amplify = 0.0;
206
207     int max[SAMPLE_COUNT] = {
208         /**
209          * dot "A" (9)
210          *
211          */
212         1, 1, 1, 1,
213
214
215         1, 1, 1, 1, 1, 1, 1, 1, 1,
216
217         /**
218          * dot "B" (9)
219          *
220          */
221         10, 8, 2, 3, 10, 11, 6, 12, 4,
222
223         /**
224          * dot "C" (15)
225          *
226          */
227          3, 5, 9, 12, 11, 8, 14, 15, 13, 11, 12, 6, 8, 3, 2,
228
229         /**
230          * reverse dot "B" (9)
231          *
232          */
233          4, 12, 6, 11, 10, 3, 2, 8, 10,
234
235         /**
236          * dot "A" (9)
237          *
238          */
239         1, 1, 1, 1, 1, 1, 1, 1, 1,
240
241         1, 1, 1, 1
242     };
243
244     amplify = (float) max[idx] / 10.0f * 1.9f;
245
246     return amplify;
247 }
248
249 /**
250  * Draw effect animation
251  *
252  * It draws volume effect. during 5 times.
253  * Center of effect area, it applies amplified value.
254  *
255  */
256 void MicEffector::DrawWave(unsigned int idx, int amount, int prev_amount, double opacity, bool is_lastcmd)
257 {
258     float ratio = GetAmplifyValue(idx);
259
260     float am = ((float) amount) * ratio;
261     float pam = ((float) prev_amount) * ratio;
262     float cnt = (float) drawcount;
263
264     float posx = spectrum_posx;
265
266     float height = pam > am?
267         pam - cubic_easy_in_out(cnt + 1.0, am, pam, 7):
268         cubic_easy_in_out(cnt + 1.0, pam, am, 7);
269
270     posx += idx * 8;
271
272     evas_vg_shape_append_move_to(shape, posx, (37.0f - (height / 2.0)));
273     evas_vg_shape_append_line_to(shape, posx, (38.0f + (height / 2.0)));
274
275 #ifdef _WEARABLE
276     evas_vg_shape_stroke_color_set(shape, 255, 255, 255, opacity);
277 #else
278     evas_vg_shape_stroke_color_set(shape, 51, 204, 255, 255);
279 #endif
280 }
281
282 /**
283  * Effect Start
284  *
285  */
286 void MicEffector::Start()
287 {
288     if (timer) {
289         ecore_timer_del(timer);
290         timer = NULL;
291     }
292
293     drawcount = 0;
294
295     prev.clear();
296     current.clear();
297
298     for (size_t i = 0; i < spectrum_count; i++)
299     {
300         prev.push_back(0);
301         current.push_back(0);
302     }
303
304     Listening();
305
306     /**
307      * Que animation
308      *
309      */
310     timer = ecore_timer_add(timeout_s,
311                 [](void *data)->Eina_Bool
312                 {
313                     MicEffector *effector = static_cast<MicEffector*>(data);
314
315                     effector->DrawQue(effector->drawcount);
316
317                     if (effector->drawcount < (int) start_stop_anim_count) {
318                         effector->drawcount += 2;
319                         return ECORE_CALLBACK_RENEW;
320                     } else {
321                         for (unsigned int i = 0; i < spectrum_count; i++)
322                             effector->DrawWave(i, 0, 0);
323
324                         evas_object_show(effector->vg);
325
326                         effector->drawcount = 0;
327                         effector->timer = NULL;
328                         effector->VolumeCheck(true);
329                         effector->Effect();
330                         return ECORE_CALLBACK_CANCEL;
331                     }
332                 },
333                 this);
334 }
335
336 /**
337  * Volume effect
338  *
339  */
340 void MicEffector::Effect(bool fake)
341 {
342     /**
343      * Volume effect animation
344      *
345      */
346     if ( timer ) {
347             ecore_timer_del(timer);
348             timer = NULL;
349     }
350
351     timer = ecore_timer_add(timeout_s,
352                 [](void *data)->Eina_Bool
353                 {
354                     MicEffector *effector = static_cast<MicEffector *>(data);
355
356                     bool is_empty_prev = effector->prev.empty();
357
358                     evas_vg_shape_reset(effector->shape);
359
360                     for (unsigned int i = 0; i < effector->current.size(); i++)
361                     {
362                         if (is_empty_prev) {
363                             effector->DrawWave(i, effector->current.at(i), 0);
364                         } else {
365                             effector->DrawWave(i, effector->current.at(i), effector->prev.at(i));
366                         }
367                     }
368                     evas_object_show(effector->vg);
369
370                     if (effector->drawcount < 7)    {
371                         effector->drawcount++;
372                         effector->VolumeCheck(true);
373                     } else {
374                         effector->drawcount = 0;
375                         effector->VolumeCheck(true);
376                     }
377
378                     return ECORE_CALLBACK_RENEW;
379                 }, this);
380 }
381
382 /**
383  * Stop volume animation effect
384  *
385  */
386 void MicEffector::Stop(bool forced)
387 {
388     if (timer)
389     {
390         ecore_timer_del(timer);
391         timer = NULL;
392     }
393
394     if (!started)
395     {
396         Idle();
397         return;
398     }
399
400     forcestop = forced;
401
402     timer = ecore_timer_add(timeout_s,
403         [](void *data)->Eina_Bool
404         {
405             MicEffector *effector = static_cast<MicEffector*>(data);
406
407             effector->DrawQue(start_stop_anim_count - effector->drawcount, false);
408
409             if (effector->drawcount < (int) start_stop_anim_count) {
410                 effector->drawcount += 2;
411                 return ECORE_CALLBACK_RENEW;
412             } else {
413                 if (!effector->forcestop) {
414 //                    effector->Processing();
415                 } else {
416 #if defined(_MOBILE) || defined(_COMMON)
417                     effector->Idle();
418 #endif
419                 }
420
421                 effector->forcestop = false;
422                 effector->drawcount = 0;
423                 effector->timer = NULL;
424                 return ECORE_CALLBACK_CANCEL;
425             }
426         }, this);
427 }
428
429 /**
430  * Signal. Refresh volume effect
431  *
432  */
433 void MicEffector::VolumeCheck(bool fake)
434 {
435     std::vector<int> volumes;
436
437     this->fake = fake;
438
439     if (!fake) {
440         volumes = ieffect.GetVolume();
441     } else {
442         for (unsigned int i = 0; i < spectrum_count; i++) {
443             unsigned int seed = time(NULL);
444 #ifdef _WEARABLE
445             volumes.push_back(rand_r(&seed) % 6);
446 #else
447             volumes.push_back(rand_r(&seed) % 15);
448 #endif
449         }
450     }
451
452     prev.clear();
453     prev.assign(current.begin(), current.end());
454
455     current.clear();
456     current.assign(volumes.begin(), volumes.end());
457 }
458
459 /**
460  * Signal. Listening effect
461  *
462  */
463 void MicEffector::Listening()
464 {
465     started = true;
466
467     elm_object_signal_emit(layout, "elm,state,listening", "elm");
468     elm_object_signal_emit(layout, "elm,state,eq,show", "eq");
469 }
470
471 /**
472  * Signal. Processing effect
473  *
474  */
475 void MicEffector::Processing()
476 {
477     started = false;
478
479     elm_object_signal_emit(layout, "elm,state,eq,hide", "eq");
480     elm_object_signal_emit(layout, "elm,state,processing", "elm");
481
482     ieffect.ProcessingAnimationStart();
483 }
484
485 /**
486  * Signal. Idle effect
487  *
488  */
489 void MicEffector::Idle()
490 {
491     const char *text;
492     const char *state;
493     double val;
494
495     started = false;
496
497     elm_object_signal_emit(layout, "elm,state,eq,hide", "eq");
498
499     text = elm_object_part_text_get(layout, "elm.text");
500     state = edje_object_part_state_get(elm_layout_edje_get(layout), "guide_text_block", &val);
501
502     if ((text && strlen(text) > 0) && (state && !strcmp(state, "bottom")))
503         elm_object_signal_emit(layout, "elm,state,init_message", "elm");
504     else
505         elm_object_signal_emit(layout, "elm,state,init", "elm");
506
507     ieffect.ProcessingAnimationStop();
508 }