[Tizen] Fix crash issue when mArgc / mArgv is null at Tizen
[platform/core/uifw/dali-adaptor.git] / dali / internal / adaptor / tizen-wayland / framework-tizen.cpp
1 /*
2  * Copyright (c) 2022 Samsung Electronics Co., Ltd.
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 // CLASS HEADER
19 #include <dali/internal/adaptor/common/framework.h>
20
21 // EXTERNAL INCLUDES
22 #include <app_common.h>
23 #include <app_control_internal.h>
24 #include <bundle.h>
25 #include <bundle_internal.h>
26 #include <dlog.h>
27 #include <glib.h>
28 #include <system_info.h>
29 #include <system_settings.h>
30 #include <widget_base.h>
31 #include <app_core_ui_base.hh>
32 #include <app_event_internal.hh>
33
34 // CONDITIONAL INCLUDES
35 #ifdef APPCORE_WATCH_AVAILABLE
36 #include <appcore-watch/watch_app.h>
37 #endif
38 #ifdef DALI_ELDBUS_AVAILABLE
39 #include <Eldbus.h>
40 #endif // DALI_ELDBUS_AVAILABLE
41
42 #if defined(TIZEN_PLATFORM_CONFIG_SUPPORTED) && TIZEN_PLATFORM_CONFIG_SUPPORTED
43 #include <tzplatform_config.h>
44 #endif // TIZEN_PLATFORM_CONFIG_SUPPORTED
45
46 #ifdef COMPONENT_APPLICATION_SUPPORT
47 #include <component_based_app_base.h>
48 #endif
49
50 #include <dali/integration-api/debug.h>
51 #include <dali/integration-api/trace.h>
52
53 // INTERNAL INCLUDES
54 #include <dali/internal/system/common/callback-manager.h>
55 #include <dali/internal/system/linux/dali-ecore.h>
56
57 using namespace tizen_cpp;
58
59 namespace Dali
60 {
61 namespace Internal
62 {
63 namespace Adaptor
64 {
65 namespace
66 {
67 #if defined(DEBUG_ENABLED)
68 Integration::Log::Filter* gDBusLogging = Integration::Log::Filter::New(Debug::NoLogging, false, "LOG_ADAPTOR_EVENTS_DBUS");
69 #endif
70 DALI_INIT_TRACE_FILTER(gTraceFilter, DALI_TRACE_FRAMEWORK, true);
71
72 bool IsWidgetFeatureEnabled()
73 {
74   static bool feature   = false;
75   static bool retrieved = false;
76   int         ret;
77
78   if(retrieved == true)
79   {
80     return feature;
81   }
82
83   ret = system_info_get_platform_bool("http://tizen.org/feature/shell.appwidget", &feature);
84   if(ret != SYSTEM_INFO_ERROR_NONE)
85   {
86     DALI_LOG_ERROR("failed to get system info");
87     return false;
88   }
89
90   retrieved = true;
91   return feature;
92 }
93
94 // Note : tizen appfw don't consider zero-arguments case.
95 // If framework argc & argv is nullptr, We should add at least one argv.
96 const int   gTizenDummyArgc    = 1;
97 const char* gTizenDummyArgv[1] = {"dali-tizen-app"};
98
99 } // anonymous namespace
100
101 namespace AppCore
102 {
103 typedef enum
104 {
105   LOW_MEMORY,                 //< The low memory event
106   LOW_BATTERY,                //< The low battery event
107   LANGUAGE_CHANGED,           //< The system language changed event
108   DEVICE_ORIENTATION_CHANGED, //< The device orientation changed event
109   REGION_FORMAT_CHANGED,      //< The region format changed event
110   SUSPENDED_STATE_CHANGED,    //< The suspended state changed event of the application
111   UPDATE_REQUESTED,           //< The update requested event. This event can occur when an app needs to be updated. It is dependent on target devices.
112 } AppEventType;
113
114 static int AppEventConverter[APPCORE_BASE_EVENT_MAX] =
115   {
116     [LOW_MEMORY]                 = APPCORE_BASE_EVENT_LOW_MEMORY,
117     [LOW_BATTERY]                = APPCORE_BASE_EVENT_LOW_BATTERY,
118     [LANGUAGE_CHANGED]           = APPCORE_BASE_EVENT_LANG_CHANGE,
119     [DEVICE_ORIENTATION_CHANGED] = APPCORE_BASE_EVENT_DEVICE_ORIENTATION_CHANGED,
120     [REGION_FORMAT_CHANGED]      = APPCORE_BASE_EVENT_REGION_CHANGE,
121     [SUSPENDED_STATE_CHANGED]    = APPCORE_BASE_EVENT_SUSPENDED_STATE_CHANGE,
122 };
123
124 struct AppEventInfo
125 {
126   AppEventType type;
127   void*        value;
128 };
129
130 typedef struct AppEventInfo* AppEventInfoPtr;
131
132 typedef void (*AppEventCallback)(AppEventInfoPtr eventInfo, void* userData);
133
134 struct AppEventHandler
135 {
136   AppEventType     type;
137   AppEventCallback cb;
138   void*            data;
139   void*            raw;
140 };
141
142 typedef struct AppEventHandler* AppEventHandlerPtr;
143
144 int EventCallback(void* event, void* data)
145 {
146   AppEventHandlerPtr handler = static_cast<AppEventHandlerPtr>(data);
147
148   struct AppEventInfo appEvent;
149
150   appEvent.type  = handler->type;
151   appEvent.value = event;
152
153   if(handler->cb)
154     handler->cb(&appEvent, handler->data);
155
156   return 0;
157 }
158
159 int AppAddEventHandler(AppEventHandlerPtr* eventHandler, AppEventType eventType, AppEventCallback callback, void* userData)
160 {
161   AppEventHandlerPtr handler;
162
163   handler = static_cast<AppEventHandlerPtr>(calloc(1, sizeof(struct AppEventHandler)));
164   if(!handler)
165   {
166     DALI_LOG_ERROR("failed to create handler");
167     return TIZEN_ERROR_UNKNOWN;
168   }
169   else
170   {
171     handler->type = eventType;
172     handler->cb   = callback;
173     handler->data = userData;
174     handler->raw  = appcore_base_add_event(static_cast<appcore_base_event>(AppEventConverter[static_cast<int>(eventType)]), EventCallback, handler);
175
176     *eventHandler = handler;
177
178     return TIZEN_ERROR_NONE;
179   }
180 }
181
182 DeviceStatus::Memory::Status GetMemoryStatus(app_event_low_memory_status_e memoryStatus)
183 {
184   switch(memoryStatus)
185   {
186     case APP_EVENT_LOW_MEMORY_SOFT_WARNING: // 0x02
187     {
188       return Dali::DeviceStatus::Memory::Status::LOW;
189     }
190     case APP_EVENT_LOW_MEMORY_HARD_WARNING: // 0x04
191     {
192       return Dali::DeviceStatus::Memory::Status::CRITICALLY_LOW;
193     }
194     default: // APP_EVENT_LOW_MEMORY_NORMAL 0x01
195     {
196       return Dali::DeviceStatus::Memory::Status::NORMAL;
197     }
198   }
199 }
200
201 DeviceStatus::Battery::Status GetBatteryStatus(app_event_low_battery_status_e batteryStatus)
202 {
203   switch(batteryStatus)
204   {
205     case APP_EVENT_LOW_BATTERY_POWER_OFF: // 1
206     {
207       return Dali::DeviceStatus::Battery::Status::POWER_OFF;
208     }
209     case APP_EVENT_LOW_BATTERY_CRITICAL_LOW: // 2
210     {
211       return Dali::DeviceStatus::Battery::Status::CRITICALLY_LOW;
212     }
213     default:
214     {
215       return Dali::DeviceStatus::Battery::Status::NORMAL;
216     }
217   }
218 }
219
220 } // namespace AppCore
221
222 /**
223  * Impl to hide EFL data members
224  */
225 struct Framework::Impl
226 {
227   class UiAppContext : public AppCoreUiBase
228   {
229   public:
230     class Task : public AppCoreTaskBase
231     {
232     public:
233       explicit Task(Framework* framework)
234       : mFramework(framework),
235         mNewBatteryStatus(Dali::DeviceStatus::Battery::Status::NORMAL),
236         mNewMemoryStatus(Dali::DeviceStatus::Memory::NORMAL)
237       {
238       }
239
240       virtual ~Task()
241       {
242       }
243
244       int OnCreate() override
245       {
246         // On the main thread, the log functions are not set. So print_log() is used directly.
247         print_log(DLOG_INFO, "DALI", "%s: %s(%d) > OnCreate() emitted", __MODULE__, __func__, __LINE__);
248         mFramework->mTaskObserver.OnTaskInit();
249         return AppCoreTaskBase::OnCreate();
250       }
251
252       int OnTerminate() override
253       {
254         print_log(DLOG_INFO, "DALI", "%s: %s(%d) > OnTerminate() emitted", __MODULE__, __func__, __LINE__);
255         mFramework->mTaskObserver.OnTaskTerminate();
256         return AppCoreTaskBase::OnTerminate();
257       }
258
259       int OnControl(tizen_base::Bundle b) override
260       {
261         print_log(DLOG_INFO, "DALI", "%s: %s(%d) > OnControl() emitted", __MODULE__, __func__, __LINE__);
262         AppCoreTaskBase::OnControl(b);
263
264         app_control_h appControl = nullptr;
265
266         auto* bundleData = b.GetHandle();
267         if(bundleData)
268         {
269           if(app_control_create_event(bundleData, &appControl) != TIZEN_ERROR_NONE)
270           {
271             print_log(DLOG_ERROR, "DALI", "%s: %s(%d) > Failed to create an app_control handle with Bundle", __MODULE__, __func__, __LINE__);
272           }
273         }
274         else
275         {
276           if(app_control_create(&appControl) != TIZEN_ERROR_NONE)
277           {
278             print_log(DLOG_ERROR, "DALI", "%s: %s(%d) > Failed to create an app_control handle", __MODULE__, __func__, __LINE__);
279           }
280         }
281         mFramework->mTaskObserver.OnTaskAppControl(appControl);
282
283         app_control_destroy(appControl);
284         return 0;
285       }
286
287       void OnUiEvent(AppCoreTaskBase::UiState state) override
288       {
289         // This event is emitted when the UI thread is paused or resumed.
290         print_log(DLOG_INFO, "DALI", "%s: %s(%d) > OnUiEvent() emitted", __MODULE__, __func__, __LINE__);
291
292         // Note: This isn't implemented.
293         AppCoreTaskBase::OnUiEvent(state);
294       }
295
296       void OnLowMemory(AppCoreTaskBase::LowMemoryState state) override
297       {
298         print_log(DLOG_INFO, "DALI", "%s: %s(%d) > OnLowMemory() emitted", __MODULE__, __func__, __LINE__);
299
300         mNewMemoryStatus = AppCore::GetMemoryStatus(static_cast<app_event_low_memory_status_e>(state));
301
302         PostToUiThread(
303           [](gpointer userData) -> gboolean {
304             auto* task      = static_cast<Task*>(userData);
305             auto* framework = static_cast<Framework*>(task->mFramework);
306             framework->mObserver.OnMemoryLow(task->mNewMemoryStatus);
307             return G_SOURCE_REMOVE;
308           });
309         mFramework->mTaskObserver.OnTaskMemoryLow(mNewMemoryStatus);
310         AppCoreTaskBase::OnLowMemory(state);
311       }
312
313       void OnLowBattery(AppCoreTaskBase::LowBatteryState state) override
314       {
315         print_log(DLOG_INFO, "DALI", "%s: %s(%d) > OnLowBattery() emitted", __MODULE__, __func__, __LINE__);
316         mNewBatteryStatus = AppCore::GetBatteryStatus(static_cast<app_event_low_battery_status_e>(state));
317
318         PostToUiThread(
319           [](gpointer userData) -> gboolean {
320             auto* task      = static_cast<Task*>(userData);
321             auto* framework = static_cast<Framework*>(task->mFramework);
322             framework->mObserver.OnBatteryLow(task->mNewBatteryStatus);
323             return G_SOURCE_REMOVE;
324           });
325         mFramework->mTaskObserver.OnTaskBatteryLow(mNewBatteryStatus);
326         AppCoreTaskBase::OnLowBattery(state);
327       }
328
329       void OnLangChanged(const std::string& lang) override
330       {
331         print_log(DLOG_INFO, "DALI", "%s: %s(%d) > OnLangChanged() emitted", __MODULE__, __func__, __LINE__);
332         mNewLanguage = lang;
333         mFramework->SetLanguage(mNewLanguage);
334
335         PostToUiThread(
336           [](gpointer userData) -> gboolean {
337             auto* task      = static_cast<Task*>(userData);
338             auto* framework = static_cast<Framework*>(task->mFramework);
339             framework->mObserver.OnLanguageChanged();
340             return G_SOURCE_REMOVE;
341           });
342
343         mFramework->mTaskObserver.OnTaskLanguageChanged();
344         AppCoreTaskBase::OnLangChanged(lang);
345       }
346
347       void OnRegionChanged(const std::string& region) override
348       {
349         print_log(DLOG_INFO, "DALI", "%s: %s(%d) > nRegionChanged() emitted", __MODULE__, __func__, __LINE__);
350         mNewRegion = region;
351         mFramework->SetRegion(mNewRegion);
352
353         PostToUiThread(
354           [](gpointer userData) -> gboolean {
355             auto* task      = static_cast<Task*>(userData);
356             auto* framework = static_cast<Framework*>(task->mFramework);
357             framework->mObserver.OnRegionChanged();
358             return G_SOURCE_REMOVE;
359           });
360
361         mFramework->mTaskObserver.OnTaskRegionChanged();
362         AppCoreTaskBase::OnRegionChanged(mNewRegion);
363       }
364
365       void OnDeviceOrientationChanged(AppCoreTaskBase::DeviceOrientationState state) override
366       {
367         print_log(DLOG_INFO, "DALI", "%s: %s(%d) > OnDeviceOrientationChanged() emitted", __MODULE__, __func__, __LINE__);
368         // Note: This isn't emitted to the App.
369         AppCoreTaskBase::OnDeviceOrientationChanged(state);
370       }
371
372     private:
373       GMainContext* GetTizenGlibContext()
374       {
375         GMainContext* context;
376         const char*   env = getenv("TIZEN_GLIB_CONTEXT");
377         if(env)
378         {
379           context = (GMainContext*)strtoul(env, nullptr, 10);
380         }
381         else
382         {
383           context = nullptr;
384         }
385
386         return context;
387       }
388
389       void PostToUiThread(GSourceFunc func)
390       {
391         GSource* source = g_idle_source_new();
392         g_source_set_callback(source, func, this, nullptr);
393         g_source_attach(source, GetTizenGlibContext());
394         g_source_unref(source);
395       }
396
397     private:
398       Framework*                          mFramework;
399       std::string                         mNewLanguage;
400       std::string                         mNewRegion;
401       Dali::DeviceStatus::Battery::Status mNewBatteryStatus;
402       Dali::DeviceStatus::Memory::Status  mNewMemoryStatus;
403     };
404
405     explicit UiAppContext(unsigned int hint, Framework* framework)
406     : AppCoreUiBase(hint),
407       mFramework(framework),
408       mUseUiThread(false)
409     {
410       if(hint & AppCoreUiBase::HINT_DUAL_THREAD)
411       {
412         mUseUiThread = true;
413       }
414
415       if(!mUseUiThread)
416       {
417         mLanguageChanged = std::make_shared<AppEvent>(IAppCore::IEvent::Type::LANG_CHANGE, OnLanguageChanged, this);
418         AddEvent(mLanguageChanged);
419
420         mDeviceOrientationChanged = std::make_shared<AppEvent>(IAppCore::IEvent::Type::DEVICE_ORIENTATION_CHANGED, OnDeviceOrientationChanged, this);
421         AddEvent(mDeviceOrientationChanged);
422
423         mRegionFormatChanged = std::make_shared<AppEvent>(IAppCore::IEvent::Type::REGION_CHANGE, OnRegionFormatChanged, this);
424         AddEvent(mRegionFormatChanged);
425
426         mLowMemory = std::make_shared<AppEvent>(IAppCore::IEvent::Type::LOW_MEMORY, OnLowMemory, this);
427         AddEvent(mLowMemory);
428
429         mLowBattery = std::make_shared<AppEvent>(IAppCore::IEvent::Type::LOW_BATTERY, OnLowBattery, this);
430         AddEvent(mLowBattery);
431       }
432     }
433
434     virtual ~UiAppContext()
435     {
436       if(!mUseUiThread)
437       {
438         RemoveEvent(mLowBattery);
439         RemoveEvent(mLowMemory);
440         RemoveEvent(mRegionFormatChanged);
441         RemoveEvent(mDeviceOrientationChanged);
442         RemoveEvent(mLanguageChanged);
443       }
444     }
445
446     std::unique_ptr<AppCoreTaskBase> CreateTask() override
447     {
448       return std::unique_ptr<AppCoreTaskBase>(
449         new Task(mFramework));
450     }
451
452     int OnCreate() override
453     {
454       AppCoreUiBase::OnCreate();
455       mFramework->Create();
456       return 0;
457     }
458
459     int OnTerminate() override
460     {
461       AppCoreUiBase::OnTerminate();
462       auto* observer = &mFramework->mObserver;
463       observer->OnTerminate();
464       return 0;
465     }
466
467     int OnPause() override
468     {
469       AppCoreUiBase::OnPause();
470       auto* observer = &mFramework->mObserver;
471       observer->OnPause();
472       return 0;
473     }
474
475     int OnResume() override
476     {
477       AppCoreUiBase::OnResume();
478       auto* observer = &mFramework->mObserver;
479       observer->OnResume();
480       return 0;
481     }
482
483     int OnControl(tizen_base::Bundle b) override
484     {
485       AppCoreUiBase::OnControl(b);
486
487       app_control_h appControl = nullptr;
488
489       auto* bundleData = b.GetHandle();
490       if(bundleData)
491       {
492         if(app_control_create_event(bundleData, &appControl) != TIZEN_ERROR_NONE)
493         {
494           DALI_LOG_ERROR("Failed to create an app_control handle");
495           return 0;
496         }
497       }
498       else
499       {
500         if(app_control_create(&appControl) != TIZEN_ERROR_NONE)
501         {
502           DALI_LOG_ERROR("Failed to create an app_control handle");
503           return 0;
504         }
505       }
506
507       auto* observer = &mFramework->mObserver;
508       ProcessBundle(mFramework, bundleData);
509       observer->OnReset();
510       observer->OnAppControl(appControl);
511       app_control_destroy(appControl);
512       return 0;
513     }
514
515     void OnLoopInit(int argc, char** argv) override
516     {
517 #pragma GCC diagnostic push
518 #pragma GCC diagnostic ignored "-Wold-style-cast"
519       ecore_init();
520       ecore_app_args_set(argc, (const char**)argv);
521 #pragma GCC diagnostic pop
522
523 #ifdef DALI_ELDBUS_AVAILABLE
524       // Initialize ElDBus.
525       DALI_LOG_INFO(gDBusLogging, Debug::General, "Starting DBus Initialization\n");
526       eldbus_init();
527 #endif
528     }
529
530     void OnLoopFinish() override
531     {
532       ecore_shutdown();
533
534       if(getenv("AUL_LOADER_INIT"))
535       {
536         setenv("AUL_LOADER_INIT", "0", 1);
537         ecore_shutdown();
538       }
539
540 #ifdef DALI_ELDBUS_AVAILABLE
541       // Shutdown ELDBus.
542       DALI_LOG_INFO(gDBusLogging, Debug::General, "Shutting down DBus\n");
543       eldbus_shutdown();
544 #endif
545     }
546
547     void OnLoopRun() override
548     {
549       ecore_main_loop_begin();
550     }
551
552     void OnLoopExit() override
553     {
554       ecore_main_loop_quit();
555     }
556
557   private:
558     static void OnLanguageChanged(app_event_info_h event_info, void* user_data)
559     {
560       auto*     context   = static_cast<UiAppContext*>(user_data);
561       auto*     framework = context->mFramework;
562       Observer* observer  = &framework->mObserver;
563
564       char* lang = nullptr;
565       app_event_get_language(event_info, &lang);
566       if(lang)
567       {
568         framework->SetLanguage(std::string(lang));
569         observer->OnLanguageChanged();
570         free(lang);
571       }
572       else
573       {
574         DALI_LOG_ERROR("NULL pointer in Language changed event\n");
575       }
576     }
577
578     static void OnDeviceOrientationChanged(app_event_info_h event_info, void* user_data)
579     {
580     }
581
582     static void OnRegionFormatChanged(app_event_info_h event_info, void* user_data)
583     {
584       auto*     context   = static_cast<UiAppContext*>(user_data);
585       auto*     framework = context->mFramework;
586       Observer* observer  = &framework->mObserver;
587
588       char* region = nullptr;
589       app_event_get_region_format(event_info, &region);
590       if(region)
591       {
592         framework->SetRegion(std::string(region));
593         observer->OnRegionChanged();
594         free(region);
595       }
596       else
597       {
598         DALI_LOG_ERROR("NULL pointer in Region changed event\n");
599       }
600     }
601
602     static void OnLowBattery(app_event_info_h event_info, void* user_data)
603     {
604       auto*     context   = static_cast<UiAppContext*>(user_data);
605       auto*     framework = context->mFramework;
606       Observer* observer  = &framework->mObserver;
607
608       app_event_low_battery_status_e status;
609       app_event_get_low_battery_status(event_info, &status);
610       Dali::DeviceStatus::Battery::Status result = AppCore::GetBatteryStatus(status);
611       observer->OnBatteryLow(result);
612     }
613
614     static void OnLowMemory(app_event_info_h event_info, void* user_data)
615     {
616       auto*     context   = static_cast<UiAppContext*>(user_data);
617       auto*     framework = context->mFramework;
618       Observer* observer  = &framework->mObserver;
619
620       app_event_low_memory_status_e status;
621       app_event_get_low_memory_status(event_info, &status);
622       Dali::DeviceStatus::Memory::Status result = AppCore::GetMemoryStatus(status);
623       observer->OnMemoryLow(result);
624     }
625
626     void ProcessBundle(Framework* framework, bundle* bundleData)
627     {
628       if(bundleData == nullptr)
629       {
630         return;
631       }
632
633       // get bundle name
634       char* bundleName = const_cast<char*>(bundle_get_val(bundleData, "name"));
635       if(bundleName != nullptr)
636       {
637         framework->SetBundleName(bundleName);
638       }
639
640       // get bundle? id
641       char* bundleId = const_cast<char*>(bundle_get_val(bundleData, "id"));
642       if(bundleId != nullptr)
643       {
644         framework->SetBundleId(bundleId);
645       }
646     }
647
648   private:
649     Framework*                mFramework;
650     std::shared_ptr<AppEvent> mLanguageChanged;
651     std::shared_ptr<AppEvent> mDeviceOrientationChanged;
652     std::shared_ptr<AppEvent> mRegionFormatChanged;
653     std::shared_ptr<AppEvent> mLowBattery;
654     std::shared_ptr<AppEvent> mLowMemory;
655     bool                      mUseUiThread;
656   };
657
658   // Constructor
659   Impl(void* data, Type type, bool useUiThread)
660   : mAbortCallBack(NULL),
661     mCallbackManager(NULL),
662     mUseUiThread(useUiThread)
663 #ifdef APPCORE_WATCH_AVAILABLE
664     ,
665     mWatchCallback()
666 #endif
667   {
668     mFramework = static_cast<Framework*>(data);
669
670 #ifndef APPCORE_WATCH_AVAILABLE
671     if(type == WATCH)
672     {
673       throw Dali::DaliException("", "Watch Application is not supported.");
674     }
675 #endif
676     mApplicationType = type;
677     mCallbackManager = CallbackManager::New();
678   }
679
680   ~Impl()
681   {
682     delete mAbortCallBack;
683
684     // we're quiting the main loop so
685     // mCallbackManager->RemoveAllCallBacks() does not need to be called
686     // to delete our abort handler
687     delete mCallbackManager;
688   }
689
690   int AppMain()
691   {
692     // TODO: The app-core-cpp has to be applied to the other app types.
693     int ret;
694     switch(mApplicationType)
695     {
696       case NORMAL:
697       {
698         ret = AppNormalMain();
699         break;
700       }
701       case WIDGET:
702       {
703         ret = AppWidgetMain();
704         break;
705       }
706       case WATCH:
707       {
708         ret = AppWatchMain();
709         break;
710       }
711 #ifdef COMPONENT_APPLICATION_SUPPORT
712       case COMPONENT:
713       {
714         ret = AppComponentMain();
715         break;
716       }
717 #endif
718     }
719     return ret;
720   }
721
722   void AppExit()
723   {
724     switch(mApplicationType)
725     {
726       case NORMAL:
727       {
728         AppNormalExit();
729         break;
730       }
731       case WIDGET:
732       {
733         AppWidgetExit();
734         break;
735       }
736       case WATCH:
737       {
738         AppWatchExit();
739         break;
740       }
741 #ifdef COMPONENT_APPLICATION_SUPPORT
742       case COMPONENT:
743       {
744         AppComponentExit();
745         break;
746       }
747 #endif
748     }
749   }
750
751   void SetLanguage(const std::string& language)
752   {
753     mLanguage = language;
754   }
755
756   void SetRegion(const std::string& region)
757   {
758     mRegion = region;
759   }
760
761   std::string GetLanguage()
762   {
763     if(mLanguage.empty())
764     {
765       char* language = nullptr;
766       system_settings_get_value_string(SYSTEM_SETTINGS_KEY_LOCALE_LANGUAGE, &language);
767
768       if(language != nullptr)
769       {
770         mLanguage = std::string(language);
771         free(language);
772       }
773     }
774     return mLanguage;
775   }
776
777   std::string GetRegion()
778   {
779     if(mRegion.empty())
780     {
781       char* region = nullptr;
782       system_settings_get_value_string(SYSTEM_SETTINGS_KEY_LOCALE_COUNTRY, &region);
783
784       if(region != nullptr)
785       {
786         mRegion = std::string(region);
787         free(region);
788       }
789     }
790     return mRegion;
791   }
792
793   // Data
794   Type             mApplicationType;
795   CallbackBase*    mAbortCallBack;
796   CallbackManager* mCallbackManager;
797   std::string      mLanguage{};
798   std::string      mRegion{};
799
800   Framework*                    mFramework;
801   AppCore::AppEventHandlerPtr   handlers[5];
802   std::unique_ptr<UiAppContext> mUiAppContext;
803   bool                          mUseUiThread;
804 #ifdef APPCORE_WATCH_AVAILABLE
805   watch_app_lifecycle_callback_s mWatchCallback;
806 #endif
807
808   static void ProcessBundle(Framework* framework, bundle* bundleData)
809   {
810     if(bundleData == NULL)
811     {
812       return;
813     }
814
815     // get bundle name
816     char* bundleName = const_cast<char*>(bundle_get_val(bundleData, "name"));
817     if(bundleName != NULL)
818     {
819       framework->SetBundleName(bundleName);
820     }
821
822     // get bundle? id
823     char* bundleId = const_cast<char*>(bundle_get_val(bundleData, "id"));
824     if(bundleId != NULL)
825     {
826       framework->SetBundleId(bundleId);
827     }
828   }
829
830   static void AppInit(int argc, char** argv, void* data)
831   {
832 #pragma GCC diagnostic push
833 #pragma GCC diagnostic ignored "-Wold-style-cast"
834     ecore_init();
835     ecore_app_args_set(argc, (const char**)argv);
836 #pragma GCC diagnostic pop
837
838 #ifdef DALI_ELDBUS_AVAILABLE
839     // Initialize ElDBus.
840     DALI_LOG_INFO(gDBusLogging, Debug::General, "Starting DBus Initialization\n");
841     eldbus_init();
842 #endif
843   }
844
845   static void AppFinish(void)
846   {
847     ecore_shutdown();
848
849     if(getenv("AUL_LOADER_INIT"))
850     {
851       setenv("AUL_LOADER_INIT", "0", 1);
852       ecore_shutdown();
853     }
854
855 #ifdef DALI_ELDBUS_AVAILABLE
856     // Shutdown ELDBus.
857     DALI_LOG_INFO(gDBusLogging, Debug::General, "Shutting down DBus\n");
858     eldbus_shutdown();
859 #endif
860   }
861
862   static void AppRun(void* data)
863   {
864     ecore_main_loop_begin();
865   }
866
867   static void AppExit(void* data)
868   {
869     ecore_main_loop_quit();
870   }
871
872   static void AppLanguageChanged(AppCore::AppEventInfoPtr event, void* data)
873   {
874     Framework* framework = static_cast<Framework*>(data);
875     Observer*  observer  = &framework->mObserver;
876
877     if(event && event->value)
878     {
879       framework->SetLanguage(std::string(static_cast<const char*>(event->value)));
880       observer->OnLanguageChanged();
881     }
882     else
883     {
884       DALI_LOG_ERROR("NULL pointer in Language changed event\n");
885     }
886   }
887
888   static void AppDeviceRotated(AppCore::AppEventInfoPtr event_info, void* data)
889   {
890   }
891
892   static void AppRegionChanged(AppCore::AppEventInfoPtr event, void* data)
893   {
894     Framework* framework = static_cast<Framework*>(data);
895     Observer*  observer  = &framework->mObserver;
896
897     if(event && event->value)
898     {
899       framework->SetRegion(std::string(static_cast<const char*>(event->value)));
900       observer->OnRegionChanged();
901     }
902     else
903     {
904       DALI_LOG_ERROR("NULL pointer in Region changed event\n");
905     }
906   }
907
908   static void AppBatteryLow(AppCore::AppEventInfoPtr event, void* data)
909   {
910     Observer*                           observer = &static_cast<Framework*>(data)->mObserver;
911     int                                 status   = *static_cast<int*>(event->value);
912     Dali::DeviceStatus::Battery::Status result   = Dali::DeviceStatus::Battery::NORMAL;
913
914     // convert to dali battery status
915     switch(status)
916     {
917       case 1:
918       {
919         result = Dali::DeviceStatus::Battery::POWER_OFF;
920         break;
921       }
922       case 2:
923       {
924         result = Dali::DeviceStatus::Battery::CRITICALLY_LOW;
925         break;
926       }
927       default:
928         break;
929     }
930     observer->OnBatteryLow(result);
931   }
932
933   static void AppMemoryLow(AppCore::AppEventInfoPtr event, void* data)
934   {
935     Observer*                          observer = &static_cast<Framework*>(data)->mObserver;
936     int                                status   = *static_cast<int*>(event->value);
937     Dali::DeviceStatus::Memory::Status result   = Dali::DeviceStatus::Memory::NORMAL;
938
939     // convert to dali memmory status
940     switch(status)
941     {
942       case 1:
943       {
944         result = Dali::DeviceStatus::Memory::NORMAL;
945         break;
946       }
947       case 2:
948       {
949         result = Dali::DeviceStatus::Memory::LOW;
950         break;
951       }
952       case 4:
953       {
954         result = Dali::DeviceStatus::Memory::CRITICALLY_LOW;
955         break;
956       }
957       default:
958         break;
959     }
960     observer->OnMemoryLow(result);
961   }
962
963   int AppNormalMain()
964   {
965     if(mUiAppContext.get() == nullptr)
966     {
967       unsigned int hint = AppCoreUiBase::HINT_WINDOW_GROUP_CONTROL |
968                           AppCoreUiBase::HINT_WINDOW_STACK_CONTROL |
969                           AppCoreUiBase::HINT_BG_LAUNCH_CONTROL |
970                           AppCoreUiBase::HINT_HW_ACC_CONTROL |
971                           AppCoreUiBase::HINT_WINDOW_AUTO_CONTROL;
972
973       // For testing UIThread model, This code turns on the UI Thread feature forcibly.
974       //  ex) app_launcher -e [APPID] __K_UI_THREAD enable
975       // This code doesn't change mUseUiThread in Internal::Application
976       bundle* b = bundle_import_from_argv(*mFramework->mArgc, *mFramework->mArgv);
977       if(b != nullptr)
978       {
979         const char* val = bundle_get_val(b, "__K_UI_THREAD");
980         if(val != nullptr && strcmp(val, "enable") == 0)
981         {
982           mUseUiThread = true;
983         }
984
985         bundle_free(b);
986       }
987
988       if(mUseUiThread)
989       {
990         hint |= AppCoreUiBase::HINT_DUAL_THREAD;
991       }
992
993       mUiAppContext = std::make_unique<UiAppContext>(hint, mFramework);
994     }
995
996     mUiAppContext->Run(*mFramework->mArgc, *mFramework->mArgv);
997     return TIZEN_ERROR_NONE;
998   }
999
1000   void AppNormalExit()
1001   {
1002     if(mUiAppContext.get() == nullptr)
1003     {
1004       return;
1005     }
1006
1007     mUiAppContext->Exit();
1008   }
1009
1010   void AppWidgetExit()
1011   {
1012     widget_base_exit();
1013   }
1014
1015   static int WidgetAppCreate(void* data)
1016   {
1017     widget_base_on_create();
1018     return static_cast<int>(static_cast<Framework*>(data)->Create());
1019   }
1020
1021   static int WidgetAppTerminate(void* data)
1022   {
1023     Observer* observer = &static_cast<Framework*>(data)->mObserver;
1024     observer->OnTerminate();
1025
1026     widget_base_on_terminate();
1027     return 0;
1028   }
1029
1030   int AppWidgetMain()
1031   {
1032     if(!IsWidgetFeatureEnabled())
1033     {
1034       DALI_LOG_ERROR("widget feature is not supported");
1035       return 0;
1036     }
1037
1038     AppCore::AppAddEventHandler(&handlers[AppCore::LOW_BATTERY], AppCore::LOW_BATTERY, AppBatteryLow, mFramework);
1039     AppCore::AppAddEventHandler(&handlers[AppCore::LOW_MEMORY], AppCore::LOW_MEMORY, AppMemoryLow, mFramework);
1040     AppCore::AppAddEventHandler(&handlers[AppCore::DEVICE_ORIENTATION_CHANGED], AppCore::DEVICE_ORIENTATION_CHANGED, AppDeviceRotated, mFramework);
1041     AppCore::AppAddEventHandler(&handlers[AppCore::LANGUAGE_CHANGED], AppCore::LANGUAGE_CHANGED, AppLanguageChanged, mFramework);
1042     AppCore::AppAddEventHandler(&handlers[AppCore::REGION_FORMAT_CHANGED], AppCore::REGION_FORMAT_CHANGED, AppRegionChanged, mFramework);
1043
1044     widget_base_ops ops = widget_base_get_default_ops();
1045
1046     /* override methods */
1047     ops.create    = WidgetAppCreate;
1048     ops.terminate = WidgetAppTerminate;
1049     ops.init      = AppInit;
1050     ops.finish    = AppFinish;
1051     ops.run       = AppRun;
1052     ops.exit      = AppExit;
1053
1054     int result = widget_base_init(ops, *mFramework->mArgc, *mFramework->mArgv, mFramework);
1055
1056     widget_base_fini();
1057
1058     return result;
1059   }
1060
1061 #ifdef APPCORE_WATCH_AVAILABLE
1062   static bool WatchAppCreate(int width, int height, void* data)
1063   {
1064     return static_cast<Framework*>(data)->Create();
1065   }
1066
1067   static void WatchAppTimeTick(watch_time_h time, void* data)
1068   {
1069     Observer* observer = &static_cast<Framework*>(data)->mObserver;
1070     WatchTime curTime(time);
1071
1072     observer->OnTimeTick(curTime);
1073   }
1074
1075   static void WatchAppAmbientTick(watch_time_h time, void* data)
1076   {
1077     Observer* observer = &static_cast<Framework*>(data)->mObserver;
1078     WatchTime curTime(time);
1079
1080     observer->OnAmbientTick(curTime);
1081   }
1082
1083   static void WatchAppAmbientChanged(bool ambient, void* data)
1084   {
1085     Observer* observer = &static_cast<Framework*>(data)->mObserver;
1086
1087     observer->OnAmbientChanged(ambient);
1088   }
1089
1090   static void WatchAppControl(app_control_h app_control, void* data)
1091   {
1092     Framework* framework  = static_cast<Framework*>(data);
1093     Observer*  observer   = &framework->mObserver;
1094     bundle*    bundleData = NULL;
1095
1096     app_control_to_bundle(app_control, &bundleData);
1097     ProcessBundle(framework, bundleData);
1098
1099     observer->OnReset();
1100     observer->OnAppControl(app_control);
1101   }
1102
1103   static void WatchAppTerminate(void* data)
1104   {
1105     Observer* observer = &static_cast<Framework*>(data)->mObserver;
1106
1107     observer->OnTerminate();
1108   }
1109
1110   static void WatchAppPause(void* data)
1111   {
1112     Observer* observer = &static_cast<Framework*>(data)->mObserver;
1113
1114     observer->OnPause();
1115   }
1116
1117   static void WatchAppResume(void* data)
1118   {
1119     Observer* observer = &static_cast<Framework*>(data)->mObserver;
1120
1121     observer->OnResume();
1122   }
1123
1124 #endif
1125
1126   int AppWatchMain()
1127   {
1128     int ret = true;
1129
1130 #ifdef APPCORE_WATCH_AVAILABLE
1131     mWatchCallback.create          = WatchAppCreate;
1132     mWatchCallback.app_control     = WatchAppControl;
1133     mWatchCallback.terminate       = WatchAppTerminate;
1134     mWatchCallback.pause           = WatchAppPause;
1135     mWatchCallback.resume          = WatchAppResume;
1136     mWatchCallback.time_tick       = WatchAppTimeTick;
1137     mWatchCallback.ambient_tick    = WatchAppAmbientTick;
1138     mWatchCallback.ambient_changed = WatchAppAmbientChanged;
1139
1140     AppCore::AppAddEventHandler(&handlers[AppCore::LOW_BATTERY], AppCore::LOW_BATTERY, AppBatteryLow, mFramework);
1141     AppCore::AppAddEventHandler(&handlers[AppCore::LOW_MEMORY], AppCore::LOW_MEMORY, AppMemoryLow, mFramework);
1142     AppCore::AppAddEventHandler(&handlers[AppCore::LANGUAGE_CHANGED], AppCore::LANGUAGE_CHANGED, AppLanguageChanged, mFramework);
1143     AppCore::AppAddEventHandler(&handlers[AppCore::REGION_FORMAT_CHANGED], AppCore::REGION_FORMAT_CHANGED, AppRegionChanged, mFramework);
1144
1145     ret = watch_app_main(*mFramework->mArgc, *mFramework->mArgv, &mWatchCallback, mFramework);
1146 #endif
1147     return ret;
1148   }
1149
1150   void AppWatchExit()
1151   {
1152 #ifdef APPCORE_WATCH_AVAILABLE
1153     watch_app_exit();
1154 #endif
1155   }
1156
1157 #ifdef COMPONENT_APPLICATION_SUPPORT
1158   int AppComponentMain()
1159   {
1160     /*Crate component_based_app_base_lifecycle_callback*/
1161     component_based_app_base_lifecycle_callback_s callback;
1162     callback.init      = AppInit;
1163     callback.run       = AppRun;
1164     callback.exit      = AppExit;
1165     callback.create    = ComponentAppCreate;
1166     callback.terminate = ComponentAppTerminate;
1167     callback.fini      = ComponentAppFinish;
1168
1169     return component_based_app_base_main(*mFramework->mArgc, *mFramework->mArgv, &callback, mFramework);
1170   }
1171
1172   static void* ComponentAppCreate(void* data)
1173   {
1174     Framework* framework = static_cast<Framework*>(data);
1175     Observer*  observer  = &framework->mObserver;
1176     observer->OnInit();
1177
1178     return Dali::AnyCast<void*>(observer->OnCreate());
1179   }
1180
1181   static void ComponentAppTerminate(void* data)
1182   {
1183     Observer* observer = &static_cast<Framework*>(data)->mObserver;
1184     observer->OnTerminate();
1185   }
1186
1187   static void ComponentAppFinish(void* data)
1188   {
1189     ecore_shutdown();
1190
1191     if(getenv("AUL_LOADER_INIT"))
1192     {
1193       setenv("AUL_LOADER_INIT", "0", 1);
1194       ecore_shutdown();
1195     }
1196   }
1197
1198   void AppComponentExit()
1199   {
1200     component_based_app_base_exit();
1201   }
1202
1203 #endif
1204
1205 private:
1206   // Undefined
1207   Impl(const Impl& impl);
1208
1209   // Undefined
1210   Impl& operator=(const Impl& impl);
1211 };
1212
1213 Framework::Framework(Framework::Observer& observer, Framework::TaskObserver& taskObserver, int* argc, char*** argv, Type type, bool useUiThread)
1214 : mObserver(observer),
1215   mTaskObserver(taskObserver),
1216   mInitialised(false),
1217   mPaused(false),
1218   mRunning(false),
1219   mArgc(argc),
1220   mArgv(argv),
1221   mBundleName(""),
1222   mBundleId(""),
1223   mAbortHandler(MakeCallback(this, &Framework::AbortCallback)),
1224   mImpl(NULL)
1225 {
1226   if(mArgc == nullptr || mArgv == nullptr)
1227   {
1228     mArgc = const_cast<int*>(&gTizenDummyArgc);
1229     mArgv = const_cast<char***>(reinterpret_cast<const char***>(&gTizenDummyArgv));
1230   }
1231
1232   bool featureFlag = true;
1233   system_info_get_platform_bool("tizen.org/feature/opengles.version.2_0", &featureFlag);
1234
1235   if(featureFlag == false)
1236   {
1237     set_last_result(TIZEN_ERROR_NOT_SUPPORTED);
1238   }
1239
1240   InitThreads();
1241
1242   mImpl = new Impl(this, type, useUiThread);
1243 }
1244
1245 Framework::~Framework()
1246 {
1247   if(mRunning)
1248   {
1249     Quit();
1250   }
1251
1252   delete mImpl;
1253 }
1254
1255 bool Framework::Create()
1256 {
1257   mInitialised = true;
1258   mObserver.OnInit();
1259   return true;
1260 }
1261
1262 void Framework::Run()
1263 {
1264   mRunning = true;
1265   int ret;
1266
1267   DALI_TRACE_BEGIN(gTraceFilter, "DALI_APPMAIN");
1268   ret = mImpl->AppMain();
1269   DALI_TRACE_END(gTraceFilter, "DALI_APPMAIN");
1270   if(ret != APP_ERROR_NONE)
1271   {
1272     DALI_LOG_ERROR("Framework::Run(), ui_app_main() is failed. err = %d\n", ret);
1273   }
1274   mRunning = false;
1275 }
1276
1277 void Framework::Quit()
1278 {
1279   mImpl->AppExit();
1280 }
1281
1282 bool Framework::IsMainLoopRunning()
1283 {
1284   return mRunning;
1285 }
1286
1287 void Framework::AddAbortCallback(CallbackBase* callback)
1288 {
1289   mImpl->mAbortCallBack = callback;
1290 }
1291
1292 std::string Framework::GetBundleName() const
1293 {
1294   return mBundleName;
1295 }
1296
1297 void Framework::SetBundleName(const std::string& name)
1298 {
1299   mBundleName = name;
1300 }
1301
1302 std::string Framework::GetBundleId() const
1303 {
1304   return mBundleId;
1305 }
1306
1307 std::string Framework::GetResourcePath()
1308 {
1309   std::string resourcePath = "";
1310 #if defined(TIZEN_PLATFORM_CONFIG_SUPPORTED) && TIZEN_PLATFORM_CONFIG_SUPPORTED
1311   char* app_rsc_path = app_get_resource_path();
1312   if(app_rsc_path)
1313   {
1314     resourcePath = app_rsc_path;
1315     free(app_rsc_path);
1316   }
1317 #else // For backwards compatibility with older Tizen versions
1318
1319   // "DALI_APPLICATION_PACKAGE" is used to get the already configured Application package path.
1320   const char* environmentVariable = "DALI_APPLICATION_PACKAGE";
1321   char*       value               = getenv(environmentVariable);
1322   if(value != NULL)
1323   {
1324     resourcePath = value;
1325   }
1326
1327   if(resourcePath.back() != '/')
1328   {
1329     resourcePath += "/";
1330   }
1331
1332 #endif // TIZEN_PLATFORM_CONFIG_SUPPORTED
1333
1334   return resourcePath;
1335 }
1336
1337 std::string Framework::GetDataPath()
1338 {
1339   std::string result;
1340   char*       dataPath = app_get_data_path();
1341   if(dataPath)
1342   {
1343     result = dataPath;
1344     free(dataPath);
1345   }
1346   return result;
1347 }
1348
1349 void Framework::SetBundleId(const std::string& id)
1350 {
1351   mBundleId = id;
1352 }
1353
1354 void Framework::AbortCallback()
1355 {
1356   // if an abort call back has been installed run it.
1357   if(mImpl->mAbortCallBack)
1358   {
1359     CallbackBase::Execute(*mImpl->mAbortCallBack);
1360   }
1361   else
1362   {
1363     Quit();
1364   }
1365 }
1366
1367 void Framework::InitThreads()
1368 {
1369 }
1370
1371 void Framework::SetLanguage(const std::string& language)
1372 {
1373   mImpl->SetLanguage(language);
1374 }
1375
1376 void Framework::SetRegion(const std::string& region)
1377 {
1378   mImpl->SetRegion(region);
1379 }
1380
1381 std::string Framework::GetLanguage() const
1382 {
1383   return mImpl->GetLanguage();
1384 }
1385
1386 std::string Framework::GetRegion() const
1387 {
1388   return mImpl->GetRegion();
1389 }
1390
1391 } // namespace Adaptor
1392
1393 } // namespace Internal
1394
1395 } // namespace Dali