2 * Copyright (c) 2020 Samsung Electronics Co., Ltd.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
20 #include <sys/types.h>
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>
31 // from android_native_app_glue.c
33 #define TAG "dalidemo"
34 #define LOGE(...) ((void)__android_log_print(ANDROID_LOG_ERROR, TAG, ##__VA_ARGS__))
36 #define LOGV(...) ((void)__android_log_print(ANDROID_LOG_VERBOSE, TAG, ##__VA_ARGS__))
38 #define LOGV(...) ((void)0)
43 void free_saved_state(struct android_app* android_app)
45 LOGV("free_saved_state");
46 pthread_mutex_lock(&android_app->mutex);
48 if(android_app->savedState != NULL)
50 free(android_app->savedState);
51 android_app->savedState = NULL;
52 android_app->savedStateSize = 0;
55 pthread_mutex_unlock(&android_app->mutex);
58 void android_app_destroy(struct android_app* android_app)
60 LOGV("android_app_destroy");
61 free_saved_state(android_app);
62 pthread_mutex_lock(&android_app->mutex);
64 if(android_app->inputQueue != NULL)
66 AInputQueue_detachLooper(android_app->inputQueue);
69 AConfiguration_delete(android_app->config);
70 android_app->destroyed = 1;
72 pthread_cond_broadcast(&android_app->cond);
73 pthread_mutex_unlock(&android_app->mutex);
75 // Can't touch android_app object after this.
80 void ExtractAsset(struct android_app* state, const std::string& assetPath, const std::string& filePath)
82 AAsset* asset = AAssetManager_open(state->activity->assetManager, assetPath.c_str(), AASSET_MODE_BUFFER);
85 size_t length = AAsset_getLength(asset) + 1;
87 char* buffer = new char[length];
88 length = AAsset_read(asset, buffer, length);
90 FILE* file = fopen(filePath.c_str(), "wb");
93 fwrite(buffer, 1, length, file);
102 void ExtractAssets(struct android_app* state, const std::string& assetDirPath, const std::string& filesDirPath)
104 AAssetDir* assetDir = AAssetManager_openDir(state->activity->assetManager, assetDirPath.c_str());
107 if(mkdir(filesDirPath.c_str(), S_IRWXU) != -1)
109 const char* filename = NULL;
110 std::string assetPath = assetDirPath + "/";
111 while((filename = AAssetDir_getNextFileName(assetDir)) != NULL)
113 ExtractAsset(state, assetPath + filename, filesDirPath + "/" + filename);
117 AAssetDir_close(assetDir);
121 void ExtractFontConfig(struct android_app* state, std::string assetFontConfig, std::string fontsPath)
123 AAsset* asset = AAssetManager_open(state->activity->assetManager, assetFontConfig.c_str(), AASSET_MODE_BUFFER);
126 size_t length = AAsset_getLength(asset) + 1;
128 char* buffer = new char[length];
129 length = AAsset_read(asset, buffer, length);
131 std::string fontConfig = std::string(buffer, length);
132 int i = fontConfig.find("~");
133 if(i != std::string::npos)
135 std::string filesDir = state->activity->internalDataPath;
136 fontConfig.replace(i, 1, filesDir);
139 std::string fontsFontConfig = fontsPath;
140 FILE* file = fopen(fontsFontConfig.c_str(), "wb");
143 fwrite(fontConfig.c_str(), 1, fontConfig.size(), file);
152 extern "C" void FcConfigPathInit(const char* path, const char* file);
154 void android_main(struct android_app* state)
156 LOGV("android_main() >>");
158 std::string filesDir = state->activity->internalDataPath;
159 LOGV("filesDir=%s", filesDir.c_str() );
161 std::string fontconfigPath = filesDir + "/fonts";
162 setenv("FONTCONFIG_PATH", fontconfigPath.c_str(), 1);
164 std::string fontconfigFile = fontconfigPath + "/fonts.conf";
165 setenv("FONTCONFIG_FILE", fontconfigFile.c_str(), 1);
167 struct stat st = {0};
168 FcConfigPathInit(fontconfigPath.c_str(), fontconfigFile.c_str());
170 if(stat(fontconfigPath.c_str(), &st) == -1)
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");
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);
187 DaliDemoNativeActivity nativeActivity(state->activity);
191 //dali requires Android 8 or higher
192 //Android 6+ support loading library directly from apk,
193 //therefore no need to extract to filesystem first then open by specifying full path
194 //unless there is need to do profiling, or export libraries so that other packages can use
195 std::string libpath = "libdali-demo.so";
197 std::string callParam = nativeActivity.GetIntentStringExtra("start");
198 if(callParam.empty())
200 callParam = nativeActivity.GetMetaData("start");
203 if(!callParam.empty())
205 libpath = "lib" + callParam + ".so";
208 void* handle = dlopen(libpath.c_str(), RTLD_LAZY);
212 LOGE("Err=%d Fail to open lib %s", err, libpath.c_str());
217 dlerror(); /* Clear any existing error */
219 int (*main)(int, char**) = (int (*)(int, char**))dlsym(handle, "main");
220 LOGV("lib=%s handle=%p main=%p", libpath.c_str(), handle, main );
223 status = main(0, nullptr);
227 LOGE("lib %s doesn't have main()", libpath.c_str());
238 android_app_destroy(state);
240 Dali::Integration::AndroidFramework::Get().SetNativeApplication(nullptr);
241 Dali::Integration::AndroidFramework::Get().SetApplicationConfiguration(nullptr);
242 Dali::Integration::AndroidFramework::Get().SetApplicationAssets(nullptr);
243 Dali::Integration::AndroidFramework::Delete();
245 LOGV("android_main() <<");
247 // We need to kill the application process manually, DALi cannot exit the process properly due to memory leaks