From af2423ba4d04ed85a5be82db70a76bab60f137dd Mon Sep 17 00:00:00 2001 From: Fredia Huya-Kouadio Date: Sun, 29 Sep 2024 18:06:11 -0700 Subject: [PATCH] Enable automatic install of export apks for the Android editor --- platform/android/export/export.cpp | 4 +++- platform/android/export/export_plugin.cpp | 8 ++++++++ .../java/editor/src/main/AndroidManifest.xml | 1 + .../org/godotengine/editor/BaseGodotEditor.kt | 20 ++++++++++++++----- .../editor/src/main/res/values/strings.xml | 1 + .../godot/utils/PermissionsUtil.java | 16 ++++++++++++--- .../java/nativeSrcsConfigs/CMakeLists.txt | 2 +- 7 files changed, 42 insertions(+), 10 deletions(-) diff --git a/platform/android/export/export.cpp b/platform/android/export/export.cpp index 93ac498ab3e1..d2b64c74a46b 100644 --- a/platform/android/export/export.cpp +++ b/platform/android/export/export.cpp @@ -49,7 +49,9 @@ void register_android_exporter() { EDITOR_DEF_BASIC("export/android/debug_keystore_pass", DEFAULT_ANDROID_KEYSTORE_DEBUG_PASSWORD); EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::STRING, "export/android/debug_keystore_pass", PROPERTY_HINT_PASSWORD)); -#ifndef ANDROID_ENABLED +#ifdef ANDROID_ENABLED + EDITOR_DEF_BASIC("export/android/install_exported_apk", true); +#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)); EDITOR_DEF_BASIC("export/android/android_sdk_path", OS::get_singleton()->get_environment("ANDROID_HOME")); diff --git a/platform/android/export/export_plugin.cpp b/platform/android/export/export_plugin.cpp index 41f460ca8f3d..aa5f4ee1b7cc 100644 --- a/platform/android/export/export_plugin.cpp +++ b/platform/android/export/export_plugin.cpp @@ -2887,6 +2887,14 @@ Error EditorExportPlatformAndroid::sign_apk(const Ref &p_pre #endif print_verbose("Successfully completed signing build."); + +#ifdef ANDROID_ENABLED + bool prompt_apk_install = EDITOR_GET("export/android/install_exported_apk"); + if (prompt_apk_install) { + OS_Android::get_singleton()->shell_open(apk_path); + } +#endif + return OK; } diff --git a/platform/android/java/editor/src/main/AndroidManifest.xml b/platform/android/java/editor/src/main/AndroidManifest.xml index a87574586053..c1eb03b31f36 100644 --- a/platform/android/java/editor/src/main/AndroidManifest.xml +++ b/platform/android/java/editor/src/main/AndroidManifest.xml @@ -25,6 +25,7 @@ + = Build.VERSION_CODES.R) { - if (!Environment.isExternalStorageManager()) { + when (requestCode) { + PermissionsUtil.REQUEST_MANAGE_EXTERNAL_STORAGE_REQ_CODE -> { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R && !Environment.isExternalStorageManager()) { Toast.makeText( this, R.string.denied_storage_permission_error_msg, @@ -463,6 +463,16 @@ abstract class BaseGodotEditor : GodotActivity() { ).show() } } + + PermissionsUtil.REQUEST_INSTALL_PACKAGES_REQ_CODE -> { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && !packageManager.canRequestPackageInstalls()) { + Toast.makeText( + this, + R.string.denied_install_packages_permission_error_msg, + Toast.LENGTH_LONG + ).show() + } + } } } @@ -514,7 +524,7 @@ abstract class BaseGodotEditor : GodotActivity() { override fun supportsFeature(featureTag: String): Boolean { if (featureTag == "xr_editor") { - return isNativeXRDevice(); + return isNativeXRDevice() } if (featureTag == "horizonos") { diff --git a/platform/android/java/editor/src/main/res/values/strings.xml b/platform/android/java/editor/src/main/res/values/strings.xml index 0ad54ac3a137..a25b6c0a2d9e 100644 --- a/platform/android/java/editor/src/main/res/values/strings.xml +++ b/platform/android/java/editor/src/main/res/values/strings.xml @@ -2,5 +2,6 @@ Godot Play window Missing storage access permission! + Missing install packages permission! Button used to toggle picture-in-picture mode for the Play window 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 c44a6dd4726b..885873e46df5 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 @@ -49,7 +49,6 @@ import java.util.ArrayList; import java.util.Arrays; -import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; @@ -66,6 +65,7 @@ public final class PermissionsUtil { public static final int REQUEST_ALL_PERMISSION_REQ_CODE = 1001; public static final int REQUEST_SINGLE_PERMISSION_REQ_CODE = 1002; public static final int REQUEST_MANAGE_EXTERNAL_STORAGE_REQ_CODE = 2002; + public static final int REQUEST_INSTALL_PACKAGES_REQ_CODE = 3002; private PermissionsUtil() { } @@ -105,6 +105,16 @@ public static boolean requestPermissions(Activity activity, List permiss activity.startActivityForResult(intent, REQUEST_MANAGE_EXTERNAL_STORAGE_REQ_CODE); } } + } else if (permission.equals(Manifest.permission.REQUEST_INSTALL_PACKAGES)) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && !activity.getPackageManager().canRequestPackageInstalls()) { + try { + 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); + } catch (Exception e) { + Log.e(TAG, "Unable to request permission " + Manifest.permission.REQUEST_INSTALL_PACKAGES); + } + } } else { PermissionInfo permissionInfo = getPermissionInfo(activity, permission); int protectionLevel = Build.VERSION.SDK_INT >= Build.VERSION_CODES.P ? permissionInfo.getProtection() : permissionInfo.protectionLevel; @@ -215,7 +225,7 @@ public static boolean requestManifestPermissions(Activity activity, @Nullable Se try { manifestPermissions = getManifestPermissions(activity); } catch (PackageManager.NameNotFoundException e) { - e.printStackTrace(); + Log.e(TAG, "Unable to retrieve manifest permissions", e); return false; } @@ -242,7 +252,7 @@ public static String[] getGrantedPermissions(Context context) { try { manifestPermissions = getManifestPermissions(context); } catch (PackageManager.NameNotFoundException e) { - e.printStackTrace(); + Log.e(TAG, "Unable to retrieve manifest permissions", e); return new String[0]; } if (manifestPermissions.isEmpty()) { diff --git a/platform/android/java/nativeSrcsConfigs/CMakeLists.txt b/platform/android/java/nativeSrcsConfigs/CMakeLists.txt index a7d2774db55d..a5ecafeb09d1 100644 --- a/platform/android/java/nativeSrcsConfigs/CMakeLists.txt +++ b/platform/android/java/nativeSrcsConfigs/CMakeLists.txt @@ -21,4 +21,4 @@ target_include_directories(${PROJECT_NAME} ${ANDROID_ROOT_DIR} ${OPENXR_INCLUDE_DIR}) -add_definitions(-DUNIX_ENABLED -DVULKAN_ENABLED -DANDROID_ENABLED -DGLES3_ENABLED -DTOOLS_ENABLED) +add_definitions(-DUNIX_ENABLED -DVULKAN_ENABLED -DANDROID_ENABLED -DGLES3_ENABLED -DTOOLS_ENABLED -DDEBUG_ENABLED)