Merge pull request #32600 from cagdasc/3.2-auto-permission-manager
Add request defined permissions in AndroidManifest.xml
This commit is contained in:
commit
4e29faaeea
13 changed files with 258 additions and 29 deletions
|
@ -1136,6 +1136,16 @@ bool _OS::request_permission(const String &p_name) {
|
|||
return OS::get_singleton()->request_permission(p_name);
|
||||
}
|
||||
|
||||
bool _OS::request_permissions() {
|
||||
|
||||
return OS::get_singleton()->request_permissions();
|
||||
}
|
||||
|
||||
Vector<String> _OS::get_granted_permissions() const {
|
||||
|
||||
return OS::get_singleton()->get_granted_permissions();
|
||||
}
|
||||
|
||||
_OS *_OS::singleton = NULL;
|
||||
|
||||
void _OS::_bind_methods() {
|
||||
|
@ -1319,6 +1329,8 @@ void _OS::_bind_methods() {
|
|||
ClassDB::bind_method(D_METHOD("get_power_percent_left"), &_OS::get_power_percent_left);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("request_permission", "name"), &_OS::request_permission);
|
||||
ClassDB::bind_method(D_METHOD("request_permissions"), &_OS::request_permissions);
|
||||
ClassDB::bind_method(D_METHOD("get_granted_permissions"), &_OS::get_granted_permissions);
|
||||
|
||||
ADD_PROPERTY(PropertyInfo(Variant::STRING, "clipboard"), "set_clipboard", "get_clipboard");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::INT, "current_screen"), "set_current_screen", "get_current_screen");
|
||||
|
|
|
@ -349,6 +349,8 @@ public:
|
|||
bool has_feature(const String &p_feature) const;
|
||||
|
||||
bool request_permission(const String &p_name);
|
||||
bool request_permissions();
|
||||
Vector<String> get_granted_permissions() const;
|
||||
|
||||
static _OS *get_singleton() { return singleton; }
|
||||
|
||||
|
|
|
@ -65,6 +65,8 @@ void MainLoop::_bind_methods() {
|
|||
BIND_CONSTANT(NOTIFICATION_OS_IME_UPDATE);
|
||||
BIND_CONSTANT(NOTIFICATION_APP_RESUMED);
|
||||
BIND_CONSTANT(NOTIFICATION_APP_PAUSED);
|
||||
|
||||
ADD_SIGNAL(MethodInfo("on_request_permissions_result", PropertyInfo(Variant::STRING, "permission"), PropertyInfo(Variant::BOOL, "granted")));
|
||||
};
|
||||
|
||||
void MainLoop::set_init_script(const Ref<Script> &p_init_script) {
|
||||
|
|
|
@ -530,6 +530,8 @@ public:
|
|||
List<String> get_restart_on_exit_arguments() const;
|
||||
|
||||
virtual bool request_permission(const String &p_name) { return true; }
|
||||
virtual bool request_permissions() { return true; }
|
||||
virtual Vector<String> get_granted_permissions() const { return Vector<String>(); }
|
||||
|
||||
virtual void process_and_drop_events() {}
|
||||
OS();
|
||||
|
|
|
@ -167,6 +167,17 @@
|
|||
</description>
|
||||
</method>
|
||||
</methods>
|
||||
<signals>
|
||||
<signal name="on_request_permissions_result">
|
||||
<argument index="0" name="permission" type="String">
|
||||
</argument>
|
||||
<argument index="1" name="granted" type="bool">
|
||||
</argument>
|
||||
<description>
|
||||
Emitted when an user responds to permission request.
|
||||
</description>
|
||||
</signal>
|
||||
</signals>
|
||||
<constants>
|
||||
<constant name="NOTIFICATION_WM_MOUSE_ENTER" value="1002">
|
||||
Notification received from the OS when the mouse enters the game window.
|
||||
|
|
|
@ -217,6 +217,13 @@
|
|||
Returns the path to the current engine executable.
|
||||
</description>
|
||||
</method>
|
||||
<method name="get_granted_permissions">
|
||||
<return type="PoolStringArray">
|
||||
</return>
|
||||
<description>
|
||||
With this function you can get the list of dangerous permissions that have been granted to the Android application.
|
||||
</description>
|
||||
</method>
|
||||
<method name="get_ime_selection" qualifiers="const">
|
||||
<return type="Vector2">
|
||||
</return>
|
||||
|
@ -744,6 +751,13 @@
|
|||
At the moment this function is only used by [code]AudioDriverOpenSL[/code] to request permission for [code]RECORD_AUDIO[/code] on Android.
|
||||
</description>
|
||||
</method>
|
||||
<method name="request_permissions">
|
||||
<return type="bool">
|
||||
</return>
|
||||
<description>
|
||||
With this function you can request dangerous permissions since normal permissions are automatically granted at install time in Android application.
|
||||
</description>
|
||||
</method>
|
||||
<method name="set_icon">
|
||||
<return type="void">
|
||||
</return>
|
||||
|
|
|
@ -30,7 +30,6 @@
|
|||
|
||||
package org.godotengine.godot;
|
||||
|
||||
import android.Manifest;
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.Activity;
|
||||
import android.app.ActivityManager;
|
||||
|
@ -64,7 +63,6 @@ import android.os.Vibrator;
|
|||
import android.provider.Settings.Secure;
|
||||
import android.support.annotation.Keep;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v4.content.ContextCompat;
|
||||
import android.view.Display;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.MotionEvent;
|
||||
|
@ -98,14 +96,12 @@ import java.util.Locale;
|
|||
import javax.microedition.khronos.opengles.GL10;
|
||||
import org.godotengine.godot.input.GodotEditText;
|
||||
import org.godotengine.godot.payments.PaymentsManager;
|
||||
import org.godotengine.godot.utils.PermissionsUtil;
|
||||
import org.godotengine.godot.xr.XRMode;
|
||||
|
||||
public abstract class Godot extends Activity implements SensorEventListener, IDownloaderClient {
|
||||
|
||||
static final int MAX_SINGLETONS = 64;
|
||||
static final int REQUEST_RECORD_AUDIO_PERMISSION = 1;
|
||||
static final int REQUEST_CAMERA_PERMISSION = 2;
|
||||
static final int REQUEST_VIBRATE_PERMISSION = 3;
|
||||
private IStub mDownloaderClientStub;
|
||||
private TextView mStatusText;
|
||||
private TextView mProgressFraction;
|
||||
|
@ -1007,32 +1003,15 @@ public abstract class Godot extends Activity implements SensorEventListener, IDo
|
|||
}
|
||||
|
||||
public boolean requestPermission(String p_name) {
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
|
||||
// Not necessary, asked on install already
|
||||
return true;
|
||||
}
|
||||
return PermissionsUtil.requestPermission(p_name, this);
|
||||
}
|
||||
|
||||
if (p_name.equals("RECORD_AUDIO")) {
|
||||
if (ContextCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED) {
|
||||
requestPermissions(new String[] { Manifest.permission.RECORD_AUDIO }, REQUEST_RECORD_AUDIO_PERMISSION);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
public boolean requestPermissions() {
|
||||
return PermissionsUtil.requestManifestPermissions(this);
|
||||
}
|
||||
|
||||
if (p_name.equals("CAMERA")) {
|
||||
if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
|
||||
requestPermissions(new String[] { Manifest.permission.CAMERA }, REQUEST_CAMERA_PERMISSION);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (p_name.equals("VIBRATE")) {
|
||||
if (ContextCompat.checkSelfPermission(this, Manifest.permission.VIBRATE) != PackageManager.PERMISSION_GRANTED) {
|
||||
requestPermissions(new String[] { Manifest.permission.VIBRATE }, REQUEST_VIBRATE_PERMISSION);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
public String[] getGrantedPermissions() {
|
||||
return PermissionsUtil.getGrantedPermissions(this);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -0,0 +1,157 @@
|
|||
package org.godotengine.godot.utils;
|
||||
|
||||
import android.Manifest;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.PermissionInfo;
|
||||
import android.os.Build;
|
||||
import android.support.v4.content.ContextCompat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import org.godotengine.godot.Godot;
|
||||
|
||||
/**
|
||||
* This class includes utility functions for Android permissions related operations.
|
||||
* @author Cagdas Caglak <cagdascaglak@gmail.com>
|
||||
*/
|
||||
public final class PermissionsUtil {
|
||||
|
||||
static final int REQUEST_RECORD_AUDIO_PERMISSION = 1;
|
||||
static final int REQUEST_CAMERA_PERMISSION = 2;
|
||||
static final int REQUEST_VIBRATE_PERMISSION = 3;
|
||||
static final int REQUEST_ALL_PERMISSION_REQ_CODE = 1001;
|
||||
|
||||
private PermissionsUtil() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Request a dangerous permission. name must be specified in <a href="https://github.com/aosp-mirror/platform_frameworks_base/blob/master/core/res/AndroidManifest.xml">this</a>
|
||||
* @param name the name of the requested permission.
|
||||
* @param activity the caller activity for this method.
|
||||
* @return true/false. "true" if permission was granted otherwise returns "false".
|
||||
*/
|
||||
public static boolean requestPermission(String name, Godot activity) {
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
|
||||
// Not necessary, asked on install already
|
||||
return true;
|
||||
}
|
||||
|
||||
if (name.equals("RECORD_AUDIO") && ContextCompat.checkSelfPermission(activity, Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED) {
|
||||
activity.requestPermissions(new String[] { Manifest.permission.RECORD_AUDIO }, REQUEST_RECORD_AUDIO_PERMISSION);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (name.equals("CAMERA") && ContextCompat.checkSelfPermission(activity, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
|
||||
activity.requestPermissions(new String[] { Manifest.permission.CAMERA }, REQUEST_CAMERA_PERMISSION);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (name.equals("VIBRATE") && ContextCompat.checkSelfPermission(activity, Manifest.permission.VIBRATE) != PackageManager.PERMISSION_GRANTED) {
|
||||
activity.requestPermissions(new String[] { Manifest.permission.VIBRATE }, REQUEST_VIBRATE_PERMISSION);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Request dangerous permissions which are defined in the Android manifest file from the user.
|
||||
* @param activity the caller activity for this method.
|
||||
* @return true/false. "true" if all permissions were granted otherwise returns "false".
|
||||
*/
|
||||
public static boolean requestManifestPermissions(Godot activity) {
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
|
||||
return true;
|
||||
}
|
||||
|
||||
String[] manifestPermissions;
|
||||
try {
|
||||
manifestPermissions = getManifestPermissions(activity);
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (manifestPermissions == null || manifestPermissions.length == 0)
|
||||
return true;
|
||||
|
||||
List<String> dangerousPermissions = new ArrayList<>();
|
||||
for (String manifestPermission : manifestPermissions) {
|
||||
try {
|
||||
PermissionInfo permissionInfo = getPermissionInfo(activity, manifestPermission);
|
||||
int protectionLevel = Build.VERSION.SDK_INT >= Build.VERSION_CODES.P ? permissionInfo.getProtection() : permissionInfo.protectionLevel;
|
||||
if (protectionLevel == PermissionInfo.PROTECTION_DANGEROUS && ContextCompat.checkSelfPermission(activity, manifestPermission) != PackageManager.PERMISSION_GRANTED) {
|
||||
dangerousPermissions.add(manifestPermission);
|
||||
}
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (dangerousPermissions.isEmpty()) {
|
||||
// If list is empty, all of dangerous permissions were granted.
|
||||
return true;
|
||||
}
|
||||
|
||||
String[] requestedPermissions = dangerousPermissions.toArray(new String[0]);
|
||||
activity.requestPermissions(requestedPermissions, REQUEST_ALL_PERMISSION_REQ_CODE);
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* With this function you can get the list of dangerous permissions that have been granted to the Android application.
|
||||
* @param activity the caller activity for this method.
|
||||
* @return granted permissions list
|
||||
*/
|
||||
public static String[] getGrantedPermissions(Godot activity) {
|
||||
String[] manifestPermissions;
|
||||
try {
|
||||
manifestPermissions = getManifestPermissions(activity);
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
return new String[0];
|
||||
}
|
||||
if (manifestPermissions == null || manifestPermissions.length == 0)
|
||||
return new String[0];
|
||||
|
||||
List<String> dangerousPermissions = new ArrayList<>();
|
||||
for (String manifestPermission : manifestPermissions) {
|
||||
try {
|
||||
PermissionInfo permissionInfo = getPermissionInfo(activity, manifestPermission);
|
||||
int protectionLevel = Build.VERSION.SDK_INT >= Build.VERSION_CODES.P ? permissionInfo.getProtection() : permissionInfo.protectionLevel;
|
||||
if (protectionLevel == PermissionInfo.PROTECTION_DANGEROUS && ContextCompat.checkSelfPermission(activity, manifestPermission) == PackageManager.PERMISSION_GRANTED) {
|
||||
dangerousPermissions.add(manifestPermission);
|
||||
}
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
return new String[0];
|
||||
}
|
||||
}
|
||||
|
||||
return dangerousPermissions.toArray(new String[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the permissions defined in the AndroidManifest.xml file.
|
||||
* @param activity the caller activity for this method.
|
||||
* @return manifest permissions list
|
||||
* @throws PackageManager.NameNotFoundException the exception is thrown when a given package, application, or component name cannot be found.
|
||||
*/
|
||||
private static String[] getManifestPermissions(Godot activity) throws PackageManager.NameNotFoundException {
|
||||
PackageManager packageManager = activity.getPackageManager();
|
||||
PackageInfo packageInfo = packageManager.getPackageInfo(activity.getPackageName(), PackageManager.GET_PERMISSIONS);
|
||||
return packageInfo.requestedPermissions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the information of the desired permission.
|
||||
* @param activity the caller activity for this method.
|
||||
* @param permission the name of the permission.
|
||||
* @return permission info object
|
||||
* @throws PackageManager.NameNotFoundException the exception is thrown when a given package, application, or component name cannot be found.
|
||||
*/
|
||||
private static PermissionInfo getPermissionInfo(Godot activity, String permission) throws PackageManager.NameNotFoundException {
|
||||
PackageManager packageManager = activity.getPackageManager();
|
||||
return packageManager.getPermissionInfo(permission, 0);
|
||||
}
|
||||
}
|
|
@ -1393,6 +1393,10 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_requestPermissionResu
|
|||
if (permission == "android.permission.RECORD_AUDIO" && p_result) {
|
||||
AudioDriver::get_singleton()->capture_start();
|
||||
}
|
||||
|
||||
if (os_android->get_main_loop()) {
|
||||
os_android->get_main_loop()->emit_signal("on_request_permissions_result", permission, p_result == JNI_TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_onRendererResumed(JNIEnv *env, jclass clazz) {
|
||||
|
|
|
@ -59,6 +59,8 @@ GodotJavaWrapper::GodotJavaWrapper(JNIEnv *p_env, jobject p_godot_instance) {
|
|||
_get_clipboard = p_env->GetMethodID(cls, "getClipboard", "()Ljava/lang/String;");
|
||||
_set_clipboard = p_env->GetMethodID(cls, "setClipboard", "(Ljava/lang/String;)V");
|
||||
_request_permission = p_env->GetMethodID(cls, "requestPermission", "(Ljava/lang/String;)Z");
|
||||
_request_permissions = p_env->GetMethodID(cls, "requestPermissions", "()Z");
|
||||
_get_granted_permissions = p_env->GetMethodID(cls, "getGrantedPermissions", "()[Ljava/lang/String;");
|
||||
_init_input_devices = p_env->GetMethodID(cls, "initInputDevices", "()V");
|
||||
_get_surface = p_env->GetMethodID(cls, "getSurface", "()Landroid/view/Surface;");
|
||||
_is_activity_resumed = p_env->GetMethodID(cls, "isActivityResumed", "()Z");
|
||||
|
@ -199,6 +201,34 @@ bool GodotJavaWrapper::request_permission(const String &p_name) {
|
|||
}
|
||||
}
|
||||
|
||||
bool GodotJavaWrapper::request_permissions() {
|
||||
if (_request_permissions) {
|
||||
JNIEnv *env = ThreadAndroid::get_env();
|
||||
return env->CallBooleanMethod(godot_instance, _request_permissions);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Vector<String> GodotJavaWrapper::get_granted_permissions() const {
|
||||
Vector<String> permissions_list;
|
||||
if (_get_granted_permissions) {
|
||||
JNIEnv *env = ThreadAndroid::get_env();
|
||||
jobject permissions_object = env->CallObjectMethod(godot_instance, _get_granted_permissions);
|
||||
jobjectArray *arr = reinterpret_cast<jobjectArray *>(&permissions_object);
|
||||
|
||||
int i = 0;
|
||||
jsize len = env->GetArrayLength(*arr);
|
||||
for (i = 0; i < len; i++) {
|
||||
jstring jstr = (jstring)env->GetObjectArrayElement(*arr, i);
|
||||
String str = jstring_to_string(jstr, env);
|
||||
permissions_list.push_back(str);
|
||||
env->DeleteLocalRef(jstr);
|
||||
}
|
||||
}
|
||||
return permissions_list;
|
||||
}
|
||||
|
||||
void GodotJavaWrapper::init_input_devices() {
|
||||
if (_init_input_devices) {
|
||||
JNIEnv *env = ThreadAndroid::get_env();
|
||||
|
|
|
@ -54,6 +54,8 @@ private:
|
|||
jmethodID _get_clipboard = 0;
|
||||
jmethodID _set_clipboard = 0;
|
||||
jmethodID _request_permission = 0;
|
||||
jmethodID _request_permissions = 0;
|
||||
jmethodID _get_granted_permissions = 0;
|
||||
jmethodID _init_input_devices = 0;
|
||||
jmethodID _get_surface = 0;
|
||||
jmethodID _is_activity_resumed = 0;
|
||||
|
@ -81,6 +83,8 @@ public:
|
|||
bool has_set_clipboard();
|
||||
void set_clipboard(const String &p_text);
|
||||
bool request_permission(const String &p_name);
|
||||
bool request_permissions();
|
||||
Vector<String> get_granted_permissions() const;
|
||||
void init_input_devices();
|
||||
jobject get_surface();
|
||||
bool is_activity_resumed();
|
||||
|
|
|
@ -220,6 +220,16 @@ bool OS_Android::request_permission(const String &p_name) {
|
|||
return godot_java->request_permission(p_name);
|
||||
}
|
||||
|
||||
bool OS_Android::request_permissions() {
|
||||
|
||||
return godot_java->request_permissions();
|
||||
}
|
||||
|
||||
Vector<String> OS_Android::get_granted_permissions() const {
|
||||
|
||||
return godot_java->get_granted_permissions();
|
||||
}
|
||||
|
||||
Error OS_Android::open_dynamic_library(const String p_path, void *&p_library_handle, bool p_also_set_library_path) {
|
||||
p_library_handle = dlopen(p_path.utf8().get_data(), RTLD_NOW);
|
||||
ERR_FAIL_COND_V_MSG(!p_library_handle, ERR_CANT_OPEN, "Can't open dynamic library: " + p_path + ", error: " + dlerror() + ".");
|
||||
|
|
|
@ -125,6 +125,8 @@ public:
|
|||
|
||||
virtual void alert(const String &p_alert, const String &p_title = "ALERT!");
|
||||
virtual bool request_permission(const String &p_name);
|
||||
virtual bool request_permissions();
|
||||
virtual Vector<String> get_granted_permissions() const;
|
||||
|
||||
virtual Error open_dynamic_library(const String p_path, void *&p_library_handle, bool p_also_set_library_path = false);
|
||||
|
||||
|
|
Loading…
Reference in a new issue