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