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