Android: Ask for permissions on demand

By looking for failed start and requesting then;
and then emitting a new event type when
permission has been granted or rejected;
and then using that event in the default
boot.lua to re-start capture.
This commit is contained in:
Nevyn Bengtsson 2020-12-01 16:16:05 +01:00 committed by Bjorn
parent aa3dc76176
commit 0265babef4
8 changed files with 82 additions and 7 deletions

View File

@ -18,6 +18,7 @@ StringEntry lovrEventType[] = {
#ifndef LOVR_DISABLE_THREAD
[EVENT_THREAD_ERROR] = ENTRY("threaderror"),
#endif
[EVENT_PERMISSION] = ENTRY("permission"),
{ 0 }
};
@ -110,6 +111,12 @@ StringEntry lovrKeyboardKey[] = {
{ 0 }
};
StringEntry lovrPermission[] = {
[AUDIO_CAPTURE_PERMISSION] = ENTRY("audio_capture"),
{ 0 }
};
static LOVR_THREAD_LOCAL int pollRef;
void luax_checkvariant(lua_State* L, int index, Variant* variant) {
@ -228,6 +235,11 @@ static int nextEvent(lua_State* L) {
return 3;
#endif
case EVENT_PERMISSION:
luax_pushenum(L, Permission, event.data.permission.permission);
lua_pushboolean(L, event.data.permission.granted);
return 3;
case EVENT_CUSTOM:
for (uint32_t i = 0; i < event.data.custom.count; i++) {
Variant* variant = &event.data.custom.data[i];

View File

@ -129,12 +129,17 @@ typedef enum {
BUTTON_RELEASED
} ButtonAction;
typedef enum {
AUDIO_CAPTURE_PERMISSION,
} Permission;
typedef void (*quitCallback)(void);
typedef void (*windowFocusCallback)(bool focused);
typedef void (*windowResizeCallback)(int width, int height);
typedef void (*mouseButtonCallback)(MouseButton button, ButtonAction action);
typedef void (*keyboardCallback)(ButtonAction action, KeyboardKey key, uint32_t scancode, bool repeat);
typedef void (*textCallback)(uint32_t codepoint);
typedef void (*permissionsCallback)(Permission permission, bool granted);
bool lovrPlatformInit(void);
void lovrPlatformDestroy(void);
@ -166,3 +171,5 @@ void lovrPlatformGetMousePosition(double* x, double* y);
void lovrPlatformSetMouseMode(MouseMode mode);
bool lovrPlatformIsMouseDown(MouseButton button);
bool lovrPlatformIsKeyDown(KeyboardKey key);
void lovrPlatformRequestAudioCapture();
void lovrPlatformOnPermissionEvent(permissionsCallback callback);

View File

@ -22,6 +22,7 @@ static struct {
quitCallback onQuit;
keyboardCallback onKeyboardEvent;
textCallback onTextEvent;
permissionsCallback onPermissionEvent;
} state;
static void onAppCmd(struct android_app* app, int32_t cmd) {
@ -470,6 +471,32 @@ bool lovrPlatformIsKeyDown(KeyboardKey key) {
return false;
}
// permissions
void lovrPlatformRequestAudioCapture() {
jobject activity = state.app->activity->clazz;
jclass class = (*state.jni)->GetObjectClass(state.jni, activity);
jmethodID requestAudioCapturePermission = (*state.jni)->GetMethodID(state.jni, class, "requestAudioCapturePermission", "()V");
if (!requestAudioCapturePermission) {
(*state.jni)->DeleteLocalRef(state.jni, class);
if(state.onPermissionEvent) state.onPermissionEvent(AUDIO_CAPTURE_PERMISSION, false);
return;
}
(*state.jni)->CallVoidMethod(state.jni, activity, requestAudioCapturePermission);
}
void lovrPlatformOnPermissionEvent(permissionsCallback callback) {
state.onPermissionEvent = callback;
}
JNIEXPORT void JNICALL Java_org_lovr_app_Activity_lovrPermissionEvent(JNIEnv* jni, jobject activity, jint permission, jboolean granted) {
if (state.onPermissionEvent) {
state.onPermissionEvent(permission, granted);
}
}
// Private, must be declared manually to use
struct ANativeActivity* lovrPlatformGetActivity() {

View File

@ -3,7 +3,7 @@
#include "data/blob.h"
#include "core/arr.h"
#include "core/ref.h"
#include "core/ref.h"
#include "core/os.h"
#include "core/util.h"
#include <string.h>
#include <stdlib.h>
@ -247,11 +247,16 @@ bool lovrAudioReset() {
bool lovrAudioStart(AudioType type) {
if(state.config[type].enable == false) {
if(lovrAudioInitDevice(type) == false) {
if (type == AUDIO_CAPTURE) {
lovrPlatformRequestAudioCapture();
// lovrAudioStart will be retried from boot.lua upon permission granted event
}
return false;
}
state.config[type].enable = state.config[type].start = true;
}
return ma_device_start(&state.devices[type]) == MA_SUCCESS;
int status = ma_device_start(&state.devices[type]);
return status == MA_SUCCESS;
}
bool lovrAudioStop(AudioType type) {

View File

@ -32,6 +32,14 @@ static void onTextEvent(uint32_t codepoint) {
lovrEventPush(event);
}
static void onPermissionEvent(Permission permission, bool granted) {
Event event;
event.type = EVENT_PERMISSION;
event.data.permission.permission = permission;
event.data.permission.granted = granted;
lovrEventPush(event);
}
void lovrVariantDestroy(Variant* variant) {
switch (variant->type) {
case TYPE_STRING: free(variant->value.string); return;
@ -45,6 +53,7 @@ bool lovrEventInit() {
arr_init(&state.events);
lovrPlatformOnKeyboardEvent(onKeyboardEvent);
lovrPlatformOnTextEvent(onTextEvent);
lovrPlatformOnPermissionEvent(onPermissionEvent);
return state.initialized = true;
}

View File

@ -1,5 +1,6 @@
#include <stdbool.h>
#include <stdint.h>
#include "core/os.h"
#pragma once
@ -19,6 +20,7 @@ typedef enum {
#ifndef LOVR_DISABLE_THREAD
EVENT_THREAD_ERROR,
#endif
EVENT_PERMISSION,
} EventType;
typedef enum {
@ -80,6 +82,11 @@ typedef struct {
uint32_t count;
} CustomEvent;
typedef struct {
Permission permission;
bool granted;
} PermissionEvent;
typedef union {
QuitEvent quit;
BoolEvent boolean;
@ -88,6 +95,7 @@ typedef union {
TextEvent text;
ThreadEvent thread;
CustomEvent custom;
PermissionEvent permission;
} EventData;
typedef struct {

View File

@ -17,23 +17,24 @@ public class Activity extends NativeActivity implements ActivityCompat.OnRequest
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.i("LOVR", "MainActivity.onCreate()");
RequestPermissionsIfNeeded();
}
protected native void lovrPermissionEvent(int permission, boolean granted);
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults)
{
if(grantResults[0] == PackageManager.PERMISSION_GRANTED)
{
Log.i("LOVR", "RECORD_AUDIO permissions have now been granted.");
lovrPermissionEvent(0, true);
}
else
{
Log.i("LOVR", "RECORD_AUDIO permissions were denied.");
lovrPermissionEvent(0, false);
}
}
private void RequestPermissionsIfNeeded()
private void requestAudioCapturePermission()
{
int existingPermission = ActivityCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO);
if(existingPermission != PackageManager.PERMISSION_GRANTED)
@ -43,7 +44,7 @@ public class Activity extends NativeActivity implements ActivityCompat.OnRequest
}
else
{
Log.i("LOVR", "RECORD_AUDIO permissions already granted.");
lovrPermissionEvent(0, true);
}
}
}

View File

@ -172,6 +172,12 @@ function lovr.boot()
return lovr.run()
end
function lovr.permission(permission, granted)
if permission == "audio_capture" and granted then
lovr.audio.start("capture")
end
end
function lovr.run()
lovr.timer.step()
if lovr.load then lovr.load(arg) end