Merge "Cleanup code to remove warning messages at buildtime." into devel/wrt2
[platform/framework/web/nwrt.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/command_line.h"
18 #include "common/string_utils.h"
19 #include "runtime/native_window.h"
20 #include "runtime/web_view.h"
21 #include "runtime/vibration_manager.h"
22 #include "runtime/app_control.h"
23 #include "runtime/locale_manager.h"
24 #include "runtime/application_data.h"
25 #include "runtime/resource_manager.h"
26
27 namespace {
28   // TODO(sngn.lee) : It should be declare in common header
29   const char* kKeyNameBack = "back";
30
31   const char* kConsoleLogEnableKey = "WRT_CONSOLE_LOG_ENABLE";
32   const char* kConsoleMessageLogTag = "ConsoleMessage";
33
34   const char* kDebugKey = "debug";
35   const char* kPortKey = "port";
36
37   // TODO(wy80.choi): consider 64bits system.
38   const char* kInjectedBundlePath = "/usr/lib/libwrt-injected-bundle.so";
39
40   const char* kAppControlEventScript = \
41         "(function(){"
42         "var __event = document.createEvent(\"CustomEvent\");\n"
43         "__event.initCustomEvent(\"appcontrol\", true, true);\n"
44         "document.dispatchEvent(__event);\n"
45         "\n"
46         "for (var i=0; i < window.frames.length; i++)\n"
47         "{ window.frames[i].document.dispatchEvent(__event); }"
48         "})()";
49   const char* kBackKeyEventScript = \
50         "(function(){"
51         "var __event = document.createEvent(\"CustomEvent\");\n"
52         "__event.initCustomEvent(\"tizenhwkey\", true, true);\n"
53         "__event.keyName = \"back\";\n"
54         "document.dispatchEvent(__event);\n"
55         "\n"
56         "for (var i=0; i < window.frames.length; i++)\n"
57         "{ window.frames[i].document.dispatchEvent(__event); }"
58         "})()";
59 }  // namespace
60
61 namespace wrt {
62
63 WebApplication::WebApplication(
64     NativeWindow* window, std::unique_ptr<ApplicationData> app_data)
65     : launched_(false),
66       debug_mode_(false),
67       ewk_context_(ewk_context_new_with_injected_bundle_path(
68           kInjectedBundlePath)),
69       window_(window),
70       appid_(app_data->app_id()),
71       locale_manager_(new LocaleManager()),
72       app_data_(std::move(app_data)),
73       terminator_(NULL),
74       uuid_(utils::GenerateUUID()) {
75   std::unique_ptr<char, decltype(std::free)*>
76     path {app_get_data_path(), std::free};
77   app_data_path_ = path.get();
78
79   resource_manager_.reset(
80       new ResourceManager(app_data_.get(), locale_manager_.get()));
81   resource_manager_->set_base_resource_path(
82       app_data_->application_path());
83   Initialize();
84 }
85
86 WebApplication::~WebApplication() {
87   if (ewk_context_)
88     ewk_context_delete(ewk_context_);
89 }
90
91 bool WebApplication::Initialize() {
92   // ewk setting
93   ewk_context_cache_model_set(ewk_context_, EWK_CACHE_MODEL_DOCUMENT_BROWSER);
94
95   // cookie
96   auto cookie_manager = ewk_context_cookie_manager_get(ewk_context_);
97   ewk_cookie_manager_accept_policy_set(cookie_manager,
98                                        EWK_COOKIE_ACCEPT_POLICY_ALWAYS);
99
100   // set persistent storage path
101   std::string cookie_path = data_path() + ".cookie";
102   ewk_cookie_manager_persistent_storage_set(
103                                       cookie_manager, cookie_path.c_str(),
104                                       EWK_COOKIE_PERSISTENT_STORAGE_SQLITE);
105
106   // vibration callback
107   auto vibration_start_callback = [](uint64_t ms, void*) {
108     platform::VibrationManager::GetInstance()->Start(static_cast<int>(ms));
109   };
110   auto vibration_stop_callback = [](void* /*user_data*/) {
111     platform::VibrationManager::GetInstance()->Stop();
112   };
113   ewk_context_vibration_client_callbacks_set(ewk_context_,
114                                              vibration_start_callback,
115                                              vibration_stop_callback,
116                                              NULL);
117
118
119
120   // TODO(sngn.lee): Find the path of certificate file
121   // ewk_context_certificate_file_set(ewk_context_, .... );
122
123   // TODO(sngn.lee): find the proxy url
124   // ewk_context_proxy_uri_set(ewk_context_, ... );
125
126   // TODO(sngn.lee): set default from config.xml
127   // locale_manager_->SetDefaultLocale(const  string & locale);
128
129   // TODO(sngn.lee): Download interface
130   // ewk_context_did_start_download_callback_set
131
132   // TODO(sngn.lee): always enable "mediastream,record"
133   // TODO(sngn.lee): always enable "encrypted,database"
134   // TODO(sngn.lee): check csp element in config.xml and enable - "csp"
135   // TODO(sngn.lee): Check Backround support and enable - "visibility,suspend"
136   // TODO(sngn.lee): Check Backround support and enable - "background,music"
137   // TODO(sngn.lee): Check setting rotation value and enable "rotation,lock"
138   // TODO(sngn.lee): always enable "fullscreen"
139   // TODO(sngn.lee): check "sound-mode":"exclusive" - in tizen:setting
140   //                 and enable - "sound,mode"
141   // TODO(sngn.lee): check "background-vibration":"enable" - in tizen:setting
142   //                 and enable - "background,vibration"
143
144   return true;
145 }
146
147 void WebApplication::Launch(std::unique_ptr<wrt::AppControl> appcontrol) {
148   resource_manager_->set_app_control(appcontrol.get());
149   WebView* view = new WebView(window_, ewk_context_);
150   SetupWebView(view);
151
152   // send widget info to injected bundle
153   // TODO(wy80.choi): ewk_send_widget_info should be fixed to receive uuid of
154   // application instead of widget_id.
155   // Currently, uuid is passed as encoded_bundle argument temporarily.
156   // ewk_send_widget_info(ewk_context_, 1,
157   //                     elm_config_scale_get(),
158   //                     elm_theme_get(NULL),
159   //                    uuid_.c_str());
160
161   // view->LoadUrl("file:///home/owner/apps_rw/33CFo0eFJe/"
162   //               "33CFo0eFJe.annex/index.html");
163   view->LoadUrl(resource_manager_->GetStartURL());
164
165   view_stack_.push_front(view);
166   window_->SetContent(view->evas_object());
167
168   // TODO(sngn.lee): below code only debug code
169   auto callback = [](void*, Evas*, Evas_Object* obj,
170                      void*) -> void {
171     int x, y, w, h;
172     evas_object_geometry_get(obj, &x, &y, &w, &h);
173     LoggerD("resize ! (%d, %d, %d, %d)\n", x, y, w, h);
174   };
175   evas_object_event_callback_add(view->evas_object(),
176                                  EVAS_CALLBACK_RESIZE,
177                                  callback, NULL);
178
179   if (appcontrol->data(kDebugKey) == "true") {
180     debug_mode_ = true;
181     LaunchInspector(appcontrol.get());
182   }
183
184   // TODO(sngn.lee): check the below code location.
185   // in Wearable, webkit can render contents before show window
186   // but Mobile, webkit can't render contents before show window
187   window_->Show();
188
189   launched_ = true;
190   received_appcontrol_ = std::move(appcontrol);
191 }
192
193 void WebApplication::AppControl(std::unique_ptr<wrt::AppControl> appcontrol) {
194   // TODO(sngn.lee): Set the injected bundle into extension process
195   resource_manager_->set_app_control(appcontrol.get());
196
197   if (true) {
198     // Reset to context
199     ClearViewStack();
200     WebView* view = new WebView(window_, ewk_context_);
201     SetupWebView(view);
202
203     view->LoadUrl(resource_manager_->GetStartURL());
204     view_stack_.push_front(view);
205     window_->SetContent(view->evas_object());
206   } else {
207     // Send Event
208     SendAppControlEvent();
209   }
210
211   if (!debug_mode_ && appcontrol->data(kDebugKey) == "true") {
212     debug_mode_ = true;
213     LaunchInspector(appcontrol.get());
214   }
215   window_->Active();
216   received_appcontrol_ = std::move(appcontrol);
217 }
218
219 void WebApplication::SendAppControlEvent() {
220   auto it = view_stack_.begin();
221   while (it != view_stack_.end()) {
222     (*it)->EvalJavascript(kAppControlEventScript);
223   }
224 }
225
226 void WebApplication::ClearViewStack() {
227   window_->SetContent(NULL);
228   auto it = view_stack_.begin();
229   for ( ; it != view_stack_.end(); ++it) {
230     (*it)->Suspend();
231     delete *it;
232   }
233   view_stack_.clear();
234 }
235
236 void WebApplication::Resume() {
237   if (view_stack_.size() > 0 && view_stack_.front() != NULL)
238     view_stack_.front()->SetVisibility(true);
239
240   if (app_data_->setting_info() != NULL &&
241       app_data_->setting_info()->background_support_enabled()) {
242     return;
243   }
244
245   auto it = view_stack_.begin();
246   for ( ; it != view_stack_.end(); ++it) {
247     (*it)->Resume();
248   }
249 }
250
251 void WebApplication::Suspend() {
252   if (view_stack_.size() > 0 && view_stack_.front() != NULL)
253     view_stack_.front()->SetVisibility(false);
254
255   if (app_data_->setting_info() != NULL &&
256       app_data_->setting_info()->background_support_enabled()) {
257     LoggerD("gone background (backgroud support enabed)");
258     return;
259   }
260
261   auto it = view_stack_.begin();
262   for ( ; it != view_stack_.end(); ++it) {
263     (*it)->Suspend();
264   }
265 }
266
267 void WebApplication::OnCreatedNewWebView(WebView* /*view*/, WebView* new_view) {
268   if (view_stack_.size() > 0 && view_stack_.front() != NULL)
269     view_stack_.front()->SetVisibility(false);
270
271   SetupWebView(new_view);
272   view_stack_.push_front(new_view);
273   window_->SetContent(new_view->evas_object());
274 }
275
276 void WebApplication::OnClosedWebView(WebView * view) {
277   if (view_stack_.size() == 0)
278     return;
279
280   WebView* current = view_stack_.front();
281   if (current == view) {
282     view_stack_.pop_front();
283   } else {
284     auto found = std::find(view_stack_.begin(), view_stack_.end(), view);
285     if (found != view_stack_.end()) {
286       view_stack_.erase(found);
287     }
288   }
289
290   if (view_stack_.size() == 0) {
291     if (terminator_ != NULL) {
292       terminator_();
293     }
294   } else if (current != view_stack_.front()) {
295     view_stack_.front()->SetVisibility(true);
296     window_->SetContent(view_stack_.front()->evas_object());
297   }
298
299   // Delete after the callback context(for ewk view) was not used
300   ecore_idler_add([](void* view) {
301       WebView* obj = static_cast<WebView*>(view);
302       delete view;
303       return EINA_FALSE;
304     }, view);
305 }
306
307 void WebApplication::OnReceivedWrtMessage(
308     WebView* /*view*/,
309     Ewk_IPC_Wrt_Message_Data* /*message*/) {
310   // TODO(wy80.choi) : Handle messages from injected bundle?
311   // ex. SendRuntimeMessage to hide / exit application.
312 }
313
314 void WebApplication::OnOrientationLock(WebView* view,
315                                        bool lock,
316                                        int preferred_rotation) {
317   if (view_stack_.size() == 0)
318     return;
319
320   // Only top-most view can set the orientation relate operation
321   if (view_stack_.front() != view)
322     return;
323
324   auto orientaion_setting = app_data_->setting_info() != NULL ?
325                             app_data_->setting_info()->screen_orientation() :
326                             // TODO(sngn.lee): check default value
327                             wgt::parse::SettingInfo::AUTO;
328   if (orientaion_setting != wgt::parse::SettingInfo::AUTO) {
329     return;
330   }
331
332   if ( lock ) {
333     window_->SetRotationLock(preferred_rotation);
334   } else {
335     window_->SetAutoRotation();
336   }
337 }
338
339 void WebApplication::OnHardwareKey(WebView* view, const std::string& keyname) {
340   bool enabled = app_data_->setting_info() != NULL ?
341                  app_data_->setting_info()->hwkey_enabled() :
342                  true;
343   if (enabled && kKeyNameBack == keyname) {
344     view->EvalJavascript(kBackKeyEventScript);
345   }
346 }
347
348 void WebApplication::OnLanguageChanged() {
349   locale_manager_->UpdateSystemLocale();
350   ewk_context_cache_clear(ewk_context_);
351   auto it = view_stack_.begin();
352   for ( ; it != view_stack_.end(); ++it) {
353     (*it)->Reload();
354   }
355 }
356
357 void WebApplication::OnConsoleMessage(const std::string& msg, int level) {
358   static bool enabled = (getenv(kConsoleLogEnableKey) != NULL);
359   if (debug_mode_ || enabled) {
360     int dlog_level = DLOG_DEBUG;
361     switch (level) {
362       case EWK_CONSOLE_MESSAGE_LEVEL_WARNING:
363           dlog_level = DLOG_WARN;
364           break;
365       case EWK_CONSOLE_MESSAGE_LEVEL_ERROR:
366           dlog_level = DLOG_ERROR;
367           break;
368       default:
369           dlog_level = DLOG_DEBUG;
370           break;
371     }
372     LOG_(LOG_ID_MAIN, dlog_level, kConsoleMessageLogTag, "%s", msg.c_str());
373   }
374 }
375
376 void WebApplication::OnLowMemory() {
377   ewk_context_cache_clear(ewk_context_);
378   ewk_context_notify_low_memory(ewk_context_);
379 }
380
381 bool WebApplication::OnContextMenuDisabled(WebView* /*view*/) {
382   return !(app_data_->setting_info() != NULL ?
383            app_data_->setting_info()->context_menu_enabled() :
384            true);
385 }
386
387 void WebApplication::OnLoadStart(WebView* /*view*/) {
388   LoggerD("LoadStart");
389 }
390 void WebApplication::OnLoadFinished(WebView* /*view*/) {
391   LoggerD("LoadFinished");
392 }
393 void WebApplication::OnRendered(WebView* /*view*/) {
394   LoggerD("Rendered");
395 }
396
397 void WebApplication::LaunchInspector(wrt::AppControl* appcontrol) {
398   unsigned int port =
399     ewk_context_inspector_server_start(ewk_context_, 0);
400   std::stringstream ss;
401   ss << port;
402   std::map<std::string, std::vector<std::string>> data;
403   data[kPortKey] = { ss.str() };
404   appcontrol->Reply(data);
405 }
406
407 void WebApplication::SetupWebView(WebView* view) {
408   view->SetEventListener(this);
409   // TODO(sngn.lee): set UserAgent to WebView
410   // TODO(sngn.lee): set CSP
411 }
412
413 bool WebApplication::OnDidNavigation(WebView* view, const std::string& url) {
414   // TODO(sngn.lee): scheme handling
415   // except(file , http, https, app) pass to appcontrol and return false
416   return true;
417 }
418
419
420 }  // namespace wrt