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.
19 #include <sys/types.h>
23 #include <android/log.h>
24 #include <android_native_app_glue.h>
25 #include <dali/devel-api/adaptor-framework/application-devel.h>
26 #include <dali/integration-api/debug.h>
27 #include <dali/integration-api/adaptor-framework/android/android-framework.h>
30 // from android_native_app_glue.c
32 #define LOGV(...) ((void)__android_log_print(ANDROID_LOG_VERBOSE, "dalidemo", __VA_ARGS__))
34 #define LOGV(...) ((void)0)
40 void free_saved_state(struct android_app *android_app)
42 pthread_mutex_lock(&android_app->mutex);
44 if (android_app->savedState != NULL)
46 free(android_app->savedState);
47 android_app->savedState = NULL;
48 android_app->savedStateSize = 0;
51 pthread_mutex_unlock(&android_app->mutex);
54 void android_app_destroy(struct android_app *android_app)
56 LOGV("android_app_destroy");
57 free_saved_state(android_app);
58 pthread_mutex_lock(&android_app->mutex);
60 if (android_app->inputQueue != NULL)
62 AInputQueue_detachLooper(android_app->inputQueue);
65 AConfiguration_delete(android_app->config);
66 android_app->destroyed = 1;
68 pthread_cond_broadcast(&android_app->cond);
69 pthread_mutex_unlock(&android_app->mutex);
71 // Can't touch android_app object after this.
76 void ExtractAsset(struct android_app* state, const std::string& assetPath, const std::string& filePath)
78 AAsset* asset = AAssetManager_open(state->activity->assetManager, assetPath.c_str(), AASSET_MODE_BUFFER);
81 size_t length = AAsset_getLength(asset) + 1;
83 char* buffer = new char[length];
84 length = AAsset_read(asset, buffer, length);
86 FILE* file = fopen(filePath.c_str(), "wb");
89 fwrite(buffer, 1, length, file);
98 void ExtractAssets(struct android_app* state, const std::string& assetDirPath, const std::string& filesDirPath)
100 AAssetDir* assetDir = AAssetManager_openDir(state->activity->assetManager, assetDirPath.c_str());
103 if (mkdir(filesDirPath.c_str(), S_IRWXU) != -1)
105 const char *filename = NULL;
106 std::string assetPath = assetDirPath + "/";
107 while ((filename = AAssetDir_getNextFileName(assetDir)) != NULL)
109 ExtractAsset(state, assetPath + filename, filesDirPath + "/" + filename);
113 AAssetDir_close(assetDir);
117 void ExtractFontConfig(struct android_app* state, std::string assetFontConfig, std::string fontsPath)
119 AAsset* asset = AAssetManager_open(state->activity->assetManager, assetFontConfig.c_str(), AASSET_MODE_BUFFER);
122 size_t length = AAsset_getLength(asset) + 1;
124 char* buffer = new char[length];
125 length = AAsset_read(asset, buffer, length);
127 std::string fontConfig = std::string(buffer, length);
128 int i = fontConfig.find("~");
129 if (i != std::string::npos)
131 std::string filesDir = state->activity->internalDataPath;
132 fontConfig.replace(i, 1, filesDir);
135 std::string fontsFontConfig = fontsPath;
136 FILE* file = fopen(fontsFontConfig.c_str(), "wb");
139 fwrite(fontConfig.c_str(), 1, fontConfig.size(), file);
148 class DaliDemoNativeActivity
151 ANativeActivity* activity;
152 DaliDemoNativeActivity(ANativeActivity* activity)
157 class NativeActivityJNI
160 ANativeActivity* activity;
164 NativeActivityJNI(ANativeActivity* activity)
167 activity->vm->AttachCurrentThread(&env, NULL);
168 clazz = env->GetObjectClass(activity->clazz);
173 activity->vm->DetachCurrentThread();
176 jstring toJString(const std::string& str)
178 return env->NewStringUTF(str.c_str());
181 std::string toString(jstring jstr)
186 const char* utf = env->GetStringUTFChars(jstr, 0);
187 out = std::string(utf);
188 env->ReleaseStringUTFChars(jstr, utf);
194 std::string callStringMethod(const std::string& name, const std::string& arg)
196 jmethodID methodID = env->GetMethodID(clazz, name.c_str(), "(Ljava/lang/String;)Ljava/lang/String;");
197 jstring jstr = (jstring)env->CallObjectMethod(activity->clazz, methodID, toJString(arg));
198 return toString(jstr);
202 std::string getMetaData(const std::string& key)
204 NativeActivityJNI nativeActivityJNI(activity);
205 return nativeActivityJNI.callStringMethod("getMetaData", key);
208 std::string getIntentStringExtra(const std::string& key)
210 NativeActivityJNI nativeActivityJNI(activity);
211 return nativeActivityJNI.callStringMethod("getIntentStringExtra", key);
215 extern "C" void FcConfigPathInit(const char* path, const char* file);
217 void android_main( struct android_app* state )
219 std::string filesDir = state->activity->internalDataPath;
221 std::string fontconfigPath = filesDir + "/fonts";
222 setenv("FONTCONFIG_PATH", fontconfigPath.c_str(), 1);
224 std::string fontconfigFile = fontconfigPath + "/fonts.conf";
225 setenv("FONTCONFIG_FILE", fontconfigFile.c_str(), 1);
227 struct stat st = { 0 };
228 FcConfigPathInit( fontconfigPath.c_str(), fontconfigFile.c_str() );
230 if (stat(fontconfigPath.c_str(), &st) == -1)
232 mkdir(fontconfigPath.c_str(), S_IRWXU);
233 ExtractFontConfig(state, "fonts/fonts.conf", fontconfigPath + "/fonts.conf");
234 ExtractFontConfig(state, "fonts/fonts.dtd", fontconfigPath + "/fonts.dtd" );
235 ExtractFontConfig(state, "fonts/local.conf", fontconfigPath + "/local.conf");
236 ExtractAssets(state, "fonts/dejavu", fontconfigPath + "/dejavu");
237 ExtractAssets(state, "fonts/tizen", fontconfigPath + "/tizen");
238 ExtractAssets(state, "fonts/bitmap", fontconfigPath + "/bitmap");
241 Dali::Integration::AndroidFramework::New();
242 Dali::Integration::AndroidFramework::Get().SetNativeApplication( state );
243 Dali::Integration::AndroidFramework::Get().SetApplicationConfiguration( state->config );
244 Dali::Integration::AndroidFramework::Get().SetApplicationAssets( state->activity->assetManager );
245 Dali::Integration::AndroidFramework::Get().SetInternalDataPath( filesDir );
247 DaliDemoNativeActivity nativeActivity(state->activity);
250 std::string libpath = "/data/data/com.sec.dalidemo/lib/libdali-demo.so";
251 std::string callParam = nativeActivity.getIntentStringExtra("start");
252 if (callParam.empty())
254 callParam = nativeActivity.getMetaData("start");
257 if (!callParam.empty())
259 libpath = "/data/data/com.sec.dalidemo/lib/lib" + callParam + ".so";
262 void* handle = dlopen( libpath.c_str(), RTLD_LAZY );
268 dlerror(); /* Clear any existing error */
270 int (*main)(int, char**) = (int(*)(int, char**))dlsym(handle, "main");
273 status = main( 0, nullptr );
282 android_app_destroy(state);
284 Dali::Integration::AndroidFramework::Get().SetNativeApplication(nullptr);
285 Dali::Integration::AndroidFramework::Get().SetApplicationConfiguration(nullptr);
286 Dali::Integration::AndroidFramework::Get().SetApplicationAssets(nullptr);
287 Dali::Integration::AndroidFramework::Delete();
289 // We need to kill the application process manually, DALi cannot restart in the same process due to memory leaks