diff --git a/platform/android/export/export.cpp b/platform/android/export/export.cpp
index dc7a287a918..7aba3d7a9a9 100644
--- a/platform/android/export/export.cpp
+++ b/platform/android/export/export.cpp
@@ -52,7 +52,7 @@ void register_android_exporter() {
EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::STRING, "export/android/debug_keystore_pass", PROPERTY_HINT_PASSWORD));
#ifdef ANDROID_ENABLED
- EDITOR_DEF_BASIC("export/android/install_exported_apk", true);
+ EDITOR_DEF_BASIC("export/android/install_exported_apk", !OS::get_singleton()->has_feature("horizonos"));
#else
EDITOR_DEF_BASIC("export/android/java_sdk_path", OS::get_singleton()->get_environment("JAVA_HOME"));
EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::STRING, "export/android/java_sdk_path", PROPERTY_HINT_GLOBAL_DIR));
diff --git a/platform/android/java/editor/src/horizonos/AndroidManifest.xml b/platform/android/java/editor/src/horizonos/AndroidManifest.xml
index 06442ac4e63..68ba11fd843 100644
--- a/platform/android/java/editor/src/horizonos/AndroidManifest.xml
+++ b/platform/android/java/editor/src/horizonos/AndroidManifest.xml
@@ -34,6 +34,9 @@
+
+
+
{
- return mutableSetOf(
+ val excludedPermissions = mutableSetOf(
// The RECORD_AUDIO permission is requested when the "audio/driver/enable_input" project
// setting is enabled.
- Manifest.permission.RECORD_AUDIO
+ Manifest.permission.RECORD_AUDIO,
)
+
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+ excludedPermissions.add(
+ // The REQUEST_INSTALL_PACKAGES permission is requested the first time we attempt to
+ // open an apk file.
+ Manifest.permission.REQUEST_INSTALL_PACKAGES,
+ )
+ }
+ return excludedPermissions
}
override fun onCreate(savedInstanceState: Bundle?) {
diff --git a/platform/android/java/lib/src/org/godotengine/godot/Godot.kt b/platform/android/java/lib/src/org/godotengine/godot/Godot.kt
index dd05559f59a..fcbb8830f90 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/Godot.kt
+++ b/platform/android/java/lib/src/org/godotengine/godot/Godot.kt
@@ -1039,7 +1039,8 @@ class Godot(private val context: Context) {
}
fun requestPermission(name: String?): Boolean {
- return requestPermission(name, getActivity())
+ val activity = getActivity() ?: return false
+ return requestPermission(name, activity)
}
fun requestPermissions(): Boolean {
diff --git a/platform/android/java/lib/src/org/godotengine/godot/GodotIO.java b/platform/android/java/lib/src/org/godotengine/godot/GodotIO.java
index 026bb3f1476..e3df9879776 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/GodotIO.java
+++ b/platform/android/java/lib/src/org/godotengine/godot/GodotIO.java
@@ -30,13 +30,12 @@
package org.godotengine.godot;
+import org.godotengine.godot.error.Error;
import org.godotengine.godot.input.GodotEditText;
import android.app.Activity;
-import android.content.ActivityNotFoundException;
import android.content.Intent;
import android.content.pm.ActivityInfo;
-import android.graphics.Point;
import android.graphics.Rect;
import android.net.Uri;
import android.os.Build;
@@ -47,7 +46,6 @@ import android.util.DisplayMetrics;
import android.util.Log;
import android.view.Display;
import android.view.DisplayCutout;
-import android.view.Surface;
import android.view.WindowInsets;
import androidx.core.content.FileProvider;
@@ -121,10 +119,10 @@ public class GodotIO {
}
activity.startActivity(intent);
- return 0;
+ return Error.OK.toNativeValue();
} catch (Exception e) {
Log.e(TAG, "Unable to open uri " + uriString, e);
- return 1;
+ return Error.FAILED.toNativeValue();
}
}
diff --git a/platform/android/java/lib/src/org/godotengine/godot/error/Error.kt b/platform/android/java/lib/src/org/godotengine/godot/error/Error.kt
index 00ef5ee3413..f24d4dc2922 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/error/Error.kt
+++ b/platform/android/java/lib/src/org/godotengine/godot/error/Error.kt
@@ -92,7 +92,7 @@ enum class Error(private val description: String) {
}
}
- internal fun toNativeValue(): Int = this.ordinal
+ fun toNativeValue(): Int = this.ordinal
override fun toString(): String {
return description
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
index 885873e46df..82dafeef8bb 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/utils/PermissionsUtil.java
+++ b/platform/android/java/lib/src/org/godotengine/godot/utils/PermissionsUtil.java
@@ -44,11 +44,13 @@ import android.provider.Settings;
import android.text.TextUtils;
import android.util.Log;
+import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.content.ContextCompat;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
@@ -76,11 +78,11 @@ public final class PermissionsUtil {
* @param activity the caller activity for this method.
* @return true/false. "true" if permissions are already granted, "false" if a permissions request was dispatched.
*/
- public static boolean requestPermissions(Activity activity, List permissions) {
- if (activity == null) {
- return false;
- }
+ public static boolean requestPermissions(@NonNull Activity activity, List permissions) {
+ return requestPermissions(activity, permissions, REQUEST_ALL_PERMISSION_REQ_CODE);
+ }
+ private static boolean requestPermissions(@NonNull Activity activity, List permissions, int requestCode) {
if (permissions == null || permissions.isEmpty()) {
return true;
}
@@ -90,6 +92,7 @@ public final class PermissionsUtil {
return true;
}
+ boolean dispatchedPermissionsRequest = false;
Set requestedPermissions = new HashSet<>();
for (String permission : permissions) {
try {
@@ -104,6 +107,7 @@ public final class PermissionsUtil {
Intent intent = new Intent(Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION);
activity.startActivityForResult(intent, REQUEST_MANAGE_EXTERNAL_STORAGE_REQ_CODE);
}
+ dispatchedPermissionsRequest = true;
}
} else if (permission.equals(Manifest.permission.REQUEST_INSTALL_PACKAGES)) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && !activity.getPackageManager().canRequestPackageInstalls()) {
@@ -111,6 +115,7 @@ public final class PermissionsUtil {
Intent intent = new Intent(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES);
intent.setData(Uri.parse(String.format("package:%s", activity.getPackageName())));
activity.startActivityForResult(intent, REQUEST_INSTALL_PACKAGES_REQ_CODE);
+ dispatchedPermissionsRequest = true;
} catch (Exception e) {
Log.e(TAG, "Unable to request permission " + Manifest.permission.REQUEST_INSTALL_PACKAGES);
}
@@ -129,13 +134,12 @@ public final class PermissionsUtil {
}
}
- if (requestedPermissions.isEmpty()) {
- // If list is empty, all of dangerous permissions were granted.
- return true;
+ if (!requestedPermissions.isEmpty()) {
+ activity.requestPermissions(requestedPermissions.toArray(new String[0]), requestCode);
+ dispatchedPermissionsRequest = true;
}
- activity.requestPermissions(requestedPermissions.toArray(new String[0]), REQUEST_ALL_PERMISSION_REQ_CODE);
- return false;
+ return !dispatchedPermissionsRequest;
}
/**
@@ -144,57 +148,37 @@ public final class PermissionsUtil {
* @param activity the caller activity for this method.
* @return true/false. "true" if permission is already granted, "false" if a permission request was dispatched.
*/
- public static boolean requestPermission(String permissionName, Activity activity) {
- if (activity == null || TextUtils.isEmpty(permissionName)) {
- return false;
- }
-
- if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
- // Not necessary, asked on install already
+ public static boolean requestPermission(String permissionName, @NonNull Activity activity) {
+ if (TextUtils.isEmpty(permissionName)) {
return true;
}
+ final int requestCode;
+ final String updatedPermissionName;
switch (permissionName) {
case "RECORD_AUDIO":
- case Manifest.permission.RECORD_AUDIO:
- if (ContextCompat.checkSelfPermission(activity, Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED) {
- activity.requestPermissions(new String[] { Manifest.permission.RECORD_AUDIO }, REQUEST_RECORD_AUDIO_PERMISSION);
- return false;
- }
- return true;
+ updatedPermissionName = Manifest.permission.RECORD_AUDIO;
+ requestCode = REQUEST_RECORD_AUDIO_PERMISSION;
+ break;
case "CAMERA":
- case Manifest.permission.CAMERA:
- if (ContextCompat.checkSelfPermission(activity, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
- activity.requestPermissions(new String[] { Manifest.permission.CAMERA }, REQUEST_CAMERA_PERMISSION);
- return false;
- }
- return true;
+ updatedPermissionName = Manifest.permission.CAMERA;
+ requestCode = REQUEST_CAMERA_PERMISSION;
+ break;
case "VIBRATE":
- case Manifest.permission.VIBRATE:
- if (ContextCompat.checkSelfPermission(activity, Manifest.permission.VIBRATE) != PackageManager.PERMISSION_GRANTED) {
- activity.requestPermissions(new String[] { Manifest.permission.VIBRATE }, REQUEST_VIBRATE_PERMISSION);
- return false;
- }
- return true;
+ updatedPermissionName = Manifest.permission.VIBRATE;
+ requestCode = REQUEST_VIBRATE_PERMISSION;
+ break;
default:
- // Check if the given permission is a dangerous permission
- try {
- PermissionInfo permissionInfo = getPermissionInfo(activity, permissionName);
- int protectionLevel = Build.VERSION.SDK_INT >= Build.VERSION_CODES.P ? permissionInfo.getProtection() : permissionInfo.protectionLevel;
- if ((protectionLevel & PermissionInfo.PROTECTION_DANGEROUS) == PermissionInfo.PROTECTION_DANGEROUS && ContextCompat.checkSelfPermission(activity, permissionName) != PackageManager.PERMISSION_GRANTED) {
- activity.requestPermissions(new String[] { permissionName }, REQUEST_SINGLE_PERMISSION_REQ_CODE);
- return false;
- }
- } catch (PackageManager.NameNotFoundException e) {
- // Unknown permission - return false as it can't be granted.
- Log.w(TAG, "Unable to identify permission " + permissionName, e);
- return false;
- }
- return true;
+ updatedPermissionName = permissionName;
+ requestCode = REQUEST_SINGLE_PERMISSION_REQ_CODE;
+ break;
}
+
+ List permissions = Collections.singletonList(updatedPermissionName);
+ return requestPermissions(activity, permissions, requestCode);
}
/**