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