Change dummy object atspi role
[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 <Ecore.h>
21 #include <aul.h>
22
23 #include <algorithm>
24 #include <map>
25 #include <memory>
26 #include <sstream>
27 #include <vector>
28
29 #include "common/application_data.h"
30 #include "common/app_db.h"
31 #include "common/app_control.h"
32 #include "common/command_line.h"
33 #include "common/locale_manager.h"
34 #include "common/logger.h"
35 #include "common/profiler.h"
36 #include "common/resource_manager.h"
37 #include "common/string_utils.h"
38 #include "runtime/browser/native_window.h"
39 #include "runtime/browser/notification_manager.h"
40 #include "runtime/browser/popup.h"
41 #include "runtime/browser/popup_string.h"
42 #include "runtime/browser/vibration_manager.h"
43 #include "runtime/browser/web_view.h"
44 #include "runtime/browser/splash_screen.h"
45 #include "extensions/common/xwalk_extension_server.h"
46
47 #ifndef INJECTED_BUNDLE_PATH
48 #error INJECTED_BUNDLE_PATH is not set.
49 #endif
50
51 namespace runtime {
52
53 namespace {
54 const char* kKeyNameBack = "back";
55 const char* kKeyNameMenu = "menu";
56
57 const char* kConsoleLogEnableKey = "WRT_CONSOLE_LOG_ENABLE";
58 const char* kConsoleMessageLogTag = "ConsoleMessage";
59
60 const char* kVerboseKey = "verbose";
61 const char* kPortKey = "port";
62
63 const char* kAppControlEventScript =
64     "(function(){"
65     "var __event = document.createEvent(\"CustomEvent\");\n"
66     "__event.initCustomEvent(\"appcontrol\", true, true, null);\n"
67     "document.dispatchEvent(__event);\n"
68     "\n"
69     "for (var i=0; i < window.frames.length; i++)\n"
70     "{ window.frames[i].document.dispatchEvent(__event); }"
71     "})()";
72 const char* kBackKeyEventScript =
73     "(function(){"
74     "var __event = document.createEvent(\"CustomEvent\");\n"
75     "__event.initCustomEvent(\"tizenhwkey\", true, true, null);\n"
76     "__event.keyName = \"back\";\n"
77     "document.dispatchEvent(__event);\n"
78     "\n"
79     "for (var i=0; i < window.frames.length; i++)\n"
80     "{ window.frames[i].document.dispatchEvent(__event); }"
81     "})()";
82 const char* kMenuKeyEventScript =
83     "(function(){"
84     "var __event = document.createEvent(\"CustomEvent\");\n"
85     "__event.initCustomEvent(\"tizenhwkey\", true, true, null);\n"
86     "__event.keyName = \"menu\";\n"
87     "document.dispatchEvent(__event);\n"
88     "\n"
89     "for (var i=0; i < window.frames.length; i++)\n"
90     "{ window.frames[i].document.dispatchEvent(__event); }"
91     "})()";
92 const char* kAmbientTickEventScript =
93     "(function(){"
94     "var __event = document.createEvent(\"CustomEvent\");\n"
95     "__event.initCustomEvent(\"timetick\", true, true);\n"
96     "document.dispatchEvent(__event);\n"
97     "\n"
98     "for (var i=0; i < window.frames.length; i++)\n"
99     "{ window.frames[i].document.dispatchEvent(__event); }"
100     "})()";
101 const char* kFullscreenPrivilege = "http://tizen.org/privilege/fullscreen";
102 const char* kFullscreenFeature = "fullscreen";
103 const char* kNotificationPrivilege = "http://tizen.org/privilege/notification";
104 const char* kLocationPrivilege = "http://tizen.org/privilege/location";
105 const char* kStoragePrivilege = "http://tizen.org/privilege/unlimitedstorage";
106 const char* kUsermediaPrivilege = "http://tizen.org/privilege/mediacapture";
107 const char* kNotiIconFile = "noti_icon.png";
108 const char* kFileScheme = "file://";
109
110 const char* kVisibilitySuspendFeature = "visibility,suspend";
111 const char* kMediastreamRecordFeature = "mediastream,record";
112 const char* kEncryptedDatabaseFeature = "encrypted,database";
113 const char* kRotationLockFeature = "rotation,lock";
114 const char* kBackgroundMusicFeature = "background,music";
115 const char* kSoundModeFeature = "sound,mode";
116 const char* kBackgroundVibrationFeature = "background,vibration";
117 const char* kCSPFeature = "csp";
118
119 const char* kGeolocationPermissionPrefix = "__WRT_GEOPERM_";
120 const char* kNotificationPermissionPrefix = "__WRT_NOTIPERM_";
121 const char* kQuotaPermissionPrefix = "__WRT_QUOTAPERM_";
122 const char* kCertificateAllowPrefix = "__WRT_CERTIPERM_";
123 const char* kUsermediaPermissionPrefix = "__WRT_USERMEDIAPERM_";
124 const char* kDBPrivateSection = "private";
125
126 const char* kDefaultCSPRule =
127     "default-src *; script-src 'self'; style-src 'self'; object-src 'none';";
128 const char* kResWgtPath = "res/wgt/";
129 const char* kAppControlMain = "http://tizen.org/appcontrol/operation/main";
130
131 bool FindPrivilege(common::ApplicationData* app_data,
132                    const std::string& privilege) {
133   if (app_data->permissions_info().get() == NULL) return false;
134   auto it = app_data->permissions_info()->GetAPIPermissions().begin();
135   auto end = app_data->permissions_info()->GetAPIPermissions().end();
136   for (; it != end; ++it) {
137     if (*it == privilege) return true;
138   }
139   return false;
140 }
141
142 static void SendDownloadRequest(const std::string& url) {
143   common::AppControl request;
144   request.set_operation(APP_CONTROL_OPERATION_DOWNLOAD);
145   request.set_uri(url);
146   request.LaunchRequest();
147 }
148
149 static void InitializeNotificationCallback(Ewk_Context* ewk_context,
150                                            WebApplication* app) {
151   auto show = [](Ewk_Context*, Ewk_Notification* noti, void* user_data) {
152     WebApplication* self = static_cast<WebApplication*>(user_data);
153     if (self == NULL) return;
154     uint64_t id = ewk_notification_id_get(noti);
155     std::string title(ewk_notification_title_get(noti)
156                           ? ewk_notification_title_get(noti)
157                           : "");
158     std::string body(
159         ewk_notification_body_get(noti) ? ewk_notification_body_get(noti) : "");
160     std::string icon_path = self->data_path() + "/" + kNotiIconFile;
161     if (!ewk_notification_icon_save_as_png(noti, icon_path.c_str())) {
162       icon_path = "";
163     }
164     if (NotificationManager::GetInstance()->Show(id, title, body, icon_path))
165       ewk_notification_showed(id);
166   };
167   auto hide = [](Ewk_Context*, uint64_t noti_id, void*) {
168     NotificationManager::GetInstance()->Hide(noti_id);
169     ewk_notification_closed(noti_id, EINA_FALSE);
170   };
171   ewk_context_notification_callbacks_set(ewk_context, show, hide, app);
172 }
173
174 static Eina_Bool ExitAppIdlerCallback(void* data) {
175   WebApplication* app = static_cast<WebApplication*>(data);
176   if (app)
177     app->Terminate();
178   return ECORE_CALLBACK_CANCEL;
179 }
180
181 static bool ClearCookie(Ewk_Context* ewk_context) {
182   Ewk_Cookie_Manager* cookie_manager =
183       ewk_context_cookie_manager_get(ewk_context);
184   if (!cookie_manager) {
185     LOGGER(ERROR) << "Fail to get cookie manager";
186     return false;
187   }
188   ewk_cookie_manager_cookies_clear(cookie_manager);
189   return true;
190 }
191
192 static bool ProcessWellKnownScheme(const std::string& url) {
193   if (common::utils::StartsWith(url, "file:") ||
194       common::utils::StartsWith(url, "app:") ||
195       common::utils::StartsWith(url, "data:") ||
196       common::utils::StartsWith(url, "http:") ||
197       common::utils::StartsWith(url, "https:") ||
198       common::utils::StartsWith(url, "widget:") ||
199       common::utils::StartsWith(url, "about:") ||
200       common::utils::StartsWith(url, "blob:")) {
201     return false;
202   }
203
204   std::unique_ptr<common::AppControl> request(
205       common::AppControl::MakeAppcontrolFromURL(url));
206   if (request.get() == NULL || !request->LaunchRequest()) {
207     LOGGER(ERROR) << "Fail to send appcontrol request";
208     SLoggerE("Fail to send appcontrol request [%s]", url.c_str());
209   }
210
211   // Should return true, to stop the WebEngine progress step about this URL
212   return true;
213 }
214
215 }  // namespace
216
217 WebApplication::WebApplication(
218     NativeWindow* window,
219     common::ApplicationData* app_data)
220     : launched_(false),
221       debug_mode_(false),
222       verbose_mode_(false),
223       ewk_context_(
224           ewk_context_new_with_injected_bundle_path(INJECTED_BUNDLE_PATH)),
225       has_ownership_of_ewk_context_(true),
226       window_(window),
227       appid_(app_data->app_id()),
228       app_data_(app_data),
229       locale_manager_(new common::LocaleManager()),
230       terminator_(NULL) {
231   Initialize();
232 }
233
234 WebApplication::WebApplication(
235     NativeWindow* window,
236     common::ApplicationData* app_data,
237     Ewk_Context* context)
238     : launched_(false),
239       debug_mode_(false),
240       verbose_mode_(false),
241       ewk_context_(context),
242       has_ownership_of_ewk_context_(false),
243       window_(window),
244       appid_(app_data->app_id()),
245       app_data_(app_data),
246       locale_manager_(new common::LocaleManager()),
247       terminator_(NULL) {
248   Initialize();
249 }
250
251 WebApplication::~WebApplication() {
252   window_->SetContent(NULL);
253   auto it = view_stack_.begin();
254   for (; it != view_stack_.end(); ++it) {
255     delete *it;
256   }
257   view_stack_.clear();
258   if (ewk_context_ && has_ownership_of_ewk_context_)
259     ewk_context_delete(ewk_context_);
260 }
261
262 bool WebApplication::Initialize() {
263   SCOPE_PROFILE();
264   std::unique_ptr<char, decltype(std::free)*> path{app_get_data_path(),
265                                                    std::free};
266   app_data_path_ = path.get();
267
268   if (app_data_->setting_info() != NULL &&
269       app_data_->setting_info()->screen_orientation() ==
270           wgt::parse::SettingInfo::ScreenOrientation::AUTO) {
271     ewk_context_tizen_extensible_api_string_set(ewk_context_,
272                                                 kRotationLockFeature, true);
273     window_->SetAutoRotation();
274   } else if (app_data_->setting_info() != NULL &&
275              app_data_->setting_info()->screen_orientation() ==
276                  wgt::parse::SettingInfo::ScreenOrientation::PORTRAIT) {
277     window_->SetRotationLock(NativeWindow::ScreenOrientation::PORTRAIT_PRIMARY);
278   } else if (app_data_->setting_info() != NULL &&
279              app_data_->setting_info()->screen_orientation() ==
280                  wgt::parse::SettingInfo::ScreenOrientation::LANDSCAPE) {
281     window_->SetRotationLock(
282         NativeWindow::ScreenOrientation::LANDSCAPE_PRIMARY);
283   }
284
285   splash_screen_.reset(new SplashScreen(
286       window_, app_data_->splash_screen_info(), app_data_->application_path()));
287   resource_manager_.reset(
288       new common::ResourceManager(app_data_, locale_manager_.get()));
289   resource_manager_->set_base_resource_path(app_data_->application_path());
290
291   auto extension_server = extensions::XWalkExtensionServer::GetInstance();
292   extension_server->SetupIPC(ewk_context_);
293
294   // ewk setting
295   ewk_context_cache_model_set(ewk_context_, EWK_CACHE_MODEL_DOCUMENT_BROWSER);
296
297   // cookie
298   auto cookie_manager = ewk_context_cookie_manager_get(ewk_context_);
299   ewk_cookie_manager_accept_policy_set(cookie_manager,
300                                        EWK_COOKIE_ACCEPT_POLICY_ALWAYS);
301
302   // set persistent storage path
303   std::string cookie_path = data_path() + ".cookie";
304   ewk_cookie_manager_persistent_storage_set(
305       cookie_manager, cookie_path.c_str(),
306       EWK_COOKIE_PERSISTENT_STORAGE_SQLITE);
307
308   // vibration callback
309   auto vibration_start_callback = [](uint64_t ms, void*) {
310     platform::VibrationManager::GetInstance()->Start(static_cast<int>(ms));
311   };
312   auto vibration_stop_callback = [](void* /*user_data*/) {
313     platform::VibrationManager::GetInstance()->Stop();
314   };
315   ewk_context_vibration_client_callbacks_set(
316       ewk_context_, vibration_start_callback, vibration_stop_callback, NULL);
317
318   auto download_callback = [](const char* downloadUrl, void* /*data*/) {
319     SendDownloadRequest(downloadUrl);
320   };
321   ewk_context_did_start_download_callback_set(ewk_context_, download_callback,
322                                               this);
323   InitializeNotificationCallback(ewk_context_, this);
324
325   if (FindPrivilege(app_data_, kFullscreenPrivilege)) {
326     ewk_context_tizen_extensible_api_string_set(ewk_context_,
327                                                 kFullscreenFeature, true);
328   }
329
330   if (app_data_->setting_info() != NULL &&
331       app_data_->setting_info()->background_support_enabled()) {
332     ewk_context_tizen_extensible_api_string_set(
333                                 ewk_context_, kVisibilitySuspendFeature, true);
334     ewk_context_tizen_extensible_api_string_set(ewk_context_,
335                                                 kBackgroundMusicFeature, true);
336   } else {
337     ewk_context_tizen_extensible_api_string_set(
338                                ewk_context_, kVisibilitySuspendFeature, false);
339     ewk_context_tizen_extensible_api_string_set(ewk_context_,
340                                                kBackgroundMusicFeature, false);
341   }
342   ewk_context_tizen_extensible_api_string_set(ewk_context_,
343                                               kMediastreamRecordFeature, true);
344   ewk_context_tizen_extensible_api_string_set(ewk_context_,
345                                               kEncryptedDatabaseFeature, true);
346
347   if (app_data_->setting_info() != NULL &&
348       app_data_->setting_info()->sound_mode() ==
349           wgt::parse::SettingInfo::SoundMode::EXCLUSIVE) {
350     ewk_context_tizen_extensible_api_string_set(ewk_context_, kSoundModeFeature,
351                                                 true);
352   }
353
354   if (app_data_->setting_info() != NULL &&
355       app_data_->setting_info()->background_vibration()) {
356     ewk_context_tizen_extensible_api_string_set(
357         ewk_context_, kBackgroundVibrationFeature, true);
358   }
359
360   if (app_data_->widget_info() != NULL &&
361       !app_data_->widget_info()->default_locale().empty()) {
362     locale_manager_->SetDefaultLocale(
363         app_data_->widget_info()->default_locale());
364   }
365
366   if (app_data_->csp_info() != NULL || app_data_->csp_report_info() != NULL ||
367       app_data_->allowed_navigation_info() != NULL) {
368     security_model_version_ = 2;
369     if (app_data_->csp_info() == NULL ||
370         app_data_->csp_info()->security_rules().empty()) {
371       csp_rule_ = kDefaultCSPRule;
372     } else {
373       csp_rule_ = app_data_->csp_info()->security_rules();
374     }
375     if (app_data_->csp_report_info() != NULL &&
376         !app_data_->csp_report_info()->security_rules().empty()) {
377       csp_report_rule_ = app_data_->csp_report_info()->security_rules();
378     }
379     ewk_context_tizen_extensible_api_string_set(ewk_context_, kCSPFeature,
380                                                 EINA_TRUE);
381   } else {
382     security_model_version_ = 1;
383   }
384
385 #ifdef MANUAL_ROTATE_FEATURE_SUPPORT
386   // Set manual rotation
387   window_->EnableManualRotation(true);
388 #endif  // MANUAL_ROTATE_FEATURE_SUPPORT
389
390   return true;
391 }
392
393 void WebApplication::Launch(std::unique_ptr<common::AppControl> appcontrol) {
394   // send widget info to injected bundle
395   ewk_context_tizen_app_id_set(ewk_context_, appid_.c_str());
396
397   // Setup View
398   WebView* view = new WebView(window_, ewk_context_);
399   SetupWebView(view);
400
401   std::unique_ptr<common::ResourceManager::Resource> res =
402       resource_manager_->GetStartResource(appcontrol.get());
403   view->SetDefaultEncoding(res->encoding());
404
405   STEP_PROFILE_END("OnCreate -> URL Set");
406   STEP_PROFILE_START("URL Set -> Rendered");
407
408   window_->SetContent(view->evas_object());
409
410 #ifdef PROFILE_MOBILE
411   // rotate and resize window forcibily for landscape mode.
412   // window rotate event is generated after window show. so
413   // when app get width and height from viewport, wrong value can be returned.
414   if (app_data_->setting_info()->screen_orientation() ==
415              wgt::parse::SettingInfo::ScreenOrientation::LANDSCAPE) {
416     LOGGER(DEBUG) << "rotate and resize window for landscape mode";
417     elm_win_rotation_with_resize_set(window_->evas_object(), 270);
418     evas_norender(evas_object_evas_get(window_->evas_object()));
419   }
420 #endif  // PROFILE_MOBILE
421
422   view->LoadUrl(res->uri(), res->mime());
423   view_stack_.push_front(view);
424
425 #ifdef PROFILE_WEARABLE
426   // ewk_view_bg_color_set is not working at webview initialization.
427   if (app_data_->app_type() == common::ApplicationData::WATCH) {
428     view->SetBGColor(0, 0, 0, 255);
429   }
430 #endif  // PROFILE_WEARABLE
431
432   if (appcontrol->data(AUL_K_DEBUG) == "1") {
433     debug_mode_ = true;
434     LaunchInspector(appcontrol.get());
435   }
436   if (appcontrol->data(kVerboseKey) == "true") {
437     verbose_mode_ = true;
438   }
439
440   launched_ = true;
441 }
442
443 void WebApplication::AppControl(
444     std::unique_ptr<common::AppControl> appcontrol) {
445   std::unique_ptr<common::ResourceManager::Resource> res =
446       resource_manager_->GetStartResource(appcontrol.get());
447
448   bool do_reset = res->should_reset();
449
450   if (!do_reset) {
451     std::string current_page = view_stack_.front()->GetUrl();
452     std::string localized_page =
453         resource_manager_->GetLocalizedPath(res->uri());
454     if (current_page != localized_page) {
455       do_reset = true;
456     } else {
457       SendAppControlEvent();
458     }
459   }
460
461   // handle http://tizen.org/appcontrol/operation/main operation specially.
462   // only menu-screen app can send launch request with main operation.
463   // in this case, web app should have to resume web app not reset.
464   if (do_reset && (appcontrol->operation() == kAppControlMain)){
465     LOGGER(DEBUG) << "resume app for main operation";
466     do_reset = false;
467     SendAppControlEvent();
468   }
469
470   if (do_reset) {
471     // Reset to context
472     ClearViewStack();
473     WebView* view = view_stack_.front();
474     SetupWebView(view);
475     view->SetDefaultEncoding(res->encoding());
476     view->LoadUrl(res->uri(), res->mime());
477     window_->SetContent(view->evas_object());
478   }
479
480   if (!debug_mode_ && appcontrol->data(AUL_K_DEBUG) == "1") {
481     debug_mode_ = true;
482     LaunchInspector(appcontrol.get());
483   }
484   if (!verbose_mode_ && appcontrol->data(kVerboseKey) == "true") {
485     verbose_mode_ = true;
486   }
487   window_->Active();
488 }
489
490 void WebApplication::SendAppControlEvent() {
491   if (view_stack_.size() > 0 && view_stack_.front() != NULL)
492     view_stack_.front()->EvalJavascript(kAppControlEventScript);
493 }
494
495 void WebApplication::ClearViewStack() {
496   window_->SetContent(NULL);
497   WebView* front = view_stack_.front();
498   auto it = view_stack_.begin();
499   for (; it != view_stack_.end(); ++it) {
500     if (*it != front) {
501       (*it)->Suspend();
502       delete *it;
503     }
504   }
505   view_stack_.clear();
506   view_stack_.push_front(front);
507 }
508
509 void WebApplication::Resume() {
510   if (view_stack_.size() > 0 && view_stack_.front() != NULL)
511     view_stack_.front()->SetVisibility(true);
512
513   if (app_data_->setting_info() != NULL &&
514       app_data_->setting_info()->background_support_enabled()) {
515     return;
516   }
517
518   auto it = view_stack_.begin();
519   for (; it != view_stack_.end(); ++it) {
520     (*it)->Resume();
521   }
522 }
523
524 void WebApplication::Suspend() {
525   if (view_stack_.size() > 0 && view_stack_.front() != NULL)
526     view_stack_.front()->SetVisibility(false);
527
528   if (app_data_->setting_info() != NULL &&
529       app_data_->setting_info()->background_support_enabled()) {
530     LOGGER(DEBUG) << "gone background (backgroud support enabed)";
531     return;
532   }
533
534   auto it = view_stack_.begin();
535   for (; it != view_stack_.end(); ++it) {
536     (*it)->Suspend();
537   }
538 }
539
540 void WebApplication::Terminate() {
541   if (terminator_) {
542     terminator_();
543   } else {
544     elm_exit();
545   }
546   auto extension_server = extensions::XWalkExtensionServer::GetInstance();
547   extension_server->Shutdown();
548 }
549
550 void WebApplication::OnCreatedNewWebView(WebView* /*view*/, WebView* new_view) {
551   if (view_stack_.size() > 0 && view_stack_.front() != NULL)
552     view_stack_.front()->SetVisibility(false);
553
554   SetupWebView(new_view);
555   view_stack_.push_front(new_view);
556   window_->SetContent(new_view->evas_object());
557 }
558
559 void WebApplication::RemoveWebViewFromStack(WebView* view) {
560   if (view_stack_.size() == 0) return;
561
562   WebView* current = view_stack_.front();
563   if (current == view) {
564     view_stack_.pop_front();
565   } else {
566     auto found = std::find(view_stack_.begin(), view_stack_.end(), view);
567     if (found != view_stack_.end()) {
568       view_stack_.erase(found);
569     }
570   }
571
572   if (view_stack_.size() == 0) {
573     Terminate();
574   } else if (current != view_stack_.front()) {
575     view_stack_.front()->SetVisibility(true);
576     window_->SetContent(view_stack_.front()->evas_object());
577   }
578
579   // Delete after the callback context(for ewk view) was not used
580   ecore_idler_add([](void* view) {
581                     WebView* obj = static_cast<WebView*>(view);
582                     delete obj;
583                     return EINA_FALSE;
584                   },
585                   view);
586 }
587
588 void WebApplication::OnClosedWebView(WebView* view) {
589     RemoveWebViewFromStack(view);
590 }
591
592 void WebApplication::OnReceivedWrtMessage(WebView* /*view*/,
593                                           Ewk_IPC_Wrt_Message_Data* msg) {
594   Eina_Stringshare* msg_type = ewk_ipc_wrt_message_data_type_get(msg);
595
596 #define TYPE_BEGIN(x) (!strncmp(msg_type, x, strlen(x)))
597 #define TYPE_IS(x) (!strcmp(msg_type, x))
598
599   if (TYPE_BEGIN("xwalk://")) {
600     auto extension_server = extensions::XWalkExtensionServer::GetInstance();
601     extension_server->HandleIPCMessage(msg);
602   } else {
603     Eina_Stringshare* msg_id = ewk_ipc_wrt_message_data_id_get(msg);
604     Eina_Stringshare* msg_ref_id =
605         ewk_ipc_wrt_message_data_reference_id_get(msg);
606     Eina_Stringshare* msg_value = ewk_ipc_wrt_message_data_value_get(msg);
607
608     if (TYPE_IS("tizen://hide")) {
609       // One Way Message
610       window_->InActive();
611     } else if (TYPE_IS("tizen://exit")) {
612       // One Way Message
613       ecore_idler_add(ExitAppIdlerCallback, this);
614     } else if (TYPE_IS("tizen://changeUA")) {
615       // Async Message
616       // Change UserAgent of current WebView
617       bool ret = false;
618       if (view_stack_.size() > 0 && view_stack_.front() != NULL) {
619         ret = view_stack_.front()->SetUserAgent(std::string(msg_value));
620       }
621       // Send response
622       Ewk_IPC_Wrt_Message_Data* ans = ewk_ipc_wrt_message_data_new();
623       ewk_ipc_wrt_message_data_type_set(ans, msg_type);
624       ewk_ipc_wrt_message_data_reference_id_set(ans, msg_id);
625       if (ret)
626         ewk_ipc_wrt_message_data_value_set(ans, "success");
627       else
628         ewk_ipc_wrt_message_data_value_set(ans, "failed");
629       if (!ewk_ipc_wrt_message_send(ewk_context_, ans)) {
630         LOGGER(ERROR) << "Failed to send response";
631       }
632       ewk_ipc_wrt_message_data_del(ans);
633     } else if (TYPE_IS("tizen://deleteAllCookies")) {
634       Ewk_IPC_Wrt_Message_Data* ans = ewk_ipc_wrt_message_data_new();
635       ewk_ipc_wrt_message_data_type_set(ans, msg_type);
636       ewk_ipc_wrt_message_data_reference_id_set(ans, msg_id);
637       if (ClearCookie(ewk_context_))
638         ewk_ipc_wrt_message_data_value_set(ans, "success");
639       else
640         ewk_ipc_wrt_message_data_value_set(ans, "failed");
641       if (!ewk_ipc_wrt_message_send(ewk_context_, ans)) {
642         LOGGER(ERROR) << "Failed to send response";
643       }
644       ewk_ipc_wrt_message_data_del(ans);
645     } else if (TYPE_IS("tizen://hide_splash_screen")) {
646       splash_screen_->HideSplashScreen(SplashScreen::HideReason::CUSTOM);
647     }
648
649     eina_stringshare_del(msg_ref_id);
650     eina_stringshare_del(msg_id);
651     eina_stringshare_del(msg_value);
652   }
653
654 #undef TYPE_IS
655 #undef TYPE_BEGIN
656
657   eina_stringshare_del(msg_type);
658 }
659
660 void WebApplication::OnOrientationLock(
661     WebView* view, bool lock,
662     NativeWindow::ScreenOrientation preferred_rotation) {
663   if (view_stack_.size() == 0) return;
664
665   // Only top-most view can set the orientation relate operation
666   if (view_stack_.front() != view) return;
667
668   auto orientaion_setting =
669       app_data_->setting_info() != NULL
670           ? app_data_->setting_info()->screen_orientation()
671           :
672           wgt::parse::SettingInfo::ScreenOrientation::AUTO;
673   if (orientaion_setting != wgt::parse::SettingInfo::ScreenOrientation::AUTO) {
674     return;
675   }
676
677   if (lock) {
678     window_->SetRotationLock(preferred_rotation);
679   } else {
680     window_->SetAutoRotation();
681   }
682 }
683
684 void WebApplication::OnHardwareKey(WebView* view, const std::string& keyname) {
685   // NOTE: This code is added to enable back-key on remote URL
686   if (!common::utils::StartsWith(view->GetUrl(), kFileScheme)) {
687     if (kKeyNameBack == keyname) {
688       LOGGER(DEBUG) << "Back to previous page for remote URL";
689       if (!view->Backward()) {
690         RemoveWebViewFromStack(view_stack_.front());
691       }
692     }
693     return;
694   }
695
696   bool enabled = app_data_->setting_info() != NULL
697                      ? app_data_->setting_info()->hwkey_enabled()
698                      : true;
699   if (enabled && kKeyNameBack == keyname) {
700     view->EvalJavascript(kBackKeyEventScript);
701     // NOTE: This code is added for backward compatibility.
702     // If the 'backbutton_presence' is true, WebView should be navigated back.
703     if (app_data_->setting_info() &&
704         app_data_->setting_info()->backbutton_presence()) {
705       if (!view->Backward()) {
706         RemoveWebViewFromStack(view_stack_.front());
707       }
708     }
709   } else if (enabled && kKeyNameMenu == keyname) {
710     view->EvalJavascript(kMenuKeyEventScript);
711   }
712 }
713
714 void WebApplication::OnLanguageChanged() {
715   locale_manager_->UpdateSystemLocale();
716   ewk_context_cache_clear(ewk_context_);
717   auto it = view_stack_.begin();
718   for (; it != view_stack_.end(); ++it) {
719     (*it)->Reload();
720   }
721 }
722
723 void WebApplication::OnConsoleMessage(const std::string& msg, int level) {
724   static bool enabled = (getenv(kConsoleLogEnableKey) != NULL);
725   enabled = true;
726
727   std::string split_msg = msg;
728   std::size_t pos = msg.find(kResWgtPath);
729   if (pos != std::string::npos) {
730     split_msg = msg.substr(pos + strlen(kResWgtPath));
731   }
732
733   if (debug_mode_ || verbose_mode_ || enabled) {
734     int dlog_level = DLOG_DEBUG;
735     switch (level) {
736       case EWK_CONSOLE_MESSAGE_LEVEL_WARNING:
737         dlog_level = DLOG_WARN;
738         break;
739       case EWK_CONSOLE_MESSAGE_LEVEL_ERROR:
740         dlog_level = DLOG_ERROR;
741         break;
742       default:
743         dlog_level = DLOG_DEBUG;
744         break;
745     }
746     LOGGER_RAW(dlog_level, kConsoleMessageLogTag)
747       << "[" << app_data_->pkg_id() << "] " << split_msg;
748   }
749 }
750
751 void WebApplication::OnLowMemory() {
752   ewk_context_cache_clear(ewk_context_);
753   ewk_context_notify_low_memory(ewk_context_);
754 }
755
756 void WebApplication::OnSoftKeyboardChangeEvent(WebView* /*view*/,
757                                SoftKeyboardChangeEventValue softkeyboard_value) {
758   LOGGER(DEBUG) << "OnSoftKeyboardChangeEvent";
759   std::stringstream script;
760   script
761     << "(function(){"
762     << "var __event = document.createEvent(\"CustomEvent\");\n"
763     << "var __detail = {};\n"
764     << "__event.initCustomEvent(\"softkeyboardchange\",true,true,__detail);\n"
765     << "__event.state = \"" << softkeyboard_value.state << "\";\n"
766     << "__event.width = " << softkeyboard_value.width << ";\n"
767     << "__event.height = " << softkeyboard_value.height << ";\n"
768     << "document.dispatchEvent(__event);\n"
769     << "\n"
770     << "for (var i=0; i < window.frames.length; i++)\n"
771     << "{ window.frames[i].document.dispatchEvent(__event); }"
772     << "})()";
773   std::string kSoftKeyboardScript = script.str();
774   if (view_stack_.size() > 0 && view_stack_.front() != NULL)
775     view_stack_.front()->EvalJavascript(kSoftKeyboardScript.c_str());
776 }
777
778 #ifdef ROTARY_EVENT_FEATURE_SUPPORT
779 void WebApplication::OnRotaryEvent(WebView* /*view*/,
780                                    RotaryEventType type) {
781   LOGGER(DEBUG) << "OnRotaryEvent";
782   std::stringstream script;
783   script
784     << "(function(){"
785     << "var __event = document.createEvent(\"CustomEvent\");\n"
786     << "var __detail = {};\n"
787     << "__event.initCustomEvent(\"rotarydetent\", true, true, __detail);\n"
788     << "__event.detail.direction = \""
789     << (type == RotaryEventType::CLOCKWISE ? "CW" : "CCW")
790     << "\";\n"
791     << "document.dispatchEvent(__event);\n"
792     << "\n"
793     << "for (var i=0; i < window.frames.length; i++)\n"
794     << "{ window.frames[i].document.dispatchEvent(__event); }"
795     << "})()";
796   std::string kRotaryEventScript = script.str();
797   if (view_stack_.size() > 0 && view_stack_.front() != NULL)
798     view_stack_.front()->EvalJavascript(kRotaryEventScript.c_str());
799 }
800 #endif  // ROTARY_EVENT_FEATURE_SUPPORT
801
802 void WebApplication::OnTimeTick(long time) {
803 #if 0
804   LOGGER(DEBUG) << "TimeTick";
805   if (view_stack_.size() > 0 && view_stack_.front() != NULL)
806     view_stack_.front()->EvalJavascript(kAmbientTickEventScript);
807 #endif
808 }
809
810 void WebApplication::OnAmbientTick(long time) {
811   LOGGER(DEBUG) << "AmbientTick";
812   if (view_stack_.size() > 0 && view_stack_.front() != NULL)
813     view_stack_.front()->EvalJavascript(kAmbientTickEventScript);
814 }
815
816 void WebApplication::OnAmbientChanged(bool ambient_mode) {
817   LOGGER(DEBUG) << "AmbientChanged";
818   std::stringstream script;
819   script
820     << "(function(){"
821     << "var __event = document.createEvent(\"CustomEvent\");\n"
822     << "var __detail = {};\n"
823     << "__event.initCustomEvent(\"ambientmodechanged\",true,true,__detail);\n"
824     << "__event.detail.ambientMode = "
825     << (ambient_mode ? "true" : "false") << ";\n"
826     << "document.dispatchEvent(__event);\n"
827     << "\n"
828     << "for (var i=0; i < window.frames.length; i++)\n"
829     << "{ window.frames[i].document.dispatchEvent(__event); }"
830     << "})()";
831   std::string kAmbientChangedEventScript = script.str();
832   if (view_stack_.size() > 0 && view_stack_.front() != NULL)
833     view_stack_.front()->EvalJavascript(kAmbientChangedEventScript.c_str());
834 }
835
836 bool WebApplication::OnContextMenuDisabled(WebView* /*view*/) {
837   return !(app_data_->setting_info() != NULL
838                ? app_data_->setting_info()->context_menu_enabled()
839                : true);
840 }
841
842 void WebApplication::OnLoadStart(WebView* /*view*/) {
843   LOGGER(DEBUG) << "LoadStart";
844 }
845
846 void WebApplication::OnLoadFinished(WebView* /*view*/) {
847   LOGGER(DEBUG) << "LoadFinished";
848   splash_screen_->HideSplashScreen(SplashScreen::HideReason::LOADFINISHED);
849 }
850
851 void WebApplication::OnRendered(WebView* /*view*/) {
852   STEP_PROFILE_END("URL Set -> Rendered");
853   STEP_PROFILE_END("Start -> Launch Completed");
854   LOGGER(DEBUG) << "Rendered";
855   splash_screen_->HideSplashScreen(SplashScreen::HideReason::RENDERED);
856
857   // Show window after frame rendered.
858   window_->Show();
859   window_->Active();
860 }
861
862 #ifdef MANUAL_ROTATE_FEATURE_SUPPORT
863 void WebApplication::OnRotatePrepared(WebView* /*view*/) {
864   window_->ManualRotationDone();
865 }
866 #endif  // MANUAL_ROTATE_FEATURE_SUPPORT
867
868 void WebApplication::LaunchInspector(common::AppControl* appcontrol) {
869   unsigned int port = ewk_context_inspector_server_start(ewk_context_, 0);
870   std::stringstream ss;
871   ss << port;
872   std::map<std::string, std::vector<std::string>> data;
873   data[kPortKey] = {ss.str()};
874   appcontrol->Reply(data);
875 }
876
877 void WebApplication::SetupWebView(WebView* view) {
878   view->SetEventListener(this);
879
880   // Setup CSP Rule
881   if (security_model_version_ == 2) {
882     view->SetCSPRule(csp_rule_, false);
883     if (!csp_report_rule_.empty()) {
884       view->SetCSPRule(csp_report_rule_, true);
885     }
886   }
887 }
888
889 bool WebApplication::OnDidNavigation(WebView* /*view*/,
890                                      const std::string& url) {
891   // scheme handling
892   // except(file , http, https, app) pass to appcontrol and return false
893   if (ProcessWellKnownScheme(url)) {
894     return false;
895   }
896
897   // send launch request for blocked URL to guarrenty backward-compatibility.
898   if (resource_manager_->AllowNavigation(url)) {
899     return true;
900   } else {
901     LOGGER(DEBUG) << "URL is blocked. send launch request for URL : " << url;
902     std::unique_ptr<common::AppControl> request(
903       common::AppControl::MakeAppcontrolFromURL(url));
904     if (request.get() == NULL || !request->LaunchRequest()) {
905       LOGGER(ERROR) << "Fail to send appcontrol request";
906     }
907     return false;
908   }
909 }
910
911 void WebApplication::OnNotificationPermissionRequest(
912     WebView*, const std::string& url,
913     std::function<void(bool)> result_handler) {
914   auto db = common::AppDB::GetInstance();
915   std::string reminder =
916       db->Get(kDBPrivateSection, kNotificationPermissionPrefix + url);
917   if (reminder == "allowed") {
918     result_handler(true);
919     return;
920   } else if (reminder == "denied") {
921     result_handler(false);
922     return;
923   }
924
925   // Local Domain: Grant permission if defined, otherwise Popup user prompt.
926   // Remote Domain: Popup user prompt.
927   if (common::utils::StartsWith(url, "file://") &&
928       FindPrivilege(app_data_, kNotificationPrivilege)) {
929     result_handler(true);
930     return;
931   }
932
933   Popup* popup = Popup::CreatePopup(window_);
934   popup->SetButtonType(Popup::ButtonType::AllowDenyButton);
935   popup->SetTitle(popup_string::kPopupTitleWebNotification);
936   popup->SetBody(popup_string::kPopupBodyWebNotification);
937   popup->SetCheckBox(popup_string::kPopupCheckRememberPreference);
938   popup->SetResultHandler(
939       [db, result_handler, url](Popup* popup, void* /*user_data*/) {
940         bool result = popup->GetButtonResult();
941         bool remember = popup->GetCheckBoxResult();
942         if (remember) {
943           db->Set(kDBPrivateSection, kNotificationPermissionPrefix + url,
944                   result ? "allowed" : "denied");
945         }
946         result_handler(result);
947       },
948       this);
949   popup->Show();
950 }
951
952 void WebApplication::OnGeolocationPermissionRequest(
953     WebView*, const std::string& url,
954     std::function<void(bool)> result_handler) {
955   auto db = common::AppDB::GetInstance();
956   std::string reminder =
957       db->Get(kDBPrivateSection, kGeolocationPermissionPrefix + url);
958   if (reminder == "allowed") {
959     result_handler(true);
960     return;
961   } else if (reminder == "denied") {
962     result_handler(false);
963     return;
964   }
965
966   // Local Domain: Grant permission if defined, otherwise block execution.
967   // Remote Domain: Popup user prompt if defined, otherwise block execution.
968   if (!FindPrivilege(app_data_, kLocationPrivilege)) {
969     result_handler(false);
970     return;
971   }
972
973   if (common::utils::StartsWith(url, "file://")) {
974     result_handler(true);
975     return;
976   }
977
978   Popup* popup = Popup::CreatePopup(window_);
979   popup->SetButtonType(Popup::ButtonType::AllowDenyButton);
980   popup->SetTitle(popup_string::kPopupTitleGeoLocation);
981   popup->SetBody(popup_string::kPopupBodyGeoLocation);
982   popup->SetCheckBox(popup_string::kPopupCheckRememberPreference);
983   popup->SetResultHandler(
984       [db, result_handler, url](Popup* popup, void* /*user_data*/) {
985         bool result = popup->GetButtonResult();
986         bool remember = popup->GetCheckBoxResult();
987         if (remember) {
988           db->Set(kDBPrivateSection, kGeolocationPermissionPrefix + url,
989                   result ? "allowed" : "denied");
990         }
991         result_handler(result);
992       },
993       this);
994   popup->Show();
995 }
996
997 void WebApplication::OnQuotaExceed(WebView*, const std::string& url,
998                                    std::function<void(bool)> result_handler) {
999   auto db = common::AppDB::GetInstance();
1000   std::string reminder =
1001       db->Get(kDBPrivateSection, kQuotaPermissionPrefix + url);
1002   if (reminder == "allowed") {
1003     result_handler(true);
1004     return;
1005   } else if (reminder == "denied") {
1006     result_handler(false);
1007     return;
1008   }
1009
1010   // Local Domain: Grant permission if defined, otherwise Popup user prompt.
1011   // Remote Domain: Popup user prompt.
1012   if (common::utils::StartsWith(url, "file://") &&
1013       FindPrivilege(app_data_, kStoragePrivilege)) {
1014     result_handler(true);
1015     return;
1016   }
1017
1018   Popup* popup = Popup::CreatePopup(window_);
1019   popup->SetButtonType(Popup::ButtonType::AllowDenyButton);
1020   popup->SetTitle(popup_string::kPopupTitleWebStorage);
1021   popup->SetBody(popup_string::kPopupBodyWebStorage);
1022   popup->SetCheckBox(popup_string::kPopupCheckRememberPreference);
1023   popup->SetResultHandler(
1024       [db, result_handler, url](Popup* popup, void* /*user_data*/) {
1025         bool result = popup->GetButtonResult();
1026         bool remember = popup->GetCheckBoxResult();
1027         if (remember) {
1028           db->Set(kDBPrivateSection, kQuotaPermissionPrefix + url,
1029                   result ? "allowed" : "denied");
1030         }
1031         result_handler(result);
1032       },
1033       this);
1034   popup->Show();
1035 }
1036
1037 void WebApplication::OnAuthenticationRequest(
1038     WebView*, const std::string& /*url*/, const std::string& /*message*/,
1039     std::function<void(bool submit, const std::string& id,
1040                        const std::string& password)> result_handler) {
1041   Popup* popup = Popup::CreatePopup(window_);
1042   popup->SetButtonType(Popup::ButtonType::LoginCancelButton);
1043   popup->SetFirstEntry(popup_string::kPopupLabelAuthusername,
1044                        Popup::EntryType::Edit);
1045   popup->SetSecondEntry(popup_string::kPopupLabelPassword,
1046                         Popup::EntryType::PwEdit);
1047   popup->SetTitle(popup_string::kPopupTitleAuthRequest);
1048   popup->SetBody(popup_string::kPopupBodyAuthRequest);
1049   popup->SetResultHandler([result_handler](Popup* popup, void* /*user_data*/) {
1050                             bool result = popup->GetButtonResult();
1051                             std::string id = popup->GetFirstEntryResult();
1052                             std::string passwd = popup->GetSecondEntryResult();
1053                             result_handler(result, id, passwd);
1054                           },
1055                           this);
1056   popup->Show();
1057 }
1058
1059 void WebApplication::OnCertificateAllowRequest(
1060     WebView*, const std::string& url, const std::string& pem,
1061     std::function<void(bool allow)> result_handler) {
1062   auto db = common::AppDB::GetInstance();
1063   std::string reminder =
1064       db->Get(kDBPrivateSection, kCertificateAllowPrefix + pem);
1065   if (reminder == "allowed") {
1066     result_handler(true);
1067     return;
1068   } else if (reminder == "denied") {
1069     result_handler(false);
1070     return;
1071   }
1072
1073   Popup* popup = Popup::CreatePopup(window_);
1074   popup->SetButtonType(Popup::ButtonType::AllowDenyButton);
1075   popup->SetTitle(popup_string::kPopupTitleCert);
1076   popup->SetBody(popup_string::GetText(
1077                  popup_string::kPopupBodyCert) + "\n\n" + url);
1078   popup->SetCheckBox(popup_string::kPopupCheckRememberPreference);
1079   popup->SetResultHandler(
1080       [db, result_handler, pem](Popup* popup, void* /*user_data*/) {
1081         bool result = popup->GetButtonResult();
1082         bool remember = popup->GetCheckBoxResult();
1083         if (remember) {
1084           db->Set(kDBPrivateSection, kCertificateAllowPrefix + pem,
1085                   result ? "allowed" : "denied");
1086         }
1087         result_handler(result);
1088       },
1089       this);
1090   popup->Show();
1091 }
1092
1093 void WebApplication::OnUsermediaPermissionRequest(
1094     WebView*, const std::string& url,
1095     std::function<void(bool)> result_handler) {
1096   auto db = common::AppDB::GetInstance();
1097   std::string reminder =
1098       db->Get(kDBPrivateSection, kUsermediaPermissionPrefix + url);
1099   if (reminder == "allowed") {
1100     result_handler(true);
1101     return;
1102   } else if (reminder == "denied") {
1103     result_handler(false);
1104     return;
1105   }
1106
1107   // Local Domain: Grant permission if defined, otherwise block execution.
1108   // Remote Domain: Popup user prompt if defined, otherwise block execution.
1109   if (!FindPrivilege(app_data_, kUsermediaPrivilege)) {
1110     result_handler(false);
1111     return;
1112   }
1113
1114   if (common::utils::StartsWith(url, "file://")) {
1115     result_handler(true);
1116     return;
1117   }
1118
1119   Popup* popup = Popup::CreatePopup(window_);
1120   popup->SetButtonType(Popup::ButtonType::AllowDenyButton);
1121   popup->SetTitle(popup_string::kPopupTitleUserMedia);
1122   popup->SetBody(popup_string::kPopupBodyUserMedia);
1123   popup->SetCheckBox(popup_string::kPopupCheckRememberPreference);
1124   popup->SetResultHandler(
1125       [db, result_handler, url](Popup* popup, void* /*user_data*/) {
1126         bool result = popup->GetButtonResult();
1127         bool remember = popup->GetCheckBoxResult();
1128         if (remember) {
1129           db->Set(kDBPrivateSection, kUsermediaPermissionPrefix + url,
1130                   result ? "allowed" : "denied");
1131         }
1132         result_handler(result);
1133       },
1134       this);
1135   popup->Show();
1136 }
1137
1138 }  // namespace runtime