1 // Copyright 2015 Samsung Electronics Co, Ltd. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "runtime/web_application.h"
9 #include <ewk_chromium.h>
16 #include "common/logger.h"
17 #include "common/command_line.h"
18 #include "common/string_utils.h"
19 #include "runtime/native_window.h"
20 #include "runtime/web_view.h"
21 #include "runtime/vibration_manager.h"
22 #include "runtime/app_control.h"
23 #include "runtime/locale_manager.h"
24 #include "runtime/application_data.h"
25 #include "runtime/resource_manager.h"
28 // TODO(sngn.lee) : It should be declare in common header
29 const char* kKeyNameBack = "back";
31 const char* kConsoleLogEnableKey = "WRT_CONSOLE_LOG_ENABLE";
32 const char* kConsoleMessageLogTag = "ConsoleMessage";
34 const char* kDebugKey = "debug";
35 const char* kPortKey = "port";
37 // TODO(wy80.choi): consider 64bits system.
38 const char* kInjectedBundlePath = "/usr/lib/libwrt-injected-bundle.so";
40 const char* kAppControlEventScript = \
42 "var __event = document.createEvent(\"CustomEvent\");\n"
43 "__event.initCustomEvent(\"appcontrol\", true, true);\n"
44 "document.dispatchEvent(__event);\n"
46 "for (var i=0; i < window.frames.length; i++)\n"
47 "{ window.frames[i].document.dispatchEvent(__event); }"
49 const char* kBackKeyEventScript = \
51 "var __event = document.createEvent(\"CustomEvent\");\n"
52 "__event.initCustomEvent(\"tizenhwkey\", true, true);\n"
53 "__event.keyName = \"back\";\n"
54 "document.dispatchEvent(__event);\n"
56 "for (var i=0; i < window.frames.length; i++)\n"
57 "{ window.frames[i].document.dispatchEvent(__event); }"
63 WebApplication::WebApplication(
64 NativeWindow* window, std::unique_ptr<ApplicationData> app_data)
67 ewk_context_(ewk_context_new_with_injected_bundle_path(
68 kInjectedBundlePath)),
70 appid_(app_data->app_id()),
71 locale_manager_(new LocaleManager()),
72 app_data_(std::move(app_data)),
74 uuid_(utils::GenerateUUID()) {
75 std::unique_ptr<char, decltype(std::free)*>
76 path {app_get_data_path(), std::free};
77 app_data_path_ = path.get();
79 resource_manager_.reset(
80 new ResourceManager(app_data_.get(), locale_manager_.get()));
81 resource_manager_->set_base_resource_path(
82 app_data_->application_path());
86 WebApplication::~WebApplication() {
88 ewk_context_delete(ewk_context_);
91 bool WebApplication::Initialize() {
93 ewk_context_cache_model_set(ewk_context_, EWK_CACHE_MODEL_DOCUMENT_BROWSER);
96 auto cookie_manager = ewk_context_cookie_manager_get(ewk_context_);
97 ewk_cookie_manager_accept_policy_set(cookie_manager,
98 EWK_COOKIE_ACCEPT_POLICY_ALWAYS);
100 // set persistent storage path
101 std::string cookie_path = data_path() + ".cookie";
102 ewk_cookie_manager_persistent_storage_set(
103 cookie_manager, cookie_path.c_str(),
104 EWK_COOKIE_PERSISTENT_STORAGE_SQLITE);
106 // vibration callback
107 auto vibration_start_callback = [](uint64_t ms, void*) {
108 platform::VibrationManager::GetInstance()->Start(static_cast<int>(ms));
110 auto vibration_stop_callback = [](void* /*user_data*/) {
111 platform::VibrationManager::GetInstance()->Stop();
113 ewk_context_vibration_client_callbacks_set(ewk_context_,
114 vibration_start_callback,
115 vibration_stop_callback,
120 // TODO(sngn.lee): Find the path of certificate file
121 // ewk_context_certificate_file_set(ewk_context_, .... );
123 // TODO(sngn.lee): find the proxy url
124 // ewk_context_proxy_uri_set(ewk_context_, ... );
126 // TODO(sngn.lee): set default from config.xml
127 // locale_manager_->SetDefaultLocale(const string & locale);
129 // TODO(sngn.lee): Download interface
130 // ewk_context_did_start_download_callback_set
132 // TODO(sngn.lee): always enable "mediastream,record"
133 // TODO(sngn.lee): always enable "encrypted,database"
134 // TODO(sngn.lee): check csp element in config.xml and enable - "csp"
135 // TODO(sngn.lee): Check Backround support and enable - "visibility,suspend"
136 // TODO(sngn.lee): Check Backround support and enable - "background,music"
137 // TODO(sngn.lee): Check setting rotation value and enable "rotation,lock"
138 // TODO(sngn.lee): always enable "fullscreen"
139 // TODO(sngn.lee): check "sound-mode":"exclusive" - in tizen:setting
140 // and enable - "sound,mode"
141 // TODO(sngn.lee): check "background-vibration":"enable" - in tizen:setting
142 // and enable - "background,vibration"
147 void WebApplication::Launch(std::unique_ptr<wrt::AppControl> appcontrol) {
148 resource_manager_->set_app_control(appcontrol.get());
149 WebView* view = new WebView(window_, ewk_context_);
152 // send widget info to injected bundle
153 // TODO(wy80.choi): ewk_send_widget_info should be fixed to receive uuid of
154 // application instead of widget_id.
155 // Currently, uuid is passed as encoded_bundle argument temporarily.
156 // ewk_send_widget_info(ewk_context_, 1,
157 // elm_config_scale_get(),
158 // elm_theme_get(NULL),
161 // view->LoadUrl("file:///home/owner/apps_rw/33CFo0eFJe/"
162 // "33CFo0eFJe.annex/index.html");
163 view->LoadUrl(resource_manager_->GetStartURL());
165 view_stack_.push_front(view);
166 window_->SetContent(view->evas_object());
168 // TODO(sngn.lee): below code only debug code
169 auto callback = [](void*, Evas*, Evas_Object* obj,
172 evas_object_geometry_get(obj, &x, &y, &w, &h);
173 LoggerD("resize ! (%d, %d, %d, %d)\n", x, y, w, h);
175 evas_object_event_callback_add(view->evas_object(),
176 EVAS_CALLBACK_RESIZE,
179 if (appcontrol->data(kDebugKey) == "true") {
181 LaunchInspector(appcontrol.get());
184 // TODO(sngn.lee): check the below code location.
185 // in Wearable, webkit can render contents before show window
186 // but Mobile, webkit can't render contents before show window
190 received_appcontrol_ = std::move(appcontrol);
193 void WebApplication::AppControl(std::unique_ptr<wrt::AppControl> appcontrol) {
194 // TODO(sngn.lee): Set the injected bundle into extension process
195 resource_manager_->set_app_control(appcontrol.get());
200 WebView* view = new WebView(window_, ewk_context_);
203 view->LoadUrl(resource_manager_->GetStartURL());
204 view_stack_.push_front(view);
205 window_->SetContent(view->evas_object());
208 SendAppControlEvent();
211 if (!debug_mode_ && appcontrol->data(kDebugKey) == "true") {
213 LaunchInspector(appcontrol.get());
216 received_appcontrol_ = std::move(appcontrol);
219 void WebApplication::SendAppControlEvent() {
220 auto it = view_stack_.begin();
221 while (it != view_stack_.end()) {
222 (*it)->EvalJavascript(kAppControlEventScript);
226 void WebApplication::ClearViewStack() {
227 window_->SetContent(NULL);
228 auto it = view_stack_.begin();
229 for ( ; it != view_stack_.end(); ++it) {
236 void WebApplication::Resume() {
237 if (view_stack_.size() > 0 && view_stack_.front() != NULL)
238 view_stack_.front()->SetVisibility(true);
240 if (app_data_->setting_info() != NULL &&
241 app_data_->setting_info()->background_support_enabled()) {
245 auto it = view_stack_.begin();
246 for ( ; it != view_stack_.end(); ++it) {
251 void WebApplication::Suspend() {
252 if (view_stack_.size() > 0 && view_stack_.front() != NULL)
253 view_stack_.front()->SetVisibility(false);
255 if (app_data_->setting_info() != NULL &&
256 app_data_->setting_info()->background_support_enabled()) {
257 LoggerD("gone background (backgroud support enabed)");
261 auto it = view_stack_.begin();
262 for ( ; it != view_stack_.end(); ++it) {
267 void WebApplication::OnCreatedNewWebView(WebView* /*view*/, WebView* new_view) {
268 if (view_stack_.size() > 0 && view_stack_.front() != NULL)
269 view_stack_.front()->SetVisibility(false);
271 SetupWebView(new_view);
272 view_stack_.push_front(new_view);
273 window_->SetContent(new_view->evas_object());
276 void WebApplication::OnClosedWebView(WebView * view) {
277 if (view_stack_.size() == 0)
280 WebView* current = view_stack_.front();
281 if (current == view) {
282 view_stack_.pop_front();
284 auto found = std::find(view_stack_.begin(), view_stack_.end(), view);
285 if (found != view_stack_.end()) {
286 view_stack_.erase(found);
290 if (view_stack_.size() == 0) {
291 if (terminator_ != NULL) {
294 } else if (current != view_stack_.front()) {
295 view_stack_.front()->SetVisibility(true);
296 window_->SetContent(view_stack_.front()->evas_object());
299 // Delete after the callback context(for ewk view) was not used
300 ecore_idler_add([](void* view) {
301 WebView* obj = static_cast<WebView*>(view);
307 void WebApplication::OnReceivedWrtMessage(
309 Ewk_IPC_Wrt_Message_Data* /*message*/) {
310 // TODO(wy80.choi) : Handle messages from injected bundle?
311 // ex. SendRuntimeMessage to hide / exit application.
314 void WebApplication::OnOrientationLock(WebView* view,
316 int preferred_rotation) {
317 if (view_stack_.size() == 0)
320 // Only top-most view can set the orientation relate operation
321 if (view_stack_.front() != view)
324 auto orientaion_setting = app_data_->setting_info() != NULL ?
325 app_data_->setting_info()->screen_orientation() :
326 // TODO(sngn.lee): check default value
327 wgt::parse::SettingInfo::AUTO;
328 if (orientaion_setting != wgt::parse::SettingInfo::AUTO) {
333 window_->SetRotationLock(preferred_rotation);
335 window_->SetAutoRotation();
339 void WebApplication::OnHardwareKey(WebView* view, const std::string& keyname) {
340 bool enabled = app_data_->setting_info() != NULL ?
341 app_data_->setting_info()->hwkey_enabled() :
343 if (enabled && kKeyNameBack == keyname) {
344 view->EvalJavascript(kBackKeyEventScript);
348 void WebApplication::OnLanguageChanged() {
349 locale_manager_->UpdateSystemLocale();
350 ewk_context_cache_clear(ewk_context_);
351 auto it = view_stack_.begin();
352 for ( ; it != view_stack_.end(); ++it) {
357 void WebApplication::OnConsoleMessage(const std::string& msg, int level) {
358 static bool enabled = (getenv(kConsoleLogEnableKey) != NULL);
359 if (debug_mode_ || enabled) {
360 int dlog_level = DLOG_DEBUG;
362 case EWK_CONSOLE_MESSAGE_LEVEL_WARNING:
363 dlog_level = DLOG_WARN;
365 case EWK_CONSOLE_MESSAGE_LEVEL_ERROR:
366 dlog_level = DLOG_ERROR;
369 dlog_level = DLOG_DEBUG;
372 LOG_(LOG_ID_MAIN, dlog_level, kConsoleMessageLogTag, "%s", msg.c_str());
376 void WebApplication::OnLowMemory() {
377 ewk_context_cache_clear(ewk_context_);
378 ewk_context_notify_low_memory(ewk_context_);
381 bool WebApplication::OnContextMenuDisabled(WebView* /*view*/) {
382 return !(app_data_->setting_info() != NULL ?
383 app_data_->setting_info()->context_menu_enabled() :
387 void WebApplication::OnLoadStart(WebView* /*view*/) {
388 LoggerD("LoadStart");
390 void WebApplication::OnLoadFinished(WebView* /*view*/) {
391 LoggerD("LoadFinished");
393 void WebApplication::OnRendered(WebView* /*view*/) {
397 void WebApplication::LaunchInspector(wrt::AppControl* appcontrol) {
399 ewk_context_inspector_server_start(ewk_context_, 0);
400 std::stringstream ss;
402 std::map<std::string, std::vector<std::string>> data;
403 data[kPortKey] = { ss.str() };
404 appcontrol->Reply(data);
407 void WebApplication::SetupWebView(WebView* view) {
408 view->SetEventListener(this);
409 // TODO(sngn.lee): set UserAgent to WebView
410 // TODO(sngn.lee): set CSP
413 bool WebApplication::OnDidNavigation(WebView* view, const std::string& url) {
414 // TODO(sngn.lee): scheme handling
415 // except(file , http, https, app) pass to appcontrol and return false