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