diff --git a/docs/README-android.md b/docs/README-android.md index cb46c604f2..9eb8ec8de0 100644 --- a/docs/README-android.md +++ b/docs/README-android.md @@ -172,6 +172,7 @@ useful paths for saving and loading data: * SDL_AndroidGetInternalStoragePath() * SDL_AndroidGetExternalStorageState() * SDL_AndroidGetExternalStoragePath() +* SDL_AndroidGetCachePath() See SDL_system.h for more details on these functions. diff --git a/include/SDL3/SDL_system.h b/include/SDL3/SDL_system.h index c7c0ad4210..a4c7e325a2 100644 --- a/include/SDL3/SDL_system.h +++ b/include/SDL3/SDL_system.h @@ -395,7 +395,7 @@ extern SDL_DECLSPEC void SDLCALL SDL_AndroidBackButton(void); #define SDL_ANDROID_EXTERNAL_STORAGE_WRITE 0x02 /** - * Get the path used for internal storage for this application. + * Get the path used for internal storage for this Android application. * * This path is unique to your application and cannot be written to by other * applications. @@ -403,6 +403,10 @@ extern SDL_DECLSPEC void SDLCALL SDL_AndroidBackButton(void); * Your internal storage path is typically: * `/data/data/your.app.package/files`. * + * This is a C wrapper over `android.content.Context.getFilesDir()`: + * + * https://developer.android.com/reference/android/content/Context#getFilesDir() + * * The returned string follows the SDL_GetStringRule. * * \returns the path used for internal storage or NULL on failure; call @@ -415,7 +419,7 @@ extern SDL_DECLSPEC void SDLCALL SDL_AndroidBackButton(void); extern SDL_DECLSPEC const char *SDLCALL SDL_AndroidGetInternalStoragePath(void); /** - * Get the current state of external storage. + * Get the current state of external storage for this Android application. * * The current state of external storage, a bitmask of these values: * `SDL_ANDROID_EXTERNAL_STORAGE_READ`, `SDL_ANDROID_EXTERNAL_STORAGE_WRITE`. @@ -434,7 +438,7 @@ extern SDL_DECLSPEC const char *SDLCALL SDL_AndroidGetInternalStoragePath(void); extern SDL_DECLSPEC int SDLCALL SDL_AndroidGetExternalStorageState(Uint32 *state); /** - * Get the path used for external storage for this application. + * Get the path used for external storage for this Android application. * * This path is unique to your application, but is public and can be written * to by other applications. @@ -442,6 +446,10 @@ extern SDL_DECLSPEC int SDLCALL SDL_AndroidGetExternalStorageState(Uint32 *state * Your external storage path is typically: * `/storage/sdcard0/Android/data/your.app.package/files`. * + * This is a C wrapper over `android.content.Context.getExternalFilesDir()`: + * + * https://developer.android.com/reference/android/content/Context#getExternalFilesDir() + * * The returned string follows the SDL_GetStringRule. * * \returns the path used for external storage for this application on success @@ -453,6 +461,28 @@ extern SDL_DECLSPEC int SDLCALL SDL_AndroidGetExternalStorageState(Uint32 *state */ extern SDL_DECLSPEC const char * SDLCALL SDL_AndroidGetExternalStoragePath(void); +/** + * Get the path used for caching data for this Android application. + * + * This path is unique to your application, but is public and can be written + * to by other applications. + * + * Your cache path is typically: + * `/data/data/your.app.package/cache/`. + * + * This is a C wrapper over `android.content.Context.getCacheDir()`: + * + * https://developer.android.com/reference/android/content/Context#getCacheDir() + * + * The returned string follows the SDL_GetStringRule. + * + * \returns the path used for caches for this application on success + * or NULL on failure; call SDL_GetError() for more information. + * + * \since This function is available since SDL 3.0.0. + */ +extern SDL_DECLSPEC const char * SDLCALL SDL_AndroidGetCachePath(void); + typedef void (SDLCALL *SDL_AndroidRequestPermissionCallback)(void *userdata, const char *permission, SDL_bool granted); diff --git a/src/core/SDL_core_unsupported.c b/src/core/SDL_core_unsupported.c index eb1370795d..ec909fd379 100644 --- a/src/core/SDL_core_unsupported.c +++ b/src/core/SDL_core_unsupported.c @@ -127,6 +127,14 @@ void *SDL_AndroidGetActivity() return NULL; } +SDL_DECLSPEC const char *SDLCALL SDL_AndroidGetCachePath(void); +const char* SDL_AndroidGetCachePath() +{ + SDL_Unsupported(); + return NULL; +} + + SDL_DECLSPEC const char *SDLCALL SDL_AndroidGetExternalStoragePath(void); const char* SDL_AndroidGetExternalStoragePath() { diff --git a/src/core/android/SDL_android.c b/src/core/android/SDL_android.c index a426506010..d80c963b50 100644 --- a/src/core/android/SDL_android.c +++ b/src/core/android/SDL_android.c @@ -2598,6 +2598,53 @@ const char *SDL_AndroidGetExternalStoragePath(void) return s_AndroidExternalFilesPath; } +// this caches a string until the process ends, so there's no need to use SDL_FreeLater. +const char *SDL_AndroidGetCachePath(void) +{ + // !!! FIXME: lots of duplication with SDL_AndroidGetExternalStoragePath and SDL_AndroidGetInternalStoragePath; consolidate these functions! + static char *s_AndroidCachePath = NULL; + + if (!s_AndroidCachePath) { + struct LocalReferenceHolder refs = LocalReferenceHolder_Setup(__FUNCTION__); + jmethodID mid; + jobject context; + jobject fileObject; + jstring pathString; + const char *path; + + JNIEnv *env = Android_JNI_GetEnv(); + if (!LocalReferenceHolder_Init(&refs, env)) { + LocalReferenceHolder_Cleanup(&refs); + return NULL; + } + + /* context = SDLActivity.getContext(); */ + context = (*env)->CallStaticObjectMethod(env, mActivityClass, midGetContext); + + /* fileObj = context.getExternalFilesDir(); */ + mid = (*env)->GetMethodID(env, (*env)->GetObjectClass(env, context), + "getCacheDir", "(Ljava/lang/String;)Ljava/io/File;"); + fileObject = (*env)->CallObjectMethod(env, context, mid, NULL); + if (!fileObject) { + SDL_SetError("Couldn't get cache directory"); + LocalReferenceHolder_Cleanup(&refs); + return NULL; + } + + /* path = fileObject.getAbsolutePath(); */ + mid = (*env)->GetMethodID(env, (*env)->GetObjectClass(env, fileObject), + "getAbsolutePath", "()Ljava/lang/String;"); + pathString = (jstring)(*env)->CallObjectMethod(env, fileObject, mid); + + path = (*env)->GetStringUTFChars(env, pathString, NULL); + s_AndroidCachePath = SDL_strdup(path); + (*env)->ReleaseStringUTFChars(env, pathString, path); + + LocalReferenceHolder_Cleanup(&refs); + } + return s_AndroidCachePath; +} + int SDL_AndroidShowToast(const char *message, int duration, int gravity, int xOffset, int yOffset) { return Android_JNI_ShowToast(message, duration, gravity, xOffset, yOffset); diff --git a/src/dynapi/SDL_dynapi.sym b/src/dynapi/SDL_dynapi.sym index 656b4b1fa2..f0742330d2 100644 --- a/src/dynapi/SDL_dynapi.sym +++ b/src/dynapi/SDL_dynapi.sym @@ -14,6 +14,7 @@ SDL3_0.0.0 { SDL_AllocateEventMemory; SDL_AndroidBackButton; SDL_AndroidGetActivity; + SDL_AndroidGetCachePath; SDL_AndroidGetExternalStoragePath; SDL_AndroidGetExternalStorageState; SDL_AndroidGetInternalStoragePath; diff --git a/src/dynapi/SDL_dynapi_overrides.h b/src/dynapi/SDL_dynapi_overrides.h index 2cdd9d2485..7d15e9819d 100644 --- a/src/dynapi/SDL_dynapi_overrides.h +++ b/src/dynapi/SDL_dynapi_overrides.h @@ -39,6 +39,7 @@ #define SDL_AllocateEventMemory SDL_AllocateEventMemory_REAL #define SDL_AndroidBackButton SDL_AndroidBackButton_REAL #define SDL_AndroidGetActivity SDL_AndroidGetActivity_REAL +#define SDL_AndroidGetCachePath SDL_AndroidGetCachePath_REAL #define SDL_AndroidGetExternalStoragePath SDL_AndroidGetExternalStoragePath_REAL #define SDL_AndroidGetExternalStorageState SDL_AndroidGetExternalStorageState_REAL #define SDL_AndroidGetInternalStoragePath SDL_AndroidGetInternalStoragePath_REAL diff --git a/src/dynapi/SDL_dynapi_procs.h b/src/dynapi/SDL_dynapi_procs.h index 66894a9881..27a35a97fe 100644 --- a/src/dynapi/SDL_dynapi_procs.h +++ b/src/dynapi/SDL_dynapi_procs.h @@ -59,6 +59,7 @@ SDL_DYNAPI_PROC(int,SDL_AddVulkanRenderSemaphores,(SDL_Renderer *a, Uint32 b, Si SDL_DYNAPI_PROC(void*,SDL_AllocateEventMemory,(size_t a),(a),return) SDL_DYNAPI_PROC(void,SDL_AndroidBackButton,(void),(),) SDL_DYNAPI_PROC(void*,SDL_AndroidGetActivity,(void),(),return) +SDL_DYNAPI_PROC(const char*,SDL_AndroidGetCachePath,(void),(),return) SDL_DYNAPI_PROC(const char*,SDL_AndroidGetExternalStoragePath,(void),(),return) SDL_DYNAPI_PROC(int,SDL_AndroidGetExternalStorageState,(Uint32 *a),(a),return) SDL_DYNAPI_PROC(const char*,SDL_AndroidGetInternalStoragePath,(void),(),return)