Fix issue that showed wrong discard message popup for voice input
[platform/core/uifw/inputdelegator.git] / src / MoreOption.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 #include "Debug.h"
18
19 #include <string>
20 #include <assert.h>
21 #include <iostream>
22 #include <stdexcept>
23
24 #include <app.h>
25 #include <app_common.h>
26
27 #include "MoreOption.h"
28 #include "w-input-selector.h"
29 #include "w-input-stt-ise.h"
30 #include "w-input-stt-voice.h"
31
32 using namespace std;
33
34 extern Evas_Object *g_setting_window;
35 static bool voice_input_back_agree = false;
36
37 static void
38 popup_hide_cb(void *data, Evas_Object *obj, void *event_info)
39 {
40         if (!obj) return;
41         elm_popup_dismiss(obj);
42 }
43
44 static void
45 popup_hide_finished_cb(void *data, Evas_Object *obj, void *event_info)
46 {
47         if (!obj) return;
48         evas_object_del(obj);
49 }
50
51 static void voice_input_back_disagree_cb(void *data, Evas_Object *obj, void *event_info)
52 {
53         if(!obj) return;
54         if(!data) return;
55
56         VoiceData *voicedata = (VoiceData *)data;
57         Evas_Object *popup = (Evas_Object *)evas_object_data_get(obj, "popup");
58
59         voicedata->mo->discard_popup_opened = EINA_FALSE;
60
61         if (popup)
62                 elm_popup_dismiss(popup);
63 }
64
65 static void voice_input_back_agree_cb(void *data, Evas_Object *obj, void *event_info)
66 {
67         if(!obj) return;
68         if(!data) return;
69
70         VoiceData *voicedata = (VoiceData *)data;
71         Evas_Object *popup = (Evas_Object *)evas_object_data_get(obj, "popup");
72
73         voicedata->mo->discard_popup_opened = EINA_FALSE;
74
75         if (popup)
76                 elm_popup_dismiss(popup);
77
78         if(voicedata->naviframe){
79                 voice_input_back_agree = true;
80
81                 if(voicedata->disclaimer == 1){
82                         voicedata->disclaimer = 0;
83                         elm_naviframe_item_pop_to(elm_naviframe_bottom_item_get(voicedata->naviframe));
84                 } else {
85                         elm_naviframe_item_pop(voicedata->naviframe);
86                 }
87         }
88 }
89
90 static void show_discard_popup(void *data)
91 {
92         if(!data) return;
93
94         VoiceData *voicedata = (VoiceData *)data;
95
96         Evas_Object *popup = NULL;
97         Evas_Object *layout = NULL;
98         Evas_Object *btn_popup = NULL;
99         Evas_Object *icon = NULL;
100
101         std::string path = get_resource_path();
102         if (_WEARABLE)
103                 path = path + "wearable/";
104         else if (_TV)
105                 path = path + "tv/";
106         else
107                 path = path + "mobile/";
108
109         popup = elm_popup_add(voicedata->naviframe);
110         elm_object_style_set(popup, "circle");
111         eext_object_event_callback_add(popup, EEXT_CALLBACK_BACK, popup_hide_cb, NULL);
112         evas_object_smart_callback_add(popup, "dismissed", popup_hide_finished_cb, NULL);
113         evas_object_size_hint_weight_set(popup, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
114
115         layout = elm_layout_add(popup);
116         elm_layout_theme_set(layout, "layout", "popup", "content/circle/buttons2");
117         elm_object_domain_translatable_part_text_set(layout, "elm.text", PACKAGE, "WDS_WNOTI_POP_ALL_CHANGES_WILL_BE_DISCARDED");
118         elm_object_content_set(popup, layout);
119         evas_object_show(layout);
120
121         btn_popup = elm_button_add(popup);
122         elm_object_style_set(btn_popup, "popup/circle/left");
123         elm_object_part_content_set(popup, "button1", btn_popup);
124         elm_access_info_set(btn_popup, ELM_ACCESS_INFO, dgettext(PACKAGE, "IDS_ST_SK_OK"));
125         evas_object_smart_callback_add(btn_popup, "clicked", voice_input_back_disagree_cb, voicedata);
126         evas_object_data_set(btn_popup, "popup", popup);
127         evas_object_show(btn_popup);
128
129         std::string path_ic_left = path + "/images/tw_ic_popup_btn_delete.png";
130         icon = elm_image_add(btn_popup);
131         elm_image_file_set(icon, path_ic_left.c_str(), NULL);
132         evas_object_size_hint_weight_set(icon, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
133         elm_object_part_content_set(btn_popup, "elm.swallow.content", icon);
134         evas_object_show(icon);
135
136         btn_popup = elm_button_add(popup);
137         elm_object_style_set(btn_popup, "popup/circle/right");
138         elm_access_info_set(btn_popup, ELM_ACCESS_INFO, dgettext(PACKAGE, "IDS_ST_SK_OK"));
139         elm_object_part_content_set(popup, "button2", btn_popup);
140         evas_object_smart_callback_add(btn_popup, "clicked", voice_input_back_agree_cb, voicedata);
141         evas_object_data_set(btn_popup, "popup", popup);
142         evas_object_show(btn_popup);
143
144         std::string path_ic_right = path + "/images/tw_ic_popup_btn_check.png";
145         icon = elm_image_add(btn_popup);
146         elm_image_file_set(icon, path_ic_right.c_str(), NULL);
147         evas_object_size_hint_weight_set(icon, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
148         elm_object_part_content_set(btn_popup, "elm.swallow.content", icon);
149         evas_object_show(icon);
150
151         evas_object_show(popup);
152
153         voicedata->mo->discard_popup_opened = EINA_TRUE;
154 }
155
156 MoreOption::MoreOption(Evas_Object *naviframe, void* voicedata)
157         : nf(naviframe)
158         , more_option_layout(NULL)
159         , item(NULL)
160         , option_opened(EINA_FALSE)
161         , voicedata(voicedata)
162         , discard_popup_opened(EINA_FALSE) {
163         /** todo. implement constructor */
164         voice_input_back_agree = false;
165 }
166
167 MoreOption::~MoreOption() {
168         /** todo. implement destructor */
169
170         if(more_option_layout)
171         {
172                 PRINTFUNC(DLOG_DEBUG, "del callbacks");
173                 evas_object_smart_callback_del(more_option_layout, "item,clicked", moreItemClicked);
174                 evas_object_smart_callback_del(more_option_layout, "item,selected", moreItemSelected);
175
176                 evas_object_smart_callback_del(more_option_layout, "more,option,opened", moreOptionOpened);
177                 evas_object_smart_callback_del(more_option_layout, "more,option,closed", moreOptionClosed);
178         }
179 }
180
181 void MoreOption::Create() {
182         try {
183                 AddLayout();
184                 AddMorePage();
185         }
186         catch(std::exception &e) {
187                 PRINTFUNC(DLOG_ERROR, "%s", e.what());
188                 assert(0);
189         }
190 }
191
192 void MoreOption::AddLayout() {
193         /** validation */
194         if(!nf)
195                 PRINTFUNC(DLOG_ERROR, "Invalid naviframe.");
196
197         /** add layout */
198         more_option_layout = eext_more_option_add(nf);
199
200         if(!more_option_layout){
201                 PRINTFUNC(DLOG_ERROR, "It's failed to create layout");
202                 return;
203         }
204
205         evas_object_smart_callback_add(more_option_layout, "more,option,opened", moreOptionOpened, this);
206         evas_object_smart_callback_add(more_option_layout, "more,option,closed", moreOptionClosed, this);
207
208         hideCue();
209
210         evas_object_show(more_option_layout);
211 }
212
213 void MoreOption::SetContentLayout(Evas_Object *content) {
214         /**
215          * Set content layout
216          *
217          */
218         elm_object_part_content_set(more_option_layout, "elm.swallow.content", content);
219
220         Elm_Object_Item *nit = NULL;
221         const char *item_style = NULL;
222         if (_WEARABLE)
223                 item_style = "empty";
224         nit = elm_naviframe_item_push(nf, NULL, NULL, NULL, more_option_layout, item_style);
225         elm_naviframe_item_title_enabled_set(nit, EINA_FALSE, EINA_FALSE);
226
227         elm_naviframe_item_pop_cb_set(nit,
228                 [](void *data, Elm_Object_Item *it)->Eina_Bool
229                 {
230                         MoreOption *opt = (MoreOption *)data;
231                         VoiceData *vd = (VoiceData *) opt->voicedata;
232
233                         if(vd->disclaimer == 1){
234                                 PRINTFUNC(DLOG_ERROR, "pop to top"); //inb case of (selector view -> disclaimer view-> stt view)
235
236                                 if(opt->option_opened == EINA_FALSE){
237                                         PRINTFUNC(DLOG_DEBUG, "pop_cb called in STT view\n");
238
239                                         if(vd->sttmanager){
240                                                 if (vd->sttmanager->GetCurrent() == STT_STATE_CREATED ||
241                                                                    vd->sttmanager->GetCurrent() == STT_STATE_READY) {
242                                                         PRINTFUNC(DLOG_DEBUG, "STT_STATE_CREATED || STT_STATE_READY\n");
243
244                                                 } else if (vd->sttmanager->GetCurrent() == STT_STATE_RECORDING || vd->sttmanager->GetCurrent() == STT_STATE_PROCESSING) {
245                                                         PRINTFUNC(DLOG_DEBUG, "STT_STATE_RECORDING or STT_STATE_PROCESSING\n");
246                                                         try{
247                                                                 vd->sttmanager->Cancel();
248                                                         }catch(is::stt::SttException &e){
249                                                                 PRINTFUNC(DLOG_ERROR, "reason : %s", e.what());
250                                                         }
251                                                 }
252                                         }
253                                 }
254
255                                 if (voice_input_back_agree == false && !is_textblock_empty(vd)){
256                                         show_discard_popup(vd);
257                                         return EINA_FALSE;
258                                 }
259
260                                 elm_naviframe_item_pop_to(elm_naviframe_bottom_item_get(vd->naviframe));
261                                 vd->disclaimer  = 0;
262
263                                 powerUnlock();
264                                 _back_to_genlist_for_selector();
265
266                                 destroy_voice();
267
268                                 return EINA_TRUE;
269                         }
270
271                         if (opt->option_opened == EINA_FALSE){
272                                 PRINTFUNC(DLOG_DEBUG, "pop_cb called in STT view\n");
273
274                                 if (vd->sttmanager){
275                                         if (vd->sttmanager->GetCurrent() == STT_STATE_CREATED ||
276                                                            vd->sttmanager->GetCurrent() == STT_STATE_READY) {
277                                                 PRINTFUNC(DLOG_DEBUG, "STT_STATE_CREATED || STT_STATE_READY\n");
278
279                                         } else if (vd->sttmanager->GetCurrent() == STT_STATE_RECORDING || vd->sttmanager->GetCurrent() == STT_STATE_PROCESSING) {
280                                                 PRINTFUNC(DLOG_DEBUG, "STT_STATE_RECORDING or STT_STATE_PROCESSING\n");
281                                                 try{
282                                                         vd->sttmanager->Cancel();
283                                                 }catch(is::stt::SttException &e){
284                                                         PRINTFUNC(DLOG_ERROR, "reason : %s", e.what());
285                                                 }
286                                         }
287                                 }
288
289                                 if (voice_input_back_agree == false && !is_textblock_empty(vd)){
290                                         show_discard_popup(vd);
291                                         return EINA_FALSE;
292                                 }
293
294                                 _back_to_genlist_for_selector();
295                                 destroy_voice();
296                                 return EINA_TRUE;
297                         }
298                         return EINA_FALSE;
299                 }, this);
300 }
301
302 void MoreOption::Update()
303 {
304         char lang[6] = {0, };
305         strncpy(lang, ((VoiceData *)voicedata)->kbd_lang , 5);
306
307         const char* display_lang = get_lang_label(lang);
308         eext_more_option_item_part_text_set(item, "selector,sub_text", display_lang);
309
310         showCue();
311 }
312
313 Evas_Object* MoreOption::AddLanguageIcon(Evas_Object *parent) {
314         Evas_Object *icon = elm_image_add(parent);
315         if (!icon) {
316                 PRINTFUNC(DLOG_ERROR, "It's failed to add image.");
317         }
318
319         string res_path = get_resource_path();
320         if (_WEARABLE)
321                 res_path = res_path + "wearable/";
322         else if (_TV)
323                 res_path = res_path + "tv/";
324         else
325                 res_path = res_path + "mobile/";
326
327         std::string image_path = res_path + "images/prompt_ic_languages.png";
328
329         elm_image_file_set(icon, image_path.c_str(), NULL);
330         evas_object_size_hint_weight_set(icon, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
331         evas_object_size_hint_align_set(icon, EVAS_HINT_FILL, EVAS_HINT_FILL);
332         evas_object_show(icon);
333
334         return icon;
335 }
336
337 void MoreOption::AddMorePage() {
338         Evas_Object *img;
339
340         item  = eext_more_option_item_append(more_option_layout);
341
342         /* Slider content */
343         eext_more_option_item_part_text_set(item, "selector,main_text", _("WDS_IME_HEADER_INPUT_LANGUAGES_ABB"));
344
345         img = AddLanguageIcon(more_option_layout);
346
347         eext_more_option_item_part_content_set(item, "item,icon", img);
348
349         evas_object_smart_callback_add(more_option_layout, "item,clicked", moreItemClicked, NULL);
350         evas_object_smart_callback_add(more_option_layout, "item,selected", moreItemSelected , NULL);
351 }
352
353 void MoreOption::moreOptionOpened(void *data, Evas_Object * obj, void *event_info)
354 {
355         PRINTFUNC(DLOG_DEBUG, "more option is opened!!! \n");
356
357         if(!data) return;
358
359         /**
360         * if more option is completed, stt have to be stopped.
361         *
362         */
363         MoreOption *opt = (MoreOption *)data;
364         VoiceData *vd = (VoiceData *) opt->voicedata;
365
366         if(vd && vd->setup_timer){
367                 ecore_timer_del(vd->setup_timer);
368                 vd->setup_timer = NULL;
369         }
370
371         try {
372                 if (vd && vd->sttmanager && (vd->sttmanager->GetCurrent() == STT_STATE_RECORDING ||
373                         vd->sttmanager->GetCurrent() == STT_STATE_PROCESSING)) {
374                         vd->sttmanager->Cancel();
375                 }
376         }
377         catch(is::stt::SttException &e) {
378                 PRINTFUNC(DLOG_ERROR, "%s", e.what());
379         }
380
381         // Clear guide text
382         if(vd && vd->layout_main){
383                 elm_object_signal_emit((Evas_Object *)vd->layout_main, "idle,state,text,hidden", "elm");
384         }
385
386         opt->option_opened = EINA_TRUE;
387 }
388
389 void MoreOption::moreOptionClosed(void *data, Evas_Object * obj, void *event_info)
390 {
391         PRINTFUNC(DLOG_DEBUG, "more option is closed!!! \n");
392
393         if (!data) return;
394
395         MoreOption *opt = (MoreOption *)data;
396         VoiceData *vd = (VoiceData *) opt->voicedata;
397
398         if (opt->option_opened == EINA_TRUE && is_textblock_empty(vd)) {
399                 restart_listening(2.0);
400         }
401
402         if (vd)
403                 activate_circle_scroller_for_stt_textbox(vd, EINA_TRUE);
404
405         opt->option_opened = EINA_FALSE;
406 }
407
408 void MoreOption::moreItemClicked(void *data, Evas_Object * obj, void *event_info)
409 {
410         PRINTFUNC(DLOG_DEBUG, "item,clicked");
411         if(g_setting_window == NULL)
412                 create_setting_window(obj);
413 }
414
415 void MoreOption::moreItemSelected(void *data, Evas_Object * obj, void *event_info)
416 {
417         PRINTFUNC(DLOG_DEBUG, "item,selected");
418         if(!obj) return;
419
420         Eext_Object_Item *selected_item = (Eext_Object_Item *)event_info;
421
422         //for custom accessibility
423         if (elm_config_access_get())
424         {
425                 Evas_Object *panel = elm_object_part_content_get(obj, "elm.swallow.right");
426                 if (!panel) return;
427
428                 Evas_Object *rotary_selector = elm_object_content_get(panel);
429                 if (!rotary_selector) return;
430
431                 Evas_Object *content = (Evas_Object *)edje_object_part_object_get(elm_layout_edje_get(rotary_selector), "content");
432                 if (!content) return;
433
434                 Evas_Object *content_access = elm_access_object_get(content);
435                 if (!content_access) return;
436
437                 if (eext_more_option_item_part_text_get(selected_item, "selector,main_text"))
438                 {
439                         std::string text;
440                         text = text + std::string(gettext("WDS_IME_HEADER_INPUT_LANGUAGES_ABB")) + " ";
441
442                         if(eext_more_option_item_part_text_get(selected_item, "selector,sub_text"))
443                                 text = text + std::string(eext_more_option_item_part_text_get(selected_item, "selector,sub_text"));
444
445                         elm_access_info_set(content_access, ELM_ACCESS_INFO, text.c_str());
446                 }
447         }
448 }
449
450 void MoreOption::hideCue()
451 {
452         Evas_Object *panel_right = NULL;
453         if (!more_option_layout) {
454                 PRINTFUNC(DLOG_ERROR, "more_option_layout == NULL");
455                 return;
456         }
457
458         panel_right = elm_object_part_content_get(more_option_layout, "elm.swallow.right");
459         if (!panel_right) {
460                 PRINTFUNC(DLOG_ERROR, "panel_right == NULL");
461                 return;
462         }
463
464         elm_object_signal_emit(panel_right, "cue,hide", "elm");
465 }
466
467 void MoreOption::showCue()
468 {
469         Evas_Object *panel_right = NULL;
470
471         if (!more_option_layout) {
472                 PRINTFUNC(DLOG_ERROR, "more_option_layout == NULL");
473                 return;
474         }
475
476         panel_right = elm_object_part_content_get(more_option_layout, "elm.swallow.right");
477         if (!panel_right) {
478                 PRINTFUNC(DLOG_ERROR, "panel_right == NULL");
479                 return;
480         }
481
482         elm_object_signal_emit(panel_right, "cue,show", "elm");
483 }
484