From f2064549d2dd2ebf5d3605eed36b6562cb9f1410 Mon Sep 17 00:00:00 2001 From: Anish Kumar Date: Sun, 19 Apr 2026 02:37:00 +0530 Subject: [PATCH] Restore Full Storage Access for XR devices to fix build issue --- app/build.gradle | 5 +- app/src/horizonos/AndroidManifest.xml | 11 ++++ app/src/main/AndroidManifest.xml | 6 --- .../BuildEnvironment.kt | 34 ++++++++++-- .../FileUtils.kt | 16 +++++- .../MainActivity.kt | 54 ++++++++++++++++--- .../ProjectInfo.kt | 8 +++ app/src/picoos/AndroidManifest.xml | 11 ++++ 8 files changed, 126 insertions(+), 19 deletions(-) create mode 100644 app/src/horizonos/AndroidManifest.xml create mode 100644 app/src/picoos/AndroidManifest.xml diff --git a/app/build.gradle b/app/build.gradle index 15d2728..dd097a8 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -59,9 +59,12 @@ android { } horizonos { dimension "android_distribution" - applicationIdSuffix ".horizonos" versionNameSuffix "-horizonos" } + picoos { + dimension "android_distribution" + versionNameSuffix "-picoos" + } } compileOptions { diff --git a/app/src/horizonos/AndroidManifest.xml b/app/src/horizonos/AndroidManifest.xml new file mode 100644 index 0000000..49ef05b --- /dev/null +++ b/app/src/horizonos/AndroidManifest.xml @@ -0,0 +1,11 @@ + + + + + + + diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 84e3d0f..2db00b2 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -2,12 +2,6 @@ - - Unit): File { + val workDir = Utils.getProjectCacheDir(context, projectPath, gradleBuildDir) + + if (BuildConfig.FLAVOR == "picoos" || BuildConfig.FLAVOR == "horizonos") { + val sourceDir = File(projectPath, gradleBuildDir) + + if (workDir.exists()) { + val apkAssetsDir = File(workDir, "src/main/assets") + if (apkAssetsDir.exists()) apkAssetsDir.deleteRecursively() + + val aabAssetsDir = File(workDir, "assetPackInstallTime/src/main/assets") + if (aabAssetsDir.exists()) aabAssetsDir.deleteRecursively() + } else { + workDir.mkdirs() + } + + outputHandler(OUTPUT_INFO, "> Importing project files...") + if (!FileUtils.tryCopyDirectory(sourceDir, workDir)) { + throw IOException("Failed to copy $sourceDir to $workDir") + } + + ProjectInfo.writeToDirectoryXR(workDir, projectPath, gradleBuildDir) + return workDir + } + var projectTreeUri = FileUtils.getProjectTreeUri(context, projectPath) if (projectTreeUri == null) { val notificationPerm = checkSelfPermission(context, Manifest.permission.POST_NOTIFICATIONS) @@ -182,7 +206,7 @@ class BuildEnvironment(private val context: Context, private val rootfs: String, projectTreeUri = waitForDirectoryAccess(DIR_ACCESS_WAIT_DURATION) ?: throw Exception("Directory access not granted in time. Build canceled.") - outputHandler(OUTPUT_INFO, "Access granted for $projectPath. Starting Gradle build...") + outputHandler(OUTPUT_INFO, "Access granted for $projectPath.\nStarting Gradle build...") FileUtils.saveProjectTreeUri(context, projectPath, projectTreeUri) // Notify user if limit is reached so they can clear older projects. @@ -197,7 +221,6 @@ class BuildEnvironment(private val context: Context, private val rootfs: String, } } - val workDir = Utils.getProjectCacheDir(context, projectPath, gradleBuildDir) if (!workDir.exists()) { workDir.mkdirs() ProjectInfo.writeToDirectory(context, workDir, projectPath, gradleBuildDir, projectTreeUri) @@ -425,7 +448,12 @@ class BuildEnvironment(private val context: Context, private val rootfs: String, outputHandler(type, line) } - val gradleArgs = fixGradleArgs(projectPath, rawGradleArgs) + val gradleArgs = if (BuildConfig.FLAVOR == "picoos" || BuildConfig.FLAVOR == "horizonos") { + // GABE has full storage access on XR devices, so we are not pulling addons dir, or keystore files. + rawGradleArgs + } else { + fixGradleArgs(projectPath, rawGradleArgs) + } var result = executeGradleInternal(gradleArgs, workDir, captureOutputHandler) diff --git a/app/src/main/java/org/godotengine/godot_gradle_build_environment/FileUtils.kt b/app/src/main/java/org/godotengine/godot_gradle_build_environment/FileUtils.kt index 0249093..aae4016 100644 --- a/app/src/main/java/org/godotengine/godot_gradle_build_environment/FileUtils.kt +++ b/app/src/main/java/org/godotengine/godot_gradle_build_environment/FileUtils.kt @@ -22,9 +22,23 @@ object FileUtils { private const val PREF_NAME = "tree_uri_prefs" const val ADDONS_DIR_NAME = "addons" + fun tryCopyDirectory(sourceDir: File, destDir: File): Boolean { + if (!sourceDir.isDirectory) { + Log.e(TAG, "Source directory ${sourceDir.absolutePath} not found") + return false + } + try { + sourceDir.copyRecursively(destDir, overwrite = true) + } catch (e: Exception) { + Log.e(TAG, "Failed to copy: ${e.message}") + return false + } + return true + } + fun tryCopyFile(source: File, dest: File): Boolean { try { - source.copyTo(dest) + source.copyTo(dest, overwrite = true) } catch (e: Exception) { Log.e(TAG, "Failed to copy ${source.absolutePath} to ${dest.absolutePath}: ${e.message}", e) return false diff --git a/app/src/main/java/org/godotengine/godot_gradle_build_environment/MainActivity.kt b/app/src/main/java/org/godotengine/godot_gradle_build_environment/MainActivity.kt index be5eb07..b03798c 100644 --- a/app/src/main/java/org/godotengine/godot_gradle_build_environment/MainActivity.kt +++ b/app/src/main/java/org/godotengine/godot_gradle_build_environment/MainActivity.kt @@ -2,15 +2,20 @@ package org.godotengine.godot_gradle_build_environment import android.Manifest import android.app.AlertDialog +import android.content.Intent import android.content.pm.PackageManager import android.os.Build import android.os.Bundle +import android.os.Environment +import android.provider.Settings import android.widget.Toast import androidx.activity.ComponentActivity import androidx.activity.compose.setContent import androidx.activity.enableEdgeToEdge import androidx.activity.result.contract.ActivityResultContracts +import androidx.annotation.RequiresApi import org.godotengine.godot_gradle_build_environment.ui.theme.GodotGradleBuildEnvironmentTheme +import androidx.core.net.toUri class MainActivity : ComponentActivity() { private val permissionRequestLauncher = @@ -22,12 +27,41 @@ class MainActivity : ComponentActivity() { } } + @RequiresApi(Build.VERSION_CODES.R) + private val manageStorageLauncher = + registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { + if (Environment.isExternalStorageManager()) { + Toast.makeText(this, "Storage Access Granted", Toast.LENGTH_SHORT).show() + } else { + Toast.makeText(this, "Storage Access Denied", Toast.LENGTH_SHORT).show() + } + } + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) enableEdgeToEdge() Utils.createNotificationChannel(this) + if (BuildConfig.FLAVOR == "picoos" || BuildConfig.FLAVOR == "horizonos") { + requestManageStoragePermission() + } else { + requestNotificationPermission() + } + + setContent { + GodotGradleBuildEnvironmentTheme { + MainScreen( + this, + AppPaths.getRootfs(this), + AppPaths.getRootfsReadyFile(this), + SettingsManager(this), + ) + } + } + } + + private fun requestNotificationPermission() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { if (checkSelfPermission(Manifest.permission.POST_NOTIFICATIONS) != PackageManager.PERMISSION_GRANTED) { AlertDialog.Builder(this) @@ -41,15 +75,19 @@ class MainActivity : ComponentActivity() { .show() } } + } - setContent { - GodotGradleBuildEnvironmentTheme { - MainScreen( - this, - AppPaths.getRootfs(this), - AppPaths.getRootfsReadyFile(this), - SettingsManager(this), - ) + private fun requestManageStoragePermission() { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { + if (!Environment.isExternalStorageManager()) { + val intent = Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION).apply { + data = "package:${packageName}".toUri() + } + manageStorageLauncher.launch(intent) + } + } else { + if (checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { + permissionRequestLauncher.launch(Manifest.permission.WRITE_EXTERNAL_STORAGE) } } } diff --git a/app/src/main/java/org/godotengine/godot_gradle_build_environment/ProjectInfo.kt b/app/src/main/java/org/godotengine/godot_gradle_build_environment/ProjectInfo.kt index 8e63cdc..8a66e2d 100644 --- a/app/src/main/java/org/godotengine/godot_gradle_build_environment/ProjectInfo.kt +++ b/app/src/main/java/org/godotengine/godot_gradle_build_environment/ProjectInfo.kt @@ -36,6 +36,14 @@ data class ProjectInfo( file.writeText(jsonString) } + fun writeToDirectoryXR(directory: File, projectPath: String, gradleBuildDir: String) { + val name = File(projectPath).name + val projectInfo = ProjectInfo(projectPath, gradleBuildDir, "", name) + val jsonString = json.encodeToString(projectInfo) + val file = File(directory, PROJECT_INFO_FILENAME) + file.writeText(jsonString) + } + fun readFromDirectory(directory: File): ProjectInfo? { val file = File(directory, PROJECT_INFO_FILENAME) return if (file.exists()) { diff --git a/app/src/picoos/AndroidManifest.xml b/app/src/picoos/AndroidManifest.xml new file mode 100644 index 0000000..49ef05b --- /dev/null +++ b/app/src/picoos/AndroidManifest.xml @@ -0,0 +1,11 @@ + + + + + + +