[WRTjs] Refactor popup
[platform/framework/web/chromium-efl.git] / wrt / src / browser / tv / popup_tv.cc
1 /*
2  * Copyright (c) 2024 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 "wrt/src/browser/tv/popup_tv.h"
18
19 #include <aul.h>
20
21 #include "base/files/file_path.h"
22 #include "base/path_service.h"
23 #include "tizen_src/chromium_impl/content/common/paths_efl.h"
24 #include "wrt/src/browser/popup_string.h"
25 #include "wrt/src/browser/wrt_native_window.h"
26 #include "wrt/src/common/locale_manager.h"
27
28 namespace wrt {
29
30 namespace {
31
32 const char* kStateFocused = "focused";
33 const char* kStyleCheck = "C_Checkbox_WhiteText";
34 const char* kStylePopup = "C_PopupBasic_WhiteBottom";
35 const char* kWRTEdjeFile = "wrtjs_tizen.edj";
36
37 const unsigned int kTimeout = 60;  // second
38
39 int syspopup_pid_ = -1;
40
41 Evas_Object* CreateNewWindow(Evas_Object* parent) {
42   if (!parent)
43     return nullptr;
44
45   Evas_Object* window = elm_win_add(parent, "WRTPopupWindow", ELM_WIN_BASIC);
46   if (!window)
47     return nullptr;
48
49   elm_win_title_set(window, "WRTPopupWindow");
50   elm_win_alpha_set(window, EINA_TRUE);
51   elm_win_indicator_mode_set(window, ELM_WIN_INDICATOR_HIDE);
52
53   if (elm_win_wm_rotation_supported_get(parent)) {
54     int rots[] = {0, 90, 180, 270};
55     elm_win_wm_rotation_available_rotations_set(window, rots, 4);
56   }
57
58   int window_width, window_height;
59   elm_win_screen_size_get(window, nullptr, nullptr, &window_width,
60                           &window_height);
61   evas_object_resize(window, window_width, window_height);
62
63   elm_win_conformant_set(window, EINA_TRUE);
64   Evas_Object* conformant = elm_conformant_add(window);
65   evas_object_size_hint_weight_set(conformant, EVAS_HINT_EXPAND,
66                                    EVAS_HINT_EXPAND);
67   elm_win_resize_object_add(window, conformant);
68   evas_object_show(conformant);
69
70   return window;
71 }
72
73 static void EntryKeyDownCallback(void* data,
74                                  Evas* e,
75                                  Evas_Object* obj,
76                                  void* event_info) {
77   if (!data || !obj || !event_info) {
78     LOG(ERROR) << "parameter is nullptr";
79     return;
80   }
81   Evas_Event_Key_Down* ev = static_cast<Evas_Event_Key_Down*>(event_info);
82   if (!ev->key) {
83     LOG(ERROR) << "ev->key is nullptr";
84     return;
85   }
86   PopupTV* popup = static_cast<PopupTV*>(data);
87   popup->HandleEntryKeyDownEvent(ev->key);
88 }
89
90 }  // namespace
91
92 // static
93 std::unique_ptr<PopupTV> PopupTV::CreatePopup(Evas_Object* window) {
94   window = CreateNewWindow(window);
95
96   Evas_Object* popup = elm_popup_add(window);
97   evas_object_size_hint_weight_set(popup, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
98   elm_object_style_set(popup, kStylePopup);
99
100   Evas_Object* box = elm_box_add(popup);
101   elm_box_padding_set(box, 0, 10);
102   evas_object_size_hint_weight_set(box, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
103   evas_object_size_hint_align_set(box, EVAS_HINT_FILL, EVAS_HINT_FILL);
104
105   Evas_Object* table = elm_table_add(popup);
106   if (!table) {
107     LOG(ERROR) << "Failed to Create Table";
108     return nullptr;
109   }
110
111   Evas_Object* rect = evas_object_rectangle_add(evas_object_evas_get(table));
112   evas_object_color_set(rect, 0, 0, 0, 0);
113   const double real_width = 800;
114   const double real_height = 300;
115   evas_object_size_hint_min_set(rect, real_width, real_height);
116   evas_object_size_hint_max_set(rect, real_width, real_height);
117   elm_table_pack(table, rect, 0, 0, 1, 1);
118   elm_table_pack(table, box, 0, 0, 1, 1);
119   elm_object_content_set(popup, table);
120   evas_object_show(box);
121
122   evas_object_event_callback_add(popup, EVAS_CALLBACK_RESIZE, nullptr, nullptr);
123
124   auto* instance = new PopupTV(popup, box, window);
125   return std::unique_ptr<PopupTV>(instance);
126 }
127
128 // static
129 void PopupTV::ShowVoiceRecognitionToast(const std::string& app_title) {
130   bool font_except = false;
131   std::string lang = LocaleManager::GetSystemLocale();
132   lang = lang.substr(0, lang.find_first_of("-"));
133
134   const std::vector<std::string> except_lang = {
135       {"zh"}, {"sl"}, {"fa"}, {"kok"}, {"am"}, {"my"}, {"km"}, {"ckb"}, {"bh"},
136   };
137
138   if (std::find(except_lang.begin(), except_lang.end(), lang) !=
139       except_lang.end()) {
140     LOG(INFO) << "locale-font exception. no font re-setting";
141     font_except = true;
142   }
143
144   const std::string mic_icon = popup_string::GetText(popup_string::kMicIcon);
145   const std::string button_search = popup_string::GetTextAndReplace(
146       popup_string::kPressButtonSearch, mic_icon);
147   const std::string speech_Recog = popup_string::GetTextAndReplace(
148       popup_string::kSpeechRecognition, app_title);
149
150   const std::string font_size_start =
151       font_except ? "" : "<font=SamsungOneUI_400 font_size=22>";
152   const std::string font_size_end = font_except ? "" : "</font>";
153   const std::string popup_text =
154       "<font=SamsungOneUI_700 font_size=32>"
155       "<align=center>" +
156       button_search +
157       "<br>"
158       "</align>"
159       "</font>" +
160       font_size_start + "<align=center>" + speech_Recog + "</align>" +
161       font_size_end;
162
163   // combine the notification text
164   LOG(INFO) << "toast popup text : " << popup_text;
165
166   // launch toast
167   auto bundle_for_popup = std::unique_ptr<bundle, decltype(bundle_free)*>(
168       bundle_create(), bundle_free);
169   if (!bundle_for_popup.get()) {
170     LOG(ERROR) << "bundle_create failed";
171     return;
172   }
173
174   int bundle_ret = bundle_add_str(bundle_for_popup.get(), "type", "toast");
175   if (BUNDLE_ERROR_NONE != bundle_ret) {
176     LOG(ERROR) << "bundle_add_str failed: " << bundle_ret;
177     return;
178   }
179   bundle_ret =
180       bundle_add_str(bundle_for_popup.get(), "text", popup_text.c_str());
181   if (BUNDLE_ERROR_NONE != bundle_ret) {
182     LOG(ERROR) << "bundle_add_str failed: " << bundle_ret;
183     return;
184   }
185   bundle_ret = bundle_add_str(bundle_for_popup.get(), "timeout", "3");
186   if (BUNDLE_ERROR_NONE != bundle_ret) {
187     LOG(ERROR) << "bundle_add_str failed: " << bundle_ret;
188     return;
189   }
190
191   syspopup_pid_ =
192       aul_launch_app("org.tizen.alert-syspopup", bundle_for_popup.get());
193   if (syspopup_pid_ < 0)
194     LOG(ERROR) << "launch toast fail, return code is " << syspopup_pid_;
195 }
196
197 // static
198 void PopupTV::HideVoiceRecognitionToast() {
199   LOG(INFO) << "hide toast, pid is " << syspopup_pid_;
200   if (syspopup_pid_ > 0) {
201     int kill_ret = aul_pause_app("org.tizen.alert-syspopup");
202     if (kill_ret != AUL_R_OK)
203       LOG(ERROR) << "hide toast fail, return code is " << kill_ret;
204     syspopup_pid_ = -1;
205   }
206 }
207
208 PopupTV::PopupTV(Evas_Object* popup, Evas_Object* box, Evas_Object* window)
209     : Popup(popup, box), window_(window) {
210   auto main_native_window = WRTNativeWindow::GetMainNativeWindow();
211   if (main_native_window)
212     main_native_window->AddObserver(this);
213 }
214
215 PopupTV::~PopupTV() {
216   auto main_native_window = WRTNativeWindow::GetMainNativeWindow();
217   if (main_native_window)
218     main_native_window->RemoveObserver(this);
219
220   if (window_) {
221     evas_object_del(window_);
222     window_ = nullptr;
223   }
224 }
225
226 void PopupTV::ShowInternal(std::unique_ptr<Popup> popup) {
227   auto popup_tv = static_cast<PopupTV*>(popup.get());
228   if (popup_tv->window_)
229     evas_object_show(popup_tv->window_);
230   evas_object_show(popup_tv->popup_);
231
232   (popup_tv->timeout_timer_)
233       .Start(FROM_HERE, base::Seconds(kTimeout), popup_tv, &PopupTV::Timeout);
234   opened_popups_.push_back(std::move(popup));
235 }
236
237 void PopupTV::OnWindowShow() {
238   if (window_) {
239     evas_object_show(window_);
240     elm_win_raise(window_);
241   }
242 }
243
244 void PopupTV::OnWindowHide() {
245   if (window_) {
246     evas_object_hide(window_);
247   }
248 }
249
250 void PopupTV::SetButtonType(ButtonType type) {
251   Popup::SetButtonType(type);
252
253   if (button2_) {
254     auto focused_callback = [](void* instance, Evas_Object* button,
255                                void* /*eventInfo*/) {
256       for (auto iterator = opened_popups_.begin();
257            iterator != opened_popups_.end(); ++iterator) {
258         if (iterator->get() == instance) {
259           if ((static_cast<PopupTV*>(instance)->timeout_timer_).IsRunning())
260             (static_cast<PopupTV*>(instance)->timeout_timer_).Reset();
261           return;
262         }
263       }
264       LOG(ERROR) << "Fail to get Popup instance";
265     };
266     evas_object_smart_callback_add(button1_, kStateFocused, focused_callback,
267                                    this);
268     evas_object_smart_callback_add(button2_, kStateFocused, focused_callback,
269                                    this);
270   }
271 }
272
273 void PopupTV::SetCheckBox(const std::string& id) {
274   checkStyle_ = kStyleCheck;
275   Popup::SetCheckBox(id);
276 }
277
278 Evas_Object* PopupTV::AddEntry(const char* id, Popup::EntryType type) {
279   base::FilePath edje_dir;
280   base::PathService::Get(PathsEfl::EDJE_RESOURCE_DIR, &edje_dir);
281   edjeFilePath_ = edje_dir.value() + "/" + kWRTEdjeFile;
282
283   Evas_Object* entry = Popup::AddEntry(id, type);
284   evas_object_event_callback_add(entry, EVAS_CALLBACK_KEY_DOWN,
285                                  EntryKeyDownCallback, this);
286   return entry;
287 }
288
289 void PopupTV::HandleEntryKeyDownEvent(const std::string& key) {
290   if (key == "Cancel") {
291     elm_object_focus_set(button1_, EINA_TRUE);
292   } else if (key == "Select") {
293     elm_object_focus_set(button2_, EINA_TRUE);
294   }
295 }
296
297 void PopupTV::Timeout() {
298   LOG(INFO) << "popup is timeout";
299   // button1 is negative, button2 is positive
300   elm_object_signal_emit(button1_, "elm,action,click", "elm");
301 }
302
303 }  // namespace wrt