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.
18 #include "runtime/web_application.h"
22 #include <ewk_chromium.h>
29 #include "common/logger.h"
30 #include "common/constants.h"
31 #include "common/command_line.h"
32 #include "common/string_utils.h"
33 #include "runtime/native_window.h"
34 #include "runtime/web_view.h"
35 #include "runtime/vibration_manager.h"
36 #include "common/app_control.h"
37 #include "common/locale_manager.h"
38 #include "common/application_data.h"
39 #include "common/resource_manager.h"
40 #include "common/app_db.h"
41 #include "runtime/notification_manager.h"
42 #include "runtime/popup.h"
43 #include "runtime/popup_string.h"
45 #ifndef INJECTED_BUNDLE_PATH
46 #error INJECTED_BUNDLE_PATH is not set.
52 // TODO(sngn.lee) : It should be declare in common header
53 const char* kKeyNameBack = "back";
55 const char* kConsoleLogEnableKey = "WRT_CONSOLE_LOG_ENABLE";
56 const char* kConsoleMessageLogTag = "ConsoleMessage";
58 const char* kDebugKey = "debug";
59 const char* kPortKey = "port";
61 const char* kDBusIntrospectionXML =
63 " <interface name='org.tizen.wrt.Application'>"
64 " <method name='NotifyEPCreated'>"
65 " <arg name='status' type='s' direction='in'/>"
67 " <method name='GetRuntimeVariable'>"
68 " <arg name='key' type='s' direction='in' />"
69 " <arg name='value' type='s' direction='out' />"
73 const char* kAppControlEventScript = \
75 "var __event = document.createEvent(\"CustomEvent\");\n"
76 "__event.initCustomEvent(\"appcontrol\", true, true);\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* kBackKeyEventScript = \
84 "var __event = document.createEvent(\"CustomEvent\");\n"
85 "__event.initCustomEvent(\"tizenhwkey\", true, true);\n"
86 "__event.keyName = \"back\";\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* kFullscreenPrivilege = "http://tizen.org/privilege/fullscreen";
93 const char* kFullscreenFeature = "fullscreen";
94 const char* kNotificationPrivilege =
95 "http://tizen.org/privilege/notification";
96 const char* kLocationPrivilege =
97 "http://tizen.org/privilege/location";
98 const char* kStoragePrivilege =
99 "http://tizen.org/privilege/unlimitedstorage";
100 const char* kNotiIconFile = "noti_icon.png";
102 const char* kVisibilitySuspendFeature = "visibility,suspend";
103 const char* kMediastreamRecordFeature = "mediastream,record";
104 const char* kEncryptedDatabaseFeature = "encrypted,database";
105 const char* kRotationLockFeature = "rotation,lock";
106 const char* kBackgroundMusicFeature = "background,music";
107 const char* kSoundModeFeature = "sound,mode";
108 const char* kBackgroundVibrationFeature = "background,vibration";
109 const char* kCSPFeature = "csp";
111 const char* kGeolocationPermissionPrefix = "__WRT_GEOPERM_";
112 const char* kNotificationPermissionPrefix = "__WRT_NOTIPERM_";
113 const char* kQuotaPermissionPrefix = "__WRT_QUOTAPERM_";
114 const char* kCertificateAllowPrefix = "__WRT_CERTIPERM_";
115 const char* kDBPrivateSection = "private";
117 const char* kDefaultCSPRule =
118 "default-src *; script-src 'self'; style-src 'self'; object-src 'none';";
120 bool FindPrivilege(wrt::ApplicationData* app_data,
121 const std::string& privilege) {
122 if (app_data->permissions_info().get() == NULL)
124 auto it = app_data->permissions_info()->GetAPIPermissions().begin();
125 auto end = app_data->permissions_info()->GetAPIPermissions().end();
126 for ( ; it != end; ++it) {
127 if (*it == privilege)
133 void ExecExtensionProcess(const std::string& uuid) {
135 if ((pid = fork()) < 0) {
136 LOGGER(ERROR) << "Failed to fork child process for extension process.";
139 CommandLine* cmd = CommandLine::ForCurrentProcess();
140 std::string switch_ext("--");
141 switch_ext.append(kSwitchExtensionServer);
142 execl(cmd->program().c_str(),
143 cmd->program().c_str(), switch_ext.c_str(), uuid.c_str(), NULL);
147 static void SendDownloadRequest(const std::string& url) {
148 wrt::AppControl request;
149 request.set_operation(APP_CONTROL_OPERATION_DOWNLOAD);
150 request.set_uri(url);
151 request.LaunchRequest();
154 static void InitializeNotificationCallback(Ewk_Context* ewk_context,
155 WebApplication* app) {
156 auto show = [](Ewk_Context*,
157 Ewk_Notification* noti,
159 WebApplication* self = static_cast<WebApplication*>(user_data);
162 uint64_t id = ewk_notification_id_get(noti);
163 std::string title(ewk_notification_title_get(noti) ?
164 ewk_notification_title_get(noti) : "");
165 std::string body(ewk_notification_body_get(noti) ?
166 ewk_notification_body_get(noti) : "");
167 std::string icon_path = self->data_path() + "/" + kNotiIconFile;
168 if (!ewk_notification_icon_save_as_png(noti, icon_path.c_str())) {
171 if (NotificationManager::GetInstance()->Show(id, title, body, icon_path))
172 ewk_notification_showed(id);
174 auto hide = [](Ewk_Context*,
177 NotificationManager::GetInstance()->Hide(noti_id);
178 ewk_notification_closed(noti_id, EINA_FALSE);
180 ewk_context_notification_callbacks_set(ewk_context,
186 static Eina_Bool ExitAppIdlerCallback(void* /*data*/) {
188 return ECORE_CALLBACK_CANCEL;
193 WebApplication::WebApplication(
194 NativeWindow* window, std::unique_ptr<ApplicationData> app_data)
197 ewk_context_(ewk_context_new_with_injected_bundle_path(
198 INJECTED_BUNDLE_PATH)),
200 appid_(app_data->app_id()),
201 app_uuid_(utils::GenerateUUID()),
202 locale_manager_(new LocaleManager()),
203 app_data_(std::move(app_data)),
205 std::unique_ptr<char, decltype(std::free)*>
206 path {app_get_data_path(), std::free};
207 app_data_path_ = path.get();
209 resource_manager_.reset(
210 new ResourceManager(app_data_.get(), locale_manager_.get()));
211 resource_manager_->set_base_resource_path(
212 app_data_->application_path());
216 WebApplication::~WebApplication() {
218 ewk_context_delete(ewk_context_);
221 bool WebApplication::Initialize() {
223 ewk_context_cache_model_set(ewk_context_, EWK_CACHE_MODEL_DOCUMENT_BROWSER);
226 auto cookie_manager = ewk_context_cookie_manager_get(ewk_context_);
227 ewk_cookie_manager_accept_policy_set(cookie_manager,
228 EWK_COOKIE_ACCEPT_POLICY_ALWAYS);
230 // set persistent storage path
231 std::string cookie_path = data_path() + ".cookie";
232 ewk_cookie_manager_persistent_storage_set(
233 cookie_manager, cookie_path.c_str(),
234 EWK_COOKIE_PERSISTENT_STORAGE_SQLITE);
236 // vibration callback
237 auto vibration_start_callback = [](uint64_t ms, void*) {
238 platform::VibrationManager::GetInstance()->Start(static_cast<int>(ms));
240 auto vibration_stop_callback = [](void* /*user_data*/) {
241 platform::VibrationManager::GetInstance()->Stop();
243 ewk_context_vibration_client_callbacks_set(ewk_context_,
244 vibration_start_callback,
245 vibration_stop_callback,
248 auto download_callback = [](const char* downloadUrl, void* /*data*/) {
249 SendDownloadRequest(downloadUrl);
251 ewk_context_did_start_download_callback_set(ewk_context_,
254 InitializeNotificationCallback(ewk_context_, this);
256 if (FindPrivilege(app_data_.get(), kFullscreenPrivilege)) {
257 ewk_context_tizen_extensible_api_string_set(ewk_context_,
262 if (app_data_->setting_info() != NULL &&
263 app_data_->setting_info()->background_support_enabled()) {
264 ewk_context_tizen_extensible_api_string_set(ewk_context_,
265 kVisibilitySuspendFeature,
267 ewk_context_tizen_extensible_api_string_set(ewk_context_,
268 kBackgroundMusicFeature,
271 ewk_context_tizen_extensible_api_string_set(ewk_context_,
272 kMediastreamRecordFeature,
274 ewk_context_tizen_extensible_api_string_set(ewk_context_,
275 kEncryptedDatabaseFeature,
277 if (app_data_->setting_info() != NULL &&
278 app_data_->setting_info()->screen_orientation()
279 == wgt::parse::SettingInfo::ScreenOrientation::AUTO) {
280 ewk_context_tizen_extensible_api_string_set(ewk_context_,
281 kRotationLockFeature,
283 } else if (app_data_->setting_info() != NULL &&
284 app_data_->setting_info()->screen_orientation()
285 == wgt::parse::SettingInfo::ScreenOrientation::PORTRAIT) {
286 window_->SetRotationLock(
287 NativeWindow::ScreenOrientation::PORTRAIT_PRIMARY);
288 } else if (app_data_->setting_info() != NULL &&
289 app_data_->setting_info()->screen_orientation()
290 == wgt::parse::SettingInfo::ScreenOrientation::LANDSCAPE) {
291 window_->SetRotationLock(
292 NativeWindow::ScreenOrientation::LANDSCAPE_PRIMARY);
295 if (app_data_->setting_info() != NULL &&
296 app_data_->setting_info()->sound_mode()
297 == wgt::parse::SettingInfo::SoundMode::EXCLUSIVE) {
298 ewk_context_tizen_extensible_api_string_set(ewk_context_,
303 if (app_data_->setting_info() != NULL &&
304 app_data_->setting_info()->background_vibration()) {
305 ewk_context_tizen_extensible_api_string_set(ewk_context_,
306 kBackgroundVibrationFeature,
310 if (app_data_->widget_info() != NULL &&
311 !app_data_->widget_info()->default_locale().empty()) {
312 locale_manager_->SetDefaultLocale(
313 app_data_->widget_info()->default_locale());
316 // TODO(sngn.lee): Find the path of certificate file
317 // ewk_context_certificate_file_set(ewk_context_, .... );
319 // TODO(sngn.lee): find the proxy url
320 // ewk_context_proxy_uri_set(ewk_context_, ... );
322 if (app_data_->csp_info() != NULL ||
323 app_data_->csp_report_info() != NULL ||
324 app_data_->allowed_navigation_info() != NULL) {
325 security_model_version_ = 2;
326 if (app_data_->csp_info() == NULL ||
327 app_data_->csp_info()->security_rules().empty()) {
328 csp_rule_ = kDefaultCSPRule;
330 csp_rule_ = app_data_->csp_info()->security_rules();
332 if (app_data_->csp_report_info() != NULL &&
333 !app_data_->csp_report_info()->security_rules().empty()) {
334 csp_report_rule_ = app_data_->csp_report_info()->security_rules();
336 ewk_context_tizen_extensible_api_string_set(ewk_context_,
340 security_model_version_ = 1;
346 void WebApplication::Launch(std::unique_ptr<wrt::AppControl> appcontrol) {
347 // Start DBus Server for Runtime
348 // TODO(wy80.choi): Should I add PeerCredentials checker?
349 using std::placeholders::_1;
350 using std::placeholders::_2;
351 using std::placeholders::_3;
352 using std::placeholders::_4;
353 dbus_server_.SetIntrospectionXML(kDBusIntrospectionXML);
354 dbus_server_.SetMethodCallback(kDBusInterfaceNameForApplication,
355 std::bind(&WebApplication::HandleDBusMethod, this, _1, _2, _3, _4));
356 dbus_server_.Start(app_uuid_ +
357 "." + std::string(kDBusNameForApplication));
359 // Execute ExtensionProcess
360 ExecExtensionProcess(app_uuid_);
363 WebView* view = new WebView(window_, ewk_context_);
366 // send widget info to injected bundle
367 // TODO(wy80.choi): ewk_send_widget_info should be fixed to receive uuid of
368 // application instead of widget_id.
369 // Currently, uuid is passed as encoded_bundle argument temporarily.
370 ewk_send_widget_info(ewk_context_, appid_.c_str(),
371 elm_config_scale_get(),
375 std::unique_ptr<ResourceManager::Resource> res =
376 resource_manager_->GetStartResource(appcontrol.get());
377 view->SetDefaultEncoding(res->encoding());
378 // TODO(wy80.choi): temporary comment for test, remove it later.
379 // view->LoadUrl("file:///home/owner/apps_rw/33CFo0eFJe/"
380 // "33CFo0eFJe.annex/index.html");
381 view->LoadUrl(res->uri());
382 view_stack_.push_front(view);
383 window_->SetContent(view->evas_object());
385 // TODO(sngn.lee): below code only debug code
386 auto callback = [](void*, Evas*, Evas_Object* obj,
389 evas_object_geometry_get(obj, &x, &y, &w, &h);
390 LOGGER(DEBUG) << "resize ! ("
391 << x << ", " << y << ", " << w << ", " << h << ")";
393 evas_object_event_callback_add(view->evas_object(),
394 EVAS_CALLBACK_RESIZE,
397 if (appcontrol->data(kDebugKey) == "true") {
399 LaunchInspector(appcontrol.get());
402 // TODO(sngn.lee): check the below code location.
403 // in Wearable, webkit can render contents before show window
404 // but Mobile, webkit can't render contents before show window
408 received_appcontrol_ = std::move(appcontrol);
411 void WebApplication::AppControl(std::unique_ptr<wrt::AppControl> appcontrol) {
412 std::unique_ptr<ResourceManager::Resource> res =
413 resource_manager_->GetStartResource(appcontrol.get());
414 if (res->should_reset()) {
417 WebView* view = new WebView(window_, ewk_context_);
419 view->SetDefaultEncoding(res->encoding());
420 view->LoadUrl(res->uri());
421 view_stack_.push_front(view);
422 window_->SetContent(view->evas_object());
425 SendAppControlEvent();
428 if (!debug_mode_ && appcontrol->data(kDebugKey) == "true") {
430 LaunchInspector(appcontrol.get());
433 received_appcontrol_ = std::move(appcontrol);
436 void WebApplication::SendAppControlEvent() {
437 auto it = view_stack_.begin();
438 while (it != view_stack_.end()) {
439 (*it)->EvalJavascript(kAppControlEventScript);
443 void WebApplication::ClearViewStack() {
444 window_->SetContent(NULL);
445 auto it = view_stack_.begin();
446 for ( ; it != view_stack_.end(); ++it) {
453 void WebApplication::Resume() {
454 if (view_stack_.size() > 0 && view_stack_.front() != NULL)
455 view_stack_.front()->SetVisibility(true);
457 if (app_data_->setting_info() != NULL &&
458 app_data_->setting_info()->background_support_enabled()) {
462 auto it = view_stack_.begin();
463 for ( ; it != view_stack_.end(); ++it) {
468 void WebApplication::Suspend() {
469 if (view_stack_.size() > 0 && view_stack_.front() != NULL)
470 view_stack_.front()->SetVisibility(false);
472 if (app_data_->setting_info() != NULL &&
473 app_data_->setting_info()->background_support_enabled()) {
474 LOGGER(DEBUG) << "gone background (backgroud support enabed)";
478 auto it = view_stack_.begin();
479 for ( ; it != view_stack_.end(); ++it) {
484 void WebApplication::OnCreatedNewWebView(WebView* /*view*/, WebView* new_view) {
485 if (view_stack_.size() > 0 && view_stack_.front() != NULL)
486 view_stack_.front()->SetVisibility(false);
488 SetupWebView(new_view);
489 view_stack_.push_front(new_view);
490 window_->SetContent(new_view->evas_object());
493 void WebApplication::OnClosedWebView(WebView * view) {
494 if (view_stack_.size() == 0)
497 WebView* current = view_stack_.front();
498 if (current == view) {
499 view_stack_.pop_front();
501 auto found = std::find(view_stack_.begin(), view_stack_.end(), view);
502 if (found != view_stack_.end()) {
503 view_stack_.erase(found);
507 if (view_stack_.size() == 0) {
508 if (terminator_ != NULL) {
511 } else if (current != view_stack_.front()) {
512 view_stack_.front()->SetVisibility(true);
513 window_->SetContent(view_stack_.front()->evas_object());
516 // Delete after the callback context(for ewk view) was not used
517 ecore_idler_add([](void* view) {
518 WebView* obj = static_cast<WebView*>(view);
524 void WebApplication::OnReceivedWrtMessage(
526 Ewk_IPC_Wrt_Message_Data* msg) {
528 Eina_Stringshare* msg_id = ewk_ipc_wrt_message_data_id_get(msg);
529 Eina_Stringshare* msg_ref_id = ewk_ipc_wrt_message_data_reference_id_get(msg);
530 Eina_Stringshare* msg_type = ewk_ipc_wrt_message_data_type_get(msg);
531 Eina_Stringshare* msg_value = ewk_ipc_wrt_message_data_value_get(msg);
533 LOGGER(DEBUG) << "RecvMsg: id = " << msg_id;
534 LOGGER(DEBUG) << "RecvMsg: refid = " << msg_ref_id;
535 LOGGER(DEBUG) << "RecvMsg: type = " << msg_type;
536 LOGGER(DEBUG) << "RecvMsg: value = " << msg_value;
538 #define TYPE_IS(x) (!strcmp(msg_type, x))
539 if (TYPE_IS("tizen://hide")) {
542 } else if (TYPE_IS("tizen://exit")) {
544 ecore_idler_add(ExitAppIdlerCallback, NULL);
545 } else if (TYPE_IS("tizen://changeUA")) {
547 // Change UserAgent of current WebView
549 if (view_stack_.size() > 0 && view_stack_.front() != NULL) {
550 ret = view_stack_.front()->SetUserAgent(std::string(msg_value));
553 Ewk_IPC_Wrt_Message_Data* ans = ewk_ipc_wrt_message_data_new();
554 ewk_ipc_wrt_message_data_type_set(ans, msg_type);
555 ewk_ipc_wrt_message_data_reference_id_set(ans, msg_id);
557 ewk_ipc_wrt_message_data_value_set(ans, "success");
559 ewk_ipc_wrt_message_data_value_set(ans, "failed");
560 if (!ewk_ipc_wrt_message_send(ewk_context_, ans)) {
561 LOGGER(ERROR) << "Failed to send response";
563 ewk_ipc_wrt_message_data_del(ans);
564 } else if (TYPE_IS("tizen://test-sync")) {
565 // TODO(wy80.choi): this type should be removed after finish test
566 ewk_ipc_wrt_message_data_value_set(msg, "Reply!!");
567 } else if (TYPE_IS("tizen://test-async")) {
568 // TODO(wy80.choi): this type should be removed after finish test
569 Ewk_IPC_Wrt_Message_Data* ans = ewk_ipc_wrt_message_data_new();
570 ewk_ipc_wrt_message_data_type_set(ans, msg_type);
571 ewk_ipc_wrt_message_data_reference_id_set(ans, msg_id);
572 ewk_ipc_wrt_message_data_value_set(ans, "Aync Reply!!");
573 if (!ewk_ipc_wrt_message_send(ewk_context_, ans)) {
574 LOGGER(ERROR) << "Failed to send response";
576 ewk_ipc_wrt_message_data_del(ans);
580 eina_stringshare_del(msg_value);
581 eina_stringshare_del(msg_type);
582 eina_stringshare_del(msg_ref_id);
583 eina_stringshare_del(msg_id);
586 void WebApplication::OnOrientationLock(
589 NativeWindow::ScreenOrientation preferred_rotation) {
590 if (view_stack_.size() == 0)
593 // Only top-most view can set the orientation relate operation
594 if (view_stack_.front() != view)
597 auto orientaion_setting = app_data_->setting_info() != NULL ?
598 app_data_->setting_info()->screen_orientation() :
599 // TODO(sngn.lee): check default value
600 wgt::parse::SettingInfo::ScreenOrientation::AUTO;
601 if (orientaion_setting != wgt::parse::SettingInfo::ScreenOrientation::AUTO) {
606 window_->SetRotationLock(preferred_rotation);
608 window_->SetAutoRotation();
612 void WebApplication::OnHardwareKey(WebView* view, const std::string& keyname) {
613 bool enabled = app_data_->setting_info() != NULL ?
614 app_data_->setting_info()->hwkey_enabled() :
616 if (enabled && kKeyNameBack == keyname) {
617 view->EvalJavascript(kBackKeyEventScript);
621 void WebApplication::OnLanguageChanged() {
622 locale_manager_->UpdateSystemLocale();
623 ewk_context_cache_clear(ewk_context_);
624 auto it = view_stack_.begin();
625 for ( ; it != view_stack_.end(); ++it) {
630 void WebApplication::OnConsoleMessage(const std::string& msg, int level) {
631 static bool enabled = (getenv(kConsoleLogEnableKey) != NULL);
634 if (debug_mode_ || enabled) {
635 int dlog_level = DLOG_DEBUG;
637 case EWK_CONSOLE_MESSAGE_LEVEL_WARNING:
638 dlog_level = DLOG_WARN;
640 case EWK_CONSOLE_MESSAGE_LEVEL_ERROR:
641 dlog_level = DLOG_ERROR;
644 dlog_level = DLOG_DEBUG;
647 LOGGER_RAW(dlog_level, kConsoleMessageLogTag) << msg;
651 void WebApplication::OnLowMemory() {
652 ewk_context_cache_clear(ewk_context_);
653 ewk_context_notify_low_memory(ewk_context_);
656 bool WebApplication::OnContextMenuDisabled(WebView* /*view*/) {
657 return !(app_data_->setting_info() != NULL ?
658 app_data_->setting_info()->context_menu_enabled() :
662 void WebApplication::OnLoadStart(WebView* /*view*/) {
663 LOGGER(DEBUG) << "LoadStart";
665 void WebApplication::OnLoadFinished(WebView* /*view*/) {
666 LOGGER(DEBUG) << "LoadFinished";
668 void WebApplication::OnRendered(WebView* /*view*/) {
669 LOGGER(DEBUG) << "Rendered";
672 void WebApplication::LaunchInspector(wrt::AppControl* appcontrol) {
674 ewk_context_inspector_server_start(ewk_context_, 0);
675 std::stringstream ss;
677 std::map<std::string, std::vector<std::string>> data;
678 data[kPortKey] = { ss.str() };
679 appcontrol->Reply(data);
682 void WebApplication::SetupWebView(WebView* view) {
683 view->SetEventListener(this);
686 if (security_model_version_ == 2) {
687 view->SetCSPRule(csp_rule_, false);
688 if (!csp_report_rule_.empty()) {
689 view->SetCSPRule(csp_report_rule_, true);
693 // TODO(sngn.lee): set UserAgent to WebView
696 bool WebApplication::OnDidNavigation(WebView* /*view*/,
697 const std::string& url) {
698 // TODO(sngn.lee): scheme handling
699 // except(file , http, https, app) pass to appcontrol and return false
701 return resource_manager_->AllowNavigation(url);
704 void WebApplication::OnNotificationPermissionRequest(
706 const std::string& url,
707 std::function<void(bool)> result_handler) {
708 auto db = AppDB::GetInstance();
709 std::string reminder = db->Get(kDBPrivateSection,
710 kNotificationPermissionPrefix + url);
711 if (reminder == "allowed") {
712 result_handler(true);
714 } else if (reminder == "denied") {
715 result_handler(false);
719 // Local Domain: Grant permission if defined, otherwise Popup user prompt.
720 // Remote Domain: Popup user prompt.
721 if (utils::StartsWith(url, "file://") &&
722 FindPrivilege(app_data_.get(), kNotificationPrivilege)) {
723 result_handler(true);
727 Popup* popup = Popup::CreatePopup(window_);
728 popup->SetButtonType(Popup::ButtonType::AllowDenyButton);
729 popup->SetTitle(popup_string::kPopupTitleWebNotification);
730 popup->SetBody(popup_string::kPopupBodyWebNotification);
731 popup->SetCheckBox(popup_string::kPopupCheckRememberPreference);
732 popup->SetResultHandler(
733 [db, result_handler, url](Popup* popup, void* /*user_data*/) {
734 bool result = popup->GetButtonResult();
735 bool remember = popup->GetCheckBoxResult();
737 db->Set(kDBPrivateSection, kNotificationPermissionPrefix + url,
738 result ? "allowed" : "denied");
740 result_handler(result);
745 void WebApplication::OnGeolocationPermissionRequest(
747 const std::string& url,
748 std::function<void(bool)> result_handler) {
749 auto db = AppDB::GetInstance();
750 std::string reminder = db->Get(kDBPrivateSection,
751 kGeolocationPermissionPrefix + url);
752 if (reminder == "allowed") {
753 result_handler(true);
755 } else if (reminder == "denied") {
756 result_handler(false);
760 // Local Domain: Grant permission if defined, otherwise block execution.
761 // Remote Domain: Popup user prompt if defined, otherwise block execution.
762 if (!FindPrivilege(app_data_.get(), kLocationPrivilege)) {
763 result_handler(false);
767 if (utils::StartsWith(url, "file://")) {
768 result_handler(true);
772 Popup* popup = Popup::CreatePopup(window_);
773 popup->SetButtonType(Popup::ButtonType::AllowDenyButton);
774 popup->SetTitle(popup_string::kPopupTitleGeoLocation);
775 popup->SetBody(popup_string::kPopupBodyGeoLocation);
776 popup->SetCheckBox(popup_string::kPopupCheckRememberPreference);
777 popup->SetResultHandler(
778 [db, result_handler, url](Popup* popup, void* /*user_data*/) {
779 bool result = popup->GetButtonResult();
780 bool remember = popup->GetCheckBoxResult();
782 db->Set(kDBPrivateSection, kGeolocationPermissionPrefix + url,
783 result ? "allowed" : "denied");
785 result_handler(result);
791 void WebApplication::OnQuotaExceed(
793 const std::string& url,
794 std::function<void(bool)> result_handler) {
795 auto db = AppDB::GetInstance();
796 std::string reminder = db->Get(kDBPrivateSection,
797 kQuotaPermissionPrefix + url);
798 if (reminder == "allowed") {
799 result_handler(true);
801 } else if (reminder == "denied") {
802 result_handler(false);
806 // Local Domain: Grant permission if defined, otherwise Popup user prompt.
807 // Remote Domain: Popup user prompt.
808 if (utils::StartsWith(url, "file://") &&
809 FindPrivilege(app_data_.get(), kStoragePrivilege)) {
810 result_handler(true);
814 Popup* popup = Popup::CreatePopup(window_);
815 popup->SetButtonType(Popup::ButtonType::AllowDenyButton);
816 popup->SetTitle(popup_string::kPopupTitleWebStorage);
817 popup->SetBody(popup_string::kPopupBodyWebStorage);
818 popup->SetCheckBox(popup_string::kPopupCheckRememberPreference);
819 popup->SetResultHandler(
820 [db, result_handler, url](Popup* popup, void* /*user_data*/) {
821 bool result = popup->GetButtonResult();
822 bool remember = popup->GetCheckBoxResult();
824 db->Set(kDBPrivateSection, kQuotaPermissionPrefix + url,
825 result ? "allowed" : "denied");
827 result_handler(result);
832 void WebApplication::OnAuthenticationRequest(
834 const std::string& /*url*/,
835 const std::string& /*message*/,
836 std::function<void(bool submit,
837 const std::string& id,
838 const std::string& password)
840 Popup* popup = Popup::CreatePopup(window_);
841 popup->SetButtonType(Popup::ButtonType::LoginCancelButton);
842 popup->SetFirstEntry(popup_string::kPopupLabelAuthusername,
843 Popup::EntryType::Edit);
844 popup->SetSecondEntry(popup_string::kPopupLabelPassword,
845 Popup::EntryType::PwEdit);
846 popup->SetTitle(popup_string::kPopupTitleAuthRequest);
847 popup->SetBody(popup_string::kPopupBodyAuthRequest);
848 popup->SetResultHandler(
849 [result_handler](Popup* popup, void* /*user_data*/) {
850 bool result = popup->GetButtonResult();
851 std::string id = popup->GetFirstEntryResult();
852 std::string passwd = popup->GetSecondEntryResult();
853 result_handler(result, id, passwd);
858 void WebApplication::OnCertificateAllowRequest(
860 const std::string& /*url*/,
861 const std::string& pem,
862 std::function<void(bool allow)> result_handler) {
863 auto db = AppDB::GetInstance();
864 std::string reminder = db->Get(kDBPrivateSection,
865 kCertificateAllowPrefix + pem);
866 if (reminder == "allowed") {
867 result_handler(true);
869 } else if (reminder == "denied") {
870 result_handler(false);
874 Popup* popup = Popup::CreatePopup(window_);
875 popup->SetButtonType(Popup::ButtonType::AllowDenyButton);
876 popup->SetTitle(popup_string::kPopupTitleCert);
877 popup->SetBody(popup_string::kPopupBodyCert);
878 popup->SetCheckBox(popup_string::kPopupCheckRememberPreference);
879 popup->SetResultHandler(
880 [db, result_handler, pem](Popup* popup, void* /*user_data*/) {
881 bool result = popup->GetButtonResult();
882 bool remember = popup->GetCheckBoxResult();
884 db->Set(kDBPrivateSection, kCertificateAllowPrefix + pem,
885 result ? "allowed" : "denied");
887 result_handler(result);
893 void WebApplication::HandleDBusMethod(GDBusConnection* /*connection*/,
894 const std::string& method_name,
895 GVariant* parameters,
896 GDBusMethodInvocation* invocation) {
897 if (method_name == kMethodNotifyEPCreated) {
898 LOGGER(DEBUG) << "Received 'NotifyEPCreated' from ExtensionServer.";
899 } else if (method_name == kMethodGetRuntimeVariable) {
902 g_variant_get(parameters, "(&s)", &key);
903 if (g_strcmp0(key, "runtime_name") == 0) {
904 value = std::string("wrt");
905 } else if (g_strcmp0(key, "app_id") == 0) {
906 // TODO(wy80.choi): TEC requries double quotes,
907 // but webapi-plugins doesn't. It should be fixed.
908 value = "\"" + appid_ + "\"";
909 } else if (g_strcmp0(key, "encoded_bundle") == 0) {
910 value = received_appcontrol_->encoded_bundle();
912 g_dbus_method_invocation_return_value(
913 invocation, g_variant_new("(s)", value.c_str()));