Initialized constructor
[platform/framework/web/crosswalk-tizen.git] / runtime / browser / web_application.cc
1 /*
2  * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  *    Licensed under the Apache License, Version 2.0 (the "License");
5  *    you may not use this file except in compliance with the License.
6  *    You may obtain a copy of the License at
7  *
8  *        http://www.apache.org/licenses/LICENSE-2.0
9  *
10  *    Unless required by applicable law or agreed to in writing, software
11  *    distributed under the License is distributed on an "AS IS" BASIS,
12  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  *    See the License for the specific language governing permissions and
14  *    limitations under the License.
15  */
16
17 #include "runtime/browser/web_application.h"
18
19 #include <app.h>
20 #include <aul.h>
21 #include <cynara-client.h>
22 #include <Ecore.h>
23
24 #include <algorithm>
25 #include <map>
26 #include <memory>
27 #include <fstream>
28 #include <sstream>
29 #include <vector>
30
31 #ifdef WATCH_FACE_FEATURE_SUPPORT
32 #include <appcore-watch.h>
33 #endif
34
35 #include "common/application_data.h"
36 #include "common/app_db.h"
37 #include "common/app_control.h"
38 #include "common/command_line.h"
39 #include "common/locale_manager.h"
40 #include "common/logger.h"
41 #include "common/profiler.h"
42 #include "common/resource_manager.h"
43 #include "common/string_utils.h"
44 #include "extensions/renderer/xwalk_extension_renderer_controller.h"
45 #include "runtime/browser/native_window.h"
46 #include "runtime/browser/notification_manager.h"
47 #include "runtime/browser/popup.h"
48 #include "runtime/browser/popup_string.h"
49 #include "runtime/browser/vibration_manager.h"
50 #include "runtime/browser/web_view.h"
51 #include "runtime/browser/splash_screen.h"
52 #include "runtime/browser/ui_runtime.h"
53 #include "extensions/common/xwalk_extension_server.h"
54
55 #ifndef INJECTED_BUNDLE_PATH
56 #error INJECTED_BUNDLE_PATH is not set.
57 #endif
58
59 #define SESSION_COUNTER_INTERVAL 0.1
60 #define MAIN_LOOP_INTERVAL 1
61
62 using namespace extensions;
63
64 namespace runtime {
65
66 namespace {
67 const char* kKeyNameBack = "back";
68 const char* kKeyNameMenu = "menu";
69
70 const char* kConsoleLogEnableKey = "WRT_CONSOLE_LOG_ENABLE";
71 const char* kConsoleMessageLogTag = "ConsoleMessage";
72
73 const char* kVerboseKey = "verbose";
74 const char* kPortKey = "port";
75
76 const char* kAppControlEventScript =
77     "(function(){"
78     "var __event = document.createEvent(\"CustomEvent\");\n"
79     "__event.initCustomEvent(\"appcontrol\", true, true, null);\n"
80     "document.dispatchEvent(__event);\n"
81     "\n"
82     "for (var i=0; i < window.frames.length; i++)\n"
83     "{ window.frames[i].document.dispatchEvent(__event); }"
84     "})()";
85 const char* kBackKeyEventScript =
86     "(function(){"
87     "var __event = document.createEvent(\"CustomEvent\");\n"
88     "__event.initCustomEvent(\"tizenhwkey\", true, true, null);\n"
89     "__event.keyName = \"back\";\n"
90     "document.dispatchEvent(__event);\n"
91     "\n"
92     "for (var i=0; i < window.frames.length; i++)\n"
93     "{ window.frames[i].document.dispatchEvent(__event); }"
94     "})()";
95 const char* kMenuKeyEventScript =
96     "(function(){"
97     "var __event = document.createEvent(\"CustomEvent\");\n"
98     "__event.initCustomEvent(\"tizenhwkey\", true, true, null);\n"
99     "__event.keyName = \"menu\";\n"
100     "document.dispatchEvent(__event);\n"
101     "\n"
102     "for (var i=0; i < window.frames.length; i++)\n"
103     "{ window.frames[i].document.dispatchEvent(__event); }"
104     "})()";
105 const char* kAmbientTickEventScript =
106     "(function(){"
107     "var __event = document.createEvent(\"CustomEvent\");\n"
108     "__event.initCustomEvent(\"timetick\", true, true);\n"
109     "document.dispatchEvent(__event);\n"
110     "\n"
111     "for (var i=0; i < window.frames.length; i++)\n"
112     "{ window.frames[i].document.dispatchEvent(__event); }"
113     "})()";
114 const char* kCameraPrivilege = "http://tizen.org/privilege/camera";
115 const char* kFullscreenPrivilege = "http://tizen.org/privilege/fullscreen";
116 const char* kFullscreenFeature = "fullscreen";
117 const char* kNotificationPrivilege = "http://tizen.org/privilege/notification";
118 const char* kLocationPrivilege = "http://tizen.org/privilege/location";
119 const char* kRecordPrivilege = "http://tizen.org/privilege/recorder";
120 const char* kStoragePrivilege = "http://tizen.org/privilege/unlimitedstorage";
121 const char* kUsermediaPrivilege = "http://tizen.org/privilege/mediacapture";
122 const char* kNotiIconFile = "noti_icon.png";
123 const char* kFileScheme = "file://";
124
125 const char* kVisibilitySuspendFeature = "visibility,suspend";
126 const char* kMediastreamRecordFeature = "mediastream,record";
127 const char* kEncryptedDatabaseFeature = "encrypted,database";
128 const char* kRotationLockFeature = "rotation,lock";
129 const char* kBackgroundMusicFeature = "background,music";
130 const char* kSoundModeFeature = "sound,mode";
131 const char* kBackgroundVibrationFeature = "background,vibration";
132 const char* kCSPFeature = "csp";
133
134 const char* kGeolocationPermissionPrefix = "__WRT_GEOPERM_";
135 const char* kNotificationPermissionPrefix = "__WRT_NOTIPERM_";
136 const char* kQuotaPermissionPrefix = "__WRT_QUOTAPERM_";
137 const char* kCertificateAllowPrefix = "__WRT_CERTIPERM_";
138 const char* kUsermediaPermissionPrefix = "__WRT_USERMEDIAPERM_";
139 const char* kDBPrivateSection = "private";
140
141 const char* kDefaultCSPRule =
142     "default-src *; script-src 'self'; style-src 'self'; object-src 'none';";
143 const char* kResWgtPath = "res/wgt/";
144 const char* kAppControlMain = "http://tizen.org/appcontrol/operation/main";
145
146 // Looking for added privilege by Application developer in config.xml.
147 bool FindPrivilegeFromConfig(common::ApplicationData* app_data,
148                    const std::string& privilege) {
149   if (app_data->permissions_info().get() == NULL) return false;
150   LOGGER(INFO) << "Finding privilege from config.xml";
151   auto it = app_data->permissions_info()->GetAPIPermissions().begin();
152   auto end = app_data->permissions_info()->GetAPIPermissions().end();
153   for (; it != end; ++it) {
154     if (*it == privilege) return true;
155   }
156   return false;
157 }
158
159 // Looking for given default privilege when application installed.
160 bool FindPrivilegeFromCynara(const std::string& privilege_name) {
161   LOGGER(INFO) << "Finding privilege from cynara db";
162   static constexpr char kSmackLabelFilePath[] = "/proc/self/attr/current";
163   std::ifstream file(kSmackLabelFilePath);
164   if (!file.is_open()) {
165     LOGGER(ERROR) << "Failed to open " << kSmackLabelFilePath;
166     return false;
167   }
168
169   int ret;
170   cynara* p_cynara = NULL;
171   ret = cynara_initialize(&p_cynara, 0);
172   if (CYNARA_API_SUCCESS != ret) {
173     LOGGER(ERROR) << "Failed. The result of cynara_initialize() : " << ret;
174     return false;
175   }
176
177   std::string uid = std::to_string(getuid());
178   std::string smack_label{std::istreambuf_iterator<char>(file),
179                           std::istreambuf_iterator<char>()};
180
181   bool result = false;
182   ret = cynara_check(p_cynara, smack_label.c_str(), "", uid.c_str(), privilege_name.c_str());
183   if (CYNARA_API_ACCESS_ALLOWED != ret) {
184     LOGGER(ERROR) << "Access denied. The result of cynara_check() : " << ret;
185   } else {
186     LOGGER(INFO) << "Access allowed! The result of cynara_check() : " << ret;
187     result = true;
188   }
189
190   if (p_cynara) {
191     ret = cynara_finish(p_cynara);
192     if (CYNARA_API_SUCCESS != ret) {
193       LOGGER(ERROR) << "Failed. The result of cynara_finish() : " << ret;
194     }
195   }
196
197   return result;
198 }
199
200 static void SendDownloadRequest(const std::string& url) {
201   common::AppControl request;
202   request.set_operation(APP_CONTROL_OPERATION_DOWNLOAD);
203   request.set_uri(url);
204   request.LaunchRequest();
205 }
206
207 static void InitializeNotificationCallback(Ewk_Context* ewk_context,
208                                            WebApplication* app) {
209   auto show = [](Ewk_Context*, Ewk_Notification* noti, void* user_data) {
210     WebApplication* self = static_cast<WebApplication*>(user_data);
211     if (self == NULL) return;
212     uint64_t id = ewk_notification_id_get(noti);
213     std::string title(ewk_notification_title_get(noti)
214                           ? ewk_notification_title_get(noti)
215                           : "");
216     std::string body(
217         ewk_notification_body_get(noti) ? ewk_notification_body_get(noti) : "");
218     std::string icon_path = self->data_path() + "/" + kNotiIconFile;
219     if (!ewk_notification_icon_save_as_png(noti, icon_path.c_str())) {
220       icon_path = "";
221     }
222     if (NotificationManager::GetInstance()->Show(id, title, body, icon_path))
223       ewk_notification_showed(id);
224   };
225   auto hide = [](Ewk_Context*, uint64_t noti_id, void*) {
226     NotificationManager::GetInstance()->Hide(noti_id);
227     ewk_notification_closed(noti_id, EINA_FALSE);
228   };
229   ewk_context_notification_callbacks_set(ewk_context, show, hide, app);
230 }
231
232 static Eina_Bool ExitAppIdlerCallback(void* data) {
233   WebApplication* app = static_cast<WebApplication*>(data);
234
235   if (app) {
236     LOGGER(DEBUG) << "Terminate";
237     app->Terminate();
238   }
239
240   return ECORE_CALLBACK_CANCEL;
241 }
242
243 static bool ClearCookie(Ewk_Context* ewk_context) {
244   Ewk_Cookie_Manager* cookie_manager =
245       ewk_context_cookie_manager_get(ewk_context);
246   if (!cookie_manager) {
247     LOGGER(ERROR) << "Fail to get cookie manager";
248     return false;
249   }
250   ewk_cookie_manager_cookies_clear(cookie_manager);
251   return true;
252 }
253
254 static bool ProcessWellKnownScheme(const std::string& url) {
255   if (common::utils::StartsWith(url, "file:") ||
256       common::utils::StartsWith(url, "app:") ||
257       common::utils::StartsWith(url, "data:") ||
258       common::utils::StartsWith(url, "http:") ||
259       common::utils::StartsWith(url, "https:") ||
260       common::utils::StartsWith(url, "widget:") ||
261       common::utils::StartsWith(url, "about:") ||
262       common::utils::StartsWith(url, "blob:")) {
263     return false;
264   }
265
266   std::unique_ptr<common::AppControl> request(
267       common::AppControl::MakeAppcontrolFromURL(url));
268   if (request.get() == NULL || !request->LaunchRequest()) {
269     LOGGER(ERROR) << "Fail to send appcontrol request";
270     SLoggerE("Fail to send appcontrol request [%s]", url.c_str());
271   }
272
273   // Should return true, to stop the WebEngine progress step about this URL
274   return true;
275 }
276
277 }  // namespace
278
279 std::vector<unsigned> ParseTizenVersion(const std::string& tizen_string) {
280   std::vector<unsigned> version(3, 0);
281   for (unsigned i = 0, index = 0; i < tizen_string.size(); i++) {
282     if ((i % 2) == 0) {
283       if (isdigit(tizen_string[i]) && index < version.size())
284         version[index++] = atoi(&tizen_string[i]);
285       else
286         return std::vector<unsigned>(3, 0);
287      } else if (tizen_string[i] != '.')
288         return std::vector<unsigned>(3, 0);
289   }
290   return version;
291 }
292
293 WebApplication::WebApplication(
294     NativeWindow* window,
295     common::ApplicationData* app_data)
296     : launched_(false),
297       debug_mode_(false),
298       verbose_mode_(false),
299       lang_changed_mode_(false),
300       is_terminate_called_(false),
301       is_close_page_called_(false),
302       ewk_context_(
303           ewk_context_new_with_injected_bundle_path(INJECTED_BUNDLE_PATH)),
304       has_ownership_of_ewk_context_(true),
305       window_(window),
306       appid_(app_data->app_id()),
307       app_data_(app_data),
308       locale_manager_(new common::LocaleManager()) {
309   Initialize();
310 }
311
312 WebApplication::WebApplication(
313     NativeWindow* window,
314     common::ApplicationData* app_data,
315     Ewk_Context* context)
316     : launched_(false),
317       debug_mode_(false),
318       verbose_mode_(false),
319       lang_changed_mode_(false),
320       is_terminate_called_(false),
321       is_close_page_called_(false),
322       ewk_context_(context),
323       has_ownership_of_ewk_context_(false),
324       window_(window),
325       appid_(app_data->app_id()),
326       app_data_(app_data),
327       locale_manager_(new common::LocaleManager()) {
328   Initialize();
329 }
330
331 WebApplication::~WebApplication() {
332   window_->SetContent(NULL);
333   auto it = view_stack_.begin();
334   for (; it != view_stack_.end(); ++it) {
335     (*it)->Suspend();
336     delete *it;
337   }
338   view_stack_.clear();
339   if (ewk_context_ && has_ownership_of_ewk_context_)
340     ewk_context_delete(ewk_context_);
341 }
342
343 bool WebApplication::Initialize() {
344   SCOPE_PROFILE();
345   std::unique_ptr<char, decltype(std::free)*> path{app_get_data_path(),
346                                                    std::free};
347   app_data_path_ = path.get();
348
349   if (app_data_->setting_info() != NULL &&
350       app_data_->setting_info()->screen_orientation() ==
351           wgt::parse::SettingInfo::ScreenOrientation::AUTO) {
352     ewk_context_tizen_extensible_api_string_set(ewk_context_,
353                                                 kRotationLockFeature, true);
354     window_->SetAutoRotation();
355   } else if (app_data_->setting_info() != NULL &&
356              app_data_->setting_info()->screen_orientation() ==
357                  wgt::parse::SettingInfo::ScreenOrientation::PORTRAIT) {
358     window_->SetRotationLock(NativeWindow::ScreenOrientation::PORTRAIT_PRIMARY);
359   } else if (app_data_->setting_info() != NULL &&
360              app_data_->setting_info()->screen_orientation() ==
361                  wgt::parse::SettingInfo::ScreenOrientation::LANDSCAPE) {
362     window_->SetRotationLock(
363         NativeWindow::ScreenOrientation::LANDSCAPE_PRIMARY);
364   }
365
366   splash_screen_.reset(new SplashScreen(
367       window_, app_data_->splash_screen_info(), app_data_->application_path()));
368   resource_manager_.reset(
369       new common::ResourceManager(app_data_, locale_manager_.get()));
370   resource_manager_->set_base_resource_path(app_data_->application_path());
371
372   auto extension_server = extensions::XWalkExtensionServer::GetInstance();
373   extension_server->SetupIPC(ewk_context_);
374
375   // ewk setting
376   ewk_context_cache_model_set(ewk_context_, EWK_CACHE_MODEL_DOCUMENT_BROWSER);
377
378   // cookie
379   auto cookie_manager = ewk_context_cookie_manager_get(ewk_context_);
380   ewk_cookie_manager_accept_policy_set(cookie_manager,
381                                        EWK_COOKIE_ACCEPT_POLICY_ALWAYS);
382
383   // set persistent storage path
384   std::string cookie_path = data_path() + ".cookie";
385   ewk_cookie_manager_persistent_storage_set(
386       cookie_manager, cookie_path.c_str(),
387       EWK_COOKIE_PERSISTENT_STORAGE_SQLITE);
388
389   // vibration callback
390   auto vibration_start_callback = [](uint64_t ms, void*) {
391     platform::VibrationManager::GetInstance()->Start(static_cast<int>(ms));
392   };
393   auto vibration_stop_callback = [](void* /*user_data*/) {
394     platform::VibrationManager::GetInstance()->Stop();
395   };
396   ewk_context_vibration_client_callbacks_set(
397       ewk_context_, vibration_start_callback, vibration_stop_callback, NULL);
398
399   auto download_callback = [](const char* downloadUrl, void* /*data*/) {
400     SendDownloadRequest(downloadUrl);
401   };
402   ewk_context_did_start_download_callback_set(ewk_context_, download_callback,
403                                               this);
404   InitializeNotificationCallback(ewk_context_, this);
405
406   if (FindPrivilegeFromConfig(app_data_, kFullscreenPrivilege)) {
407     ewk_context_tizen_extensible_api_string_set(ewk_context_,
408                                                 kFullscreenFeature, true);
409   }
410
411   if (app_data_->setting_info() != NULL &&
412       app_data_->setting_info()->background_support_enabled()) {
413     ewk_context_tizen_extensible_api_string_set(
414                                 ewk_context_, kVisibilitySuspendFeature, true);
415     ewk_context_tizen_extensible_api_string_set(ewk_context_,
416                                                 kBackgroundMusicFeature, true);
417   } else {
418     ewk_context_tizen_extensible_api_string_set(
419                                ewk_context_, kVisibilitySuspendFeature, false);
420     ewk_context_tizen_extensible_api_string_set(ewk_context_,
421                                                kBackgroundMusicFeature, false);
422   }
423   ewk_context_tizen_extensible_api_string_set(ewk_context_,
424                                               kMediastreamRecordFeature, true);
425   ewk_context_tizen_extensible_api_string_set(ewk_context_,
426                                               kEncryptedDatabaseFeature, true);
427
428   if (app_data_->setting_info() != NULL &&
429       app_data_->setting_info()->sound_mode() ==
430           wgt::parse::SettingInfo::SoundMode::EXCLUSIVE) {
431     ewk_context_tizen_extensible_api_string_set(ewk_context_, kSoundModeFeature,
432                                                 true);
433   }
434
435   if (app_data_->setting_info() != NULL &&
436       app_data_->setting_info()->background_vibration()) {
437     ewk_context_tizen_extensible_api_string_set(
438         ewk_context_, kBackgroundVibrationFeature, true);
439   }
440
441   if (app_data_->widget_info() != NULL &&
442       !app_data_->widget_info()->default_locale().empty()) {
443     locale_manager_->SetDefaultLocale(
444         app_data_->widget_info()->default_locale());
445   }
446
447   if (app_data_->widget_info() != NULL &&
448         app_data_->widget_info()->view_modes() == "fullscreen") {
449       window_->SetCurrentViewModeFullScreen(true);
450       window_->FullScreen(true);
451   }
452
453   if (app_data_->csp_info() != NULL || app_data_->csp_report_info() != NULL ||
454       app_data_->allowed_navigation_info() != NULL) {
455     security_model_version_ = 2;
456     if (app_data_->csp_info() == NULL ||
457         app_data_->csp_info()->security_rules().empty()) {
458       csp_rule_ = kDefaultCSPRule;
459     } else {
460       csp_rule_ = app_data_->csp_info()->security_rules();
461     }
462     if (app_data_->csp_report_info() != NULL &&
463         !app_data_->csp_report_info()->security_rules().empty()) {
464       csp_report_rule_ = app_data_->csp_report_info()->security_rules();
465     }
466     ewk_context_tizen_extensible_api_string_set(ewk_context_, kCSPFeature,
467                                                 EINA_TRUE);
468   } else {
469     security_model_version_ = 1;
470   }
471
472 #ifdef MANUAL_ROTATE_FEATURE_SUPPORT
473   // Set manual rotation
474   window_->EnableManualRotation(true);
475 #endif  // MANUAL_ROTATE_FEATURE_SUPPORT
476
477   main_loop.application = NULL;
478   main_loop.timer = NULL;
479   session_counter.application = NULL;
480   session_counter.timer = NULL;
481   m_tizenCompatibilitySettings.m_major = 0;
482   m_tizenCompatibilitySettings.m_minor = 0;
483   m_tizenCompatibilitySettings.m_release = 0;
484
485   return true;
486 }
487
488 void WebApplication::SetupTizenVersion() {
489     if (app_data_->tizen_application_info() != NULL &&
490             !app_data_->tizen_application_info()->required_version().empty()) {
491         std::string tizen_version = app_data_->tizen_application_info()->required_version();
492         std::vector<unsigned> parsed_tizen_version = ParseTizenVersion(tizen_version);
493         m_tizenCompatibilitySettings.m_major = parsed_tizen_version[0];
494         m_tizenCompatibilitySettings.m_minor = parsed_tizen_version[1];
495         m_tizenCompatibilitySettings.m_release = parsed_tizen_version[2];
496     }
497 }
498
499 bool WebApplication::tizenWebKitCompatibilityEnabled() const {
500   return m_tizenCompatibilitySettings.tizenWebKitCompatibilityEnabled();
501 }
502
503 void WebApplication::Launch(std::unique_ptr<common::AppControl> appcontrol) {
504   // send widget info to injected bundle
505   ewk_context_tizen_app_id_set(ewk_context_, appid_.c_str());
506
507   SetupTizenVersion();
508
509   // Setup View
510   WebView* view = new WebView(window_, ewk_context_);
511   SetupWebView(view);
512   SetupWebViewCompatibilitySettings(view);
513
514   std::unique_ptr<common::ResourceManager::Resource> res =
515       resource_manager_->GetStartResource(appcontrol.get());
516   view->SetDefaultEncoding(res->encoding());
517
518   STEP_PROFILE_END("OnCreate -> URL Set");
519   STEP_PROFILE_START("URL Set -> Rendered");
520
521   window_->SetContent(view->evas_object());
522
523 #ifdef PROFILE_MOBILE
524   // rotate and resize window forcibily for landscape mode.
525   // window rotate event is generated after window show. so
526   // when app get width and height from viewport, wrong value can be returned.
527   if (app_data_->setting_info()->screen_orientation() ==
528              wgt::parse::SettingInfo::ScreenOrientation::LANDSCAPE) {
529     LOGGER(DEBUG) << "rotate and resize window for landscape mode";
530     elm_win_rotation_with_resize_set(window_->evas_object(), 270);
531     evas_norender(evas_object_evas_get(window_->evas_object()));
532   }
533 #endif  // PROFILE_MOBILE
534
535   view->LoadUrl(res->uri(), res->mime());
536   view_stack_.push_front(view);
537
538 #ifdef PROFILE_WEARABLE
539   // ewk_view_bg_color_set is not working at webview initialization.
540   if (app_data_->app_type() == common::ApplicationData::WATCH) {
541     view->SetBGColor(0, 0, 0, 255);
542   }
543 #endif  // PROFILE_WEARABLE
544
545   if (appcontrol->data(AUL_K_DEBUG) == "1") {
546     debug_mode_ = true;
547     LaunchInspector(appcontrol.get());
548   }
549   if (appcontrol->data(kVerboseKey) == "true") {
550     verbose_mode_ = true;
551   }
552
553   launched_ = true;
554
555 #ifdef PROFILE_MOBILE
556   if (!common::utils::StartsWith(view->GetUrl(), kFileScheme)) {
557     LOGGER(DEBUG) << "Show window after launch for remote URL";
558     window_->Show();
559     window_->Active();
560   }
561 #endif  // PROFILE_MOBILE
562 }
563
564 void WebApplication::AppControl(
565     std::unique_ptr<common::AppControl> appcontrol) {
566   std::unique_ptr<common::ResourceManager::Resource> res =
567       resource_manager_->GetStartResource(appcontrol.get());
568
569   bool do_reset = res->should_reset();
570
571   if (!do_reset) {
572     std::string current_page = view_stack_.front()->GetUrl();
573     std::string localized_page = res->uri();
574
575     if (current_page != localized_page) {
576       do_reset = true;
577     } else {
578       SendAppControlEvent();
579     }
580   }
581
582   // handle http://tizen.org/appcontrol/operation/main operation specially.
583   // only menu-screen app can send launch request with main operation.
584   // in this case, web app should have to resume web app not reset.
585   if (do_reset && (appcontrol->operation() == kAppControlMain)){
586     LOGGER(DEBUG) << "resume app for main operation";
587     do_reset = false;
588     SendAppControlEvent();
589   }
590
591   if (do_reset) {
592     // Reset to context
593     ClearViewStack();
594     WebView* view = view_stack_.front();
595     SetupWebView(view);
596     SetupWebViewCompatibilitySettings(view);
597     view->SetDefaultEncoding(res->encoding());
598     view->LoadUrl(res->uri(), res->mime());
599     window_->SetContent(view->evas_object());
600   }
601
602   if (!debug_mode_ && appcontrol->data(AUL_K_DEBUG) == "1") {
603     debug_mode_ = true;
604     LaunchInspector(appcontrol.get());
605   }
606   if (!verbose_mode_ && appcontrol->data(kVerboseKey) == "true") {
607     verbose_mode_ = true;
608   }
609   window_->Active();
610 }
611
612 void WebApplication::SendAppControlEvent() {
613   if (view_stack_.size() > 0 && view_stack_.front() != NULL)
614     view_stack_.front()->EvalJavascript(kAppControlEventScript);
615 }
616
617 void WebApplication::ClearViewStack() {
618   window_->SetContent(NULL);
619   WebView* front = view_stack_.front();
620   auto it = view_stack_.begin();
621   for (; it != view_stack_.end(); ++it) {
622     if (*it != front) {
623       (*it)->Suspend();
624       delete *it;
625     }
626   }
627   view_stack_.clear();
628   view_stack_.push_front(front);
629 }
630
631 void WebApplication::Resume() {
632   if (view_stack_.size() > 0 && view_stack_.front() != NULL)
633     view_stack_.front()->SetVisibility(true);
634
635   if (app_data_->setting_info() != NULL &&
636       app_data_->setting_info()->background_support_enabled()) {
637     return;
638   }
639
640   auto it = view_stack_.begin();
641   for (; it != view_stack_.end(); ++it) {
642     (*it)->Resume();
643   }
644 }
645
646 void WebApplication::Suspend() {
647   if (view_stack_.size() > 0 && view_stack_.front() != NULL)
648     view_stack_.front()->SetVisibility(false);
649
650   if (app_data_->setting_info() != NULL &&
651       app_data_->setting_info()->background_support_enabled()) {
652     LOGGER(DEBUG) << "gone background (backgroud support enabed)";
653     return;
654   }
655
656   auto it = view_stack_.begin();
657   for (; it != view_stack_.end(); ++it) {
658     (*it)->Suspend();
659   }
660 }
661
662 void WebApplication::Terminate() {
663   // Just process closing page once.
664   if (is_terminate_called_ || is_close_page_called_)
665     return;
666
667   is_terminate_called_ = true;
668   ClosePage();
669 }
670
671 // static
672 Eina_Bool WebApplication::ClosePageInExtendedMainLoop(void* user_data)
673 {
674   LOGGER(DEBUG);
675   struct Timer* main_loop = static_cast<Timer*>(user_data);
676   main_loop->application->ClosePage();
677   return ECORE_CALLBACK_CANCEL;
678 }
679
680 void WebApplication::ProcessClosingPage() {
681   LOGGER(DEBUG);
682
683   main_loop.application = this;
684   main_loop.timer = ecore_timer_add(MAIN_LOOP_INTERVAL,
685       ClosePageInExtendedMainLoop, &main_loop);
686   if (!main_loop.timer)
687     LOGGER(ERROR) << "It's failed to create main_loop timer";
688   LOGGER(DEBUG) << "Defer termination of main loop";
689   ecore_main_loop_begin();
690   ecore_timer_del(main_loop.timer);
691   ecore_timer_del(session_counter.timer);
692 }
693
694 void WebApplication::ClosePage() {
695   LOGGER(DEBUG);
696   is_close_page_called_ = true;
697
698   int valid_evas_object_count = 0;
699   auto it = view_stack_.begin();
700   if (it != view_stack_.end()) {
701     for (; it != view_stack_.end(); ++it) {
702       (*it)->ReplyToJavascriptDialog();
703       view_stack_.front()->SetVisibility(false);
704       if (ewk_view_page_close((*it)->evas_object())) {
705         LOGGER(DEBUG) << "ewk_view_page_close returns true";
706         valid_evas_object_count++;
707       } else {
708         LOGGER(DEBUG) << "ewk_view_page_close returns false";
709       }
710     }
711   }
712   if (valid_evas_object_count == 0)
713     Exit();
714 }
715
716 void WebApplication::Exit() {
717   if (!is_terminate_called_)
718     ecore_main_loop_quit();
719
720   switch (app_data_->app_type()) {
721     case common::ApplicationData::AppType::UI:
722       LOGGER(ERROR) << "app_ui_exit";
723       ui_app_exit();
724       break;
725 #ifdef WATCH_FACE_FEATURE_SUPPORT
726     case common::ApplicationData::AppType::WATCH:
727       LOGGER(ERROR) << "watch_ui_exit";
728       watch_app_exit();
729       break;
730 #endif
731     default:
732       LOGGER(ERROR) << "default terminator";
733       elm_exit();
734   }
735 }
736
737 void WebApplication::OnCreatedNewWebView(WebView* /*view*/, WebView* new_view) {
738   if (view_stack_.size() > 0 && view_stack_.front() != NULL)
739     view_stack_.front()->SetVisibility(false);
740
741   SetupWebView(new_view);
742   SetupWebViewCompatibilitySettings(new_view);
743   view_stack_.push_front(new_view);
744   window_->SetContent(new_view->evas_object());
745 }
746
747 void WebApplication::RemoveWebViewFromStack(WebView* view) {
748   if (view_stack_.size() == 0)
749     return;
750
751   WebView* current = view_stack_.front();
752   if (current == view) {
753     // In order to prevent the crash issue due to the callback
754     // which occur after destroying WebApplication class,
755     // we have to set the 'SetEventListener' to NULL.
756     view->SetEventListener(NULL);
757     view_stack_.pop_front();
758   } else {
759     auto found = std::find(view_stack_.begin(), view_stack_.end(), view);
760     if (found != view_stack_.end()) {
761       // In order to prevent the crash issue due to the callback
762       // which occur after destroying WebApplication class,
763       // we have to set the 'SetEventListener' to NULL.
764       view->SetEventListener(NULL);
765       view_stack_.erase(found);
766     }
767   }
768
769   if (view_stack_.size() == 0) {
770     auto extension_server = XWalkExtensionServer::GetInstance();
771     LOGGER(DEBUG) << "Shutdown extension server";
772     extension_server->Shutdown();
773 #if !defined(TIZEN_PRODUCT_TV)
774     // Hide the window object for preventing the white screen
775     // during termination of web application.
776     evas_object_hide(window_->evas_object());
777     Exit();
778 #endif
779   } else if (current != view_stack_.front()) {
780     view_stack_.front()->SetVisibility(true);
781     window_->SetContent(view_stack_.front()->evas_object());
782   }
783
784   // Delete after the callback context(for ewk view) was not used
785   ecore_idler_add([](void* view) {
786                     WebView* obj = static_cast<WebView*>(view);
787                     delete obj;
788                     return EINA_FALSE;
789                   },
790                   view);
791 }
792
793 Eina_Bool WebApplication::CheckPluginSession(void* user_data)
794 {
795   struct Timer* session_counter = static_cast<Timer*>(user_data);
796   if(XWalkExtensionRendererController::plugin_session_count > 0) {
797     LOGGER(ERROR) << "plugin_session_count : " <<
798         XWalkExtensionRendererController::plugin_session_count;
799     return ECORE_CALLBACK_RENEW;
800   }
801   LOGGER(DEBUG) << "plugin_session_count : " <<
802       XWalkExtensionRendererController::plugin_session_count;
803   LOGGER(DEBUG) << "Execute deferred termination of main loop";
804   session_counter->application->Exit();
805   return ECORE_CALLBACK_CANCEL;
806 }
807
808 void WebApplication::OnClosedWebView(WebView* view) {
809   // Reply to javascript dialog for preventing freeze issue.
810   view->ReplyToJavascriptDialog();
811   RemoveWebViewFromStack(view);
812
813 #if defined(TIZEN_PRODUCT_TV)
814   LOGGER(DEBUG) << "plugin_session_count : " <<
815       XWalkExtensionRendererController::plugin_session_count;
816
817   // Hide the window object for preventing the white screen
818   // during termination of web application.
819   evas_object_hide(window_->evas_object());
820
821   session_counter.application = this;
822   session_counter.timer = ecore_timer_add(SESSION_COUNTER_INTERVAL,
823       CheckPluginSession, &session_counter);
824   if (!session_counter.timer)
825     LOGGER(ERROR) << "It's failed to create session_counter timer";
826 #endif
827 }
828
829 void WebApplication::OnReceivedWrtMessage(WebView* view,
830                                           Ewk_IPC_Wrt_Message_Data* msg) {
831   Eina_Stringshare* msg_type = ewk_ipc_wrt_message_data_type_get(msg);
832
833 #define TYPE_BEGIN(x) (!strncmp(msg_type, x, strlen(x)))
834 #define TYPE_IS(x) (!strcmp(msg_type, x))
835
836   if (TYPE_BEGIN("xwalk://")) {
837     auto extension_server = extensions::XWalkExtensionServer::GetInstance();
838     extension_server->HandleIPCMessage(msg);
839   } else {
840     Eina_Stringshare* msg_id = ewk_ipc_wrt_message_data_id_get(msg);
841     Eina_Stringshare* msg_ref_id =
842         ewk_ipc_wrt_message_data_reference_id_get(msg);
843     Eina_Stringshare* msg_value = ewk_ipc_wrt_message_data_value_get(msg);
844
845     if (TYPE_IS("tizen://hide")) {
846       // One Way Message
847       window_->InActive();
848     } else if (TYPE_IS("tizen://exit")) {
849       // One Way Message
850       // Reply to javascript dialog for preventing freeze issue.
851       view->ReplyToJavascriptDialog();
852       ecore_idler_add(ExitAppIdlerCallback, this);
853     } else if (TYPE_IS("tizen://changeUA")) {
854       // Async Message
855       // Change UserAgent of current WebView
856       bool ret = false;
857       if (view_stack_.size() > 0 && view_stack_.front() != NULL) {
858         ret = view_stack_.front()->SetUserAgent(std::string(msg_value));
859       }
860       // Send response
861       Ewk_IPC_Wrt_Message_Data* ans = ewk_ipc_wrt_message_data_new();
862       ewk_ipc_wrt_message_data_type_set(ans, msg_type);
863       ewk_ipc_wrt_message_data_reference_id_set(ans, msg_id);
864       if (ret)
865         ewk_ipc_wrt_message_data_value_set(ans, "success");
866       else
867         ewk_ipc_wrt_message_data_value_set(ans, "failed");
868       if (!ewk_ipc_wrt_message_send(ewk_context_, ans)) {
869         LOGGER(ERROR) << "Failed to send response";
870       }
871       ewk_ipc_wrt_message_data_del(ans);
872     } else if (TYPE_IS("tizen://deleteAllCookies")) {
873       Ewk_IPC_Wrt_Message_Data* ans = ewk_ipc_wrt_message_data_new();
874       ewk_ipc_wrt_message_data_type_set(ans, msg_type);
875       ewk_ipc_wrt_message_data_reference_id_set(ans, msg_id);
876       if (ClearCookie(ewk_context_))
877         ewk_ipc_wrt_message_data_value_set(ans, "success");
878       else
879         ewk_ipc_wrt_message_data_value_set(ans, "failed");
880       if (!ewk_ipc_wrt_message_send(ewk_context_, ans)) {
881         LOGGER(ERROR) << "Failed to send response";
882       }
883       ewk_ipc_wrt_message_data_del(ans);
884     } else if (TYPE_IS("tizen://hide_splash_screen")) {
885       splash_screen_->HideSplashScreen(SplashScreen::HideReason::CUSTOM);
886     }
887
888     eina_stringshare_del(msg_ref_id);
889     eina_stringshare_del(msg_id);
890     eina_stringshare_del(msg_value);
891   }
892
893 #undef TYPE_IS
894 #undef TYPE_BEGIN
895
896   eina_stringshare_del(msg_type);
897 }
898
899 void WebApplication::OnOrientationLock(
900     WebView* view, bool lock,
901     NativeWindow::ScreenOrientation preferred_rotation) {
902   if (view_stack_.size() == 0) return;
903
904   // Only top-most view can set the orientation relate operation
905   if (view_stack_.front() != view) return;
906
907   // This is for 2.4 compatibility. Requested by Webengine Team.
908   //
909   // In Tizen 2.4 WebKit locking screen orientation was possible with Web API
910   // screen.lockOrientation(). This API was deprecated and replaced with
911   // screen.orientation.lock(). But for compatibility case we need to support
912   // old API.
913   if(!tizenWebKitCompatibilityEnabled()) {
914     auto orientaion_setting = app_data_->setting_info() != NULL
915         ? app_data_->setting_info()->screen_orientation()
916         : wgt::parse::SettingInfo::ScreenOrientation::AUTO;
917     if (wgt::parse::SettingInfo::ScreenOrientation::AUTO != orientaion_setting) {
918         // If Tizen version is 3.0, it return.
919         return;
920     }
921   }
922
923   if (lock) {
924     window_->SetRotationLock(preferred_rotation);
925   } else {
926     window_->SetAutoRotation();
927   }
928 }
929
930 void WebApplication::OnHardwareKey(WebView* view, const std::string& keyname) {
931   // NOTE: This code is added to enable back-key on remote URL
932   bool enabled = app_data_->setting_info() != NULL
933                      ? app_data_->setting_info()->hwkey_enabled()
934                      : true;
935
936   if (!common::utils::StartsWith(view->GetUrl(), kFileScheme)) {
937     if (kKeyNameBack == keyname) {
938       LOGGER(DEBUG) << "Back to previous page for remote URL";
939       if(enabled)
940         view->EvalJavascript(kBackKeyEventScript);
941       if (!view->Backward()) {
942         LOGGER(DEBUG) << "Terminate";
943         Terminate();
944       }
945     }
946     return;
947   }
948
949   if (enabled && kKeyNameBack == keyname) {
950     view->EvalJavascript(kBackKeyEventScript);
951     // NOTE: This code is added for backward compatibility.
952     // If the 'backbutton_presence' is true, WebView should be navigated back.
953     if ((app_data_->setting_info() != NULL &&
954          app_data_->setting_info()->backbutton_presence()) ||
955         (app_data_->widget_info() != NULL &&
956          app_data_->widget_info()->view_modes() == "windowed")) {
957       if (!view->Backward()) {
958         LOGGER(DEBUG) << "Terminate";
959         Terminate();
960       }
961     }
962   } else if (enabled && kKeyNameMenu == keyname) {
963     view->EvalJavascript(kMenuKeyEventScript);
964   }
965 }
966
967 void WebApplication::OnLanguageChanged() {
968   lang_changed_mode_ = true;
969   locale_manager_->UpdateSystemLocale();
970   ewk_context_cache_clear(ewk_context_);
971   auto it = view_stack_.begin();
972   for (; it != view_stack_.end(); ++it) {
973     (*it)->Reload();
974   }
975 }
976
977 void WebApplication::OnConsoleMessage(const std::string& msg, int level) {
978   static bool enabled = (getenv(kConsoleLogEnableKey) != NULL);
979   enabled = true;
980
981   std::string split_msg = msg;
982   std::size_t pos = msg.find(kResWgtPath);
983   if (pos != std::string::npos) {
984     split_msg = msg.substr(pos + strlen(kResWgtPath));
985   }
986
987   if (debug_mode_ || verbose_mode_ || enabled) {
988     int dlog_level = DLOG_DEBUG;
989     switch (level) {
990       case EWK_CONSOLE_MESSAGE_LEVEL_WARNING:
991         dlog_level = DLOG_WARN;
992         break;
993       case EWK_CONSOLE_MESSAGE_LEVEL_ERROR:
994         dlog_level = DLOG_ERROR;
995         break;
996       default:
997         dlog_level = DLOG_DEBUG;
998         break;
999     }
1000     LOGGER_RAW(dlog_level, kConsoleMessageLogTag)
1001       << "[" << app_data_->pkg_id() << "] " << split_msg;
1002   }
1003 }
1004
1005 void WebApplication::OnLowMemory() {
1006   ewk_context_cache_clear(ewk_context_);
1007   ewk_context_notify_low_memory(ewk_context_);
1008 }
1009
1010 void WebApplication::OnSoftKeyboardChangeEvent(WebView* /*view*/,
1011                                SoftKeyboardChangeEventValue softkeyboard_value) {
1012   LOGGER(DEBUG) << "OnSoftKeyboardChangeEvent";
1013   std::stringstream script;
1014   script
1015     << "(function(){"
1016     << "var __event = document.createEvent(\"CustomEvent\");\n"
1017     << "var __detail = {};\n"
1018     << "__event.initCustomEvent(\"softkeyboardchange\",true,true,__detail);\n"
1019     << "__event.state = \"" << softkeyboard_value.state << "\";\n"
1020     << "__event.width = " << softkeyboard_value.width << ";\n"
1021     << "__event.height = " << softkeyboard_value.height << ";\n"
1022     << "document.dispatchEvent(__event);\n"
1023     << "\n"
1024     << "for (var i=0; i < window.frames.length; i++)\n"
1025     << "{ window.frames[i].document.dispatchEvent(__event); }"
1026     << "})()";
1027   std::string kSoftKeyboardScript = script.str();
1028   if (view_stack_.size() > 0 && view_stack_.front() != NULL)
1029     view_stack_.front()->EvalJavascript(kSoftKeyboardScript.c_str());
1030 }
1031
1032 #ifdef ROTARY_EVENT_FEATURE_SUPPORT
1033 void WebApplication::OnRotaryEvent(WebView* /*view*/,
1034                                    RotaryEventType type) {
1035   LOGGER(DEBUG) << "OnRotaryEvent";
1036   std::stringstream script;
1037   script
1038     << "(function(){"
1039     << "var __event = document.createEvent(\"CustomEvent\");\n"
1040     << "var __detail = {};\n"
1041     << "__event.initCustomEvent(\"rotarydetent\", true, true, __detail);\n"
1042     << "__event.detail.direction = \""
1043     << (type == RotaryEventType::CLOCKWISE ? "CW" : "CCW")
1044     << "\";\n"
1045     << "document.dispatchEvent(__event);\n"
1046     << "\n"
1047     << "for (var i=0; i < window.frames.length; i++)\n"
1048     << "{ window.frames[i].document.dispatchEvent(__event); }"
1049     << "})()";
1050   std::string kRotaryEventScript = script.str();
1051   if (view_stack_.size() > 0 && view_stack_.front() != NULL)
1052     view_stack_.front()->EvalJavascript(kRotaryEventScript.c_str());
1053 }
1054 #endif  // ROTARY_EVENT_FEATURE_SUPPORT
1055
1056 void WebApplication::OnTimeTick(long time) {
1057 #if 0
1058   LOGGER(DEBUG) << "TimeTick";
1059   if (view_stack_.size() > 0 && view_stack_.front() != NULL)
1060     view_stack_.front()->EvalJavascript(kAmbientTickEventScript);
1061 #endif
1062 }
1063
1064 void WebApplication::OnAmbientTick(long time) {
1065   LOGGER(DEBUG) << "AmbientTick";
1066   if (view_stack_.size() > 0 && view_stack_.front() != NULL)
1067     view_stack_.front()->EvalJavascript(kAmbientTickEventScript);
1068 }
1069
1070 void WebApplication::OnAmbientChanged(bool ambient_mode) {
1071   LOGGER(DEBUG) << "AmbientChanged";
1072   std::stringstream script;
1073   script
1074     << "(function(){"
1075     << "var __event = document.createEvent(\"CustomEvent\");\n"
1076     << "var __detail = {};\n"
1077     << "__event.initCustomEvent(\"ambientmodechanged\",true,true,__detail);\n"
1078     << "__event.detail.ambientMode = "
1079     << (ambient_mode ? "true" : "false") << ";\n"
1080     << "document.dispatchEvent(__event);\n"
1081     << "\n"
1082     << "for (var i=0; i < window.frames.length; i++)\n"
1083     << "{ window.frames[i].document.dispatchEvent(__event); }"
1084     << "})()";
1085   std::string kAmbientChangedEventScript = script.str();
1086   if (view_stack_.size() > 0 && view_stack_.front() != NULL)
1087     view_stack_.front()->EvalJavascript(kAmbientChangedEventScript.c_str());
1088 }
1089
1090 bool WebApplication::OnContextMenuDisabled(WebView* /*view*/) {
1091   return !(app_data_->setting_info() != NULL
1092                ? app_data_->setting_info()->context_menu_enabled()
1093                : true);
1094 }
1095
1096 void WebApplication::OnLoadStart(WebView* /*view*/) {
1097   LOGGER(DEBUG) << "LoadStart";
1098 }
1099
1100 void WebApplication::OnLoadFinished(WebView* /*view*/) {
1101   LOGGER(DEBUG) << "LoadFinished";
1102   splash_screen_->HideSplashScreen(SplashScreen::HideReason::LOADFINISHED);
1103 }
1104
1105 void WebApplication::OnRendered(WebView* view) {
1106   STEP_PROFILE_END("URL Set -> Rendered");
1107   STEP_PROFILE_END("Start -> Launch Completed");
1108   LOGGER(DEBUG) << "Rendered";
1109   splash_screen_->HideSplashScreen(SplashScreen::HideReason::RENDERED);
1110
1111   // Do not show(), active() for language change
1112   if(lang_changed_mode_ == false){
1113       // Show window after frame rendered.
1114 #ifdef PROFILE_MOBILE
1115       if (common::utils::StartsWith(view->GetUrl(), kFileScheme)) {
1116         window_->Show();
1117         window_->Active();
1118       }
1119 #else  // PROFILE_MOBILE
1120       window_->Show();
1121       window_->Active();
1122 #endif
1123   }
1124   else{
1125       lang_changed_mode_ = false;
1126   }
1127 }
1128
1129 #ifdef MANUAL_ROTATE_FEATURE_SUPPORT
1130 void WebApplication::OnRotatePrepared(WebView* /*view*/) {
1131   window_->ManualRotationDone();
1132 }
1133 #endif  // MANUAL_ROTATE_FEATURE_SUPPORT
1134
1135 void WebApplication::LaunchInspector(common::AppControl* appcontrol) {
1136   unsigned int port = ewk_context_inspector_server_start(ewk_context_, 0);
1137   std::stringstream ss;
1138   ss << port;
1139   std::map<std::string, std::vector<std::string>> data;
1140   data[kPortKey] = {ss.str()};
1141   appcontrol->Reply(data);
1142 }
1143
1144 void WebApplication::SetupWebView(WebView* view) {
1145   view->SetEventListener(this);
1146
1147   // Setup CSP Rule
1148   if (security_model_version_ == 2) {
1149     view->SetCSPRule(csp_rule_, false);
1150     if (!csp_report_rule_.empty()) {
1151       view->SetCSPRule(csp_report_rule_, true);
1152     }
1153   }
1154
1155 // Setup longpolling value
1156   if (app_data_->setting_info() != NULL &&
1157      app_data_->setting_info()->long_polling()) {
1158     boost::optional <unsigned int> polling_val(app_data_->setting_info()->long_polling());
1159     unsigned long *ptr =  reinterpret_cast <unsigned long *> (&polling_val.get());
1160     view->SetLongPolling(*ptr);
1161   }
1162 }
1163
1164 void WebApplication::SetupWebViewCompatibilitySettings(WebView* view) {
1165   if (tizenWebKitCompatibilityEnabled()) {
1166     Ewk_Settings* settings = ewk_view_settings_get(view->evas_object());
1167     ewk_settings_tizen_compatibility_mode_set(settings,
1168             m_tizenCompatibilitySettings.m_major,
1169             m_tizenCompatibilitySettings.m_minor,
1170             m_tizenCompatibilitySettings.m_release);
1171     ewk_settings_text_autosizing_enabled_set(settings, EINA_FALSE);
1172   }
1173 }
1174
1175 bool WebApplication::OnDidNavigation(WebView* /*view*/,
1176                                      const std::string& url) {
1177   // scheme handling
1178   // except(file , http, https, app) pass to appcontrol and return false
1179   if (ProcessWellKnownScheme(url)) {
1180     return false;
1181   }
1182
1183   // send launch request for blocked URL to guarrenty backward-compatibility.
1184   if (resource_manager_->AllowNavigation(url)) {
1185     return true;
1186   } else {
1187     LOGGER(DEBUG) << "URL is blocked. send launch request for URL : " << url;
1188     std::unique_ptr<common::AppControl> request(
1189       common::AppControl::MakeAppcontrolFromURL(url));
1190     if (request.get() == NULL || !request->LaunchRequest()) {
1191       LOGGER(ERROR) << "Fail to send appcontrol request";
1192     }
1193     return false;
1194   }
1195 }
1196
1197 void WebApplication::OnNotificationPermissionRequest(
1198     WebView*, const std::string& url,
1199     std::function<void(bool)> result_handler) {
1200   auto db = common::AppDB::GetInstance();
1201   std::string reminder =
1202       db->Get(kDBPrivateSection, kNotificationPermissionPrefix + url);
1203   if (reminder == "allowed") {
1204     result_handler(true);
1205     return;
1206   } else if (reminder == "denied") {
1207     result_handler(false);
1208     return;
1209   }
1210
1211   // Local Domain: Grant permission if defined, otherwise Popup user prompt.
1212   // Remote Domain: Popup user prompt.
1213   if (common::utils::StartsWith(url, "file://") &&
1214       FindPrivilegeFromConfig(app_data_, kNotificationPrivilege)) {
1215     result_handler(true);
1216     return;
1217   }
1218
1219   Popup* popup = Popup::CreatePopup(window_);
1220   popup->SetButtonType(Popup::ButtonType::AllowDenyButton);
1221   popup->SetTitle(popup_string::kPopupTitleWebNotification);
1222   popup->SetBody(popup_string::kPopupBodyWebNotification);
1223   popup->SetCheckBox(popup_string::kPopupCheckRememberPreference);
1224   popup->SetResultHandler(
1225       [db, result_handler, url](Popup* popup, void* /*user_data*/) {
1226         bool result = popup->GetButtonResult();
1227         bool remember = popup->GetCheckBoxResult();
1228         if (remember) {
1229           db->Set(kDBPrivateSection, kNotificationPermissionPrefix + url,
1230                   result ? "allowed" : "denied");
1231         }
1232         result_handler(result);
1233       },
1234       this);
1235   popup->Show();
1236 }
1237
1238 void WebApplication::OnGeolocationPermissionRequest(
1239     WebView*, const std::string& url,
1240     std::function<void(bool)> result_handler) {
1241   auto db = common::AppDB::GetInstance();
1242   std::string reminder =
1243       db->Get(kDBPrivateSection, kGeolocationPermissionPrefix + url);
1244   if (reminder == "allowed") {
1245     result_handler(true);
1246     return;
1247   } else if (reminder == "denied") {
1248     result_handler(false);
1249     return;
1250   }
1251
1252   // Local Domain: Grant permission if defined, otherwise block execution.
1253   // Remote Domain: Popup user prompt if defined, otherwise block execution.
1254   if (!FindPrivilegeFromConfig(app_data_, kLocationPrivilege) &&
1255       !FindPrivilegeFromCynara(kLocationPrivilege)) {
1256     result_handler(false);
1257     return;
1258   }
1259
1260   if (common::utils::StartsWith(url, "file://")) {
1261     result_handler(true);
1262     return;
1263   }
1264
1265   Popup* popup = Popup::CreatePopup(window_);
1266   popup->SetButtonType(Popup::ButtonType::AllowDenyButton);
1267   popup->SetTitle(popup_string::kPopupTitleGeoLocation);
1268   popup->SetBody(popup_string::kPopupBodyGeoLocation);
1269   popup->SetCheckBox(popup_string::kPopupCheckRememberPreference);
1270   popup->SetResultHandler(
1271       [db, result_handler, url](Popup* popup, void* /*user_data*/) {
1272         bool result = popup->GetButtonResult();
1273         bool remember = popup->GetCheckBoxResult();
1274         if (remember) {
1275           db->Set(kDBPrivateSection, kGeolocationPermissionPrefix + url,
1276                   result ? "allowed" : "denied");
1277         }
1278         result_handler(result);
1279       },
1280       this);
1281   popup->Show();
1282 }
1283
1284 void WebApplication::OnQuotaExceed(WebView*, const std::string& url,
1285                                    std::function<void(bool)> result_handler) {
1286   auto db = common::AppDB::GetInstance();
1287   std::string reminder =
1288       db->Get(kDBPrivateSection, kQuotaPermissionPrefix + url);
1289   if (reminder == "allowed") {
1290     result_handler(true);
1291     return;
1292   } else if (reminder == "denied") {
1293     result_handler(false);
1294     return;
1295   }
1296
1297   // Local Domain: Grant permission if defined, otherwise Popup user prompt.
1298   // Remote Domain: Popup user prompt.
1299   if (common::utils::StartsWith(url, "file://") &&
1300       FindPrivilegeFromConfig(app_data_, kStoragePrivilege)) {
1301     result_handler(true);
1302     return;
1303   }
1304
1305   Popup* popup = Popup::CreatePopup(window_);
1306   popup->SetButtonType(Popup::ButtonType::AllowDenyButton);
1307   popup->SetTitle(popup_string::kPopupTitleWebStorage);
1308   popup->SetBody(popup_string::kPopupBodyWebStorage);
1309   popup->SetCheckBox(popup_string::kPopupCheckRememberPreference);
1310   popup->SetResultHandler(
1311       [db, result_handler, url](Popup* popup, void* /*user_data*/) {
1312         bool result = popup->GetButtonResult();
1313         bool remember = popup->GetCheckBoxResult();
1314         if (remember) {
1315           db->Set(kDBPrivateSection, kQuotaPermissionPrefix + url,
1316                   result ? "allowed" : "denied");
1317         }
1318         result_handler(result);
1319       },
1320       this);
1321   popup->Show();
1322 }
1323
1324 void WebApplication::OnAuthenticationRequest(
1325     WebView*, const std::string& /*url*/, const std::string& /*message*/,
1326     std::function<void(bool submit, const std::string& id,
1327                        const std::string& password)> result_handler) {
1328   Popup* popup = Popup::CreatePopup(window_);
1329   popup->SetButtonType(Popup::ButtonType::LoginCancelButton);
1330   popup->SetFirstEntry(popup_string::kPopupLabelAuthusername,
1331                        Popup::EntryType::Edit);
1332   popup->SetSecondEntry(popup_string::kPopupLabelPassword,
1333                         Popup::EntryType::PwEdit);
1334   popup->SetTitle(popup_string::kPopupTitleAuthRequest);
1335   popup->SetBody(popup_string::kPopupBodyAuthRequest);
1336   popup->SetResultHandler([result_handler](Popup* popup, void* /*user_data*/) {
1337                             bool result = popup->GetButtonResult();
1338                             std::string id = popup->GetFirstEntryResult();
1339                             std::string passwd = popup->GetSecondEntryResult();
1340                             result_handler(result, id, passwd);
1341                           },
1342                           this);
1343   popup->Show();
1344 }
1345
1346 void WebApplication::OnCertificateAllowRequest(
1347     WebView*, const std::string& url, const std::string& pem,
1348     std::function<void(bool allow)> result_handler) {
1349   auto db = common::AppDB::GetInstance();
1350   std::string reminder =
1351       db->Get(kDBPrivateSection, kCertificateAllowPrefix + pem);
1352   if (reminder == "allowed") {
1353     result_handler(true);
1354     return;
1355   } else if (reminder == "denied") {
1356     result_handler(false);
1357     return;
1358   }
1359
1360   Popup* popup = Popup::CreatePopup(window_);
1361   popup->SetButtonType(Popup::ButtonType::AllowDenyButton);
1362   popup->SetTitle(popup_string::kPopupTitleCert);
1363   popup->SetBody(popup_string::GetText(
1364                  popup_string::kPopupBodyCert) + "\n\n" + url);
1365   popup->SetCheckBox(popup_string::kPopupCheckRememberPreference);
1366   popup->SetResultHandler(
1367       [db, result_handler, pem](Popup* popup, void* /*user_data*/) {
1368         bool result = popup->GetButtonResult();
1369         bool remember = popup->GetCheckBoxResult();
1370         if (remember) {
1371           db->Set(kDBPrivateSection, kCertificateAllowPrefix + pem,
1372                   result ? "allowed" : "denied");
1373         }
1374         result_handler(result);
1375       },
1376       this);
1377   popup->Show();
1378 }
1379
1380 void WebApplication::OnUsermediaPermissionRequest(
1381     WebView*, const std::string& url,
1382     std::function<void(bool)> result_handler) {
1383   auto db = common::AppDB::GetInstance();
1384   std::string reminder =
1385       db->Get(kDBPrivateSection, kUsermediaPermissionPrefix + url);
1386   if (reminder == "allowed") {
1387     result_handler(true);
1388     return;
1389   } else if (reminder == "denied") {
1390     result_handler(false);
1391     return;
1392   }
1393
1394   // Local Domain: Grant permission if defined, otherwise block execution.
1395   // Remote Domain: Popup user prompt if defined, otherwise block execution.
1396   if (!FindPrivilegeFromConfig(app_data_, kUsermediaPrivilege) &&
1397       !(FindPrivilegeFromCynara(kCameraPrivilege) && FindPrivilegeFromCynara(kRecordPrivilege))) {
1398     result_handler(false);
1399     return;
1400   }
1401
1402   if (common::utils::StartsWith(url, "file://")) {
1403     result_handler(true);
1404     return;
1405   }
1406
1407   Popup* popup = Popup::CreatePopup(window_);
1408   popup->SetButtonType(Popup::ButtonType::AllowDenyButton);
1409   popup->SetTitle(popup_string::kPopupTitleUserMedia);
1410   popup->SetBody(popup_string::kPopupBodyUserMedia);
1411   popup->SetCheckBox(popup_string::kPopupCheckRememberPreference);
1412   popup->SetResultHandler(
1413       [db, result_handler, url](Popup* popup, void* /*user_data*/) {
1414         bool result = popup->GetButtonResult();
1415         bool remember = popup->GetCheckBoxResult();
1416         if (remember) {
1417           db->Set(kDBPrivateSection, kUsermediaPermissionPrefix + url,
1418                   result ? "allowed" : "denied");
1419         }
1420         result_handler(result);
1421       },
1422       this);
1423   popup->Show();
1424 }
1425
1426 }  // namespace runtime