summaryrefslogtreecommitdiff
path: root/platform/android/java
diff options
context:
space:
mode:
Diffstat (limited to 'platform/android/java')
-rw-r--r--platform/android/java/app/AndroidManifest.xml7
-rw-r--r--platform/android/java/app/src/com/godot/game/GodotApp.java30
-rw-r--r--platform/android/java/build.gradle87
-rw-r--r--platform/android/java/lib/build.gradle29
-rw-r--r--platform/android/java/lib/res/drawable-hdpi/notify_panel_notification_icon_bg.pngbin1843 -> 1116 bytes
-rw-r--r--platform/android/java/lib/res/drawable-mdpi/notify_panel_notification_icon_bg.pngbin718 -> 388 bytes
-rw-r--r--platform/android/java/lib/res/drawable-xxhdpi/notify_panel_notification_icon_bg.pngbin2830 -> 1556 bytes
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/Godot.java71
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/GodotLib.java5
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/input/GodotInputHandler.java19
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/utils/PermissionsUtil.java157
11 files changed, 332 insertions, 73 deletions
diff --git a/platform/android/java/app/AndroidManifest.xml b/platform/android/java/app/AndroidManifest.xml
index d5f4ba18d6..ba01ec313b 100644
--- a/platform/android/java/app/AndroidManifest.xml
+++ b/platform/android/java/app/AndroidManifest.xml
@@ -26,11 +26,8 @@
<!-- Any tag in this line after android:icon will be erased when doing custom builds. -->
<!-- If you want to add tags manually, do before it. -->
- <application
- android:label="@string/godot_project_name_string"
- android:allowBackup="false"
- tools:ignore="GoogleAppIndexingWarning"
- android:icon="@drawable/icon" >
+ <!-- WARNING: This should stay on a single line until the parsing code is improved. See GH-32414. -->
+ <application android:label="@string/godot_project_name_string" android:allowBackup="false" tools:ignore="GoogleAppIndexingWarning" android:icon="@drawable/icon" >
<!-- The following metadata values are replaced when Godot exports, modifying them here has no effect. -->
<!-- Do these changes in the export preset. Adding new ones is fine. -->
diff --git a/platform/android/java/app/src/com/godot/game/GodotApp.java b/platform/android/java/app/src/com/godot/game/GodotApp.java
index fabd7b1dbb..d7469a8765 100644
--- a/platform/android/java/app/src/com/godot/game/GodotApp.java
+++ b/platform/android/java/app/src/com/godot/game/GodotApp.java
@@ -1,3 +1,33 @@
+/*************************************************************************/
+/* GodotApp.java */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
package com.godot.game;
import org.godotengine.godot.Godot;
diff --git a/platform/android/java/build.gradle b/platform/android/java/build.gradle
index 99ffa937b0..2052017888 100644
--- a/platform/android/java/build.gradle
+++ b/platform/android/java/build.gradle
@@ -20,14 +20,33 @@ allprojects {
}
}
-def binDir = "../../../bin/"
+ext {
+ sconsExt = org.gradle.internal.os.OperatingSystem.current().isWindows() ? ".bat" : ""
+
+ supportedAbis = ["armv7", "arm64v8", "x86", "x86_64"]
+ supportedTargets = ['release':"release", 'debug':"release_debug"]
+
+ // Used by gradle to specify which architecture to build for by default when running `./gradlew build`.
+ // This command is usually used by Android Studio.
+ // If building manually on the command line, it's recommended to use the
+ // `./gradlew generateGodotTemplates` build command instead after running the `scons` command.
+ // The defaultAbi must be one of the {supportedAbis} values.
+ defaultAbi = "arm64v8"
+}
+
+def rootDir = "../../.."
+def binDir = "$rootDir/bin/"
+
+def getSconsTaskName(String buildType) {
+ return "compileGodotNativeLibs" + buildType.capitalize()
+}
/**
* Copy the generated 'android_debug.apk' binary template into the Godot bin directory.
* Depends on the app build task to ensure the binary is generated prior to copying.
*/
task copyDebugBinaryToBin(type: Copy) {
- dependsOn ':app:build'
+ dependsOn ':app:assembleDebug'
from('app/build/outputs/apk/debug')
into(binDir)
include('android_debug.apk')
@@ -38,7 +57,7 @@ task copyDebugBinaryToBin(type: Copy) {
* Depends on the app build task to ensure the binary is generated prior to copying.
*/
task copyReleaseBinaryToBin(type: Copy) {
- dependsOn ':app:build'
+ dependsOn ':app:assembleRelease'
from('app/build/outputs/apk/release')
into(binDir)
include('android_release.apk')
@@ -49,7 +68,7 @@ task copyReleaseBinaryToBin(type: Copy) {
* Depends on the library build task to ensure the AAR file is generated prior to copying.
*/
task copyDebugAAR(type: Copy) {
- dependsOn ':lib:build'
+ dependsOn ':lib:assembleDebug'
from('lib/build/outputs/aar')
into('app/libs/debug')
include('godot-lib.debug.aar')
@@ -60,7 +79,7 @@ task copyDebugAAR(type: Copy) {
* Depends on the library build task to ensure the AAR file is generated prior to copying.
*/
task copyReleaseAAR(type: Copy) {
- dependsOn ':lib:build'
+ dependsOn ':lib:assembleRelease'
from('lib/build/outputs/aar')
into('app/libs/release')
include('godot-lib.release.aar')
@@ -72,8 +91,10 @@ task copyReleaseAAR(type: Copy) {
* The zip file also includes some gradle tools to allow building of the custom build.
*/
task zipCustomBuild(type: Zip) {
- dependsOn 'copyDebugAAR'
- dependsOn 'copyReleaseAAR'
+ dependsOn ':generateGodotTemplates'
+ doFirst {
+ logger.lifecycle("Generating Godot custom build template")
+ }
from(fileTree(dir: 'app', excludes: ['**/build/**', '**/.gradle/**', '**/*.iml']), fileTree(dir: '.', includes: ['gradle.properties','gradlew', 'gradlew.bat', 'gradle/**']))
include '**/*'
archiveName 'android_source.zip'
@@ -84,12 +105,48 @@ task zipCustomBuild(type: Zip) {
* Master task used to coordinate the tasks defined above to generate the set of Godot templates.
*/
task generateGodotTemplates(type: GradleBuild) {
- tasks = [
- // Copy the generated aar library files to the custom build directory.
- 'copyDebugAAR', 'copyReleaseAAR',
- // Zip the custom build directory.
- 'zipCustomBuild',
- // Copy the prebuilt binary templates to the bin directory.
- 'copyDebugBinaryToBin', 'copyReleaseBinaryToBin',
- ]
+ // We exclude these gradle tasks so we can run the scons command manually.
+ for (String buildType : supportedTargets.keySet()) {
+ startParameter.excludedTaskNames += ":lib:" + getSconsTaskName(buildType)
+ }
+
+ tasks = []
+
+ // Only build the apks and aar files for which we have native shared libraries.
+ for (String target : supportedTargets.keySet()) {
+ File targetLibs = new File("lib/libs/" + target)
+ if (targetLibs != null && targetLibs.isDirectory()) {
+ File[] targetLibsContents = targetLibs.listFiles()
+ if (targetLibsContents != null && targetLibsContents.length > 0) {
+ // Copy the generated aar library files to the custom build directory.
+ tasks += "copy" + target.capitalize() + "AAR"
+ // Copy the prebuilt binary templates to the bin directory.
+ tasks += "copy" + target.capitalize() + "BinaryToBin"
+ }
+ }
+ }
+
+ finalizedBy 'zipCustomBuild'
+}
+
+/**
+ * Clean the generated artifacts.
+ */
+task cleanGodotTemplates(type: Delete) {
+ // Delete the generated native libs
+ delete("lib/libs")
+
+ // Delete the library generated AAR files
+ delete("lib/build/outputs/aar")
+
+ // Delete the app libs directory contents
+ delete("app/libs")
+
+ // Delete the generated binary apks
+ delete("app/build/outputs/apk")
+
+ // Delete the Godot templates in the Godot bin directory
+ delete("$binDir/android_debug.apk")
+ delete("$binDir/android_release.apk")
+ delete("$binDir/android_source.zip")
}
diff --git a/platform/android/java/lib/build.gradle b/platform/android/java/lib/build.gradle
index 6d07504e45..13a14422ed 100644
--- a/platform/android/java/lib/build.gradle
+++ b/platform/android/java/lib/build.gradle
@@ -5,8 +5,6 @@ dependencies {
}
def pathToRootDir = "../../../../"
-// Note: Only keep the abis you support to speed up the gradle 'assemble' task.
-def supportedAbis = ["armv7", "arm64v8", "x86", "x86_64"]
android {
compileSdkVersion versions.compileSdk
@@ -56,27 +54,20 @@ android {
// files is only setup for editing support.
gradle.startParameter.excludedTaskNames += taskPrefix + "externalNativeBuild" + buildType
- // Create tasks to generate the Godot native libraries.
- def taskName = "compileGodotNativeLibs" + buildType
- def releaseTarget = "release"
- if (buildType == "Debug") {
- releaseTarget += "_debug"
+ def releaseTarget = supportedTargets[buildType.toLowerCase()]
+ if (releaseTarget == null || releaseTarget == "") {
+ throw new GradleException("Invalid build type: " + buildType)
}
- def abiTaskNames = []
- // Creating gradle tasks to generate the native libraries for the supported abis.
- supportedAbis.each { abi ->
- def abiTaskName = taskName + abi.capitalize()
- abiTaskNames += abiTaskName
- tasks.create(name: abiTaskName, type: Exec) {
- executable "scons"
- args "--directory=${pathToRootDir}", "platform=android", "target=${releaseTarget}", "android_arch=${abi}"
- }
+ if (!supportedAbis.contains(defaultAbi)) {
+ throw new GradleException("Invalid default abi: " + defaultAbi)
}
- // Creating gradle task to run all of the previously generated tasks.
- tasks.create(name: taskName, type: GradleBuild) {
- tasks = abiTaskNames
+ // Creating gradle task to generate the native libraries for the default abi.
+ def taskName = getSconsTaskName(buildType)
+ tasks.create(name: taskName, type: Exec) {
+ executable "scons" + sconsExt
+ args "--directory=${pathToRootDir}", "platform=android", "target=${releaseTarget}", "android_arch=${defaultAbi}", "-j" + Runtime.runtime.availableProcessors()
}
// Schedule the tasks so the generated libs are present before the aar file is packaged.
diff --git a/platform/android/java/lib/res/drawable-hdpi/notify_panel_notification_icon_bg.png b/platform/android/java/lib/res/drawable-hdpi/notify_panel_notification_icon_bg.png
index 2c246b04a4..f849d8e90d 100644
--- a/platform/android/java/lib/res/drawable-hdpi/notify_panel_notification_icon_bg.png
+++ b/platform/android/java/lib/res/drawable-hdpi/notify_panel_notification_icon_bg.png
Binary files differ
diff --git a/platform/android/java/lib/res/drawable-mdpi/notify_panel_notification_icon_bg.png b/platform/android/java/lib/res/drawable-mdpi/notify_panel_notification_icon_bg.png
index 8bcd464bed..1dfb28b33a 100644
--- a/platform/android/java/lib/res/drawable-mdpi/notify_panel_notification_icon_bg.png
+++ b/platform/android/java/lib/res/drawable-mdpi/notify_panel_notification_icon_bg.png
Binary files differ
diff --git a/platform/android/java/lib/res/drawable-xxhdpi/notify_panel_notification_icon_bg.png b/platform/android/java/lib/res/drawable-xxhdpi/notify_panel_notification_icon_bg.png
index b458ff3057..302a972049 100644
--- a/platform/android/java/lib/res/drawable-xxhdpi/notify_panel_notification_icon_bg.png
+++ b/platform/android/java/lib/res/drawable-xxhdpi/notify_panel_notification_icon_bg.png
Binary files differ
diff --git a/platform/android/java/lib/src/org/godotengine/godot/Godot.java b/platform/android/java/lib/src/org/godotengine/godot/Godot.java
index 739aa285bf..4dae2dcc53 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/Godot.java
+++ b/platform/android/java/lib/src/org/godotengine/godot/Godot.java
@@ -30,7 +30,6 @@
package org.godotengine.godot;
-import android.Manifest;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.ActivityManager;
@@ -56,12 +55,14 @@ import android.hardware.SensorManager;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
+import android.os.Handler;
+import android.os.Looper;
import android.os.Messenger;
import android.os.VibrationEffect;
import android.os.Vibrator;
import android.provider.Settings.Secure;
import android.support.annotation.Keep;
-import android.support.v4.content.ContextCompat;
+import android.support.annotation.Nullable;
import android.view.Display;
import android.view.KeyEvent;
import android.view.MotionEvent;
@@ -95,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;
@@ -126,6 +125,9 @@ public abstract class Godot extends Activity implements SensorEventListener, IDo
private boolean activityResumed;
private int mState;
+ // Used to dispatch events to the main thread.
+ private final Handler mainThreadHandler = new Handler(Looper.getMainLooper());
+
static private Intent mCurrentIntent;
@Override
@@ -187,6 +189,20 @@ public abstract class Godot extends Activity implements SensorEventListener, IDo
Godot.singletons[Godot.singleton_count++] = this;
}
+ /**
+ * Invoked once during the Godot Android initialization process after creation of the
+ * {@link GodotView} view.
+ * <p>
+ * This method should be overridden by descendants of this class that would like to add
+ * their view/layout to the Godot view hierarchy.
+ *
+ * @return the view to be included; null if no views should be included.
+ */
+ @Nullable
+ protected View onMainCreateView(Activity activity) {
+ return null;
+ }
+
protected void onMainActivityResult(int requestCode, int resultCode, Intent data) {
}
@@ -306,6 +322,20 @@ public abstract class Godot extends Activity implements SensorEventListener, IDo
public void run() {
GodotLib.setup(current_command_line);
setKeepScreenOn("True".equals(GodotLib.getGlobal("display/window/energy_saving/keep_screen_on")));
+
+ // The Godot Android plugins are setup on completion of GodotLib.setup
+ mainThreadHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ // Include the non-null views returned in the Godot view hierarchy.
+ for (int i = 0; i < singleton_count; i++) {
+ View view = singletons[i].onMainCreateView(Godot.this);
+ if (view != null) {
+ layout.addView(view);
+ }
+ }
+ }
+ });
}
});
}
@@ -973,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;
- }
-
- 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;
- }
- }
+ return PermissionsUtil.requestPermission(p_name, 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;
- }
- }
+ public boolean requestPermissions() {
+ return PermissionsUtil.requestManifestPermissions(this);
+ }
- 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);
}
/**
diff --git a/platform/android/java/lib/src/org/godotengine/godot/GodotLib.java b/platform/android/java/lib/src/org/godotengine/godot/GodotLib.java
index 067fa6f4b9..67dce172dc 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/GodotLib.java
+++ b/platform/android/java/lib/src/org/godotengine/godot/GodotLib.java
@@ -95,6 +95,11 @@ public class GodotLib {
public static native void touch(int what, int pointer, int howmany, int[] arr);
/**
+ * Forward hover events from the main thread to the GL thread.
+ */
+ public static native void hover(int type, int x, int y);
+
+ /**
* Forward accelerometer sensor events from the main thread to the GL thread.
* @see android.hardware.SensorEventListener#onSensorChanged(SensorEvent)
*/
diff --git a/platform/android/java/lib/src/org/godotengine/godot/input/GodotInputHandler.java b/platform/android/java/lib/src/org/godotengine/godot/input/GodotInputHandler.java
index a443a0ad90..2756ca6c83 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/input/GodotInputHandler.java
+++ b/platform/android/java/lib/src/org/godotengine/godot/input/GodotInputHandler.java
@@ -96,7 +96,6 @@ public class GodotInputHandler implements InputDeviceListener {
GodotLib.joybutton(device_id, button, false);
}
});
- return true;
}
} else {
final int chr = event.getUnicodeChar(0);
@@ -108,7 +107,7 @@ public class GodotInputHandler implements InputDeviceListener {
});
};
- return false;
+ return true;
}
public boolean onKeyDown(final int keyCode, KeyEvent event) {
@@ -142,7 +141,6 @@ public class GodotInputHandler implements InputDeviceListener {
GodotLib.joybutton(device_id, button, true);
}
});
- return true;
}
} else {
final int chr = event.getUnicodeChar(0);
@@ -154,7 +152,7 @@ public class GodotInputHandler implements InputDeviceListener {
});
};
- return false;
+ return true;
}
public boolean onGenericMotionEvent(MotionEvent event) {
@@ -190,7 +188,18 @@ public class GodotInputHandler implements InputDeviceListener {
}
return true;
}
- };
+ } else if ((event.getSource() & InputDevice.SOURCE_STYLUS) == InputDevice.SOURCE_STYLUS) {
+ final int x = Math.round(event.getX());
+ final int y = Math.round(event.getY());
+ final int type = event.getAction();
+ queueEvent(new Runnable() {
+ @Override
+ public void run() {
+ GodotLib.hover(type, x, y);
+ }
+ });
+ return true;
+ }
return false;
}
diff --git a/platform/android/java/lib/src/org/godotengine/godot/utils/PermissionsUtil.java b/platform/android/java/lib/src/org/godotengine/godot/utils/PermissionsUtil.java
new file mode 100644
index 0000000000..2c4a444e5a
--- /dev/null
+++ b/platform/android/java/lib/src/org/godotengine/godot/utils/PermissionsUtil.java
@@ -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);
+ }
+}