Add ERROR message in the case of serious error
[platform/core/uifw/dali-demo.git] / build / android / app / src / main / cpp / main.cpp
1 /*
2  * Copyright (c) 2020 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 // EXTERNAL INCLUDES
19 #include <sys/stat.h>
20 #include <sys/types.h>
21 #include <unistd.h>
22
23 #include <android/log.h>
24 #include <android_native_app_glue.h>
25 #include <dali-demo-native-activity-jni.h>
26 #include <dali/devel-api/adaptor-framework/application-devel.h>
27 #include <dali/integration-api/adaptor-framework/android/android-framework.h>
28 #include <dali/integration-api/debug.h>
29 #include <dlfcn.h>
30
31 // from android_native_app_glue.c
32
33 #define TAG "dalidemo"
34 #define LOGE(...) ((void)__android_log_print(ANDROID_LOG_ERROR,   TAG, ##__VA_ARGS__))
35 #ifndef NDEBUG
36 #define LOGV(...) ((void)__android_log_print(ANDROID_LOG_VERBOSE, TAG, ##__VA_ARGS__))
37 #else
38 #define LOGV(...) ((void)0)
39 #endif
40
41 namespace
42 {
43 void free_saved_state(struct android_app* android_app)
44 {
45   LOGV("free_saved_state");
46   pthread_mutex_lock(&android_app->mutex);
47
48   if(android_app->savedState != NULL)
49   {
50     free(android_app->savedState);
51     android_app->savedState     = NULL;
52     android_app->savedStateSize = 0;
53   }
54
55   pthread_mutex_unlock(&android_app->mutex);
56 }
57
58 void android_app_destroy(struct android_app* android_app)
59 {
60   LOGV("android_app_destroy");
61   free_saved_state(android_app);
62   pthread_mutex_lock(&android_app->mutex);
63
64   if(android_app->inputQueue != NULL)
65   {
66     AInputQueue_detachLooper(android_app->inputQueue);
67   }
68
69   AConfiguration_delete(android_app->config);
70   android_app->destroyed = 1;
71
72   pthread_cond_broadcast(&android_app->cond);
73   pthread_mutex_unlock(&android_app->mutex);
74
75   // Can't touch android_app object after this.
76 }
77
78 } // namespace
79
80 void ExtractAsset(struct android_app* state, const std::string& assetPath, const std::string& filePath)
81 {
82   AAsset* asset = AAssetManager_open(state->activity->assetManager, assetPath.c_str(), AASSET_MODE_BUFFER);
83   if(asset)
84   {
85     size_t length = AAsset_getLength(asset) + 1;
86
87     char* buffer = new char[length];
88     length       = AAsset_read(asset, buffer, length);
89
90     FILE* file = fopen(filePath.c_str(), "wb");
91     if(file)
92     {
93       fwrite(buffer, 1, length, file);
94       fclose(file);
95     }
96
97     delete[] buffer;
98     AAsset_close(asset);
99   }
100 }
101
102 void ExtractAssets(struct android_app* state, const std::string& assetDirPath, const std::string& filesDirPath)
103 {
104   AAssetDir* assetDir = AAssetManager_openDir(state->activity->assetManager, assetDirPath.c_str());
105   if(assetDir)
106   {
107     if(mkdir(filesDirPath.c_str(), S_IRWXU) != -1)
108     {
109       const char* filename  = NULL;
110       std::string assetPath = assetDirPath + "/";
111       while((filename = AAssetDir_getNextFileName(assetDir)) != NULL)
112       {
113         ExtractAsset(state, assetPath + filename, filesDirPath + "/" + filename);
114       }
115     }
116
117     AAssetDir_close(assetDir);
118   }
119 }
120
121 void ExtractFontConfig(struct android_app* state, std::string assetFontConfig, std::string fontsPath)
122 {
123   AAsset* asset = AAssetManager_open(state->activity->assetManager, assetFontConfig.c_str(), AASSET_MODE_BUFFER);
124   if(asset)
125   {
126     size_t length = AAsset_getLength(asset) + 1;
127
128     char* buffer = new char[length];
129     length       = AAsset_read(asset, buffer, length);
130
131     std::string fontConfig = std::string(buffer, length);
132     int         i          = fontConfig.find("~");
133     if(i != std::string::npos)
134     {
135       std::string filesDir = state->activity->internalDataPath;
136       fontConfig.replace(i, 1, filesDir);
137     }
138
139     std::string fontsFontConfig = fontsPath;
140     FILE*       file            = fopen(fontsFontConfig.c_str(), "wb");
141     if(file)
142     {
143       fwrite(fontConfig.c_str(), 1, fontConfig.size(), file);
144       fclose(file);
145     }
146
147     delete[] buffer;
148     AAsset_close(asset);
149   }
150 }
151
152 extern "C" void FcConfigPathInit(const char* path, const char* file);
153
154 void android_main(struct android_app* state)
155 {
156   LOGV("android_main() >>");
157
158   std::string filesDir = state->activity->internalDataPath;
159   LOGV("filesDir=%s", filesDir.c_str() );
160
161   std::string fontconfigPath = filesDir + "/fonts";
162   setenv("FONTCONFIG_PATH", fontconfigPath.c_str(), 1);
163
164   std::string fontconfigFile = fontconfigPath + "/fonts.conf";
165   setenv("FONTCONFIG_FILE", fontconfigFile.c_str(), 1);
166
167   struct stat st = {0};
168   FcConfigPathInit(fontconfigPath.c_str(), fontconfigFile.c_str());
169
170   if(stat(fontconfigPath.c_str(), &st) == -1)
171   {
172     mkdir(fontconfigPath.c_str(), S_IRWXU);
173     ExtractFontConfig(state, "fonts/fonts.conf", fontconfigPath + "/fonts.conf");
174     ExtractFontConfig(state, "fonts/fonts.dtd", fontconfigPath + "/fonts.dtd");
175     ExtractFontConfig(state, "fonts/local.conf", fontconfigPath + "/local.conf");
176     ExtractAssets(state, "fonts/dejavu", fontconfigPath + "/dejavu");
177     ExtractAssets(state, "fonts/tizen", fontconfigPath + "/tizen");
178     ExtractAssets(state, "fonts/bitmap", fontconfigPath + "/bitmap");
179   }
180
181   Dali::Integration::AndroidFramework::New();
182   Dali::Integration::AndroidFramework::Get().SetNativeApplication(state);
183   Dali::Integration::AndroidFramework::Get().SetApplicationConfiguration(state->config);
184   Dali::Integration::AndroidFramework::Get().SetApplicationAssets(state->activity->assetManager);
185   Dali::Integration::AndroidFramework::Get().SetInternalDataPath(filesDir);
186
187   DaliDemoNativeActivity nativeActivity(state->activity);
188
189   int         status    = 0;
190   std::string libpath   = "/data/data/com.sec.dalidemo/lib/libdali-demo.so";
191   std::string callParam = nativeActivity.GetIntentStringExtra("start");
192   if(callParam.empty())
193   {
194     callParam = nativeActivity.GetMetaData("start");
195   }
196
197   if(!callParam.empty())
198   {
199     libpath = "/data/data/com.sec.dalidemo/lib/lib" + callParam + ".so";
200   }
201
202   void* handle = dlopen(libpath.c_str(), RTLD_LAZY);
203   if(!handle)
204   {
205     int err = errno;
206     LOGE("Err=%d Fail to open lib %s", err, libpath.c_str());
207     status = err;
208     std::exit(status);
209   }
210
211   dlerror(); /* Clear any existing error */
212
213   int (*main)(int, char**) = (int (*)(int, char**))dlsym(handle, "main");
214   if(main)
215   {
216     status = main(0, nullptr);
217   }
218
219   if(handle)
220   {
221     dlclose(handle);
222     handle = nullptr;
223   }
224
225   android_app_destroy(state);
226
227   Dali::Integration::AndroidFramework::Get().SetNativeApplication(nullptr);
228   Dali::Integration::AndroidFramework::Get().SetApplicationConfiguration(nullptr);
229   Dali::Integration::AndroidFramework::Get().SetApplicationAssets(nullptr);
230   Dali::Integration::AndroidFramework::Delete();
231
232   LOGV("android_main() <<");
233
234   // We need to kill the application process manually, DALi cannot exit the process properly due to memory leaks
235   std::exit(status);
236 }
237
238 //END_INCLUDE(all)