2 * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 #include "runtime/browser/web_application.h"
29 #include "common/application_data.h"
30 #include "common/app_db.h"
31 #include "common/app_control.h"
32 #include "common/command_line.h"
33 #include "common/locale_manager.h"
34 #include "common/logger.h"
35 #include "common/profiler.h"
36 #include "common/resource_manager.h"
37 #include "common/string_utils.h"
38 #include "runtime/browser/native_window.h"
39 #include "runtime/browser/notification_manager.h"
40 #include "runtime/browser/popup.h"
41 #include "runtime/browser/popup_string.h"
42 #include "runtime/browser/vibration_manager.h"
43 #include "runtime/browser/web_view.h"
44 #include "runtime/browser/splash_screen.h"
45 #include "extensions/common/xwalk_extension_server.h"
47 #ifndef INJECTED_BUNDLE_PATH
48 #error INJECTED_BUNDLE_PATH is not set.
54 const char* kKeyNameBack = "back";
55 const char* kKeyNameMenu = "menu";
57 const char* kConsoleLogEnableKey = "WRT_CONSOLE_LOG_ENABLE";
58 const char* kConsoleMessageLogTag = "ConsoleMessage";
60 const char* kVerboseKey = "verbose";
61 const char* kPortKey = "port";
63 const char* kAppControlEventScript =
65 "var __event = document.createEvent(\"CustomEvent\");\n"
66 "__event.initCustomEvent(\"appcontrol\", true, true, null);\n"
67 "document.dispatchEvent(__event);\n"
69 "for (var i=0; i < window.frames.length; i++)\n"
70 "{ window.frames[i].document.dispatchEvent(__event); }"
72 const char* kBackKeyEventScript =
74 "var __event = document.createEvent(\"CustomEvent\");\n"
75 "__event.initCustomEvent(\"tizenhwkey\", true, true, null);\n"
76 "__event.keyName = \"back\";\n"
77 "document.dispatchEvent(__event);\n"
79 "for (var i=0; i < window.frames.length; i++)\n"
80 "{ window.frames[i].document.dispatchEvent(__event); }"
82 const char* kMenuKeyEventScript =
84 "var __event = document.createEvent(\"CustomEvent\");\n"
85 "__event.initCustomEvent(\"tizenhwkey\", true, true, null);\n"
86 "__event.keyName = \"menu\";\n"
87 "document.dispatchEvent(__event);\n"
89 "for (var i=0; i < window.frames.length; i++)\n"
90 "{ window.frames[i].document.dispatchEvent(__event); }"
92 const char* kAmbientTickEventScript =
94 "var __event = document.createEvent(\"CustomEvent\");\n"
95 "__event.initCustomEvent(\"timetick\", true, true);\n"
96 "document.dispatchEvent(__event);\n"
98 "for (var i=0; i < window.frames.length; i++)\n"
99 "{ window.frames[i].document.dispatchEvent(__event); }"
101 const char* kFullscreenPrivilege = "http://tizen.org/privilege/fullscreen";
102 const char* kFullscreenFeature = "fullscreen";
103 const char* kNotificationPrivilege = "http://tizen.org/privilege/notification";
104 const char* kLocationPrivilege = "http://tizen.org/privilege/location";
105 const char* kStoragePrivilege = "http://tizen.org/privilege/unlimitedstorage";
106 const char* kUsermediaPrivilege = "http://tizen.org/privilege/mediacapture";
107 const char* kNotiIconFile = "noti_icon.png";
108 const char* kFileScheme = "file://";
110 const char* kVisibilitySuspendFeature = "visibility,suspend";
111 const char* kMediastreamRecordFeature = "mediastream,record";
112 const char* kEncryptedDatabaseFeature = "encrypted,database";
113 const char* kRotationLockFeature = "rotation,lock";
114 const char* kBackgroundMusicFeature = "background,music";
115 const char* kSoundModeFeature = "sound,mode";
116 const char* kBackgroundVibrationFeature = "background,vibration";
117 const char* kCSPFeature = "csp";
119 const char* kGeolocationPermissionPrefix = "__WRT_GEOPERM_";
120 const char* kNotificationPermissionPrefix = "__WRT_NOTIPERM_";
121 const char* kQuotaPermissionPrefix = "__WRT_QUOTAPERM_";
122 const char* kCertificateAllowPrefix = "__WRT_CERTIPERM_";
123 const char* kUsermediaPermissionPrefix = "__WRT_USERMEDIAPERM_";
124 const char* kDBPrivateSection = "private";
126 const char* kDefaultCSPRule =
127 "default-src *; script-src 'self'; style-src 'self'; object-src 'none';";
128 const char* kResWgtPath = "res/wgt/";
129 const char* kAppControlMain = "http://tizen.org/appcontrol/operation/main";
131 bool FindPrivilege(common::ApplicationData* app_data,
132 const std::string& privilege) {
133 if (app_data->permissions_info().get() == NULL) return false;
134 auto it = app_data->permissions_info()->GetAPIPermissions().begin();
135 auto end = app_data->permissions_info()->GetAPIPermissions().end();
136 for (; it != end; ++it) {
137 if (*it == privilege) return true;
142 static void SendDownloadRequest(const std::string& url) {
143 common::AppControl request;
144 request.set_operation(APP_CONTROL_OPERATION_DOWNLOAD);
145 request.set_uri(url);
146 request.LaunchRequest();
149 static void InitializeNotificationCallback(Ewk_Context* ewk_context,
150 WebApplication* app) {
151 auto show = [](Ewk_Context*, Ewk_Notification* noti, void* user_data) {
152 WebApplication* self = static_cast<WebApplication*>(user_data);
153 if (self == NULL) return;
154 uint64_t id = ewk_notification_id_get(noti);
155 std::string title(ewk_notification_title_get(noti)
156 ? ewk_notification_title_get(noti)
159 ewk_notification_body_get(noti) ? ewk_notification_body_get(noti) : "");
160 std::string icon_path = self->data_path() + "/" + kNotiIconFile;
161 if (!ewk_notification_icon_save_as_png(noti, icon_path.c_str())) {
164 if (NotificationManager::GetInstance()->Show(id, title, body, icon_path))
165 ewk_notification_showed(id);
167 auto hide = [](Ewk_Context*, uint64_t noti_id, void*) {
168 NotificationManager::GetInstance()->Hide(noti_id);
169 ewk_notification_closed(noti_id, EINA_FALSE);
171 ewk_context_notification_callbacks_set(ewk_context, show, hide, app);
174 static Eina_Bool ExitAppIdlerCallback(void* data) {
175 WebApplication* app = static_cast<WebApplication*>(data);
178 std::list<WebView*> vstack = app->view_stack();
179 auto it = vstack.begin();
181 for (; it != vstack.end(); ++it) {
182 vstack.front()->SetVisibility(false);
184 ewk_view_page_close((*it)->evas_object());
188 return ECORE_CALLBACK_CANCEL;
191 static bool ClearCookie(Ewk_Context* ewk_context) {
192 Ewk_Cookie_Manager* cookie_manager =
193 ewk_context_cookie_manager_get(ewk_context);
194 if (!cookie_manager) {
195 LOGGER(ERROR) << "Fail to get cookie manager";
198 ewk_cookie_manager_cookies_clear(cookie_manager);
202 static bool ProcessWellKnownScheme(const std::string& url) {
203 if (common::utils::StartsWith(url, "file:") ||
204 common::utils::StartsWith(url, "app:") ||
205 common::utils::StartsWith(url, "data:") ||
206 common::utils::StartsWith(url, "http:") ||
207 common::utils::StartsWith(url, "https:") ||
208 common::utils::StartsWith(url, "widget:") ||
209 common::utils::StartsWith(url, "about:") ||
210 common::utils::StartsWith(url, "blob:")) {
214 std::unique_ptr<common::AppControl> request(
215 common::AppControl::MakeAppcontrolFromURL(url));
216 if (request.get() == NULL || !request->LaunchRequest()) {
217 LOGGER(ERROR) << "Fail to send appcontrol request";
218 SLoggerE("Fail to send appcontrol request [%s]", url.c_str());
221 // Should return true, to stop the WebEngine progress step about this URL
227 std::vector<unsigned> ParseTizenVersion(const std::string& tizen_string) {
228 std::vector<unsigned> version(3, 0);
229 for (unsigned i = 0, index = 0; i < tizen_string.size(); i++) {
231 if (isdigit(tizen_string[i]) && index < version.size())
232 version[index++] = atoi(&tizen_string[i]);
234 return std::vector<unsigned>(3, 0);
235 } else if (tizen_string[i] != '.')
236 return std::vector<unsigned>(3, 0);
241 WebApplication::WebApplication(
242 NativeWindow* window,
243 common::ApplicationData* app_data)
246 verbose_mode_(false),
247 lang_changed_mode_(false),
249 ewk_context_new_with_injected_bundle_path(INJECTED_BUNDLE_PATH)),
250 has_ownership_of_ewk_context_(true),
251 is_terminated_by_callback_(false),
253 appid_(app_data->app_id()),
255 locale_manager_(new common::LocaleManager()),
260 WebApplication::WebApplication(
261 NativeWindow* window,
262 common::ApplicationData* app_data,
263 Ewk_Context* context)
266 verbose_mode_(false),
267 ewk_context_(context),
268 has_ownership_of_ewk_context_(false),
269 is_terminated_by_callback_(false),
271 appid_(app_data->app_id()),
273 locale_manager_(new common::LocaleManager()),
278 WebApplication::~WebApplication() {
279 window_->SetContent(NULL);
280 auto it = view_stack_.begin();
281 for (; it != view_stack_.end(); ++it) {
286 if (ewk_context_ && has_ownership_of_ewk_context_)
287 ewk_context_delete(ewk_context_);
290 bool WebApplication::Initialize() {
292 std::unique_ptr<char, decltype(std::free)*> path{app_get_data_path(),
294 app_data_path_ = path.get();
296 if (app_data_->setting_info() != NULL &&
297 app_data_->setting_info()->screen_orientation() ==
298 wgt::parse::SettingInfo::ScreenOrientation::AUTO) {
299 ewk_context_tizen_extensible_api_string_set(ewk_context_,
300 kRotationLockFeature, true);
301 window_->SetAutoRotation();
302 } else if (app_data_->setting_info() != NULL &&
303 app_data_->setting_info()->screen_orientation() ==
304 wgt::parse::SettingInfo::ScreenOrientation::PORTRAIT) {
305 window_->SetRotationLock(NativeWindow::ScreenOrientation::PORTRAIT_PRIMARY);
306 } else if (app_data_->setting_info() != NULL &&
307 app_data_->setting_info()->screen_orientation() ==
308 wgt::parse::SettingInfo::ScreenOrientation::LANDSCAPE) {
309 window_->SetRotationLock(
310 NativeWindow::ScreenOrientation::LANDSCAPE_PRIMARY);
313 splash_screen_.reset(new SplashScreen(
314 window_, app_data_->splash_screen_info(), app_data_->application_path()));
315 resource_manager_.reset(
316 new common::ResourceManager(app_data_, locale_manager_.get()));
317 resource_manager_->set_base_resource_path(app_data_->application_path());
319 auto extension_server = extensions::XWalkExtensionServer::GetInstance();
320 extension_server->SetupIPC(ewk_context_);
323 ewk_context_cache_model_set(ewk_context_, EWK_CACHE_MODEL_DOCUMENT_BROWSER);
326 auto cookie_manager = ewk_context_cookie_manager_get(ewk_context_);
327 ewk_cookie_manager_accept_policy_set(cookie_manager,
328 EWK_COOKIE_ACCEPT_POLICY_ALWAYS);
330 // set persistent storage path
331 std::string cookie_path = data_path() + ".cookie";
332 ewk_cookie_manager_persistent_storage_set(
333 cookie_manager, cookie_path.c_str(),
334 EWK_COOKIE_PERSISTENT_STORAGE_SQLITE);
336 // vibration callback
337 auto vibration_start_callback = [](uint64_t ms, void*) {
338 platform::VibrationManager::GetInstance()->Start(static_cast<int>(ms));
340 auto vibration_stop_callback = [](void* /*user_data*/) {
341 platform::VibrationManager::GetInstance()->Stop();
343 ewk_context_vibration_client_callbacks_set(
344 ewk_context_, vibration_start_callback, vibration_stop_callback, NULL);
346 auto download_callback = [](const char* downloadUrl, void* /*data*/) {
347 SendDownloadRequest(downloadUrl);
349 ewk_context_did_start_download_callback_set(ewk_context_, download_callback,
351 InitializeNotificationCallback(ewk_context_, this);
353 if (FindPrivilege(app_data_, kFullscreenPrivilege)) {
354 ewk_context_tizen_extensible_api_string_set(ewk_context_,
355 kFullscreenFeature, true);
358 if (app_data_->setting_info() != NULL &&
359 app_data_->setting_info()->background_support_enabled()) {
360 ewk_context_tizen_extensible_api_string_set(
361 ewk_context_, kVisibilitySuspendFeature, true);
362 ewk_context_tizen_extensible_api_string_set(ewk_context_,
363 kBackgroundMusicFeature, true);
365 ewk_context_tizen_extensible_api_string_set(
366 ewk_context_, kVisibilitySuspendFeature, false);
367 ewk_context_tizen_extensible_api_string_set(ewk_context_,
368 kBackgroundMusicFeature, false);
370 ewk_context_tizen_extensible_api_string_set(ewk_context_,
371 kMediastreamRecordFeature, true);
372 ewk_context_tizen_extensible_api_string_set(ewk_context_,
373 kEncryptedDatabaseFeature, true);
375 if (app_data_->setting_info() != NULL &&
376 app_data_->setting_info()->sound_mode() ==
377 wgt::parse::SettingInfo::SoundMode::EXCLUSIVE) {
378 ewk_context_tizen_extensible_api_string_set(ewk_context_, kSoundModeFeature,
382 if (app_data_->setting_info() != NULL &&
383 app_data_->setting_info()->background_vibration()) {
384 ewk_context_tizen_extensible_api_string_set(
385 ewk_context_, kBackgroundVibrationFeature, true);
388 if (app_data_->widget_info() != NULL &&
389 !app_data_->widget_info()->default_locale().empty()) {
390 locale_manager_->SetDefaultLocale(
391 app_data_->widget_info()->default_locale());
394 if (app_data_->widget_info() != NULL &&
395 app_data_->widget_info()->view_modes() == "fullscreen") {
396 window_->FullScreen(true);
399 if (app_data_->csp_info() != NULL || app_data_->csp_report_info() != NULL ||
400 app_data_->allowed_navigation_info() != NULL) {
401 security_model_version_ = 2;
402 if (app_data_->csp_info() == NULL ||
403 app_data_->csp_info()->security_rules().empty()) {
404 csp_rule_ = kDefaultCSPRule;
406 csp_rule_ = app_data_->csp_info()->security_rules();
408 if (app_data_->csp_report_info() != NULL &&
409 !app_data_->csp_report_info()->security_rules().empty()) {
410 csp_report_rule_ = app_data_->csp_report_info()->security_rules();
412 ewk_context_tizen_extensible_api_string_set(ewk_context_, kCSPFeature,
415 security_model_version_ = 1;
418 #ifdef MANUAL_ROTATE_FEATURE_SUPPORT
419 // Set manual rotation
420 window_->EnableManualRotation(true);
421 #endif // MANUAL_ROTATE_FEATURE_SUPPORT
426 void WebApplication::SetupTizenVersion() {
427 if (app_data_->tizen_application_info() != NULL &&
428 !app_data_->tizen_application_info()->required_version().empty()) {
429 std::string tizen_version = app_data_->tizen_application_info()->required_version();
430 std::vector<unsigned> parsed_tizen_version = ParseTizenVersion(tizen_version);
431 m_tizenCompatibilitySettings.m_major = parsed_tizen_version[0];
432 m_tizenCompatibilitySettings.m_minor = parsed_tizen_version[1];
433 m_tizenCompatibilitySettings.m_release = parsed_tizen_version[2];
437 bool WebApplication::tizenWebKitCompatibilityEnabled() const {
438 return m_tizenCompatibilitySettings.tizenWebKitCompatibilityEnabled();
441 void WebApplication::Launch(std::unique_ptr<common::AppControl> appcontrol) {
442 // send widget info to injected bundle
443 ewk_context_tizen_app_id_set(ewk_context_, appid_.c_str());
448 WebView* view = new WebView(window_, ewk_context_);
450 SetupWebViewTizenApplicationInfo(view);
452 std::unique_ptr<common::ResourceManager::Resource> res =
453 resource_manager_->GetStartResource(appcontrol.get());
454 view->SetDefaultEncoding(res->encoding());
456 STEP_PROFILE_END("OnCreate -> URL Set");
457 STEP_PROFILE_START("URL Set -> Rendered");
459 window_->SetContent(view->evas_object());
461 #ifdef PROFILE_MOBILE
462 // rotate and resize window forcibily for landscape mode.
463 // window rotate event is generated after window show. so
464 // when app get width and height from viewport, wrong value can be returned.
465 if (app_data_->setting_info()->screen_orientation() ==
466 wgt::parse::SettingInfo::ScreenOrientation::LANDSCAPE) {
467 LOGGER(DEBUG) << "rotate and resize window for landscape mode";
468 elm_win_rotation_with_resize_set(window_->evas_object(), 270);
469 evas_norender(evas_object_evas_get(window_->evas_object()));
471 #endif // PROFILE_MOBILE
473 view->LoadUrl(res->uri(), res->mime());
474 view_stack_.push_front(view);
476 #ifdef PROFILE_WEARABLE
477 // ewk_view_bg_color_set is not working at webview initialization.
478 if (app_data_->app_type() == common::ApplicationData::WATCH) {
479 view->SetBGColor(0, 0, 0, 255);
481 #endif // PROFILE_WEARABLE
483 if (appcontrol->data(AUL_K_DEBUG) == "1") {
485 LaunchInspector(appcontrol.get());
487 if (appcontrol->data(kVerboseKey) == "true") {
488 verbose_mode_ = true;
493 #ifdef PROFILE_MOBILE
494 if (!common::utils::StartsWith(view->GetUrl(), kFileScheme)) {
495 LOGGER(DEBUG) << "Show window after launch for remote URL";
499 #endif // PROFILE_MOBILE
502 void WebApplication::AppControl(
503 std::unique_ptr<common::AppControl> appcontrol) {
504 std::unique_ptr<common::ResourceManager::Resource> res =
505 resource_manager_->GetStartResource(appcontrol.get());
507 bool do_reset = res->should_reset();
510 std::string current_page = view_stack_.front()->GetUrl();
511 std::string localized_page = res->uri();
513 if (current_page != localized_page) {
516 SendAppControlEvent();
520 // handle http://tizen.org/appcontrol/operation/main operation specially.
521 // only menu-screen app can send launch request with main operation.
522 // in this case, web app should have to resume web app not reset.
523 if (do_reset && (appcontrol->operation() == kAppControlMain)){
524 LOGGER(DEBUG) << "resume app for main operation";
526 SendAppControlEvent();
532 WebView* view = view_stack_.front();
534 view->SetDefaultEncoding(res->encoding());
535 view->LoadUrl(res->uri(), res->mime());
536 window_->SetContent(view->evas_object());
539 if (!debug_mode_ && appcontrol->data(AUL_K_DEBUG) == "1") {
541 LaunchInspector(appcontrol.get());
543 if (!verbose_mode_ && appcontrol->data(kVerboseKey) == "true") {
544 verbose_mode_ = true;
549 void WebApplication::SendAppControlEvent() {
550 if (view_stack_.size() > 0 && view_stack_.front() != NULL)
551 view_stack_.front()->EvalJavascript(kAppControlEventScript);
554 void WebApplication::ClearViewStack() {
555 window_->SetContent(NULL);
556 WebView* front = view_stack_.front();
557 auto it = view_stack_.begin();
558 for (; it != view_stack_.end(); ++it) {
565 view_stack_.push_front(front);
568 void WebApplication::Resume() {
569 if (view_stack_.size() > 0 && view_stack_.front() != NULL)
570 view_stack_.front()->SetVisibility(true);
572 if (app_data_->setting_info() != NULL &&
573 app_data_->setting_info()->background_support_enabled()) {
577 auto it = view_stack_.begin();
578 for (; it != view_stack_.end(); ++it) {
583 void WebApplication::Suspend() {
584 if (view_stack_.size() > 0 && view_stack_.front() != NULL)
585 view_stack_.front()->SetVisibility(false);
587 if (app_data_->setting_info() != NULL &&
588 app_data_->setting_info()->background_support_enabled()) {
589 LOGGER(DEBUG) << "gone background (backgroud support enabed)";
593 auto it = view_stack_.begin();
594 for (; it != view_stack_.end(); ++it) {
599 void WebApplication::Terminate() {
600 is_terminated_by_callback_ = false;
606 auto extension_server = extensions::XWalkExtensionServer::GetInstance();
607 extension_server->Shutdown();
610 void WebApplication::OnCreatedNewWebView(WebView* /*view*/, WebView* new_view) {
611 if (view_stack_.size() > 0 && view_stack_.front() != NULL)
612 view_stack_.front()->SetVisibility(false);
614 SetupWebView(new_view);
615 view_stack_.push_front(new_view);
616 window_->SetContent(new_view->evas_object());
619 void WebApplication::RemoveWebViewFromStack(WebView* view) {
620 if (view_stack_.size() == 0) {
621 if (is_terminated_by_callback_) {
628 WebView* current = view_stack_.front();
629 if (current == view) {
630 view_stack_.pop_front();
632 auto found = std::find(view_stack_.begin(), view_stack_.end(), view);
633 if (found != view_stack_.end()) {
634 view_stack_.erase(found);
638 if (view_stack_.size() == 0) {
639 if (is_terminated_by_callback_) {
640 // In order to prevent the crash issue due to the callback
641 // which occur after destroying WebApplication class,
642 // we have to set the 'SetEventListener' to NULL.
643 view->SetEventListener(NULL);
647 ewk_view_page_close(view->evas_object());
650 } else if (current != view_stack_.front()) {
651 view_stack_.front()->SetVisibility(true);
652 window_->SetContent(view_stack_.front()->evas_object());
655 // Delete after the callback context(for ewk view) was not used
656 ecore_idler_add([](void* view) {
657 WebView* obj = static_cast<WebView*>(view);
664 void WebApplication::OnClosedWebView(WebView* view) {
665 is_terminated_by_callback_ = true;
666 RemoveWebViewFromStack(view);
669 void WebApplication::OnReceivedWrtMessage(WebView* /*view*/,
670 Ewk_IPC_Wrt_Message_Data* msg) {
671 Eina_Stringshare* msg_type = ewk_ipc_wrt_message_data_type_get(msg);
673 #define TYPE_BEGIN(x) (!strncmp(msg_type, x, strlen(x)))
674 #define TYPE_IS(x) (!strcmp(msg_type, x))
676 if (TYPE_BEGIN("xwalk://")) {
677 auto extension_server = extensions::XWalkExtensionServer::GetInstance();
678 extension_server->HandleIPCMessage(msg);
680 Eina_Stringshare* msg_id = ewk_ipc_wrt_message_data_id_get(msg);
681 Eina_Stringshare* msg_ref_id =
682 ewk_ipc_wrt_message_data_reference_id_get(msg);
683 Eina_Stringshare* msg_value = ewk_ipc_wrt_message_data_value_get(msg);
685 if (TYPE_IS("tizen://hide")) {
688 } else if (TYPE_IS("tizen://exit")) {
690 ecore_idler_add(ExitAppIdlerCallback, this);
691 } else if (TYPE_IS("tizen://changeUA")) {
693 // Change UserAgent of current WebView
695 if (view_stack_.size() > 0 && view_stack_.front() != NULL) {
696 ret = view_stack_.front()->SetUserAgent(std::string(msg_value));
699 Ewk_IPC_Wrt_Message_Data* ans = ewk_ipc_wrt_message_data_new();
700 ewk_ipc_wrt_message_data_type_set(ans, msg_type);
701 ewk_ipc_wrt_message_data_reference_id_set(ans, msg_id);
703 ewk_ipc_wrt_message_data_value_set(ans, "success");
705 ewk_ipc_wrt_message_data_value_set(ans, "failed");
706 if (!ewk_ipc_wrt_message_send(ewk_context_, ans)) {
707 LOGGER(ERROR) << "Failed to send response";
709 ewk_ipc_wrt_message_data_del(ans);
710 } else if (TYPE_IS("tizen://deleteAllCookies")) {
711 Ewk_IPC_Wrt_Message_Data* ans = ewk_ipc_wrt_message_data_new();
712 ewk_ipc_wrt_message_data_type_set(ans, msg_type);
713 ewk_ipc_wrt_message_data_reference_id_set(ans, msg_id);
714 if (ClearCookie(ewk_context_))
715 ewk_ipc_wrt_message_data_value_set(ans, "success");
717 ewk_ipc_wrt_message_data_value_set(ans, "failed");
718 if (!ewk_ipc_wrt_message_send(ewk_context_, ans)) {
719 LOGGER(ERROR) << "Failed to send response";
721 ewk_ipc_wrt_message_data_del(ans);
722 } else if (TYPE_IS("tizen://hide_splash_screen")) {
723 splash_screen_->HideSplashScreen(SplashScreen::HideReason::CUSTOM);
726 eina_stringshare_del(msg_ref_id);
727 eina_stringshare_del(msg_id);
728 eina_stringshare_del(msg_value);
734 eina_stringshare_del(msg_type);
737 void WebApplication::OnOrientationLock(
738 WebView* view, bool lock,
739 NativeWindow::ScreenOrientation preferred_rotation) {
740 if (view_stack_.size() == 0) return;
742 // Only top-most view can set the orientation relate operation
743 if (view_stack_.front() != view) return;
745 // This is for 2.4 compatibility. Requested by Webengine Team.
747 // In Tizen 2.4 WebKit locking screen orientation was possible with Web API
748 // screen.lockOrientation(). This API was deprecated and replaced with
749 // screen.orientation.lock(). But for compatibility case we need to support
751 if(!tizenWebKitCompatibilityEnabled()) {
752 auto orientaion_setting = app_data_->setting_info() != NULL
753 ? app_data_->setting_info()->screen_orientation()
754 : wgt::parse::SettingInfo::ScreenOrientation::AUTO;
755 if (wgt::parse::SettingInfo::ScreenOrientation::AUTO != orientaion_setting) {
756 // If Tizen version is 3.0, it return.
762 window_->SetRotationLock(preferred_rotation);
764 window_->SetAutoRotation();
768 void WebApplication::OnHardwareKey(WebView* view, const std::string& keyname) {
769 // NOTE: This code is added to enable back-key on remote URL
770 bool enabled = app_data_->setting_info() != NULL
771 ? app_data_->setting_info()->hwkey_enabled()
774 if (!common::utils::StartsWith(view->GetUrl(), kFileScheme)) {
775 if (kKeyNameBack == keyname) {
776 LOGGER(DEBUG) << "Back to previous page for remote URL";
778 view->EvalJavascript(kBackKeyEventScript);
779 if (!view->Backward()) {
780 RemoveWebViewFromStack(view_stack_.front());
786 if (enabled && kKeyNameBack == keyname) {
787 view->EvalJavascript(kBackKeyEventScript);
788 // NOTE: This code is added for backward compatibility.
789 // If the 'backbutton_presence' is true, WebView should be navigated back.
790 if ((app_data_->setting_info() != NULL &&
791 app_data_->setting_info()->backbutton_presence()) ||
792 (app_data_->widget_info() != NULL &&
793 app_data_->widget_info()->view_modes() == "windowed")) {
794 if (!view->Backward()) {
795 RemoveWebViewFromStack(view_stack_.front());
798 } else if (enabled && kKeyNameMenu == keyname) {
799 view->EvalJavascript(kMenuKeyEventScript);
803 void WebApplication::OnLanguageChanged() {
804 lang_changed_mode_ = true;
805 locale_manager_->UpdateSystemLocale();
806 ewk_context_cache_clear(ewk_context_);
807 auto it = view_stack_.begin();
808 for (; it != view_stack_.end(); ++it) {
813 void WebApplication::OnConsoleMessage(const std::string& msg, int level) {
814 static bool enabled = (getenv(kConsoleLogEnableKey) != NULL);
817 std::string split_msg = msg;
818 std::size_t pos = msg.find(kResWgtPath);
819 if (pos != std::string::npos) {
820 split_msg = msg.substr(pos + strlen(kResWgtPath));
823 if (debug_mode_ || verbose_mode_ || enabled) {
824 int dlog_level = DLOG_DEBUG;
826 case EWK_CONSOLE_MESSAGE_LEVEL_WARNING:
827 dlog_level = DLOG_WARN;
829 case EWK_CONSOLE_MESSAGE_LEVEL_ERROR:
830 dlog_level = DLOG_ERROR;
833 dlog_level = DLOG_DEBUG;
836 LOGGER_RAW(dlog_level, kConsoleMessageLogTag)
837 << "[" << app_data_->pkg_id() << "] " << split_msg;
841 void WebApplication::OnLowMemory() {
842 ewk_context_cache_clear(ewk_context_);
843 ewk_context_notify_low_memory(ewk_context_);
846 void WebApplication::OnSoftKeyboardChangeEvent(WebView* /*view*/,
847 SoftKeyboardChangeEventValue softkeyboard_value) {
848 LOGGER(DEBUG) << "OnSoftKeyboardChangeEvent";
849 std::stringstream script;
852 << "var __event = document.createEvent(\"CustomEvent\");\n"
853 << "var __detail = {};\n"
854 << "__event.initCustomEvent(\"softkeyboardchange\",true,true,__detail);\n"
855 << "__event.state = \"" << softkeyboard_value.state << "\";\n"
856 << "__event.width = " << softkeyboard_value.width << ";\n"
857 << "__event.height = " << softkeyboard_value.height << ";\n"
858 << "document.dispatchEvent(__event);\n"
860 << "for (var i=0; i < window.frames.length; i++)\n"
861 << "{ window.frames[i].document.dispatchEvent(__event); }"
863 std::string kSoftKeyboardScript = script.str();
864 if (view_stack_.size() > 0 && view_stack_.front() != NULL)
865 view_stack_.front()->EvalJavascript(kSoftKeyboardScript.c_str());
868 #ifdef ROTARY_EVENT_FEATURE_SUPPORT
869 void WebApplication::OnRotaryEvent(WebView* /*view*/,
870 RotaryEventType type) {
871 LOGGER(DEBUG) << "OnRotaryEvent";
872 std::stringstream script;
875 << "var __event = document.createEvent(\"CustomEvent\");\n"
876 << "var __detail = {};\n"
877 << "__event.initCustomEvent(\"rotarydetent\", true, true, __detail);\n"
878 << "__event.detail.direction = \""
879 << (type == RotaryEventType::CLOCKWISE ? "CW" : "CCW")
881 << "document.dispatchEvent(__event);\n"
883 << "for (var i=0; i < window.frames.length; i++)\n"
884 << "{ window.frames[i].document.dispatchEvent(__event); }"
886 std::string kRotaryEventScript = script.str();
887 if (view_stack_.size() > 0 && view_stack_.front() != NULL)
888 view_stack_.front()->EvalJavascript(kRotaryEventScript.c_str());
890 #endif // ROTARY_EVENT_FEATURE_SUPPORT
892 void WebApplication::OnTimeTick(long time) {
894 LOGGER(DEBUG) << "TimeTick";
895 if (view_stack_.size() > 0 && view_stack_.front() != NULL)
896 view_stack_.front()->EvalJavascript(kAmbientTickEventScript);
900 void WebApplication::OnAmbientTick(long time) {
901 LOGGER(DEBUG) << "AmbientTick";
902 if (view_stack_.size() > 0 && view_stack_.front() != NULL)
903 view_stack_.front()->EvalJavascript(kAmbientTickEventScript);
906 void WebApplication::OnAmbientChanged(bool ambient_mode) {
907 LOGGER(DEBUG) << "AmbientChanged";
908 std::stringstream script;
911 << "var __event = document.createEvent(\"CustomEvent\");\n"
912 << "var __detail = {};\n"
913 << "__event.initCustomEvent(\"ambientmodechanged\",true,true,__detail);\n"
914 << "__event.detail.ambientMode = "
915 << (ambient_mode ? "true" : "false") << ";\n"
916 << "document.dispatchEvent(__event);\n"
918 << "for (var i=0; i < window.frames.length; i++)\n"
919 << "{ window.frames[i].document.dispatchEvent(__event); }"
921 std::string kAmbientChangedEventScript = script.str();
922 if (view_stack_.size() > 0 && view_stack_.front() != NULL)
923 view_stack_.front()->EvalJavascript(kAmbientChangedEventScript.c_str());
926 bool WebApplication::OnContextMenuDisabled(WebView* /*view*/) {
927 return !(app_data_->setting_info() != NULL
928 ? app_data_->setting_info()->context_menu_enabled()
932 void WebApplication::OnLoadStart(WebView* /*view*/) {
933 LOGGER(DEBUG) << "LoadStart";
936 void WebApplication::OnLoadFinished(WebView* /*view*/) {
937 LOGGER(DEBUG) << "LoadFinished";
938 splash_screen_->HideSplashScreen(SplashScreen::HideReason::LOADFINISHED);
941 void WebApplication::OnRendered(WebView* view) {
942 STEP_PROFILE_END("URL Set -> Rendered");
943 STEP_PROFILE_END("Start -> Launch Completed");
944 LOGGER(DEBUG) << "Rendered";
945 splash_screen_->HideSplashScreen(SplashScreen::HideReason::RENDERED);
947 // Do not show(), active() for language change
948 if(lang_changed_mode_ == false){
949 // Show window after frame rendered.
950 #ifdef PROFILE_MOBILE
951 if (common::utils::StartsWith(view->GetUrl(), kFileScheme)) {
955 #else // PROFILE_MOBILE
961 lang_changed_mode_ = false;
965 #ifdef MANUAL_ROTATE_FEATURE_SUPPORT
966 void WebApplication::OnRotatePrepared(WebView* /*view*/) {
967 window_->ManualRotationDone();
969 #endif // MANUAL_ROTATE_FEATURE_SUPPORT
971 void WebApplication::LaunchInspector(common::AppControl* appcontrol) {
972 unsigned int port = ewk_context_inspector_server_start(ewk_context_, 0);
973 std::stringstream ss;
975 std::map<std::string, std::vector<std::string>> data;
976 data[kPortKey] = {ss.str()};
977 appcontrol->Reply(data);
980 void WebApplication::SetupWebView(WebView* view) {
981 view->SetEventListener(this);
984 if (security_model_version_ == 2) {
985 view->SetCSPRule(csp_rule_, false);
986 if (!csp_report_rule_.empty()) {
987 view->SetCSPRule(csp_report_rule_, true);
991 // Setup longpolling value
992 if (app_data_->setting_info() != NULL &&
993 app_data_->setting_info()->long_polling()) {
994 boost::optional <unsigned int> polling_val(app_data_->setting_info()->long_polling());
995 unsigned long *ptr = reinterpret_cast <unsigned long *> (&polling_val.get());
996 view->SetLongPolling(*ptr);
1000 void WebApplication::SetupWebViewTizenApplicationInfo(WebView* view) {
1001 if (tizenWebKitCompatibilityEnabled()) {
1002 Ewk_Settings* settings = ewk_view_settings_get(view->evas_object());
1003 ewk_settings_tizen_compatibility_mode_set(settings,
1004 m_tizenCompatibilitySettings.m_major,
1005 m_tizenCompatibilitySettings.m_minor,
1006 m_tizenCompatibilitySettings.m_release);
1010 bool WebApplication::OnDidNavigation(WebView* /*view*/,
1011 const std::string& url) {
1013 // except(file , http, https, app) pass to appcontrol and return false
1014 if (ProcessWellKnownScheme(url)) {
1018 // send launch request for blocked URL to guarrenty backward-compatibility.
1019 if (resource_manager_->AllowNavigation(url)) {
1022 LOGGER(DEBUG) << "URL is blocked. send launch request for URL : " << url;
1023 std::unique_ptr<common::AppControl> request(
1024 common::AppControl::MakeAppcontrolFromURL(url));
1025 if (request.get() == NULL || !request->LaunchRequest()) {
1026 LOGGER(ERROR) << "Fail to send appcontrol request";
1032 void WebApplication::OnNotificationPermissionRequest(
1033 WebView*, const std::string& url,
1034 std::function<void(bool)> result_handler) {
1035 auto db = common::AppDB::GetInstance();
1036 std::string reminder =
1037 db->Get(kDBPrivateSection, kNotificationPermissionPrefix + url);
1038 if (reminder == "allowed") {
1039 result_handler(true);
1041 } else if (reminder == "denied") {
1042 result_handler(false);
1046 // Local Domain: Grant permission if defined, otherwise Popup user prompt.
1047 // Remote Domain: Popup user prompt.
1048 if (common::utils::StartsWith(url, "file://") &&
1049 FindPrivilege(app_data_, kNotificationPrivilege)) {
1050 result_handler(true);
1054 Popup* popup = Popup::CreatePopup(window_);
1055 popup->SetButtonType(Popup::ButtonType::AllowDenyButton);
1056 popup->SetTitle(popup_string::kPopupTitleWebNotification);
1057 popup->SetBody(popup_string::kPopupBodyWebNotification);
1058 popup->SetCheckBox(popup_string::kPopupCheckRememberPreference);
1059 popup->SetResultHandler(
1060 [db, result_handler, url](Popup* popup, void* /*user_data*/) {
1061 bool result = popup->GetButtonResult();
1062 bool remember = popup->GetCheckBoxResult();
1064 db->Set(kDBPrivateSection, kNotificationPermissionPrefix + url,
1065 result ? "allowed" : "denied");
1067 result_handler(result);
1073 void WebApplication::OnGeolocationPermissionRequest(
1074 WebView*, const std::string& url,
1075 std::function<void(bool)> result_handler) {
1076 auto db = common::AppDB::GetInstance();
1077 std::string reminder =
1078 db->Get(kDBPrivateSection, kGeolocationPermissionPrefix + url);
1079 if (reminder == "allowed") {
1080 result_handler(true);
1082 } else if (reminder == "denied") {
1083 result_handler(false);
1087 // Local Domain: Grant permission if defined, otherwise block execution.
1088 // Remote Domain: Popup user prompt if defined, otherwise block execution.
1089 if (!FindPrivilege(app_data_, kLocationPrivilege)) {
1090 result_handler(false);
1094 if (common::utils::StartsWith(url, "file://")) {
1095 result_handler(true);
1099 Popup* popup = Popup::CreatePopup(window_);
1100 popup->SetButtonType(Popup::ButtonType::AllowDenyButton);
1101 popup->SetTitle(popup_string::kPopupTitleGeoLocation);
1102 popup->SetBody(popup_string::kPopupBodyGeoLocation);
1103 popup->SetCheckBox(popup_string::kPopupCheckRememberPreference);
1104 popup->SetResultHandler(
1105 [db, result_handler, url](Popup* popup, void* /*user_data*/) {
1106 bool result = popup->GetButtonResult();
1107 bool remember = popup->GetCheckBoxResult();
1109 db->Set(kDBPrivateSection, kGeolocationPermissionPrefix + url,
1110 result ? "allowed" : "denied");
1112 result_handler(result);
1118 void WebApplication::OnQuotaExceed(WebView*, const std::string& url,
1119 std::function<void(bool)> result_handler) {
1120 auto db = common::AppDB::GetInstance();
1121 std::string reminder =
1122 db->Get(kDBPrivateSection, kQuotaPermissionPrefix + url);
1123 if (reminder == "allowed") {
1124 result_handler(true);
1126 } else if (reminder == "denied") {
1127 result_handler(false);
1131 // Local Domain: Grant permission if defined, otherwise Popup user prompt.
1132 // Remote Domain: Popup user prompt.
1133 if (common::utils::StartsWith(url, "file://") &&
1134 FindPrivilege(app_data_, kStoragePrivilege)) {
1135 result_handler(true);
1139 Popup* popup = Popup::CreatePopup(window_);
1140 popup->SetButtonType(Popup::ButtonType::AllowDenyButton);
1141 popup->SetTitle(popup_string::kPopupTitleWebStorage);
1142 popup->SetBody(popup_string::kPopupBodyWebStorage);
1143 popup->SetCheckBox(popup_string::kPopupCheckRememberPreference);
1144 popup->SetResultHandler(
1145 [db, result_handler, url](Popup* popup, void* /*user_data*/) {
1146 bool result = popup->GetButtonResult();
1147 bool remember = popup->GetCheckBoxResult();
1149 db->Set(kDBPrivateSection, kQuotaPermissionPrefix + url,
1150 result ? "allowed" : "denied");
1152 result_handler(result);
1158 void WebApplication::OnAuthenticationRequest(
1159 WebView*, const std::string& /*url*/, const std::string& /*message*/,
1160 std::function<void(bool submit, const std::string& id,
1161 const std::string& password)> result_handler) {
1162 Popup* popup = Popup::CreatePopup(window_);
1163 popup->SetButtonType(Popup::ButtonType::LoginCancelButton);
1164 popup->SetFirstEntry(popup_string::kPopupLabelAuthusername,
1165 Popup::EntryType::Edit);
1166 popup->SetSecondEntry(popup_string::kPopupLabelPassword,
1167 Popup::EntryType::PwEdit);
1168 popup->SetTitle(popup_string::kPopupTitleAuthRequest);
1169 popup->SetBody(popup_string::kPopupBodyAuthRequest);
1170 popup->SetResultHandler([result_handler](Popup* popup, void* /*user_data*/) {
1171 bool result = popup->GetButtonResult();
1172 std::string id = popup->GetFirstEntryResult();
1173 std::string passwd = popup->GetSecondEntryResult();
1174 result_handler(result, id, passwd);
1180 void WebApplication::OnCertificateAllowRequest(
1181 WebView*, const std::string& url, const std::string& pem,
1182 std::function<void(bool allow)> result_handler) {
1183 auto db = common::AppDB::GetInstance();
1184 std::string reminder =
1185 db->Get(kDBPrivateSection, kCertificateAllowPrefix + pem);
1186 if (reminder == "allowed") {
1187 result_handler(true);
1189 } else if (reminder == "denied") {
1190 result_handler(false);
1194 Popup* popup = Popup::CreatePopup(window_);
1195 popup->SetButtonType(Popup::ButtonType::AllowDenyButton);
1196 popup->SetTitle(popup_string::kPopupTitleCert);
1197 popup->SetBody(popup_string::GetText(
1198 popup_string::kPopupBodyCert) + "\n\n" + url);
1199 popup->SetCheckBox(popup_string::kPopupCheckRememberPreference);
1200 popup->SetResultHandler(
1201 [db, result_handler, pem](Popup* popup, void* /*user_data*/) {
1202 bool result = popup->GetButtonResult();
1203 bool remember = popup->GetCheckBoxResult();
1205 db->Set(kDBPrivateSection, kCertificateAllowPrefix + pem,
1206 result ? "allowed" : "denied");
1208 result_handler(result);
1214 void WebApplication::OnUsermediaPermissionRequest(
1215 WebView*, const std::string& url,
1216 std::function<void(bool)> result_handler) {
1217 auto db = common::AppDB::GetInstance();
1218 std::string reminder =
1219 db->Get(kDBPrivateSection, kUsermediaPermissionPrefix + url);
1220 if (reminder == "allowed") {
1221 result_handler(true);
1223 } else if (reminder == "denied") {
1224 result_handler(false);
1228 // Local Domain: Grant permission if defined, otherwise block execution.
1229 // Remote Domain: Popup user prompt if defined, otherwise block execution.
1230 if (!FindPrivilege(app_data_, kUsermediaPrivilege)) {
1231 result_handler(false);
1235 if (common::utils::StartsWith(url, "file://")) {
1236 result_handler(true);
1240 Popup* popup = Popup::CreatePopup(window_);
1241 popup->SetButtonType(Popup::ButtonType::AllowDenyButton);
1242 popup->SetTitle(popup_string::kPopupTitleUserMedia);
1243 popup->SetBody(popup_string::kPopupBodyUserMedia);
1244 popup->SetCheckBox(popup_string::kPopupCheckRememberPreference);
1245 popup->SetResultHandler(
1246 [db, result_handler, url](Popup* popup, void* /*user_data*/) {
1247 bool result = popup->GetButtonResult();
1248 bool remember = popup->GetCheckBoxResult();
1250 db->Set(kDBPrivateSection, kUsermediaPermissionPrefix + url,
1251 result ? "allowed" : "denied");
1253 result_handler(result);
1259 } // namespace runtime