Fix for N_SE-10234 and Redefine of system language change action
[platform/framework/web/wrt.git] / src / wrt-client / wrt-client.cpp
1 /*
2  * Copyright (c) 2011 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 #include "wrt-client.h"
17 #include <cstdlib>
18 #include <cstdio>
19 #include <string>
20 #include <dpl/log/log.h>
21 #include <dpl/optional_typedefs.h>
22 #include <common/application_data.h>
23 #include <core_module.h>
24 #include <global_logic.h>
25 #include <widget_model.h>
26 #include <widget_localize_model.h>
27 #include <localization_setting.h>
28 #include <widget_deserialize_model.h>
29 #include <launch_user_data.h>
30 #include <EWebKit2.h>
31
32 //W3C PACKAGING enviroment variable name
33 #define W3C_DEBUG_ENV_VARIABLE "DEBUG_LOAD_FINISH"
34
35 // window signal callback
36 const char *EDJE_SHOW_BACKWARD_SIGNAL = "show,backward,signal";
37 const std::string VIEWMODE_TYPE_FULLSCREEN = "fullscreen";
38 const std::string VIEWMODE_TYPE_MAXIMIZED = "maximized";
39
40 WrtClient::WrtClient(int argc, char **argv) :
41     Application(argc, argv, "wrt-client", false),
42     DPL::TaskDecl<WrtClient>(this),
43     m_handle(-1),
44     m_launched(false),
45     m_initializing(false),
46     m_initialized(false),
47     m_sdkLauncherPid(0),
48     m_debugMode(false),
49     m_debuggerPort(0),
50     m_returnStatus(ReturnStatus::Succeeded),
51     m_widgetState(WidgetState::WidgetState_Stopped)
52 {
53     Touch();
54     LogDebug("App Created");
55 }
56
57 WrtClient::~WrtClient()
58 {
59     LogDebug("App Finished");
60 }
61
62 WrtClient::ReturnStatus::Type WrtClient::getReturnStatus() const
63 {
64     return m_returnStatus;
65 }
66
67 void WrtClient::OnStop()
68 {
69     LogInfo("Stopping Dummy Client");
70 }
71
72
73 void WrtClient::OnCreate()
74 {
75     LogInfo("On Create");
76 }
77
78
79 void WrtClient::OnResume()
80 {
81     if (m_widgetState != WidgetState_Suspended) {
82         LogWarning("Widget is not suspended, resuming was skipped");
83         return;
84     }
85     m_widget->Resume();
86     evas_object_focus_set(m_widget->GetCurrentWebview(), EINA_TRUE);
87     m_widgetState = WidgetState_Running;
88 }
89
90
91 void WrtClient::OnPause()
92 {
93     if (m_widgetState != WidgetState_Running) {
94         LogWarning("Widget is not running to be suspended");
95         return;
96     }
97     m_widget->Suspend();
98     m_widgetState = WidgetState_Suspended;
99 }
100
101 void WrtClient::OnReset(bundle *b)
102 {
103     LogDebug("OnReset");
104     // bundle argument is freed after OnReset() is returned
105     // So bundle duplication is needed
106     ApplicationDataSingleton::Instance().setBundle(bundle_dup(b));
107
108     if (true == m_initializing) {
109         LogDebug("can not handle reset event");
110         return;
111     }
112     if (true == m_launched) {
113         if (m_widgetState == WidgetState_Stopped) {
114             LogError("Widget is not running to be reset");
115             return;
116         }
117         m_widget->Reset();
118         m_windowData->emitSignalForUserLayout(EDJE_SHOW_BACKWARD_SIGNAL, "");
119         elm_win_raise(m_windowData->m_win);
120         evas_object_focus_set(m_widget->GetCurrentWebview(), EINA_TRUE);
121         m_widgetState = WidgetState_Running;
122     } else {
123         if (true == checkArgument())
124         {
125             setStep();
126         }
127         else
128         {
129             showHelpAndQuit();
130         }
131     }
132 }
133
134 void WrtClient::OnTerminate()
135 {
136     LogDebug("Wrt Shutdown now");
137     shutdownStep();
138 }
139
140 void WrtClient::showHelpAndQuit()
141 {
142     printf("Usage: wrt-client [OPTION]... [WIDGET: ID]...\n"
143            "launch widgets.\n"
144            "Mandatory arguments to long options are mandatory for short "
145            "options too.\n"
146            "  -h,    --help                                 show this help\n"
147            "  -l,    --launch                               "
148            "launch widget with given ID\n"
149            "\n");
150
151     Quit();
152 }
153
154 bool WrtClient::checkArgument()
155 {
156     LogInfo("checkArgument");
157
158     std::string arg = m_argv[0];
159
160     if (arg.empty()) {
161         return false;
162     }
163
164     if (arg.find("wrt-client") != std::string::npos)
165     {
166         if (m_argc <= 1) {
167             return false;
168         }
169
170         arg = m_argv[1];
171
172         if (arg == "-h" || arg == "--help") {
173             // Just show help
174             return false;
175         } else if (arg == "-l" || arg == "--launch") {
176             if (m_argc != 3) {
177                 return false;
178             }
179             m_handle = atoi(m_argv[2]);
180         } else {
181             return false;
182         }
183     } else {
184         size_t pos = arg.find_last_of('/');
185
186         if (pos != std::string::npos) {
187             arg = arg.erase(0, pos + 1);
188         }
189
190         // Launch widget based on application basename
191         if (sscanf(arg.c_str(), "%i", &m_handle) != 1) {
192             printf("failed: invalid widget handle\n");
193             return false;
194         }
195
196         LogDebug("Widget Id: " << m_handle << " (" << arg << ")");
197     }
198
199     return true;
200 }
201
202 void WrtClient::setStep()
203 {
204     LogInfo("setStep");
205
206     AddStep(&WrtClient::initStep);
207
208     setSdkLauncherDebugData();
209
210     AddStep(&WrtClient::launchStep);
211     AddStep(&WrtClient::shutdownStep);
212
213     m_initializing = true;
214
215     DPL::Event::ControllerEventHandler<NextStepEvent>::PostEvent(NextStepEvent());
216 }
217
218 void WrtClient::setSdkLauncherDebugData()
219 {
220     LogDebug("setSdkLauncherDebugData");
221
222     /* check bundle from sdk launcher */
223     bundle *bundleFromSdkLauncher;
224     bundleFromSdkLauncher = bundle_import_from_argv(m_argc, m_argv);
225     const char *bundle_debug = bundle_get_val(bundleFromSdkLauncher, "debug");
226     const char *bundle_pid = bundle_get_val(bundleFromSdkLauncher, "pid");
227     if (bundle_debug != NULL && bundle_pid != NULL) {
228         if (strcmp(bundle_debug, "true") == 0) {
229             m_debugMode = true;
230             m_sdkLauncherPid = atoi(bundle_pid);
231         } else {
232             m_debugMode = false;
233         }
234     }
235 }
236
237 bool WrtClient::checkDebugMode(WidgetModel* model, SDKDebugData* debugData)
238 {
239     LogError("Checking for debug mode");
240     Assert(model && "Passed widget model is NULL!");
241
242     bool debugMode = debugData->debugMode;
243
244     LogInfo("[DEBUG_MODE] Widget is launched in " <<
245             (debugMode ? "DEBUG" : "RETAIL") <<
246             " mode.");
247
248     if (debugMode == true) {
249         // In WAC widget, only test widgets can use web inspector.
250         // In TIZEN widget,
251         // every launched widgets as debug mode can use it.
252         if (model->Type.Get().appType ==
253             WrtDB::APP_TYPE_WAC20)
254         {
255             bool developerMode =
256                 GlobalLogicSingleton::Instance().GetGlobalModel()
257                 ->DeveloperMode.Get();
258             //This code will be activated
259             //after WAC test certificate is used by SDK
260             //bool isTestWidget = view->m_widgetModel->IsTestWidget.Get();
261             //if(!isTestWidget)
262             //{
263             //    LogInfo("This is not WAC Test Widget");
264             //    break;
265             //}
266             if (!developerMode) {
267                 LogInfo("This is not WAC Developer Mode");
268                 debugMode = false;
269             }
270         }
271     }
272     return debugMode;
273 }
274
275 void WrtClient::OnEventReceived(const NextStepEvent& /*event*/)
276 {
277     LogDebug("Executing next step");
278     NextStep();
279 }
280
281 void WrtClient::initStep()
282 {
283     LogDebug("");
284     if (WRT::CoreModuleSingleton::Instance().Init()) {
285         m_initialized = true;
286     } else {
287         m_returnStatus = ReturnStatus::Failed;
288         SwitchToStep(&WrtClient::shutdownStep);
289     }
290     DPL::Event::ControllerEventHandler<NextStepEvent>::PostEvent(
291             NextStepEvent());
292 }
293
294 void WrtClient::localizeWidgetModel() {
295     Assert(!!m_widget);
296     WRT::WidgetModelPtr model = m_widget->GetModel();
297     Assert(!!model);
298     Domain::localizeWidgetModel(model);
299     model->RunningName.Set(model->Name.Get());
300     model->RunningIcon.Set(model->Icon.Get());
301     model->RunningStartURL.Set(model->StartURL.Get());
302     model->RunningShortName.Set(model->ShortName.Get());
303     model->RunningDescription.Set(model->Description.Get());
304     model->RunningLicense.Set(model->License.Get());
305     model->RunningLicenseHref.Set(model->LicenseHref.Get());
306     model->RunningStartFileInfo.Set(
307         model->StartFileInfo.Get());
308 }
309
310 bool WrtClient::checkWACTestCertififedWidget()
311 {
312     // WAC Waikiki Beta Release Core Specification: Widget Runtime
313     // 10 Dec 2010
314     //
315     // WR-4710 The WRT MUST enable debug functions only for WAC test widgets
316     // i.e. the functions must not be usable for normal WAC widgets, even when
317     // a WAC test widget is executing.
318     ADD_PROFILING_POINT("DeveloperModeCheck", "start");
319     Assert(!!m_widget);
320     WRT::WidgetModelPtr model = m_widget->GetModel();
321     Assert(!!model);
322     // WAC test widget
323     // A widget signed with a WAC-issued test certificate as described in
324     // Developer Mode.
325
326     bool developerWidget = model->IsTestWidget.Get();
327     bool developerMode =
328         GlobalLogicSingleton::Instance().GetGlobalModel()->DeveloperMode.Get();
329
330     LogDebug("Is WAC test widget: " << developerWidget);
331     LogDebug("Is developer Mode: " << developerMode);
332
333     if (developerWidget) {
334         if(!developerMode)
335         {
336             LogError("WAC test certified developer widget is needed for " <<
337                     "developer mode");
338             return false;
339         }else{
340             //TODO: WR-4660 (show popup about developer widget
341             //      during launch
342             LogInfo("POPUP: THIS IS TEST WIDGET!");
343         }
344     }
345     ADD_PROFILING_POINT("DeveloperModeCheck", "stop");
346     return true;
347 }
348
349 void WrtClient::loadFinishCallback(bool success, void* data)
350 {
351     WrtClient* wrtClient = static_cast<WrtClient*>(data);
352     SDKDebugData* debug = new SDKDebugData;
353     debug->debugMode = wrtClient->m_debugMode;
354     debug->pid = new unsigned long(getpid());
355
356     LogInfo("Post result of launch");
357
358     // Start inspector server, if current mode is debugger mode.
359     // In the WK2 case, ewk_view_inspector_server_start should
360     // be called after WebProcess is created.
361     if (wrtClient->checkDebugMode(
362                 wrtClient->m_widget->GetModel().get(), debug))
363     {
364         debug->portnum =
365             ewk_view_inspector_server_start(
366                     wrtClient->m_widget->GetCurrentWebview(), 0);
367         if (debug->portnum == 0) {
368             LogWarning("Failed to get portnum");
369         } else {
370             LogInfo("Assigned port number for inspector : "
371                     << debug->portnum);
372         }
373     } else {
374         LogDebug("Debug mode is disabled");
375     }
376
377     //w3c packaging test debug (message on 4>)
378     const char * makeScreen = getenv(W3C_DEBUG_ENV_VARIABLE);
379     if(makeScreen != NULL && strcmp(makeScreen, "1") == 0)
380     {
381         FILE* doutput = fdopen(4, "w");
382         fprintf(doutput,"didFinishLoadForFrameCallback: ready\n");
383         fclose(doutput);
384     }
385
386     if (success) {
387         LogDebug("Launch succesfull");
388
389         wrtClient->m_launched = true;
390         wrtClient->m_initializing = false;
391         setlinebuf(stdout);
392         printf("launched\n");
393         fflush(stdout);
394     } else {
395         printf("failed\n");
396
397         wrtClient->m_returnStatus = ReturnStatus::Failed;
398         //shutdownStep
399         wrtClient->DPL::Event::ControllerEventHandler<NextStepEvent>::
400                 PostEvent(NextStepEvent());
401     }
402
403     if(debug->debugMode)
404     {
405         LogDebug("Send RT signal to wrt-launcher(pid: "
406                 << wrtClient->m_sdkLauncherPid << ", status: " << success);
407         union sigval sv;
408         /* send real time signal with result to wrt-launcher */
409         if(success)
410         {
411             LogDebug("userData->portnum : " << debug->portnum);
412             sv.sival_int = debug->portnum;
413         }
414         else
415         {
416            sv.sival_int = -1;
417         }
418         sigqueue(wrtClient->m_sdkLauncherPid, SIGRTMIN, sv);
419     }
420
421     ApplicationDataSingleton::Instance().freeBundle();
422
423     LogDebug("Cleaning wrtClient launch resources...");
424     delete debug->pid;
425     delete debug;
426 }
427
428 void WrtClient::progressFinishCallback(void* data)
429 {
430     WrtClient* wrtClient = static_cast<WrtClient*>(data);
431     wrtClient->m_splashScreen->stopSplashScreen();
432 }
433
434 void WrtClient::windowCloseCallback(void* data)
435 {
436     LogDebug("window close called, terminating app");
437     WrtClient* wrtClient = static_cast<WrtClient*>(data);
438     wrtClient->SwitchToStep(&WrtClient::shutdownStep);
439     wrtClient->DPL::Event::ControllerEventHandler<NextStepEvent>::PostEvent(
440             NextStepEvent());
441 }
442
443 void WrtClient::webCrashCallback(void* data)
444 {
445     LogDebug("webProcess crashed");
446     WrtClient* wrtClient = static_cast<WrtClient*>(data);
447     wrtClient->SwitchToStep(&WrtClient::shutdownStep);
448     wrtClient->DPL::Event::ControllerEventHandler<NextStepEvent>::PostEvent(
449             NextStepEvent());
450 }
451
452 void WrtClient::launchStep()
453 {
454     LogDebug("Launching widget ...");
455
456     m_widget =
457         WRT::CoreModuleSingleton::Instance().getRunnableWidgetObject(m_handle);
458     if (!m_widget) {
459         LogError("RunnableWidgetObject is NULL, stop launchStep");
460         DPL::Event::ControllerEventHandler<NextStepEvent>::PostEvent(
461                     NextStepEvent());
462         return;
463     }
464
465     if (m_widgetState == WidgetState_Running) {
466         LogWarning("Widget already running, stop launchStep");
467         DPL::Event::ControllerEventHandler<NextStepEvent>::PostEvent(
468                     NextStepEvent());
469         return;
470     }
471
472     if (m_widgetState == WidgetState_Authorizing) {
473         LogWarning("Widget already authorizing, stop launchStep");
474         DPL::Event::ControllerEventHandler<NextStepEvent>::PostEvent(
475                     NextStepEvent());
476         return;
477     }
478
479     // Widget is not running, localized data can be updated
480     localizeWidgetModel();
481     LocalizationSetting::SetLanguageChangedCallback(
482             languageChangedCallback, this);
483
484     ADD_PROFILING_POINT("CreateWindow", "start");
485     m_windowData.reset(new WindowData(static_cast<unsigned long>(getpid())));
486     ADD_PROFILING_POINT("CreateWindow", "stop");
487
488     WRT::UserCallbacksPtr cbs(new WRT::UserCallbacks);
489     m_splashScreen.reset(
490             new SplashScreenSupport(m_windowData->m_win));
491     if (m_splashScreen->createSplashScreen(m_handle)) {
492         m_splashScreen->startSplashScreen();
493         cbs->progressFinish = progressFinishCallback;
494     }
495     DPL::OptionalString startUrl = m_widget->GetModel()->RunningStartURL.Get();
496     m_widget->PrepareView(DPL::ToUTF8String(*startUrl),
497             m_windowData->m_win);
498     //you can't show window with splash screen before PrepareView
499     //ewk_view_add_with_context() in viewLogic breaks window
500     evas_object_show(m_windowData->m_win);
501     initializeWindowModes();
502     connectElmCallback();
503
504     if (!checkWACTestCertififedWidget())
505     {
506         LogWarning("WAC Certificate failed, stop launchStep");
507         return;
508     }
509
510     m_widgetState = WidgetState_Authorizing;
511     if (!m_widget->CheckBeforeLaunch()) {
512         LogError("CheckBeforeLaunch failed, stop launchStep");
513         DPL::Event::ControllerEventHandler<NextStepEvent>::PostEvent(
514                     NextStepEvent());
515         return;
516     }
517     LogInfo("Widget launch accepted. Entering running state");
518     m_widgetState = WidgetState_Running;
519
520     cbs->loadFinish = loadFinishCallback;
521     cbs->bufferSet = setLayout;
522     cbs->bufferUnset = unsetLayout;
523     cbs->windowClose = windowCloseCallback;
524     cbs->webCrash = webCrashCallback;
525
526     m_widget->SetUserCallbacks(cbs, this);
527     m_widget->Show();
528     m_windowData->emitSignalForUserLayout(EDJE_SHOW_BACKWARD_SIGNAL, "");
529 }
530
531 void WrtClient::initializeWindowModes()
532 {
533     Assert(m_windowData);
534     WRT::WidgetModelPtr model = m_widget->GetModel();
535     Assert(model);
536     auto windowModes = model->WindowModes.Get();
537     bool fullscreen = false;
538     FOREACH(it, windowModes)
539     {
540         std::string viewMode = DPL::ToUTF8String(*it);
541         if (viewMode == VIEWMODE_TYPE_FULLSCREEN) {
542             fullscreen = true;
543             break;
544         } else if (viewMode == VIEWMODE_TYPE_MAXIMIZED) {
545             break;
546         }
547     }
548     bool indicator = true;
549     bool backbutton = false;
550     if (model->Type.Get().appType == WrtDB::APP_TYPE_TIZENWEBAPP) {
551         indicator
552         = (model->SettingList.Get().getIndicatorPresence()
553            == Indicator_Enable);
554         backbutton
555         = (model->SettingList.Get().getBackButtonPresence()
556            == BackButton_Enable);
557     }
558
559     if (!fullscreen) {
560         std::string name = "";
561         if (!(model->Name.Get().IsNull())) {
562             name = DPL::ToUTF8String(*(model->Name.Get()));
563         }
564         m_windowData->setViewModeMaximized(
565             name.c_str(), indicator, backbutton);
566     } else {
567         m_windowData->setViewModeFullScreen(
568             indicator, backbutton);
569     }
570 }
571
572 void WrtClient::backButtonCallback(void* data,
573                                      Evas_Object * /*obj*/,
574                                      void * /*event_info*/)
575 {
576     LogInfo("BackButtonCallback");
577     Assert(data);
578
579     WrtClient* This = static_cast<WrtClient*>(data);
580
581     This->m_widget->GoBack();
582 }
583
584 void WrtClient::connectElmCallback()
585 {
586     Assert(m_windowData);
587     WRT::WidgetModelPtr model = m_widget->GetModel();
588     Assert(model);
589     if (model->Type.Get().appType == WrtDB::APP_TYPE_TIZENWEBAPP) {
590         if (model->SettingList.Get().getBackButtonPresence() ==
591                 BackButton_Enable)
592         {
593             m_windowData->addFloatBackButtonCallback(
594                 "clicked",
595                 &WrtClient::backButtonCallback,
596                 this);
597         }
598
599         WidgetSettingScreenLock rotationValue =
600                 model->SettingList.Get().getRotationValue();
601         if (rotationValue == Screen_Portrait) {
602             elm_win_rotation_with_resize_set(m_windowData->m_win, 0);
603         } else if (rotationValue == Screen_Landscape) {
604             elm_win_rotation_with_resize_set(m_windowData->m_win, 270);
605         } else {
606             elm_win_rotation_with_resize_set(m_windowData->m_win, 0);
607         }
608     }
609 }
610
611 void WrtClient::setLayout(Evas_Object* newBuffer, void* data) {
612     LogDebug("add new webkit buffer to window");
613     Assert(data);
614     Assert(newBuffer);
615     WrtClient* wrtClient = static_cast<WrtClient*>(data);
616     elm_object_content_set(wrtClient->m_windowData->m_conformant, newBuffer);
617     evas_object_show(newBuffer);
618     evas_object_focus_set(newBuffer, EINA_TRUE);
619 }
620
621 void WrtClient::unsetLayout(Evas_Object* currentBuffer, void* data) {
622     LogDebug("remove current webkit buffer from window");
623     Assert(data);
624     Assert(currentBuffer);
625     WrtClient* wrtClient = static_cast<WrtClient*>(data);
626     evas_object_hide(currentBuffer);
627     elm_object_content_unset(wrtClient->m_windowData->m_conformant);
628 }
629
630 void WrtClient::shutdownStep()
631 {
632     LogDebug("Closing Wrt connection ...");
633     if (m_initialized && m_widget) {
634         m_widgetState = WidgetState_Stopped;
635         m_widget->Hide();
636         m_widget.reset();
637         m_windowData.reset();
638         WRT::CoreModuleSingleton::Instance().Terminate();
639         m_initialized = false;
640     }
641     Quit();
642 }
643
644 int WrtClient::languageChangedCallback(void *data)
645 {
646     LogDebug("Language Changed");
647     WrtClient* wrtClient = static_cast<WrtClient*>(data);
648     WRT::WidgetModelPtr model = wrtClient->m_widget->GetModel();
649
650     LocalizationSetting::SetLocalization();
651
652     LanguageTagsList tags = LocalizationUtils::GetUserAgentLanguageTags();
653     if (model->LanguageTags.Get() != tags) {
654         // update localized data
655         wrtClient->localizeWidgetModel();
656
657         if (true == wrtClient->m_launched &&
658                 wrtClient->m_widgetState != WidgetState_Stopped) {
659             wrtClient->m_widget->ReloadStartPage();
660         }
661     }
662     return 0;
663 }
664
665 int main(int argc,
666          char *argv[])
667 {
668     ADD_PROFILING_POINT("main-entered", "point");
669
670     // Output on stdout will be flushed after every newline character,
671     // even if it is redirected to a pipe. This is useful for running
672     // from a script and parsing output.
673     // (Standard behavior of stdlib is to use full buffering when
674     // redirected to a pipe, which means even after an end of line
675     // the output may not be flushed).
676     setlinebuf(stdout);
677
678     // set evas backend type
679     if (!getenv("ELM_ENGINE")) {
680         if (setenv("ELM_ENGINE", "gl", 1)) {
681                 LogDebug("Enable backend");
682         }
683     }
684     // Set log tagging
685     DPL::Log::LogSystemSingleton::Instance().SetTag("WRT-CLIENT");
686
687     WrtClient app(argc, argv);
688     int ret = app.Exec();
689     LogDebug("App returned: " << ret);
690     ret = app.getReturnStatus();
691     LogDebug("WrtClient returned: " << ret);
692     return ret;
693 }