/* * Copyright (c) 2020 Samsung Electronics Co., Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ // EXTERNAL INCLUDES #include #include #include #include #include #include #include #include #include // from android_native_app_glue.c #ifndef NDEBUG #define LOGV(...) ((void)__android_log_print(ANDROID_LOG_VERBOSE, "dalidemo", __VA_ARGS__)) #else #define LOGV(...) ((void)0) #endif namespace { void free_saved_state(struct android_app *android_app) { pthread_mutex_lock(&android_app->mutex); if (android_app->savedState != NULL) { free(android_app->savedState); android_app->savedState = NULL; android_app->savedStateSize = 0; } pthread_mutex_unlock(&android_app->mutex); } void android_app_destroy(struct android_app *android_app) { LOGV("android_app_destroy"); free_saved_state(android_app); pthread_mutex_lock(&android_app->mutex); if (android_app->inputQueue != NULL) { AInputQueue_detachLooper(android_app->inputQueue); } AConfiguration_delete(android_app->config); android_app->destroyed = 1; pthread_cond_broadcast(&android_app->cond); pthread_mutex_unlock(&android_app->mutex); // Can't touch android_app object after this. } } void ExtractAsset(struct android_app* state, const std::string& assetPath, const std::string& filePath) { AAsset* asset = AAssetManager_open(state->activity->assetManager, assetPath.c_str(), AASSET_MODE_BUFFER); if (asset) { size_t length = AAsset_getLength(asset) + 1; char* buffer = new char[length]; length = AAsset_read(asset, buffer, length); FILE* file = fopen(filePath.c_str(), "wb"); if (file) { fwrite(buffer, 1, length, file); fclose(file); } delete[] buffer; AAsset_close(asset); } } void ExtractAssets(struct android_app* state, const std::string& assetDirPath, const std::string& filesDirPath) { AAssetDir* assetDir = AAssetManager_openDir(state->activity->assetManager, assetDirPath.c_str()); if (assetDir) { if (mkdir(filesDirPath.c_str(), S_IRWXU) != -1) { const char *filename = NULL; std::string assetPath = assetDirPath + "/"; while ((filename = AAssetDir_getNextFileName(assetDir)) != NULL) { ExtractAsset(state, assetPath + filename, filesDirPath + "/" + filename); } } AAssetDir_close(assetDir); } } void ExtractFontConfig(struct android_app* state, std::string assetFontConfig, std::string fontsPath) { AAsset* asset = AAssetManager_open(state->activity->assetManager, assetFontConfig.c_str(), AASSET_MODE_BUFFER); if (asset) { size_t length = AAsset_getLength(asset) + 1; char* buffer = new char[length]; length = AAsset_read(asset, buffer, length); std::string fontConfig = std::string(buffer, length); int i = fontConfig.find("~"); if (i != std::string::npos) { std::string filesDir = state->activity->internalDataPath; fontConfig.replace(i, 1, filesDir); } std::string fontsFontConfig = fontsPath; FILE* file = fopen(fontsFontConfig.c_str(), "wb"); if (file) { fwrite(fontConfig.c_str(), 1, fontConfig.size(), file); fclose(file); } delete[] buffer; AAsset_close(asset); } } class DaliDemoNativeActivity { public: ANativeActivity* activity; DaliDemoNativeActivity(ANativeActivity* activity) : activity(activity) { } class NativeActivityJNI { public: ANativeActivity* activity; JNIEnv* env; jclass clazz; NativeActivityJNI(ANativeActivity* activity) : activity(activity) { activity->vm->AttachCurrentThread(&env, NULL); clazz = env->GetObjectClass(activity->clazz); } ~NativeActivityJNI() { activity->vm->DetachCurrentThread(); } jstring toJString(const std::string& str) { return env->NewStringUTF(str.c_str()); } std::string toString(jstring jstr) { std::string out; if (jstr) { const char* utf = env->GetStringUTFChars(jstr, 0); out = std::string(utf); env->ReleaseStringUTFChars(jstr, utf); } return out; } std::string callStringMethod(const std::string& name, const std::string& arg) { jmethodID methodID = env->GetMethodID(clazz, name.c_str(), "(Ljava/lang/String;)Ljava/lang/String;"); jstring jstr = (jstring)env->CallObjectMethod(activity->clazz, methodID, toJString(arg)); return toString(jstr); } }; std::string getMetaData(const std::string& key) { NativeActivityJNI nativeActivityJNI(activity); return nativeActivityJNI.callStringMethod("getMetaData", key); } std::string getIntentStringExtra(const std::string& key) { NativeActivityJNI nativeActivityJNI(activity); return nativeActivityJNI.callStringMethod("getIntentStringExtra", key); } }; extern "C" void FcConfigPathInit(const char* path, const char* file); void android_main( struct android_app* state ) { std::string filesDir = state->activity->internalDataPath; std::string fontconfigPath = filesDir + "/fonts"; setenv("FONTCONFIG_PATH", fontconfigPath.c_str(), 1); std::string fontconfigFile = fontconfigPath + "/fonts.conf"; setenv("FONTCONFIG_FILE", fontconfigFile.c_str(), 1); struct stat st = { 0 }; FcConfigPathInit( fontconfigPath.c_str(), fontconfigFile.c_str() ); if (stat(fontconfigPath.c_str(), &st) == -1) { mkdir(fontconfigPath.c_str(), S_IRWXU); ExtractFontConfig(state, "fonts/fonts.conf", fontconfigPath + "/fonts.conf"); ExtractFontConfig(state, "fonts/fonts.dtd", fontconfigPath + "/fonts.dtd" ); ExtractFontConfig(state, "fonts/local.conf", fontconfigPath + "/local.conf"); ExtractAssets(state, "fonts/dejavu", fontconfigPath + "/dejavu"); ExtractAssets(state, "fonts/tizen", fontconfigPath + "/tizen"); ExtractAssets(state, "fonts/bitmap", fontconfigPath + "/bitmap"); } Dali::Integration::AndroidFramework::New(); Dali::Integration::AndroidFramework::Get().SetNativeApplication( state ); Dali::Integration::AndroidFramework::Get().SetApplicationConfiguration( state->config ); Dali::Integration::AndroidFramework::Get().SetApplicationAssets( state->activity->assetManager ); Dali::Integration::AndroidFramework::Get().SetInternalDataPath( filesDir ); DaliDemoNativeActivity nativeActivity(state->activity); int status = 0; std::string libpath = "/data/data/com.sec.dalidemo/lib/libdali-demo.so"; std::string callParam = nativeActivity.getIntentStringExtra("start"); if (callParam.empty()) { callParam = nativeActivity.getMetaData("start"); } if (!callParam.empty()) { libpath = "/data/data/com.sec.dalidemo/lib/lib" + callParam + ".so"; } void* handle = dlopen( libpath.c_str(), RTLD_LAZY ); if (!handle) { std::exit(status); } dlerror(); /* Clear any existing error */ int (*main)(int, char**) = (int(*)(int, char**))dlsym(handle, "main"); if (main) { status = main( 0, nullptr ); } if (handle) { dlclose(handle); handle = nullptr; } android_app_destroy(state); Dali::Integration::AndroidFramework::Get().SetNativeApplication(nullptr); Dali::Integration::AndroidFramework::Get().SetApplicationConfiguration(nullptr); Dali::Integration::AndroidFramework::Get().SetApplicationAssets(nullptr); Dali::Integration::AndroidFramework::Delete(); // We need to kill the application process manually, DALi cannot restart in the same process due to memory leaks std::exit(status); } //END_INCLUDE(all)