mirror of
https://github.com/libsdl-org/SDL.git
synced 2025-05-25 22:19:10 +00:00
android: Added SDL_AndroidRequestPermissionAsync.
This commit is contained in:
parent
310f21bf84
commit
af61cfd5e0
7 changed files with 144 additions and 23 deletions
|
@ -402,7 +402,18 @@ extern DECLSPEC const char * SDLCALL SDL_AndroidGetExternalStoragePath(void);
|
||||||
/**
|
/**
|
||||||
* Request permissions at runtime.
|
* Request permissions at runtime.
|
||||||
*
|
*
|
||||||
|
* You do not need to call this for built-in functionality of SDL; recording
|
||||||
|
* from a microphone or reading images from a camera, using standard SDL
|
||||||
|
* APIs, will manage permission requests for you.
|
||||||
|
*
|
||||||
* This blocks the calling thread until the permission is granted or denied.
|
* This blocks the calling thread until the permission is granted or denied.
|
||||||
|
* if the app already has the requested permission, this returns immediately,
|
||||||
|
* but may block indefinitely until the user responds to the system's
|
||||||
|
* permission request dialog.
|
||||||
|
*
|
||||||
|
* If possible, you should _not_ use this function. You should use
|
||||||
|
* SDL_AndroidRequestPermissionAsync and deal with the response in a callback
|
||||||
|
* at a later time, and possibly in a different thread.
|
||||||
*
|
*
|
||||||
* \param permission The permission to request.
|
* \param permission The permission to request.
|
||||||
* \returns SDL_TRUE if the permission was granted, SDL_FALSE otherwise.
|
* \returns SDL_TRUE if the permission was granted, SDL_FALSE otherwise.
|
||||||
|
@ -411,6 +422,39 @@ extern DECLSPEC const char * SDLCALL SDL_AndroidGetExternalStoragePath(void);
|
||||||
*/
|
*/
|
||||||
extern DECLSPEC SDL_bool SDLCALL SDL_AndroidRequestPermission(const char *permission);
|
extern DECLSPEC SDL_bool SDLCALL SDL_AndroidRequestPermission(const char *permission);
|
||||||
|
|
||||||
|
|
||||||
|
typedef void (SDLCALL *SDL_AndroidRequestPermissionCallback)(void *userdata, const char *permission, SDL_bool granted);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Request permissions at runtime, asynchronously.
|
||||||
|
*
|
||||||
|
* You do not need to call this for built-in functionality of SDL; recording
|
||||||
|
* from a microphone or reading images from a camera, using standard SDL
|
||||||
|
* APIs, will manage permission requests for you.
|
||||||
|
*
|
||||||
|
* This function never blocks. Instead, the app-supplied callback will be
|
||||||
|
* called when a decision has been made. This callback may happen on a
|
||||||
|
* different thread, and possibly much later, as it might wait on a user to
|
||||||
|
* respond to a system dialog. If permission has already been granted for
|
||||||
|
* a specific entitlement, the callback will still fire, probably on the
|
||||||
|
* current thread and before this function returns.
|
||||||
|
*
|
||||||
|
* If the request submission fails, this function returns -1 and the
|
||||||
|
* callback will NOT be called, but this should only happen in
|
||||||
|
* catastrophic conditions, like memory running out. Normally there will
|
||||||
|
* be a yes or no to the request through the callback.
|
||||||
|
*
|
||||||
|
* \param permission The permission to request.
|
||||||
|
* \param cb The callback to trigger when the request has a response.
|
||||||
|
* \param userdata An app-controlled pointer that is passed to the callback.
|
||||||
|
* \returns zero if the request was submitted, -1 if there was an error
|
||||||
|
* submitting. The result of the request is only ever reported
|
||||||
|
* through the callback, not this return value.
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 3.0.0.
|
||||||
|
*/
|
||||||
|
extern DECLSPEC int SDLCALL SDL_AndroidRequestPermissionAsync(const char *permission, SDL_AndroidRequestPermissionCallback cb, void *userdata);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Shows an Android toast notification.
|
* Shows an Android toast notification.
|
||||||
*
|
*
|
||||||
|
|
|
@ -169,6 +169,16 @@ SDL_bool SDL_AndroidRequestPermission(const char *permission)
|
||||||
return SDL_FALSE;
|
return SDL_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
typedef void (SDLCALL *SDL_AndroidRequestPermissionCallback)(void *userdata, const char *permission, SDL_bool granted);
|
||||||
|
DECLSPEC int SDLCALL SDL_AndroidRequestPermissionAsync(const char *permission, SDL_AndroidRequestPermissionCallback cb, void *userdata);
|
||||||
|
int SDL_AndroidRequestPermissionAsync(const char *permission, SDL_AndroidRequestPermissionCallback cb, void *userdata)
|
||||||
|
{
|
||||||
|
(void)permission;
|
||||||
|
(void)cb;
|
||||||
|
(void)userdata;
|
||||||
|
return SDL_Unsupported();
|
||||||
|
}
|
||||||
|
|
||||||
DECLSPEC int SDLCALL SDL_AndroidSendMessage(Uint32 command, int param);
|
DECLSPEC int SDLCALL SDL_AndroidSendMessage(Uint32 command, int param);
|
||||||
int SDL_AndroidSendMessage(Uint32 command, int param)
|
int SDL_AndroidSendMessage(Uint32 command, int param)
|
||||||
{
|
{
|
||||||
|
|
|
@ -381,9 +381,6 @@ static SDL_bool bHasNewData;
|
||||||
|
|
||||||
static SDL_bool bHasEnvironmentVariables;
|
static SDL_bool bHasEnvironmentVariables;
|
||||||
|
|
||||||
static SDL_AtomicInt bPermissionRequestPending;
|
|
||||||
static SDL_bool bPermissionRequestResult;
|
|
||||||
|
|
||||||
/* Android AssetManager */
|
/* Android AssetManager */
|
||||||
static void Internal_Android_Create_AssetManager(void);
|
static void Internal_Android_Create_AssetManager(void);
|
||||||
static void Internal_Android_Destroy_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);
|
(*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
|
JNIEXPORT void JNICALL
|
||||||
SDL_JAVA_AUDIO_INTERFACE(addAudioDevice)(JNIEnv *env, jclass jcls, jboolean is_capture,
|
SDL_JAVA_AUDIO_INTERFACE(addAudioDevice)(JNIEnv *env, jclass jcls, jboolean is_capture,
|
||||||
jstring name, jint device_id)
|
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));
|
return (*env)->CallStaticBooleanMethod(env, mActivityClass, midSetRelativeMouseEnabled, (enabled == 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
SDL_bool Android_JNI_RequestPermission(const char *permission)
|
typedef struct NativePermissionRequestInfo
|
||||||
{
|
{
|
||||||
JNIEnv *env = Android_JNI_GetEnv();
|
int request_code;
|
||||||
jstring jpermission;
|
char *permission;
|
||||||
const int requestCode = 1;
|
SDL_AndroidRequestPermissionCallback callback;
|
||||||
|
void *userdata;
|
||||||
|
struct NativePermissionRequestInfo *next;
|
||||||
|
} NativePermissionRequestInfo;
|
||||||
|
|
||||||
/* Wait for any pending request on another thread */
|
static NativePermissionRequestInfo pending_permissions;
|
||||||
while (SDL_AtomicGet(&bPermissionRequestPending) == SDL_TRUE) {
|
|
||||||
SDL_Delay(10);
|
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);
|
SDL_UnlockMutex(Android_ActivityMutex);
|
||||||
(*env)->CallStaticVoidMethod(env, mActivityClass, midRequestPermission, jpermission, requestCode);
|
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);
|
(*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 */
|
/* Wait for the request to complete */
|
||||||
while (SDL_AtomicGet(&bPermissionRequestPending) == SDL_TRUE) {
|
while (SDL_AtomicGet(&response) == 0) {
|
||||||
SDL_Delay(10);
|
SDL_Delay(10);
|
||||||
}
|
}
|
||||||
return bPermissionRequestResult;
|
|
||||||
|
return (SDL_AtomicGet(&response) < 0) ? SDL_FALSE : SDL_TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Show toast notification */
|
/* Show toast notification */
|
||||||
int Android_JNI_ShowToast(const char *message, int duration, int gravity, int xOffset, int yOffset)
|
int Android_JNI_ShowToast(const char *message, int duration, int gravity, int xOffset, int yOffset)
|
||||||
{
|
{
|
||||||
|
|
|
@ -972,6 +972,7 @@ SDL3_0.0.0 {
|
||||||
SDL_RenderGeometryRawFloat;
|
SDL_RenderGeometryRawFloat;
|
||||||
SDL_SetWindowShape;
|
SDL_SetWindowShape;
|
||||||
SDL_RenderViewportSet;
|
SDL_RenderViewportSet;
|
||||||
|
SDL_AndroidRequestPermissionAsync;
|
||||||
# extra symbols go here (don't modify this line)
|
# extra symbols go here (don't modify this line)
|
||||||
local: *;
|
local: *;
|
||||||
};
|
};
|
||||||
|
|
|
@ -997,3 +997,4 @@
|
||||||
#define SDL_RenderGeometryRawFloat SDL_RenderGeometryRawFloat_REAL
|
#define SDL_RenderGeometryRawFloat SDL_RenderGeometryRawFloat_REAL
|
||||||
#define SDL_SetWindowShape SDL_SetWindowShape_REAL
|
#define SDL_SetWindowShape SDL_SetWindowShape_REAL
|
||||||
#define SDL_RenderViewportSet SDL_RenderViewportSet_REAL
|
#define SDL_RenderViewportSet SDL_RenderViewportSet_REAL
|
||||||
|
#define SDL_AndroidRequestPermissionAsync SDL_AndroidRequestPermissionAsync_REAL
|
||||||
|
|
|
@ -1022,3 +1022,4 @@ SDL_DYNAPI_PROC(int,SDL_GetRenderColorScale,(SDL_Renderer *a, float *b),(a,b),re
|
||||||
SDL_DYNAPI_PROC(int,SDL_RenderGeometryRawFloat,(SDL_Renderer *a, SDL_Texture *b, const float *c, int d, const SDL_FColor *e, int f, const float *g, int h, int i, const void *j, int k, int l),(a,b,c,d,e,f,g,h,i,j,k,l),return)
|
SDL_DYNAPI_PROC(int,SDL_RenderGeometryRawFloat,(SDL_Renderer *a, SDL_Texture *b, const float *c, int d, const SDL_FColor *e, int f, const float *g, int h, int i, const void *j, int k, int l),(a,b,c,d,e,f,g,h,i,j,k,l),return)
|
||||||
SDL_DYNAPI_PROC(int,SDL_SetWindowShape,(SDL_Window *a, SDL_Surface *b),(a,b),return)
|
SDL_DYNAPI_PROC(int,SDL_SetWindowShape,(SDL_Window *a, SDL_Surface *b),(a,b),return)
|
||||||
SDL_DYNAPI_PROC(SDL_bool,SDL_RenderViewportSet,(SDL_Renderer *a),(a),return)
|
SDL_DYNAPI_PROC(SDL_bool,SDL_RenderViewportSet,(SDL_Renderer *a),(a),return)
|
||||||
|
SDL_DYNAPI_PROC(int,SDL_AndroidRequestPermissionAsync,(const char *a, SDL_AndroidRequestPermissionCallback b, void *c),(a,b,c),return)
|
||||||
|
|
|
@ -45,4 +45,8 @@ typedef int SDL_WinRT_Path;
|
||||||
typedef struct XUserHandle XUserHandle;
|
typedef struct XUserHandle XUserHandle;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef SDL_PLATFORM_ANDROID
|
||||||
|
typedef void *SDL_AndroidRequestPermissionCallback;
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue