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