[WRTjs] Refactor popup 85/307885/6
authorzhaosy <shiyusy.zhao@samsung.com>
Wed, 13 Mar 2024 06:02:23 +0000 (14:02 +0800)
committerDongHyun Song <dh81.song@samsung.com>
Tue, 19 Mar 2024 05:09:39 +0000 (05:09 +0000)
Separate tv feature from common popup

Change-Id: I689617cc36d4acf8bafe611a49f87c769063433e
Signed-off-by: zhaosy <shiyusy.zhao@samsung.com>
wrt/filenames.gni
wrt/src/browser/api/wrt_api_web_contents.cc
wrt/src/browser/popup.cc
wrt/src/browser/popup.h [changed mode: 0755->0644]
wrt/src/browser/tv/popup_tv.cc [new file with mode: 0644]
wrt/src/browser/tv/popup_tv.h [new file with mode: 0644]

index a97eb3c..a08c7bb 100644 (file)
@@ -198,6 +198,8 @@ wrt_lib_sources_tv = [
   "src/browser/tv/mounter.h",
   "src/browser/tv/native_web_runtime_delegate_tv.cc",
   "src/browser/tv/native_web_runtime_delegate_tv.h",
+  "src/browser/tv/popup_tv.cc",
+  "src/browser/tv/popup_tv.h",
   "src/browser/tv/splash_screen_delegate_tv.cc",
   "src/browser/tv/splash_screen_delegate_tv.h",
   "src/browser/tv/tv_window_manager.cc",
index 1552034..b7867b3 100644 (file)
@@ -16,8 +16,8 @@
 #include "wrt/src/common/application_data.h"
 
 #if BUILDFLAG(IS_TIZEN_TV)
-#include "wrt/src/browser/popup.h"
 #include "wrt/src/browser/tv/native_web_runtime_delegate_tv.h"
+#include "wrt/src/browser/tv/popup_tv.h"
 #endif
 
 namespace wrt {
@@ -142,10 +142,10 @@ void WebContents::ShowMicOpenedNotification(bool show) {
     auto pcm_title =
         NativeWebRuntimeDelegateTV::GetInstance().GetAppTitleForPcm();
     if (!pcm_title.empty()) {
-      Popup::ShowVoiceRecognitionToast(pcm_title);
+      PopupTV::ShowVoiceRecognitionToast(pcm_title);
     }
   } else {
-    Popup::HideVoiceRecognitionToast();
+    PopupTV::HideVoiceRecognitionToast();
   }
 }
 #endif
index bcba234..bffb948 100644 (file)
 #include "base/logging.h"
 #include "tizen_src/chromium_impl/tizen/system_info.h"
 #include "wrt/src/browser/popup_string.h"
-#include "wrt/src/browser/wrt_native_window.h"
 #include "wrt/src/common/constants.h"
 
 #if BUILDFLAG(IS_TIZEN_TV)
-#include <aul.h>
-#include <algorithm>
-#include <memory>
-
-#include "base/files/file_path.h"
-#include "base/path_service.h"
-#include "tizen_src/chromium_impl/content/common/paths_efl.h"
-#include "wrt/src/common/locale_manager.h"
+#include "wrt/src/browser/tv/popup_tv.h"
 #endif
 
 namespace wrt {
@@ -49,99 +41,34 @@ const char* kSignalEdit = "elm,action,hide,search_icon";
 const char* kStyleButton = "popup";
 const char* kStyleButtonLeft = "popup";
 const char* kStyleButtonRight = "popup";
+const char* kStyleCheck = "multiline";
 const char* kStyleEditPw = "editfield/password/popup";
 const char* kStyleLabel = "popup/default";
-
-#if BUILDFLAG(IS_TIZEN_TV)
-const char* kStateFocused = "focused";
-const char* kStyleCheck = "C_Checkbox_WhiteText";
-const char* kStylePopup = "C_PopupBasic_WhiteBottom";
-const char* kWRTEdjeFile = "wrtjs_tizen.edj";
-const unsigned int kTimeout = 60;  // second
-#else
-const char* kStyleCheck = "default";
 const char* kStylePopup = "default";
 const char* kWRTEdjePath = "/usr/share/edje/wrtjs/wrtjs_tizen.edj";
-#endif
-
-std::vector<std::unique_ptr<Popup>> opened_popups;
-
-#if BUILDFLAG(IS_TIZEN_TV)
-int syspopup_pid_ = -1;
-
-static void EntryKeyDownCallback(void* data,
-                                 Evas* e,
-                                 Evas_Object* obj,
-                                 void* event_info) {
-  if (!data || !obj || !event_info) {
-    LOG(ERROR) << "parameter is nullptr";
-    return;
-  }
-  Evas_Event_Key_Down* ev = static_cast<Evas_Event_Key_Down*>(event_info);
-  if (!ev->key) {
-    LOG(ERROR) << "ev->key is nullptr";
-    return;
-  }
-  Popup* popup = static_cast<Popup*>(data);
-  popup->HandleEntryKeyDownEvent(ev->key);
-}
-#endif
 
-static Evas_Object* AddCheckBox(Evas_Object* parent) {
+static Evas_Object* AddCheckBox(Evas_Object* parent, const std::string& style) {
   Evas_Object* check = elm_check_add(parent);
-  elm_object_style_set(check, kStyleCheck);
+  elm_object_style_set(check, style.c_str());
   evas_object_size_hint_align_set(check, EVAS_HINT_FILL, EVAS_HINT_FILL);
-#if !BUILDFLAG(IS_TIZEN_TV)
-  elm_object_style_set(check, "multiline");
-#endif  // IS_TIZEN_TV
   elm_check_state_set(check, EINA_FALSE);
   return check;
 }
 
-Evas_Object* CreateNewWindow(Evas_Object* parent) {
-  if (!parent)
-    return nullptr;
-
-  Evas_Object* window = elm_win_add(parent, "WRTPopupWindow", ELM_WIN_BASIC);
-  if (!window)
-    return nullptr;
-
-  elm_win_title_set(window, "WRTPopupWindow");
-  elm_win_alpha_set(window, EINA_TRUE);
-  elm_win_indicator_mode_set(window, ELM_WIN_INDICATOR_HIDE);
-
-  if (elm_win_wm_rotation_supported_get(parent)) {
-    int rots[] = {0, 90, 180, 270};
-    elm_win_wm_rotation_available_rotations_set(window, rots, 4);
-  }
-
-  int window_width, window_height;
-  elm_win_screen_size_get(window, nullptr, nullptr, &window_width,
-                          &window_height);
-  evas_object_resize(window, window_width, window_height);
-
-  elm_win_conformant_set(window, EINA_TRUE);
-  Evas_Object* conformant = elm_conformant_add(window);
-  evas_object_size_hint_weight_set(conformant, EVAS_HINT_EXPAND,
-                                   EVAS_HINT_EXPAND);
-  elm_win_resize_object_add(window, conformant);
-  evas_object_show(conformant);
-
-  return window;
-}
-
 }  // namespace
 
 // static
+std::vector<std::unique_ptr<Popup>> Popup::opened_popups_;
+
+// static
 std::unique_ptr<Popup> Popup::CreatePopup(Evas_Object* window) {
 #if BUILDFLAG(IS_TIZEN_TV)
-  window = CreateNewWindow(window);
+  return PopupTV::CreatePopup(window);
 #endif
 
   Evas_Object* popup = elm_popup_add(window);
-#if !BUILDFLAG(IS_TIZEN_TV)
+
   elm_popup_align_set(popup, ELM_NOTIFY_ALIGN_FILL, 1.0);
-#endif
   evas_object_size_hint_weight_set(popup, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
   elm_object_style_set(popup, kStylePopup);
 
@@ -149,90 +76,43 @@ std::unique_ptr<Popup> Popup::CreatePopup(Evas_Object* window) {
   elm_box_padding_set(box, 0, 10);
   evas_object_size_hint_weight_set(box, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
   evas_object_size_hint_align_set(box, EVAS_HINT_FILL, EVAS_HINT_FILL);
-
-#if BUILDFLAG(IS_TIZEN_TV)
-  Evas_Object* table = elm_table_add(popup);
-  if (!table) {
-    LOG(ERROR) << "Failed to Create Table";
-    return nullptr;
-  }
-
-  Evas_Object* rect = evas_object_rectangle_add(evas_object_evas_get(table));
-  evas_object_color_set(rect, 0, 0, 0, 0);
-  const double real_width = 800;
-  const double real_height = 300;
-  evas_object_size_hint_min_set(rect, real_width, real_height);
-  evas_object_size_hint_max_set(rect, real_width, real_height);
-  elm_table_pack(table, rect, 0, 0, 1, 1);
-  elm_table_pack(table, box, 0, 0, 1, 1);
-  elm_object_content_set(popup, table);
-#else
   elm_object_part_content_set(popup, "default", box);
-#endif  // IS_TIZEN_TV
   evas_object_show(box);
 
   evas_object_event_callback_add(
       popup, EVAS_CALLBACK_RESIZE, nullptr, nullptr);
 
-  auto* instance = new Popup(popup, box, IsTvProfile() ? window : nullptr);
+  auto* instance = new Popup(popup, box);
   return std::unique_ptr<Popup>(instance);
 }
 
 // static
 void Popup::Show(std::unique_ptr<Popup> popup) {
-  if (popup->window_)
-    evas_object_show(popup->window_);
-  evas_object_show(popup->popup_);
-
-#if BUILDFLAG(IS_TIZEN_TV)
-  (popup->timeout_timer_)
-      .Start(FROM_HERE, base::Seconds(kTimeout), popup.get(), &Popup::Timeout);
-#endif
-  opened_popups.push_back(std::move(popup));
+  if (popup)
+    popup->ShowInternal(std::move(popup));
 }
 
 // static
 void Popup::ForceCloseAllPopup() {
-  for (auto& popup : opened_popups) {
-    // will cause modification of opened_popups
+  for (auto& popup : opened_popups_) {
+    // will cause modification of opened_popups_
     popup->Hide();
   }
-  opened_popups.clear();
+  opened_popups_.clear();
 }
 
-Popup::Popup(Evas_Object* popup, Evas_Object* box, Evas_Object* window)
-    : popup_(popup), box_(box), window_(window) {
-  if (window_) {
-    auto main_native_window = WRTNativeWindow::GetMainNativeWindow();
-    if (main_native_window)
-      main_native_window->AddObserver(this);
-  }
-}
+Popup::Popup(Evas_Object* popup, Evas_Object* box) : popup_(popup), box_(box) {}
 
 Popup::~Popup() {
-  if (window_) {
-    auto main_native_window = WRTNativeWindow::GetMainNativeWindow();
-    if (main_native_window)
-      main_native_window->RemoveObserver(this);
-    evas_object_del(window_);
-    window_ = popup_ = nullptr;
-  } else if (popup_) {
+  if (popup_) {
     evas_object_del(popup_);
     popup_ = nullptr;
   }
 }
 
-void Popup::OnWindowShow() {
-  if (window_) {
-    evas_object_show(window_);
-    elm_win_raise(window_);
-  }
-}
-
-void Popup::OnWindowHide() {
-  if (window_) {
-    evas_object_hide(window_);
-  }
+void Popup::ShowInternal(std::unique_ptr<Popup> popup) {
+  evas_object_show(popup->popup_);
+  opened_popups_.push_back(std::move(popup));
 }
 
 void Popup::SetButtonType(ButtonType type) {
@@ -260,27 +140,6 @@ void Popup::SetButtonType(ButtonType type) {
                            kContentButton2, kStyleButtonRight);
       break;
   }
-
-#if BUILDFLAG(IS_TIZEN_TV)
-  if (button2_) {
-    auto focused_callback = [](void* instance, Evas_Object* button,
-                              void* /*eventInfo*/) {
-      for (auto iterator = opened_popups.begin();
-           iterator != opened_popups.end(); ++iterator) {
-        if (iterator->get() == instance) {
-          if (((*iterator)->timeout_timer_).IsRunning())
-            ((*iterator)->timeout_timer_).Reset();
-          return;
-        }
-      }
-      LOG(ERROR) << "Fail to get Popup instance";
-    };
-    evas_object_smart_callback_add(button1_, kStateFocused, focused_callback,
-                                   this);
-    evas_object_smart_callback_add(button2_, kStateFocused, focused_callback,
-                                   this);
-  }
-#endif
 }
 
 Evas_Object* Popup::AddButton(const char* id, const char* content,
@@ -292,11 +151,11 @@ Evas_Object* Popup::AddButton(const char* id, const char* content,
   elm_object_part_content_set(popup_, content, button);
 
   auto callback = [](void* data, Evas_Object* button, void* /*eventInfo*/) {
-    for (auto iterator = opened_popups.begin();
-         iterator != opened_popups.end(); ++iterator) {
+    for (auto iterator = opened_popups_.begin();
+         iterator != opened_popups_.end(); ++iterator) {
       if (iterator->get() == data) {
         std::unique_ptr<Popup> popup(iterator->release());
-        opened_popups.erase(iterator);
+        opened_popups_.erase(iterator);
         popup->HandleButtonClickEvent(button);
         return;
       }
@@ -330,11 +189,6 @@ Evas_Object* Popup::AddEntry(const char* id, Popup::EntryType type) {
   elm_object_signal_emit(entry, kSignalEdit, "");
   elm_entry_autocapital_type_set(entry, ELM_AUTOCAPITAL_TYPE_NONE);
 
-#if BUILDFLAG(IS_TIZEN_TV)
-  evas_object_event_callback_add(entry, EVAS_CALLBACK_KEY_DOWN,
-                                 EntryKeyDownCallback, this);
-#endif
-
   if (type == Popup::EntryType::Edit) {
     evas_object_smart_callback_add(entry, kStateActivated,
                                    [](void*, Evas_Object* obj, void*) {
@@ -347,14 +201,9 @@ Evas_Object* Popup::AddEntry(const char* id, Popup::EntryType type) {
   evas_object_show(entry);
 
   Evas_Object* layout = elm_layout_add(box_);
-#if BUILDFLAG(IS_TIZEN_TV)
-  base::FilePath edje_dir;
-  base::PathService::Get(PathsEfl::EDJE_RESOURCE_DIR, &edje_dir);
-  elm_layout_file_set(layout, (edje_dir.value() + "/" + kWRTEdjeFile).c_str(),
-                      "PopupTextEntrySet");
-#else
-  elm_layout_file_set(layout, kWRTEdjePath, "PopupTextEntrySet");
-#endif
+  if (edjeFilePath_.empty())
+    edjeFilePath_ = kWRTEdjePath;
+  elm_layout_file_set(layout, edjeFilePath_.c_str(), "PopupTextEntrySet");
 
   Evas_Object* rectangle = evas_object_rectangle_add(
                                evas_object_evas_get(layout));
@@ -376,7 +225,9 @@ Evas_Object* Popup::AddEntry(const char* id, Popup::EntryType type) {
 }
 
 void Popup::SetCheckBox(const std::string& id) {
-  check_box_ = AddCheckBox(box_);
+  if (checkStyle_.empty())
+    checkStyle_ = kStyleCheck;
+  check_box_ = AddCheckBox(box_, checkStyle_);
   if (!id.empty()) {
     elm_object_domain_translatable_part_text_set(
         check_box_, kContentText,
@@ -446,98 +297,4 @@ void Popup::HandleButtonClickEvent(Evas_Object* button) {
   std::move(handler_).Run(is_positive, is_checked, entry1, entry2);
 }
 
-#if BUILDFLAG(IS_TIZEN_TV)
-void Popup::ShowVoiceRecognitionToast(const std::string& app_title) {
-  bool font_except = false;
-  std::string lang = LocaleManager::GetSystemLocale();
-  lang = lang.substr(0, lang.find_first_of("-"));
-
-  const std::vector<std::string> except_lang = {
-      {"zh"}, {"sl"}, {"fa"}, {"kok"}, {"am"}, {"my"}, {"km"}, {"ckb"}, {"bh"},
-  };
-
-  if (std::find(except_lang.begin(), except_lang.end(), lang) !=
-      except_lang.end()) {
-    LOG(INFO) << "locale-font exception. no font re-setting";
-    font_except = true;
-  }
-
-  const std::string mic_icon = popup_string::GetText(popup_string::kMicIcon);
-  const std::string button_search = popup_string::GetTextAndReplace(
-      popup_string::kPressButtonSearch, mic_icon);
-  const std::string speech_Recog = popup_string::GetTextAndReplace(
-      popup_string::kSpeechRecognition, app_title);
-
-  const std::string font_size_start =
-      font_except ? "" : "<font=SamsungOneUI_400 font_size=22>";
-  const std::string font_size_end = font_except ? "" : "</font>";
-  const std::string popup_text =
-      "<font=SamsungOneUI_700 font_size=32>"
-      "<align=center>" +
-      button_search +
-      "<br>"
-      "</align>"
-      "</font>" +
-      font_size_start + "<align=center>" + speech_Recog + "</align>" +
-      font_size_end;
-
-  // combine the notification text
-  LOG(INFO) << "toast popup text : " << popup_text;
-
-  // launch toast
-  auto bundle_for_popup = std::unique_ptr<bundle, decltype(bundle_free)*>(
-      bundle_create(), bundle_free);
-  if (!bundle_for_popup.get()) {
-    LOG(ERROR) << "bundle_create failed";
-    return;
-  }
-
-  int bundle_ret = bundle_add_str(bundle_for_popup.get(), "type", "toast");
-  if (BUNDLE_ERROR_NONE != bundle_ret) {
-    LOG(ERROR) << "bundle_add_str failed: " << bundle_ret;
-    return;
-  }
-  bundle_ret =
-      bundle_add_str(bundle_for_popup.get(), "text", popup_text.c_str());
-  if (BUNDLE_ERROR_NONE != bundle_ret) {
-    LOG(ERROR) << "bundle_add_str failed: " << bundle_ret;
-    return;
-  }
-  bundle_ret = bundle_add_str(bundle_for_popup.get(), "timeout", "3");
-  if (BUNDLE_ERROR_NONE != bundle_ret) {
-    LOG(ERROR) << "bundle_add_str failed: " << bundle_ret;
-    return;
-  }
-
-  syspopup_pid_ =
-      aul_launch_app("org.tizen.alert-syspopup", bundle_for_popup.get());
-  if (syspopup_pid_ < 0)
-    LOG(ERROR) << "launch toast fail, return code is " << syspopup_pid_;
-}
-
-void Popup::HideVoiceRecognitionToast() {
-  LOG(INFO) << "hide toast, pid is " << syspopup_pid_;
-  if (syspopup_pid_ > 0) {
-    int kill_ret = aul_pause_app("org.tizen.alert-syspopup");
-    if (kill_ret != AUL_R_OK)
-      LOG(ERROR) << "hide toast fail, return code is " << kill_ret;
-    syspopup_pid_ = -1;
-  }
-}
-
-void Popup::HandleEntryKeyDownEvent(const std::string& key) {
-  if (key == "Cancel") {
-    elm_object_focus_set(button1_, EINA_TRUE);
-  } else if (key == "Select") {
-    elm_object_focus_set(button2_, EINA_TRUE);
-  }
-}
-
-void Popup::Timeout() {
-  LOG(INFO) << "popup is timeout";
-  // button1 is negative, button2 is positive
-  elm_object_signal_emit(button1_, "elm,action,click", "elm");
-}
-#endif
-
 }  // namespace wrt
old mode 100755 (executable)
new mode 100644 (file)
index f700de0..a49b883
 #define BROWSER_POPUP_H_
 
 #include <Elementary.h>
-#include <Evas.h>
 
 #include <string>
 
 #include "base/functional/callback.h"
-#include "electron/shell/browser/native_window_observer.h"
-
-#if BUILDFLAG(IS_TIZEN_TV)
-#include "base/timer/timer.h"
-#endif
 
 namespace wrt {
 
-class Popup : electron::NativeWindowObserver {
+class Popup {
  public:
   enum class ButtonType {
     OkButton,
@@ -49,12 +43,13 @@ class Popup : electron::NativeWindowObserver {
   static void Show(std::unique_ptr<Popup> popup);
   static void ForceCloseAllPopup();
 
-  ~Popup();
+  virtual ~Popup();
+
+  virtual void SetButtonType(ButtonType type);
+  virtual void SetCheckBox(const std::string& id);
 
-  void SetButtonType(ButtonType type);
   void SetFirstEntry(const std::string& id, EntryType type);
   void SetSecondEntry(const std::string& id, EntryType type);
-  void SetCheckBox(const std::string& id);
   void SetTitle(const std::string& id);
   void SetBody(const std::string& id);
 
@@ -65,42 +60,33 @@ class Popup : electron::NativeWindowObserver {
 
   void SetResultHandler(ResultHandler handler);
 
-#if BUILDFLAG(IS_TIZEN_TV)
-  static void ShowVoiceRecognitionToast(const std::string& app_title);
-  static void HideVoiceRecognitionToast();
+ protected:
+  Popup(Evas_Object* popup, Evas_Object* box);
 
-  void HandleEntryKeyDownEvent(const std::string& key);
-#endif
+  virtual Evas_Object* AddEntry(const char* id, Popup::EntryType type);
+  virtual void ShowInternal(std::unique_ptr<Popup> popup);
 
- private:
-  Popup(Evas_Object* popup, Evas_Object* box, Evas_Object* window);
+  Evas_Object* popup_;
+  Evas_Object* button2_ = nullptr;
+  Evas_Object* button1_ = nullptr;
+
+  std::string edjeFilePath_ = std::string();
+  std::string checkStyle_ = std::string();
+
+  static std::vector<std::unique_ptr<Popup>> opened_popups_;
 
+ private:
   Evas_Object* AddButton(const char* id, const char* content,
                          const char* button_style);
-  Evas_Object* AddEntry(const char* id, Popup::EntryType type);
 
   void HandleButtonClickEvent(Evas_Object* button);
 
   void Hide();
 
-  // electron::NativeWindowObserver
-  void OnWindowHide() override;
-  void OnWindowShow() override;
-
-#if BUILDFLAG(IS_TIZEN_TV)
-  void Timeout();
-
-  base::OneShotTimer timeout_timer_;
-#endif
-
-  Evas_Object* popup_;
   Evas_Object* box_;
-  Evas_Object* button1_ = nullptr;
-  Evas_Object* button2_ = nullptr;
   Evas_Object* entry1_ = nullptr;
   Evas_Object* entry2_ = nullptr;
   Evas_Object* check_box_ = nullptr;
-  Evas_Object* window_ = nullptr;
 
   ResultHandler handler_;
 };
diff --git a/wrt/src/browser/tv/popup_tv.cc b/wrt/src/browser/tv/popup_tv.cc
new file mode 100644 (file)
index 0000000..b205c95
--- /dev/null
@@ -0,0 +1,303 @@
+/*
+ * Copyright (c) 2024 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *    Licensed under the Apache License, Version 2.0 (the "License");
+ *    you may not use this file except in compliance with the License.
+ *    You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing, software
+ *    distributed under the License is distributed on an "AS IS" BASIS,
+ *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *    See the License for the specific language governing permissions and
+ *    limitations under the License.
+ */
+
+#include "wrt/src/browser/tv/popup_tv.h"
+
+#include <aul.h>
+
+#include "base/files/file_path.h"
+#include "base/path_service.h"
+#include "tizen_src/chromium_impl/content/common/paths_efl.h"
+#include "wrt/src/browser/popup_string.h"
+#include "wrt/src/browser/wrt_native_window.h"
+#include "wrt/src/common/locale_manager.h"
+
+namespace wrt {
+
+namespace {
+
+const char* kStateFocused = "focused";
+const char* kStyleCheck = "C_Checkbox_WhiteText";
+const char* kStylePopup = "C_PopupBasic_WhiteBottom";
+const char* kWRTEdjeFile = "wrtjs_tizen.edj";
+
+const unsigned int kTimeout = 60;  // second
+
+int syspopup_pid_ = -1;
+
+Evas_Object* CreateNewWindow(Evas_Object* parent) {
+  if (!parent)
+    return nullptr;
+
+  Evas_Object* window = elm_win_add(parent, "WRTPopupWindow", ELM_WIN_BASIC);
+  if (!window)
+    return nullptr;
+
+  elm_win_title_set(window, "WRTPopupWindow");
+  elm_win_alpha_set(window, EINA_TRUE);
+  elm_win_indicator_mode_set(window, ELM_WIN_INDICATOR_HIDE);
+
+  if (elm_win_wm_rotation_supported_get(parent)) {
+    int rots[] = {0, 90, 180, 270};
+    elm_win_wm_rotation_available_rotations_set(window, rots, 4);
+  }
+
+  int window_width, window_height;
+  elm_win_screen_size_get(window, nullptr, nullptr, &window_width,
+                          &window_height);
+  evas_object_resize(window, window_width, window_height);
+
+  elm_win_conformant_set(window, EINA_TRUE);
+  Evas_Object* conformant = elm_conformant_add(window);
+  evas_object_size_hint_weight_set(conformant, EVAS_HINT_EXPAND,
+                                   EVAS_HINT_EXPAND);
+  elm_win_resize_object_add(window, conformant);
+  evas_object_show(conformant);
+
+  return window;
+}
+
+static void EntryKeyDownCallback(void* data,
+                                 Evas* e,
+                                 Evas_Object* obj,
+                                 void* event_info) {
+  if (!data || !obj || !event_info) {
+    LOG(ERROR) << "parameter is nullptr";
+    return;
+  }
+  Evas_Event_Key_Down* ev = static_cast<Evas_Event_Key_Down*>(event_info);
+  if (!ev->key) {
+    LOG(ERROR) << "ev->key is nullptr";
+    return;
+  }
+  PopupTV* popup = static_cast<PopupTV*>(data);
+  popup->HandleEntryKeyDownEvent(ev->key);
+}
+
+}  // namespace
+
+// static
+std::unique_ptr<PopupTV> PopupTV::CreatePopup(Evas_Object* window) {
+  window = CreateNewWindow(window);
+
+  Evas_Object* popup = elm_popup_add(window);
+  evas_object_size_hint_weight_set(popup, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
+  elm_object_style_set(popup, kStylePopup);
+
+  Evas_Object* box = elm_box_add(popup);
+  elm_box_padding_set(box, 0, 10);
+  evas_object_size_hint_weight_set(box, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
+  evas_object_size_hint_align_set(box, EVAS_HINT_FILL, EVAS_HINT_FILL);
+
+  Evas_Object* table = elm_table_add(popup);
+  if (!table) {
+    LOG(ERROR) << "Failed to Create Table";
+    return nullptr;
+  }
+
+  Evas_Object* rect = evas_object_rectangle_add(evas_object_evas_get(table));
+  evas_object_color_set(rect, 0, 0, 0, 0);
+  const double real_width = 800;
+  const double real_height = 300;
+  evas_object_size_hint_min_set(rect, real_width, real_height);
+  evas_object_size_hint_max_set(rect, real_width, real_height);
+  elm_table_pack(table, rect, 0, 0, 1, 1);
+  elm_table_pack(table, box, 0, 0, 1, 1);
+  elm_object_content_set(popup, table);
+  evas_object_show(box);
+
+  evas_object_event_callback_add(popup, EVAS_CALLBACK_RESIZE, nullptr, nullptr);
+
+  auto* instance = new PopupTV(popup, box, window);
+  return std::unique_ptr<PopupTV>(instance);
+}
+
+// static
+void PopupTV::ShowVoiceRecognitionToast(const std::string& app_title) {
+  bool font_except = false;
+  std::string lang = LocaleManager::GetSystemLocale();
+  lang = lang.substr(0, lang.find_first_of("-"));
+
+  const std::vector<std::string> except_lang = {
+      {"zh"}, {"sl"}, {"fa"}, {"kok"}, {"am"}, {"my"}, {"km"}, {"ckb"}, {"bh"},
+  };
+
+  if (std::find(except_lang.begin(), except_lang.end(), lang) !=
+      except_lang.end()) {
+    LOG(INFO) << "locale-font exception. no font re-setting";
+    font_except = true;
+  }
+
+  const std::string mic_icon = popup_string::GetText(popup_string::kMicIcon);
+  const std::string button_search = popup_string::GetTextAndReplace(
+      popup_string::kPressButtonSearch, mic_icon);
+  const std::string speech_Recog = popup_string::GetTextAndReplace(
+      popup_string::kSpeechRecognition, app_title);
+
+  const std::string font_size_start =
+      font_except ? "" : "<font=SamsungOneUI_400 font_size=22>";
+  const std::string font_size_end = font_except ? "" : "</font>";
+  const std::string popup_text =
+      "<font=SamsungOneUI_700 font_size=32>"
+      "<align=center>" +
+      button_search +
+      "<br>"
+      "</align>"
+      "</font>" +
+      font_size_start + "<align=center>" + speech_Recog + "</align>" +
+      font_size_end;
+
+  // combine the notification text
+  LOG(INFO) << "toast popup text : " << popup_text;
+
+  // launch toast
+  auto bundle_for_popup = std::unique_ptr<bundle, decltype(bundle_free)*>(
+      bundle_create(), bundle_free);
+  if (!bundle_for_popup.get()) {
+    LOG(ERROR) << "bundle_create failed";
+    return;
+  }
+
+  int bundle_ret = bundle_add_str(bundle_for_popup.get(), "type", "toast");
+  if (BUNDLE_ERROR_NONE != bundle_ret) {
+    LOG(ERROR) << "bundle_add_str failed: " << bundle_ret;
+    return;
+  }
+  bundle_ret =
+      bundle_add_str(bundle_for_popup.get(), "text", popup_text.c_str());
+  if (BUNDLE_ERROR_NONE != bundle_ret) {
+    LOG(ERROR) << "bundle_add_str failed: " << bundle_ret;
+    return;
+  }
+  bundle_ret = bundle_add_str(bundle_for_popup.get(), "timeout", "3");
+  if (BUNDLE_ERROR_NONE != bundle_ret) {
+    LOG(ERROR) << "bundle_add_str failed: " << bundle_ret;
+    return;
+  }
+
+  syspopup_pid_ =
+      aul_launch_app("org.tizen.alert-syspopup", bundle_for_popup.get());
+  if (syspopup_pid_ < 0)
+    LOG(ERROR) << "launch toast fail, return code is " << syspopup_pid_;
+}
+
+// static
+void PopupTV::HideVoiceRecognitionToast() {
+  LOG(INFO) << "hide toast, pid is " << syspopup_pid_;
+  if (syspopup_pid_ > 0) {
+    int kill_ret = aul_pause_app("org.tizen.alert-syspopup");
+    if (kill_ret != AUL_R_OK)
+      LOG(ERROR) << "hide toast fail, return code is " << kill_ret;
+    syspopup_pid_ = -1;
+  }
+}
+
+PopupTV::PopupTV(Evas_Object* popup, Evas_Object* box, Evas_Object* window)
+    : Popup(popup, box), window_(window) {
+  auto main_native_window = WRTNativeWindow::GetMainNativeWindow();
+  if (main_native_window)
+    main_native_window->AddObserver(this);
+}
+
+PopupTV::~PopupTV() {
+  auto main_native_window = WRTNativeWindow::GetMainNativeWindow();
+  if (main_native_window)
+    main_native_window->RemoveObserver(this);
+
+  if (window_) {
+    evas_object_del(window_);
+    window_ = nullptr;
+  }
+}
+
+void PopupTV::ShowInternal(std::unique_ptr<Popup> popup) {
+  auto popup_tv = static_cast<PopupTV*>(popup.get());
+  if (popup_tv->window_)
+    evas_object_show(popup_tv->window_);
+  evas_object_show(popup_tv->popup_);
+
+  (popup_tv->timeout_timer_)
+      .Start(FROM_HERE, base::Seconds(kTimeout), popup_tv, &PopupTV::Timeout);
+  opened_popups_.push_back(std::move(popup));
+}
+
+void PopupTV::OnWindowShow() {
+  if (window_) {
+    evas_object_show(window_);
+    elm_win_raise(window_);
+  }
+}
+
+void PopupTV::OnWindowHide() {
+  if (window_) {
+    evas_object_hide(window_);
+  }
+}
+
+void PopupTV::SetButtonType(ButtonType type) {
+  Popup::SetButtonType(type);
+
+  if (button2_) {
+    auto focused_callback = [](void* instance, Evas_Object* button,
+                               void* /*eventInfo*/) {
+      for (auto iterator = opened_popups_.begin();
+           iterator != opened_popups_.end(); ++iterator) {
+        if (iterator->get() == instance) {
+          if ((static_cast<PopupTV*>(instance)->timeout_timer_).IsRunning())
+            (static_cast<PopupTV*>(instance)->timeout_timer_).Reset();
+          return;
+        }
+      }
+      LOG(ERROR) << "Fail to get Popup instance";
+    };
+    evas_object_smart_callback_add(button1_, kStateFocused, focused_callback,
+                                   this);
+    evas_object_smart_callback_add(button2_, kStateFocused, focused_callback,
+                                   this);
+  }
+}
+
+void PopupTV::SetCheckBox(const std::string& id) {
+  checkStyle_ = kStyleCheck;
+  Popup::SetCheckBox(id);
+}
+
+Evas_Object* PopupTV::AddEntry(const char* id, Popup::EntryType type) {
+  base::FilePath edje_dir;
+  base::PathService::Get(PathsEfl::EDJE_RESOURCE_DIR, &edje_dir);
+  edjeFilePath_ = edje_dir.value() + "/" + kWRTEdjeFile;
+
+  Evas_Object* entry = Popup::AddEntry(id, type);
+  evas_object_event_callback_add(entry, EVAS_CALLBACK_KEY_DOWN,
+                                 EntryKeyDownCallback, this);
+  return entry;
+}
+
+void PopupTV::HandleEntryKeyDownEvent(const std::string& key) {
+  if (key == "Cancel") {
+    elm_object_focus_set(button1_, EINA_TRUE);
+  } else if (key == "Select") {
+    elm_object_focus_set(button2_, EINA_TRUE);
+  }
+}
+
+void PopupTV::Timeout() {
+  LOG(INFO) << "popup is timeout";
+  // button1 is negative, button2 is positive
+  elm_object_signal_emit(button1_, "elm,action,click", "elm");
+}
+
+}  // namespace wrt
diff --git a/wrt/src/browser/tv/popup_tv.h b/wrt/src/browser/tv/popup_tv.h
new file mode 100644 (file)
index 0000000..f1b5152
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2024 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *    Licensed under the Apache License, Version 2.0 (the "License");
+ *    you may not use this file except in compliance with the License.
+ *    You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing, software
+ *    distributed under the License is distributed on an "AS IS" BASIS,
+ *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *    See the License for the specific language governing permissions and
+ *    limitations under the License.
+ */
+
+#ifndef BROWSER_POPUP_TV_H_
+#define BROWSER_POPUP_TV_H_
+
+#include "base/timer/timer.h"
+#include "electron/shell/browser/native_window_observer.h"
+#include "wrt/src/browser/popup.h"
+
+namespace wrt {
+
+class PopupTV : public Popup, public electron::NativeWindowObserver {
+ public:
+  ~PopupTV() override;
+
+  static std::unique_ptr<PopupTV> CreatePopup(Evas_Object* window);
+  static void ShowVoiceRecognitionToast(const std::string& app_title);
+  static void HideVoiceRecognitionToast();
+
+  // Popup
+  void SetButtonType(ButtonType type) override;
+
+  void HandleEntryKeyDownEvent(const std::string& key);
+
+ private:
+  explicit PopupTV(Evas_Object* popup, Evas_Object* box, Evas_Object* window);
+
+  // Popup
+  Evas_Object* AddEntry(const char* id, Popup::EntryType type) override;
+  void SetCheckBox(const std::string& id) override;
+  void ShowInternal(std::unique_ptr<Popup> popup) override;
+
+  // electron::NativeWindowObserver
+  void OnWindowHide() override;
+  void OnWindowShow() override;
+
+  void Timeout();
+
+  base::OneShotTimer timeout_timer_;
+  Evas_Object* window_ = nullptr;
+};
+
+}  // namespace wrt
+
+#endif  // BROWSER_POPUP_TV_H_