android: Added SDL_AndroidRequestPermissionAsync.

This commit is contained in:
Ryan C. Gordon 2024-02-12 15:26:09 -05:00
parent 310f21bf84
commit af61cfd5e0
7 changed files with 144 additions and 23 deletions

View file

@ -381,9 +381,6 @@ static SDL_bool bHasNewData;
static SDL_bool bHasEnvironmentVariables;
static SDL_AtomicInt bPermissionRequestPending;
static SDL_bool bPermissionRequestResult;
/* Android AssetManager */
static void Internal_Android_Create_AssetManager(void);
static void Internal_Android_Destroy_AssetManager(void);
@ -997,14 +994,6 @@ JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(nativeAddTouch)(
(*env)->ReleaseStringUTFChars(env, name, utfname);
}
JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(nativePermissionResult)(
JNIEnv *env, jclass cls,
jint requestCode, jboolean result)
{
bPermissionRequestResult = result;
SDL_AtomicSet(&bPermissionRequestPending, SDL_FALSE);
}
JNIEXPORT void JNICALL
SDL_JAVA_AUDIO_INTERFACE(addAudioDevice)(JNIEnv *env, jclass jcls, jboolean is_capture,
jstring name, jint device_id)
@ -2640,29 +2629,100 @@ SDL_bool Android_JNI_SetRelativeMouseEnabled(SDL_bool enabled)
return (*env)->CallStaticBooleanMethod(env, mActivityClass, midSetRelativeMouseEnabled, (enabled == 1));
}
SDL_bool Android_JNI_RequestPermission(const char *permission)
typedef struct NativePermissionRequestInfo
{
JNIEnv *env = Android_JNI_GetEnv();
jstring jpermission;
const int requestCode = 1;
int request_code;
char *permission;
SDL_AndroidRequestPermissionCallback callback;
void *userdata;
struct NativePermissionRequestInfo *next;
} NativePermissionRequestInfo;
/* Wait for any pending request on another thread */
while (SDL_AtomicGet(&bPermissionRequestPending) == SDL_TRUE) {
SDL_Delay(10);
static NativePermissionRequestInfo pending_permissions;
JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(nativePermissionResult)(
JNIEnv *env, jclass cls,
jint requestCode, jboolean result)
{
SDL_LockMutex(Android_ActivityMutex);
NativePermissionRequestInfo *prev = &pending_permissions;
for (NativePermissionRequestInfo *info = prev->next; info != NULL; info = info->next) {
if (info->request_code == (int) requestCode) {
prev->next = info->next;
SDL_UnlockMutex(Android_ActivityMutex);
info->callback(info->userdata, info->permission, result ? SDL_TRUE : SDL_FALSE);
SDL_free(info->permission);
SDL_free(info);
return;
}
prev = info;
}
SDL_AtomicSet(&bPermissionRequestPending, SDL_TRUE);
jpermission = (*env)->NewStringUTF(env, permission);
(*env)->CallStaticVoidMethod(env, mActivityClass, midRequestPermission, jpermission, requestCode);
SDL_UnlockMutex(Android_ActivityMutex);
SDL_assert(!"Shouldn't have hit this code"); // we had a permission response for a request we never made...?
}
int SDL_AndroidRequestPermissionAsync(const char *permission, SDL_AndroidRequestPermissionCallback cb, void *userdata)
{
if (!permission) {
return SDL_InvalidParamError("permission");
} else if (!cb) {
return SDL_InvalidParamError("cb");
}
NativePermissionRequestInfo *info = (NativePermissionRequestInfo *) SDL_calloc(1, sizeof (NativePermissionRequestInfo));
if (!info) {
return -1;
}
info->permission = SDL_strdup(permission);
if (!info->permission) {
SDL_free(info);
return -1;
}
static SDL_AtomicInt next_request_code;
info->request_code = SDL_AtomicAdd(&next_request_code, 1);
info->callback = cb;
info->userdata = userdata;
SDL_LockMutex(Android_ActivityMutex);
info->next = pending_permissions.next;
pending_permissions.next = info;
SDL_UnlockMutex(Android_ActivityMutex);
JNIEnv *env = Android_JNI_GetEnv();
jstring jpermission = (*env)->NewStringUTF(env, permission);
(*env)->CallStaticVoidMethod(env, mActivityClass, midRequestPermission, jpermission, info->request_code);
(*env)->DeleteLocalRef(env, jpermission);
return 0;
}
static void SDLCALL AndroidRequestPermissionBlockingCallback(void *userdata, const char *permission, SDL_bool granted)
{
SDL_AtomicSet((SDL_AtomicInt *) userdata, granted ? 1 : -1);
}
SDL_bool Android_JNI_RequestPermission(const char *permission)
{
SDL_AtomicInt response;
SDL_AtomicSet(&response, 0);
if (SDL_AndroidRequestPermissionAsync(permission, AndroidRequestPermissionBlockingCallback, &response) == -1) {
return SDL_FALSE;
}
/* Wait for the request to complete */
while (SDL_AtomicGet(&bPermissionRequestPending) == SDL_TRUE) {
while (SDL_AtomicGet(&response) == 0) {
SDL_Delay(10);
}
return bPermissionRequestResult;
return (SDL_AtomicGet(&response) < 0) ? SDL_FALSE : SDL_TRUE;
}
/* Show toast notification */
int Android_JNI_ShowToast(const char *message, int duration, int gravity, int xOffset, int yOffset)
{