Merge pull request #6 from myroot/handle-scheme-to-appcontrol
[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 <ewk_chromium.h>
22 #include <algorithm>
23 #include <memory>
24 #include <sstream>
25 #include <vector>
26 #include <map>
27
28 #include "common/logger.h"
29 #include "common/command_line.h"
30 #include "common/string_utils.h"
31 #include "common/app_control.h"
32 #include "common/locale_manager.h"
33 #include "common/application_data.h"
34 #include "common/resource_manager.h"
35 #include "common/app_db.h"
36 #include "common/profiler.h"
37
38 #include "runtime/browser/native_window.h"
39 #include "runtime/browser/web_view.h"
40 #include "runtime/browser/vibration_manager.h"
41 #include "runtime/browser/notification_manager.h"
42 #include "runtime/browser/popup.h"
43 #include "runtime/browser/popup_string.h"
44
45 #ifndef INJECTED_BUNDLE_PATH
46   #error INJECTED_BUNDLE_PATH is not set.
47 #endif
48
49 namespace runtime {
50
51 namespace {
52 // TODO(sngn.lee) : It should be declare in common header
53 const char* kKeyNameBack = "back";
54 const char* kKeyNameMenu = "menu";
55
56 const char* kConsoleLogEnableKey = "WRT_CONSOLE_LOG_ENABLE";
57 const char* kConsoleMessageLogTag = "ConsoleMessage";
58
59 const char* kDebugKey = "debug";
60 const char* kPortKey = "port";
61
62 const char* kAppControlEventScript = \
63     "(function(){"
64     "var __event = document.createEvent(\"CustomEvent\");\n"
65     "__event.initCustomEvent(\"appcontrol\", true, true);\n"
66     "document.dispatchEvent(__event);\n"
67     "\n"
68     "for (var i=0; i < window.frames.length; i++)\n"
69     "{ window.frames[i].document.dispatchEvent(__event); }"
70     "})()";
71 const char* kBackKeyEventScript = \
72     "(function(){"
73     "var __event = document.createEvent(\"CustomEvent\");\n"
74     "__event.initCustomEvent(\"tizenhwkey\", true, true);\n"
75     "__event.keyName = \"back\";\n"
76     "document.dispatchEvent(__event);\n"
77     "\n"
78     "for (var i=0; i < window.frames.length; i++)\n"
79     "{ window.frames[i].document.dispatchEvent(__event); }"
80     "})()";
81 const char* kMenuKeyEventScript = \
82     "(function(){"
83     "var __event = document.createEvent(\"CustomEvent\");\n"
84     "__event.initCustomEvent(\"tizenhwkey\", true, true);\n"
85     "__event.keyName = \"menu\";\n"
86     "document.dispatchEvent(__event);\n"
87     "\n"
88     "for (var i=0; i < window.frames.length; i++)\n"
89     "{ window.frames[i].document.dispatchEvent(__event); }"
90     "})()";
91 const char* kFullscreenPrivilege = "http://tizen.org/privilege/fullscreen";
92 const char* kFullscreenFeature = "fullscreen";
93 const char* kNotificationPrivilege =
94     "http://tizen.org/privilege/notification";
95 const char* kLocationPrivilege =
96     "http://tizen.org/privilege/location";
97 const char* kStoragePrivilege =
98     "http://tizen.org/privilege/unlimitedstorage";
99 const char* kUsermediaPrivilege =
100     "http://tizen.org/privilege/mediacapture";
101 const char* kNotiIconFile = "noti_icon.png";
102
103 const char* kVisibilitySuspendFeature = "visibility,suspend";
104 const char* kMediastreamRecordFeature = "mediastream,record";
105 const char* kEncryptedDatabaseFeature = "encrypted,database";
106 const char* kRotationLockFeature = "rotation,lock";
107 const char* kBackgroundMusicFeature = "background,music";
108 const char* kSoundModeFeature = "sound,mode";
109 const char* kBackgroundVibrationFeature = "background,vibration";
110 const char* kCSPFeature = "csp";
111
112 const char* kGeolocationPermissionPrefix = "__WRT_GEOPERM_";
113 const char* kNotificationPermissionPrefix = "__WRT_NOTIPERM_";
114 const char* kQuotaPermissionPrefix = "__WRT_QUOTAPERM_";
115 const char* kCertificateAllowPrefix = "__WRT_CERTIPERM_";
116 const char* kUsermediaPermissionPrefix = "__WRT_USERMEDIAPERM_";
117 const char* kDBPrivateSection = "private";
118
119 const char* kDefaultCSPRule =
120     "default-src *; script-src 'self'; style-src 'self'; object-src 'none';";
121
122 bool FindPrivilege(common::ApplicationData* app_data,
123                    const std::string& privilege) {
124   if (app_data->permissions_info().get() == NULL)
125     return false;
126   auto it = app_data->permissions_info()->GetAPIPermissions().begin();
127   auto end = app_data->permissions_info()->GetAPIPermissions().end();
128   for ( ; it != end; ++it) {
129     if (*it == privilege)
130       return true;
131   }
132   return false;
133 }
134
135 static void SendDownloadRequest(const std::string& url) {
136   common::AppControl request;
137   request.set_operation(APP_CONTROL_OPERATION_DOWNLOAD);
138   request.set_uri(url);
139   request.LaunchRequest();
140 }
141
142 static void InitializeNotificationCallback(Ewk_Context* ewk_context,
143                                            WebApplication* app) {
144   auto show = [](Ewk_Context*,
145                  Ewk_Notification* noti,
146                  void* user_data) {
147     WebApplication* self = static_cast<WebApplication*>(user_data);
148     if (self == NULL)
149       return;
150     uint64_t id = ewk_notification_id_get(noti);
151     std::string title(ewk_notification_title_get(noti) ?
152                       ewk_notification_title_get(noti) : "");
153     std::string body(ewk_notification_body_get(noti) ?
154                      ewk_notification_body_get(noti) : "");
155     std::string icon_path = self->data_path() + "/" + kNotiIconFile;
156     if (!ewk_notification_icon_save_as_png(noti, icon_path.c_str())) {
157       icon_path = "";
158     }
159     if (NotificationManager::GetInstance()->Show(id, title, body, icon_path))
160       ewk_notification_showed(id);
161   };
162   auto hide = [](Ewk_Context*,
163                  uint64_t noti_id,
164                  void *) {
165     NotificationManager::GetInstance()->Hide(noti_id);
166     ewk_notification_closed(noti_id, EINA_FALSE);
167   };
168   ewk_context_notification_callbacks_set(ewk_context,
169                                          show,
170                                          hide,
171                                          app);
172 }
173
174 static Eina_Bool ExitAppIdlerCallback(void* /*data*/) {
175   elm_exit();
176   return ECORE_CALLBACK_CANCEL;
177 }
178
179 static bool ClearCookie(Ewk_Context* ewk_context) {
180   Ewk_Cookie_Manager* cookie_manager =
181       ewk_context_cookie_manager_get(ewk_context);
182   if (!cookie_manager) {
183     LOGGER(ERROR) << "Fail to get cookie manager";
184     return false;
185   }
186   ewk_cookie_manager_cookies_clear(cookie_manager);
187   return true;
188 }
189
190 static bool ProcessWellKnownScheme(const std::string& url) {
191   if (utils::StartsWith(url, "file:") ||
192       utils::StartsWith(url, "app:") ||
193       utils::StartsWith(url, "data:") ||
194       utils::StartsWith(url, "http:") ||
195       utils::StartsWith(url, "https:") ||
196       utils::StartsWith(url, "widget:") ||
197       utils::StartsWith(url, "about:") ||
198       utils::StartsWith(url, "blob:")) {
199     return false;
200   }
201
202   std::unique_ptr<AppControl> request(AppControl::MakeAppcontrolFromURL(url));
203   if (request.get() == NULL || !request->LaunchRequest()) {
204     LOGGER(ERROR) << "Fail to send appcontrol request";
205     SLoggerE("Fail to send appcontrol request [%s]", url.c_str());
206   }
207
208   // Should return true, to stop the WebEngine progress step about this URL
209   return true;
210 }
211
212 }  // namespace
213
214 WebApplication::WebApplication(
215     NativeWindow* window, std::unique_ptr<common::ApplicationData> app_data)
216     : launched_(false),
217       debug_mode_(false),
218       ewk_context_(ewk_context_new_with_injected_bundle_path(
219           INJECTED_BUNDLE_PATH)),
220       window_(window),
221       appid_(app_data->app_id()),
222       locale_manager_(new common::LocaleManager()),
223       app_data_(std::move(app_data)),
224       terminator_(NULL) {
225   std::unique_ptr<char, decltype(std::free)*>
226     path {app_get_data_path(), std::free};
227   app_data_path_ = path.get();
228
229   resource_manager_.reset(
230       new common::ResourceManager(app_data_.get(), locale_manager_.get()));
231   resource_manager_->set_base_resource_path(
232       app_data_->application_path());
233   Initialize();
234 }
235
236 WebApplication::~WebApplication() {
237   if (ewk_context_)
238     ewk_context_delete(ewk_context_);
239 }
240
241 bool WebApplication::Initialize() {
242   SCOPE_PROFILE();
243   // ewk setting
244   ewk_context_cache_model_set(ewk_context_, EWK_CACHE_MODEL_DOCUMENT_BROWSER);
245
246   // cookie
247   auto cookie_manager = ewk_context_cookie_manager_get(ewk_context_);
248   ewk_cookie_manager_accept_policy_set(cookie_manager,
249                                        EWK_COOKIE_ACCEPT_POLICY_ALWAYS);
250
251   // set persistent storage path
252   std::string cookie_path = data_path() + ".cookie";
253   ewk_cookie_manager_persistent_storage_set(
254                                       cookie_manager, cookie_path.c_str(),
255                                       EWK_COOKIE_PERSISTENT_STORAGE_SQLITE);
256
257   // vibration callback
258   auto vibration_start_callback = [](uint64_t ms, void*) {
259     platform::VibrationManager::GetInstance()->Start(static_cast<int>(ms));
260   };
261   auto vibration_stop_callback = [](void* /*user_data*/) {
262     platform::VibrationManager::GetInstance()->Stop();
263   };
264   ewk_context_vibration_client_callbacks_set(ewk_context_,
265                                              vibration_start_callback,
266                                              vibration_stop_callback,
267                                              NULL);
268
269   auto download_callback = [](const char* downloadUrl, void* /*data*/) {
270     SendDownloadRequest(downloadUrl);
271   };
272   ewk_context_did_start_download_callback_set(ewk_context_,
273                                               download_callback,
274                                               this);
275   InitializeNotificationCallback(ewk_context_, this);
276
277   if (FindPrivilege(app_data_.get(), kFullscreenPrivilege)) {
278     ewk_context_tizen_extensible_api_string_set(ewk_context_,
279                                                 kFullscreenFeature,
280                                                 true);
281   }
282
283   if (app_data_->setting_info() != NULL &&
284       app_data_->setting_info()->background_support_enabled()) {
285     ewk_context_tizen_extensible_api_string_set(ewk_context_,
286                                                 kVisibilitySuspendFeature,
287                                                 true);
288     ewk_context_tizen_extensible_api_string_set(ewk_context_,
289                                                 kBackgroundMusicFeature,
290                                                 true);
291   }
292   ewk_context_tizen_extensible_api_string_set(ewk_context_,
293                                               kMediastreamRecordFeature,
294                                               true);
295   ewk_context_tizen_extensible_api_string_set(ewk_context_,
296                                               kEncryptedDatabaseFeature,
297                                               true);
298   if (app_data_->setting_info() != NULL &&
299       app_data_->setting_info()->screen_orientation()
300       == wgt::parse::SettingInfo::ScreenOrientation::AUTO) {
301     ewk_context_tizen_extensible_api_string_set(ewk_context_,
302                                                 kRotationLockFeature,
303                                                 true);
304   } else if (app_data_->setting_info() != NULL &&
305              app_data_->setting_info()->screen_orientation()
306              == wgt::parse::SettingInfo::ScreenOrientation::PORTRAIT) {
307     window_->SetRotationLock(
308         NativeWindow::ScreenOrientation::PORTRAIT_PRIMARY);
309   } else if (app_data_->setting_info() != NULL &&
310              app_data_->setting_info()->screen_orientation()
311              == wgt::parse::SettingInfo::ScreenOrientation::LANDSCAPE) {
312     window_->SetRotationLock(
313         NativeWindow::ScreenOrientation::LANDSCAPE_PRIMARY);
314   }
315
316   if (app_data_->setting_info() != NULL &&
317       app_data_->setting_info()->sound_mode()
318       == wgt::parse::SettingInfo::SoundMode::EXCLUSIVE) {
319     ewk_context_tizen_extensible_api_string_set(ewk_context_,
320                                                 kSoundModeFeature,
321                                                 true);
322   }
323
324   if (app_data_->setting_info() != NULL &&
325       app_data_->setting_info()->background_vibration()) {
326     ewk_context_tizen_extensible_api_string_set(ewk_context_,
327                                                 kBackgroundVibrationFeature,
328                                                 true);
329   }
330
331   if (app_data_->widget_info() != NULL &&
332       !app_data_->widget_info()->default_locale().empty()) {
333     locale_manager_->SetDefaultLocale(
334         app_data_->widget_info()->default_locale());
335   }
336
337   // TODO(sngn.lee): Find the path of certificate file
338   // ewk_context_certificate_file_set(ewk_context_, .... );
339
340   // TODO(sngn.lee): find the proxy url
341   // ewk_context_proxy_uri_set(ewk_context_, ... );
342
343   if (app_data_->csp_info() != NULL ||
344       app_data_->csp_report_info() != NULL ||
345       app_data_->allowed_navigation_info() != NULL) {
346     security_model_version_ = 2;
347     if (app_data_->csp_info() == NULL ||
348         app_data_->csp_info()->security_rules().empty()) {
349       csp_rule_ = kDefaultCSPRule;
350     } else {
351       csp_rule_ = app_data_->csp_info()->security_rules();
352     }
353     if (app_data_->csp_report_info() != NULL &&
354         !app_data_->csp_report_info()->security_rules().empty()) {
355       csp_report_rule_ = app_data_->csp_report_info()->security_rules();
356     }
357     ewk_context_tizen_extensible_api_string_set(ewk_context_,
358                                                 kCSPFeature,
359                                                 EINA_TRUE);
360   } else {
361     security_model_version_ = 1;
362   }
363
364   return true;
365 }
366
367 void WebApplication::Launch(std::unique_ptr<common::AppControl> appcontrol) {
368   // Setup View
369   WebView* view = new WebView(window_, ewk_context_);
370   SetupWebView(view);
371
372   // send widget info to injected bundle
373   ewk_send_widget_info(ewk_context_, appid_.c_str(),
374                        elm_config_scale_get(),
375                        elm_theme_get(NULL),
376                        "");
377
378   std::unique_ptr<common::ResourceManager::Resource> res =
379     resource_manager_->GetStartResource(appcontrol.get());
380   view->SetDefaultEncoding(res->encoding());
381
382   STEP_PROFILE_END("OnCreate -> URL Set");
383   STEP_PROFILE_START("URL Set -> Rendered");
384
385   view->LoadUrl(res->uri(), res->mime());
386   view_stack_.push_front(view);
387   window_->SetContent(view->evas_object());
388
389   if (appcontrol->data(kDebugKey) == "true") {
390     debug_mode_ = true;
391     LaunchInspector(appcontrol.get());
392   }
393
394   // TODO(sngn.lee): check the below code location.
395   // in Wearable, webkit can render contents before show window
396   // but Mobile, webkit can't render contents before show window
397   window_->Show();
398
399   launched_ = true;
400   received_appcontrol_ = std::move(appcontrol);
401 }
402
403 void WebApplication::AppControl(
404     std::unique_ptr<common::AppControl> appcontrol) {
405   std::unique_ptr<common::ResourceManager::Resource> res =
406     resource_manager_->GetStartResource(appcontrol.get());
407   if (res->should_reset()) {
408     // Reset to context
409     ClearViewStack();
410     WebView* view = new WebView(window_, ewk_context_);
411     SetupWebView(view);
412     view->SetDefaultEncoding(res->encoding());
413     view->LoadUrl(res->uri(), res->mime());
414     view_stack_.push_front(view);
415     window_->SetContent(view->evas_object());
416   } else {
417     // Send Event
418     SendAppControlEvent();
419   }
420
421   if (!debug_mode_ && appcontrol->data(kDebugKey) == "true") {
422     debug_mode_ = true;
423     LaunchInspector(appcontrol.get());
424   }
425   window_->Active();
426   received_appcontrol_ = std::move(appcontrol);
427 }
428
429 void WebApplication::SendAppControlEvent() {
430   auto it = view_stack_.begin();
431   while (it != view_stack_.end()) {
432     (*it)->EvalJavascript(kAppControlEventScript);
433   }
434 }
435
436 void WebApplication::ClearViewStack() {
437   window_->SetContent(NULL);
438   auto it = view_stack_.begin();
439   for ( ; it != view_stack_.end(); ++it) {
440     (*it)->Suspend();
441     delete *it;
442   }
443   view_stack_.clear();
444 }
445
446 void WebApplication::Resume() {
447   if (view_stack_.size() > 0 && view_stack_.front() != NULL)
448     view_stack_.front()->SetVisibility(true);
449
450   if (app_data_->setting_info() != NULL &&
451       app_data_->setting_info()->background_support_enabled()) {
452     return;
453   }
454
455   auto it = view_stack_.begin();
456   for ( ; it != view_stack_.end(); ++it) {
457     (*it)->Resume();
458   }
459 }
460
461 void WebApplication::Suspend() {
462   if (view_stack_.size() > 0 && view_stack_.front() != NULL)
463     view_stack_.front()->SetVisibility(false);
464
465   if (app_data_->setting_info() != NULL &&
466       app_data_->setting_info()->background_support_enabled()) {
467     LOGGER(DEBUG) << "gone background (backgroud support enabed)";
468     return;
469   }
470
471   auto it = view_stack_.begin();
472   for ( ; it != view_stack_.end(); ++it) {
473     (*it)->Suspend();
474   }
475 }
476
477 void WebApplication::OnCreatedNewWebView(WebView* /*view*/, WebView* new_view) {
478   if (view_stack_.size() > 0 && view_stack_.front() != NULL)
479     view_stack_.front()->SetVisibility(false);
480
481   SetupWebView(new_view);
482   view_stack_.push_front(new_view);
483   window_->SetContent(new_view->evas_object());
484 }
485
486 void WebApplication::OnClosedWebView(WebView * view) {
487   if (view_stack_.size() == 0)
488     return;
489
490   WebView* current = view_stack_.front();
491   if (current == view) {
492     view_stack_.pop_front();
493   } else {
494     auto found = std::find(view_stack_.begin(), view_stack_.end(), view);
495     if (found != view_stack_.end()) {
496       view_stack_.erase(found);
497     }
498   }
499
500   if (view_stack_.size() == 0) {
501     if (terminator_ != NULL) {
502       terminator_();
503     }
504   } else if (current != view_stack_.front()) {
505     view_stack_.front()->SetVisibility(true);
506     window_->SetContent(view_stack_.front()->evas_object());
507   }
508
509   // Delete after the callback context(for ewk view) was not used
510   ecore_idler_add([](void* view) {
511       WebView* obj = static_cast<WebView*>(view);
512       delete obj;
513       return EINA_FALSE;
514     }, view);
515 }
516
517 void WebApplication::OnReceivedWrtMessage(
518     WebView* /*view*/,
519     Ewk_IPC_Wrt_Message_Data* msg) {
520
521   Eina_Stringshare* msg_id = ewk_ipc_wrt_message_data_id_get(msg);
522   Eina_Stringshare* msg_ref_id = ewk_ipc_wrt_message_data_reference_id_get(msg);
523   Eina_Stringshare* msg_type = ewk_ipc_wrt_message_data_type_get(msg);
524   Eina_Stringshare* msg_value = ewk_ipc_wrt_message_data_value_get(msg);
525
526   LOGGER(DEBUG) << "RecvMsg: id = " << msg_id;
527   LOGGER(DEBUG) << "RecvMsg: refid = " << msg_ref_id;
528   LOGGER(DEBUG) << "RecvMsg: type = " << msg_type;
529   LOGGER(DEBUG) << "RecvMsg: value = " << msg_value;
530
531   #define TYPE_IS(x) (!strcmp(msg_type, x))
532   if (TYPE_IS("tizen://hide")) {
533     // One Way Message
534     window_->InActive();
535   } else if (TYPE_IS("tizen://exit")) {
536     // One Way Message
537     ecore_idler_add(ExitAppIdlerCallback, NULL);
538   } else if (TYPE_IS("tizen://changeUA")) {
539     // Async Message
540     // Change UserAgent of current WebView
541     bool ret = false;
542     if (view_stack_.size() > 0 && view_stack_.front() != NULL) {
543       ret = view_stack_.front()->SetUserAgent(std::string(msg_value));
544     }
545     // Send response
546     Ewk_IPC_Wrt_Message_Data* ans = ewk_ipc_wrt_message_data_new();
547     ewk_ipc_wrt_message_data_type_set(ans, msg_type);
548     ewk_ipc_wrt_message_data_reference_id_set(ans, msg_id);
549     if (ret)
550       ewk_ipc_wrt_message_data_value_set(ans, "success");
551     else
552       ewk_ipc_wrt_message_data_value_set(ans, "failed");
553     if (!ewk_ipc_wrt_message_send(ewk_context_, ans)) {
554       LOGGER(ERROR) << "Failed to send response";
555     }
556     ewk_ipc_wrt_message_data_del(ans);
557   } else if (TYPE_IS("tizen://deleteAllCookies")) {
558     Ewk_IPC_Wrt_Message_Data* ans = ewk_ipc_wrt_message_data_new();
559     ewk_ipc_wrt_message_data_type_set(ans, msg_type);
560     ewk_ipc_wrt_message_data_reference_id_set(ans, msg_id);
561     if (ClearCookie(ewk_context_))
562       ewk_ipc_wrt_message_data_value_set(ans, "success");
563     else
564       ewk_ipc_wrt_message_data_value_set(ans, "failed");
565     if (!ewk_ipc_wrt_message_send(ewk_context_, ans)) {
566       LOGGER(ERROR) << "Failed to send response";
567     }
568     ewk_ipc_wrt_message_data_del(ans);
569   }
570   #undef TYPE_IS
571
572   eina_stringshare_del(msg_value);
573   eina_stringshare_del(msg_type);
574   eina_stringshare_del(msg_ref_id);
575   eina_stringshare_del(msg_id);
576 }
577
578 void WebApplication::OnOrientationLock(
579     WebView* view,
580     bool lock,
581     NativeWindow::ScreenOrientation preferred_rotation) {
582   if (view_stack_.size() == 0)
583     return;
584
585   // Only top-most view can set the orientation relate operation
586   if (view_stack_.front() != view)
587     return;
588
589   auto orientaion_setting = app_data_->setting_info() != NULL ?
590                             app_data_->setting_info()->screen_orientation() :
591                             // TODO(sngn.lee): check default value
592                             wgt::parse::SettingInfo::ScreenOrientation::AUTO;
593   if (orientaion_setting != wgt::parse::SettingInfo::ScreenOrientation::AUTO) {
594     return;
595   }
596
597   if (lock) {
598     window_->SetRotationLock(preferred_rotation);
599   } else {
600     window_->SetAutoRotation();
601   }
602 }
603
604 void WebApplication::OnHardwareKey(WebView* view, const std::string& keyname) {
605   bool enabled = app_data_->setting_info() != NULL ?
606                  app_data_->setting_info()->hwkey_enabled() :
607                  true;
608   if (enabled && kKeyNameBack == keyname) {
609     view->EvalJavascript(kBackKeyEventScript);
610   } else if (enabled && kKeyNameMenu == keyname) {
611     view->EvalJavascript(kMenuKeyEventScript);
612   }
613 }
614
615 void WebApplication::OnLanguageChanged() {
616   locale_manager_->UpdateSystemLocale();
617   ewk_context_cache_clear(ewk_context_);
618   auto it = view_stack_.begin();
619   for ( ; it != view_stack_.end(); ++it) {
620     (*it)->Reload();
621   }
622 }
623
624 void WebApplication::OnConsoleMessage(const std::string& msg, int level) {
625   static bool enabled = (getenv(kConsoleLogEnableKey) != NULL);
626   enabled = true;
627
628   if (debug_mode_ || enabled) {
629     int dlog_level = DLOG_DEBUG;
630     switch (level) {
631       case EWK_CONSOLE_MESSAGE_LEVEL_WARNING:
632           dlog_level = DLOG_WARN;
633           break;
634       case EWK_CONSOLE_MESSAGE_LEVEL_ERROR:
635           dlog_level = DLOG_ERROR;
636           break;
637       default:
638           dlog_level = DLOG_DEBUG;
639           break;
640     }
641     LOGGER_RAW(dlog_level, kConsoleMessageLogTag) << msg;
642   }
643 }
644
645 void WebApplication::OnLowMemory() {
646   ewk_context_cache_clear(ewk_context_);
647   ewk_context_notify_low_memory(ewk_context_);
648 }
649
650 bool WebApplication::OnContextMenuDisabled(WebView* /*view*/) {
651   return !(app_data_->setting_info() != NULL ?
652            app_data_->setting_info()->context_menu_enabled() :
653            true);
654 }
655
656 void WebApplication::OnLoadStart(WebView* /*view*/) {
657   LOGGER(DEBUG) << "LoadStart";
658 }
659 void WebApplication::OnLoadFinished(WebView* /*view*/) {
660   LOGGER(DEBUG) << "LoadFinished";
661 }
662 void WebApplication::OnRendered(WebView* /*view*/) {
663   STEP_PROFILE_END("URL Set -> Rendered");
664   STEP_PROFILE_END("Start -> Launch Completed");
665   LOGGER(DEBUG) << "Rendered";
666 }
667
668 void WebApplication::LaunchInspector(common::AppControl* appcontrol) {
669   unsigned int port =
670     ewk_context_inspector_server_start(ewk_context_, 0);
671   std::stringstream ss;
672   ss << port;
673   std::map<std::string, std::vector<std::string>> data;
674   data[kPortKey] = { ss.str() };
675   appcontrol->Reply(data);
676 }
677
678 void WebApplication::SetupWebView(WebView* view) {
679   view->SetEventListener(this);
680
681   // Setup CSP Rule
682   if (security_model_version_ == 2) {
683     view->SetCSPRule(csp_rule_, false);
684     if (!csp_report_rule_.empty()) {
685       view->SetCSPRule(csp_report_rule_, true);
686     }
687   }
688
689   // TODO(sngn.lee): set UserAgent to WebView
690 }
691
692 bool WebApplication::OnDidNavigation(WebView* /*view*/,
693                                      const std::string& url) {
694   // scheme handling
695   // except(file , http, https, app) pass to appcontrol and return false
696   if (ProcessWellKnownScheme(url)) {
697     return false;
698   }
699   return resource_manager_->AllowNavigation(url);
700 }
701
702 void WebApplication::OnNotificationPermissionRequest(
703     WebView*,
704     const std::string& url,
705     std::function<void(bool)> result_handler) {
706   auto db = common::AppDB::GetInstance();
707   std::string reminder = db->Get(kDBPrivateSection,
708                                  kNotificationPermissionPrefix + url);
709   if (reminder == "allowed") {
710     result_handler(true);
711     return;
712   } else if (reminder == "denied") {
713     result_handler(false);
714     return;
715   }
716
717   // Local Domain: Grant permission if defined, otherwise Popup user prompt.
718   // Remote Domain: Popup user prompt.
719   if (common::utils::StartsWith(url, "file://") &&
720       FindPrivilege(app_data_.get(), kNotificationPrivilege)) {
721     result_handler(true);
722     return;
723   }
724
725   Popup* popup = Popup::CreatePopup(window_);
726   popup->SetButtonType(Popup::ButtonType::AllowDenyButton);
727   popup->SetTitle(popup_string::kPopupTitleWebNotification);
728   popup->SetBody(popup_string::kPopupBodyWebNotification);
729   popup->SetCheckBox(popup_string::kPopupCheckRememberPreference);
730   popup->SetResultHandler(
731     [db, result_handler, url](Popup* popup, void* /*user_data*/) {
732       bool result = popup->GetButtonResult();
733       bool remember = popup->GetCheckBoxResult();
734       if (remember) {
735         db->Set(kDBPrivateSection, kNotificationPermissionPrefix + url,
736                 result ? "allowed" : "denied");
737       }
738       result_handler(result);
739     }, this);
740   popup->Show();
741 }
742
743 void WebApplication::OnGeolocationPermissionRequest(
744     WebView*,
745     const std::string& url,
746     std::function<void(bool)> result_handler) {
747   auto db = common::AppDB::GetInstance();
748   std::string reminder = db->Get(kDBPrivateSection,
749                                  kGeolocationPermissionPrefix + url);
750   if (reminder == "allowed") {
751     result_handler(true);
752     return;
753   } else if (reminder == "denied") {
754     result_handler(false);
755     return;
756   }
757
758   // Local Domain: Grant permission if defined, otherwise block execution.
759   // Remote Domain: Popup user prompt if defined, otherwise block execution.
760   if (!FindPrivilege(app_data_.get(), kLocationPrivilege)) {
761     result_handler(false);
762     return;
763   }
764
765   if (common::utils::StartsWith(url, "file://")) {
766     result_handler(true);
767     return;
768   }
769
770   Popup* popup = Popup::CreatePopup(window_);
771   popup->SetButtonType(Popup::ButtonType::AllowDenyButton);
772   popup->SetTitle(popup_string::kPopupTitleGeoLocation);
773   popup->SetBody(popup_string::kPopupBodyGeoLocation);
774   popup->SetCheckBox(popup_string::kPopupCheckRememberPreference);
775   popup->SetResultHandler(
776     [db, result_handler, url](Popup* popup, void* /*user_data*/) {
777       bool result = popup->GetButtonResult();
778       bool remember = popup->GetCheckBoxResult();
779       if (remember) {
780         db->Set(kDBPrivateSection, kGeolocationPermissionPrefix + url,
781                 result ? "allowed" : "denied");
782       }
783       result_handler(result);
784     }, this);
785   popup->Show();
786 }
787
788
789 void WebApplication::OnQuotaExceed(
790     WebView*,
791     const std::string& url,
792     std::function<void(bool)> result_handler) {
793   auto db = common::AppDB::GetInstance();
794   std::string reminder = db->Get(kDBPrivateSection,
795                                  kQuotaPermissionPrefix + url);
796   if (reminder == "allowed") {
797     result_handler(true);
798     return;
799   } else if (reminder == "denied") {
800     result_handler(false);
801     return;
802   }
803
804   // Local Domain: Grant permission if defined, otherwise Popup user prompt.
805   // Remote Domain: Popup user prompt.
806   if (common::utils::StartsWith(url, "file://") &&
807       FindPrivilege(app_data_.get(), kStoragePrivilege)) {
808     result_handler(true);
809     return;
810   }
811
812   Popup* popup = Popup::CreatePopup(window_);
813   popup->SetButtonType(Popup::ButtonType::AllowDenyButton);
814   popup->SetTitle(popup_string::kPopupTitleWebStorage);
815   popup->SetBody(popup_string::kPopupBodyWebStorage);
816   popup->SetCheckBox(popup_string::kPopupCheckRememberPreference);
817   popup->SetResultHandler(
818     [db, result_handler, url](Popup* popup, void* /*user_data*/) {
819       bool result = popup->GetButtonResult();
820       bool remember = popup->GetCheckBoxResult();
821       if (remember) {
822         db->Set(kDBPrivateSection, kQuotaPermissionPrefix + url,
823                 result ? "allowed" : "denied");
824       }
825       result_handler(result);
826     }, this);
827   popup->Show();
828 }
829
830 void WebApplication::OnAuthenticationRequest(
831       WebView*,
832       const std::string& /*url*/,
833       const std::string& /*message*/,
834       std::function<void(bool submit,
835                          const std::string& id,
836                          const std::string& password)
837                    > result_handler) {
838   Popup* popup = Popup::CreatePopup(window_);
839   popup->SetButtonType(Popup::ButtonType::LoginCancelButton);
840   popup->SetFirstEntry(popup_string::kPopupLabelAuthusername,
841                        Popup::EntryType::Edit);
842   popup->SetSecondEntry(popup_string::kPopupLabelPassword,
843                         Popup::EntryType::PwEdit);
844   popup->SetTitle(popup_string::kPopupTitleAuthRequest);
845   popup->SetBody(popup_string::kPopupBodyAuthRequest);
846   popup->SetResultHandler(
847     [result_handler](Popup* popup, void* /*user_data*/) {
848       bool result = popup->GetButtonResult();
849       std::string id = popup->GetFirstEntryResult();
850       std::string passwd = popup->GetSecondEntryResult();
851       result_handler(result, id, passwd);
852     }, this);
853   popup->Show();
854 }
855
856 void WebApplication::OnCertificateAllowRequest(
857       WebView*,
858       const std::string& /*url*/,
859       const std::string& pem,
860       std::function<void(bool allow)> result_handler) {
861   auto db = common::AppDB::GetInstance();
862   std::string reminder = db->Get(kDBPrivateSection,
863                                  kCertificateAllowPrefix + pem);
864   if (reminder == "allowed") {
865     result_handler(true);
866     return;
867   } else if (reminder == "denied") {
868     result_handler(false);
869     return;
870   }
871
872   Popup* popup = Popup::CreatePopup(window_);
873   popup->SetButtonType(Popup::ButtonType::AllowDenyButton);
874   popup->SetTitle(popup_string::kPopupTitleCert);
875   popup->SetBody(popup_string::kPopupBodyCert);
876   popup->SetCheckBox(popup_string::kPopupCheckRememberPreference);
877   popup->SetResultHandler(
878     [db, result_handler, pem](Popup* popup, void* /*user_data*/) {
879       bool result = popup->GetButtonResult();
880       bool remember = popup->GetCheckBoxResult();
881       if (remember) {
882         db->Set(kDBPrivateSection, kCertificateAllowPrefix + pem,
883                 result ? "allowed" : "denied");
884       }
885       result_handler(result);
886     }, this);
887   popup->Show();
888 }
889
890 void WebApplication::OnUsermediaPermissionRequest(
891       WebView*,
892       const std::string& url,
893       std::function<void(bool)> result_handler) {
894   auto db = common::AppDB::GetInstance();
895   std::string reminder = db->Get(kDBPrivateSection,
896                                  kUsermediaPermissionPrefix + url);
897   if (reminder == "allowed") {
898     result_handler(true);
899     return;
900   } else if (reminder == "denied") {
901     result_handler(false);
902     return;
903   }
904
905   // Local Domain: Grant permission if defined, otherwise block execution.
906   // Remote Domain: Popup user prompt if defined, otherwise block execution.
907   if (!FindPrivilege(app_data_.get(), kUsermediaPrivilege)) {
908     result_handler(false);
909     return;
910   }
911
912   if (common::utils::StartsWith(url, "file://")) {
913     result_handler(true);
914     return;
915   }
916
917   Popup* popup = Popup::CreatePopup(window_);
918   popup->SetButtonType(Popup::ButtonType::AllowDenyButton);
919   popup->SetTitle(popup_string::kPopupTitleUserMedia);
920   popup->SetBody(popup_string::kPopupBodyUserMedia);
921   popup->SetCheckBox(popup_string::kPopupCheckRememberPreference);
922   popup->SetResultHandler(
923     [db, result_handler, url](Popup* popup, void* /*user_data*/) {
924       bool result = popup->GetButtonResult();
925       bool remember = popup->GetCheckBoxResult();
926       if (remember) {
927         db->Set(kDBPrivateSection, kUsermediaPermissionPrefix + url,
928                 result ? "allowed" : "denied");
929       }
930       result_handler(result);
931     }, this);
932   popup->Show();
933 }
934
935 }  // namespace runtime