diff --git a/src/clientmedia.cpp b/src/clientmedia.cpp index ea11ad239..bca3f67c2 100644 --- a/src/clientmedia.cpp +++ b/src/clientmedia.cpp @@ -34,7 +34,7 @@ with this program; if not, write to the Free Software Foundation, Inc., static std::string getMediaCacheDir() { - return porting::path_user + DIR_DELIM + "cache" + DIR_DELIM + "media"; + return porting::path_cache + DIR_DELIM + "media"; } /* diff --git a/src/filesys.cpp b/src/filesys.cpp index 4cefdb807..5fdc97634 100644 --- a/src/filesys.cpp +++ b/src/filesys.cpp @@ -707,5 +707,10 @@ bool safeWriteToFile(const std::string &path, const std::string &content) } } +bool Rename(const std::string &from, const std::string &to) +{ + return rename(from.c_str(), to.c_str()) == 0; +} + } // namespace fs diff --git a/src/filesys.h b/src/filesys.h index cc6f43ec4..94d0c874d 100644 --- a/src/filesys.h +++ b/src/filesys.h @@ -115,6 +115,8 @@ const char *GetFilenameFromPath(const char *path); bool safeWriteToFile(const std::string &path, const std::string &content); +bool Rename(const std::string &from, const std::string &to); + } // namespace fs #endif diff --git a/src/main.cpp b/src/main.cpp index 151ea7148..72daaef01 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -164,7 +164,13 @@ int main(int argc, char *argv[]) setup_log_params(cmd_args); porting::signal_handler_init(); + +#ifdef __ANDROID__ + porting::initAndroid(); + porting::initializePathsAndroid(); +#else porting::initializePaths(); +#endif if (!create_userdata_path()) { errorstream << "Cannot create user data directory" << std::endl; @@ -422,9 +428,6 @@ static bool create_userdata_path() bool success; #ifdef __ANDROID__ - porting::initAndroid(); - - porting::setExternalStorageDir(porting::jnienv); if (!fs::PathExists(porting::path_user)) { success = fs::CreateDir(porting::path_user); } else { @@ -436,9 +439,6 @@ static bool create_userdata_path() success = fs::CreateDir(porting::path_user); #endif - infostream << "path_share = " << porting::path_share << std::endl; - infostream << "path_user = " << porting::path_user << std::endl; - return success; } diff --git a/src/porting.cpp b/src/porting.cpp index 3e39fc813..4a72e90fd 100644 --- a/src/porting.cpp +++ b/src/porting.cpp @@ -139,6 +139,7 @@ void signal_handler_init(void) std::string path_share = ".."; std::string path_user = ".."; std::string path_locale = path_share + DIR_DELIM + "locale"; +std::string path_cache = path_user + DIR_DELIM + "cache"; std::string getDataPath(const char *subpath) @@ -463,6 +464,25 @@ bool setSystemPaths() #endif +void migrateCachePath() +{ + const std::string local_cache_path = path_user + DIR_DELIM + "cache"; + + // Delete tmp folder if it exists (it only ever contained + // a temporary ogg file, which is no longer used). + if (fs::PathExists(local_cache_path + DIR_DELIM + "tmp")) + fs::RecursiveDelete(local_cache_path + DIR_DELIM + "tmp"); + + // Bail if migration impossible + if (path_cache == local_cache_path || !fs::PathExists(local_cache_path) + || fs::PathExists(path_cache)) { + return; + } + if (!fs::Rename(local_cache_path, path_cache)) { + errorstream << "Failed to migrate local cache path " + "to system path!" << std::endl; + } +} void initializePaths() { @@ -513,10 +533,27 @@ void initializePaths() if (!setSystemPaths()) errorstream << "Failed to get one or more system-wide path" << std::endl; + // Initialize path_cache + // First try $XDG_CACHE_HOME/PROJECT_NAME + const char *cache_dir = getenv("XDG_CACHE_HOME"); + if (cache_dir) { + path_cache = std::string(cache_dir) + DIR_DELIM + PROJECT_NAME; + } else { + // Then try $HOME/.cache/PROJECT_NAME + const char *home_dir = getenv("HOME"); + if (home_dir) { + path_cache = std::string(home_dir) + DIR_DELIM + ".cache" + + DIR_DELIM + PROJECT_NAME; + } + // If neither works, leave it at $PATH_USER/cache + } + // Migrate cache folder to new location if possible + migrateCachePath(); #endif infostream << "Detected share path: " << path_share << std::endl; infostream << "Detected user path: " << path_user << std::endl; + infostream << "Detected cache path: " << path_cache << std::endl; bool found_localedir = false; #ifdef STATIC_LOCALEDIR @@ -542,7 +579,6 @@ void initializePaths() if (!found_localedir) { errorstream << "Couldn't find a locale directory!" << std::endl; } - } diff --git a/src/porting.h b/src/porting.h index 1e89cd044..5da32607c 100644 --- a/src/porting.h +++ b/src/porting.h @@ -147,12 +147,23 @@ extern std::string path_user; */ extern std::string path_locale; +/* + Path to directory for storing caches. +*/ +extern std::string path_cache; + /* Get full path of stuff in data directory. Example: "stone.png" -> "../data/stone.png" */ std::string getDataPath(const char *subpath); +/* + Move cache folder from path_user to the + system cache location if possible. +*/ +void migrateCachePath(); + /* Initialize path_*. */ diff --git a/src/porting_android.cpp b/src/porting_android.cpp index c7e28cc9a..72b625d73 100644 --- a/src/porting_android.cpp +++ b/src/porting_android.cpp @@ -164,29 +164,63 @@ void cleanupAndroid() jvm->DetachCurrentThread(); } -void setExternalStorageDir(JNIEnv* lJNIEnv) +static std::string javaStringToUTF8(jstring js) { - // Android: Retrieve ablsolute path to external storage device (sdcard) - jclass ClassEnv = lJNIEnv->FindClass("android/os/Environment"); - jmethodID MethodDir = - lJNIEnv->GetStaticMethodID(ClassEnv, - "getExternalStorageDirectory","()Ljava/io/File;"); - jobject ObjectFile = lJNIEnv->CallStaticObjectMethod(ClassEnv, MethodDir); - jclass ClassFile = lJNIEnv->FindClass("java/io/File"); + std::string str; + // Get string as a UTF-8 c-string + const char *c_str = jnienv->GetStringUTFChars(js, NULL); + // Save it + str = c_str; + // And free the c-string + jnienv->ReleaseStringUTFChars(js, c_str); + return str; +} - jmethodID MethodPath = - lJNIEnv->GetMethodID(ClassFile, "getAbsolutePath", - "()Ljava/lang/String;"); - jstring StringPath = - (jstring) lJNIEnv->CallObjectMethod(ObjectFile, MethodPath); +// Calls static method if obj is NULL +static std::string getAndroidPath(jclass cls, jobject obj, jclass cls_File, + jmethodID mt_getAbsPath, const char *getter) +{ + // Get getter method + jmethodID mt_getter; + if (obj) + mt_getter = jnienv->GetMethodID(cls, getter, + "()Ljava/io/File;"); + else + mt_getter = jnienv->GetStaticMethodID(cls, getter, + "()Ljava/io/File;"); - const char *externalPath = lJNIEnv->GetStringUTFChars(StringPath, NULL); - std::string userPath(externalPath); - lJNIEnv->ReleaseStringUTFChars(StringPath, externalPath); + // Call getter + jobject ob_file; + if (obj) + ob_file = jnienv->CallObjectMethod(obj, mt_getter); + else + ob_file = jnienv->CallStaticObjectMethod(cls, mt_getter); - path_storage = userPath; - path_user = userPath + DIR_DELIM + PROJECT_NAME_C; - path_share = userPath + DIR_DELIM + PROJECT_NAME_C; + // Call getAbsolutePath + jstring js_path = (jstring) jnienv->CallObjectMethod(ob_file, + mt_getAbsPath); + + return javaStringToUTF8(js_path); +} + +void initializePathsAndroid() +{ + // Get Environment class + jclass cls_Env = jnienv->FindClass("android/os/Environment"); + // Get File class + jclass cls_File = jnienv->FindClass("java/io/File"); + // Get getAbsolutePath method + jmethodID mt_getAbsPath = jnienv->GetMethodID(cls_File, + "getAbsolutePath", "()Ljava/lang/String;"); + + path_cache = getAndroidPath(nativeActivity, app_global->activity->clazz, + cls_File, mt_getAbsPath, "getCacheDir"); + path_storage = getAndroidPath(cls_Env, NULL, cls_File, mt_getAbsPath, + "getExternalStorageDirectory"); + path_user = path_storage + DIR_DELIM + PROJECT_NAME_C; + path_share = path_storage + DIR_DELIM + PROJECT_NAME_C; + + migrateCachePath(); } void showInputDialog(const std::string& acceptButton, const std::string& hint, diff --git a/src/porting_android.h b/src/porting_android.h index bfdadfbff..e4be0740d 100644 --- a/src/porting_android.h +++ b/src/porting_android.h @@ -43,10 +43,10 @@ void initAndroid(); void cleanupAndroid(); /** - * set storage dir on external sdcard# - * @param lJNIEnv environment from android + * Initializes path_* variables for Android + * @param env Android JNI environment */ -void setExternalStorageDir(JNIEnv* lJNIEnv); +void initializePathsAndroid(); /** * use java function to copy media from assets to external storage