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); } /**