Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -270,7 +270,7 @@ class BuildEnvironment(private val context: Context, private val rootfs: String,
}
}

fun installRootfs(outputHandler: (Int, String) -> Unit) {
fun installRootfs(localUri: Uri? = null, outputHandler: (Int, String) -> Unit) {
val rootfs = File(this.rootfs)

if (rootfs.exists()) {
Expand All @@ -280,34 +280,39 @@ class BuildEnvironment(private val context: Context, private val rootfs: String,

rootfs.mkdirs()

val hasAsset = try {
context.assets.list("linux-rootfs")?.contains(ROOTFS_FILENAME) == true
} catch (e: Exception) {
false
}

val version: String
if (hasAsset) {
outputHandler(OUTPUT_INFO, "> Extracting rootfs from assets...")
TarXzExtractor.extractAssetTarXz(context, ROOTFS_ASSET_PATH, rootfs)
Comment on lines -290 to -292

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd really like to be able to keep the ability to get this from the APK's assets. I use this when working on the rootfs itself, and it makes it very easy to quickly test changes.

Could we keep this in the else branch if the localUri is null?

if (localUri != null) {
outputHandler(OUTPUT_INFO, "> Extracting rootfs from local file...")
TarXzExtractor.extractLocalTarXz(context, localUri, rootfs)
version = ROOTFS_VERSION_CUSTOM
} else {
val tempFile = File(context.cacheDir, ROOTFS_FILENAME)
try {
val releaseTag = GitHubReleaseDownloader.downloadLatestReleaseAsset(
ROOTFS_GITHUB_REPO,
ROOTFS_FILENAME,
tempFile
) { message ->
outputHandler(OUTPUT_INFO, message)
}
version = releaseTag
val hasAsset = try {
context.assets.list("linux-rootfs")?.contains(ROOTFS_FILENAME) == true
} catch (e: Exception) {
false
}
if (hasAsset) {
outputHandler(OUTPUT_INFO, "> Extracting rootfs from assets...")
TarXzExtractor.extractAssetTarXz(context, ROOTFS_ASSET_PATH, rootfs)
version = ROOTFS_VERSION_CUSTOM
} else {
val tempFile = File(context.cacheDir, ROOTFS_FILENAME)
try {
val releaseTag = GitHubReleaseDownloader.downloadLatestReleaseAsset(
ROOTFS_GITHUB_REPO,
ROOTFS_FILENAME,
tempFile
) { message ->
outputHandler(OUTPUT_INFO, message)
}
version = releaseTag

outputHandler(OUTPUT_INFO, "> Extracting rootfs...")
TarXzExtractor.extractFileTarXz(tempFile, rootfs)
} finally {
if (tempFile.exists()) {
tempFile.delete()
outputHandler(OUTPUT_INFO, "> Extracting rootfs...")
TarXzExtractor.extractFileTarXz(tempFile, rootfs)
} finally {
if (tempFile.exists()) {
tempFile.delete()
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ class BuildEnvironmentService : Service() {
const val MSG_INSTALL_ROOTFS = 7
const val MSG_DELETE_ROOTFS = 8
const val MSG_BUILD_DIR_ACCESS_GRANTED = 9

const val EXTRA_LOCAL_ROOTFS_URI = "local_rootfs_uri"
}

private lateinit var mMessenger: Messenger
Expand Down Expand Up @@ -195,9 +197,10 @@ class BuildEnvironmentService : Service() {
val id = msg.arg1
var result = 0
var errorMessage: String? = null
val localUri = msg.data.getString(EXTRA_LOCAL_ROOTFS_URI)?.toUri()

try {
mBuildEnvironment.installRootfs { type, line ->
mBuildEnvironment.installRootfs(localUri) { type, line ->
val outputMsg = Message.obtain(null, MSG_COMMAND_OUTPUT, id, type)
val outputData = Bundle()
outputData.putString("line", line)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,6 @@ class MainActivity : ComponentActivity() {
GodotGradleBuildEnvironmentTheme {
MainScreen(
this,
AppPaths.getRootfs(this),
AppPaths.getRootfsReadyFile(this),
SettingsManager(this),
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@ enum class AppTab(
@Composable
fun MainScreen(
context: Context,
rootfs: File,
rootfsReadyFile: File,
settingsManager: SettingsManager,
) {
Expand Down Expand Up @@ -75,7 +74,6 @@ fun MainScreen(

AppTab.ROOTFS -> RootfsScreen(
context = context,
rootfs = rootfs,
rootfsReadyFile = rootfsReadyFile,
modifier = Modifier.padding(innerPadding)
)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,27 @@
package org.godotengine.godot_gradle_build_environment

import android.content.Context
import android.net.Uri
import android.system.ErrnoException
import android.system.Os
import org.apache.commons.compress.archivers.tar.TarArchiveInputStream
import org.apache.commons.compress.compressors.xz.XZCompressorInputStream
import java.io.BufferedInputStream
import java.io.File
import java.io.FileOutputStream
import java.io.IOException
import java.io.InputStream

object TarXzExtractor {
fun extractLocalTarXz(context: Context, localTarXzUri: Uri, destDir: File) {
context.contentResolver.openInputStream(localTarXzUri).use { inputStream ->
if (inputStream == null) {
throw IOException("Failed to open local rootfs file")
}
extractTarXz(inputStream, destDir)
}
}

fun extractAssetTarXz(context: Context, assetTarXz: String, destDir: File) {
context.assets.open(assetTarXz).use { inputStream ->
extractTarXz(inputStream, destDir)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,16 @@ import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.content.ServiceConnection
import android.net.Uri
import android.os.Bundle
import android.os.Handler
import android.os.IBinder
import android.os.Looper
import android.os.Message
import android.os.Messenger
import android.util.Log
import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.result.contract.ActivityResultContracts
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
Expand All @@ -23,6 +27,7 @@ import androidx.compose.material3.Card
import androidx.compose.material3.CardDefaults
import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedButton
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
Expand All @@ -48,7 +53,6 @@ import java.io.File
@Composable
fun RootfsScreen(
context: Context,
rootfs: File,
rootfsReadyFile: File,
modifier: Modifier = Modifier
) {
Expand Down Expand Up @@ -133,7 +137,6 @@ fun RootfsScreen(
) {
RootfsInstallOrDeleteButton(
context,
rootfs,
rootfsReadyFile,
)
}
Expand All @@ -143,7 +146,6 @@ fun RootfsScreen(
@Composable
fun RootfsInstallOrDeleteButton(
context: Context,
rootfs: File,
rootfsReadyFile: File,
) {
var fileExists by remember { mutableStateOf(rootfsReadyFile.exists()) }
Expand All @@ -155,6 +157,41 @@ fun RootfsInstallOrDeleteButton(
var serviceMessenger by remember { mutableStateOf<Messenger?>(null) }
var replyMessenger by remember { mutableStateOf<Messenger?>(null) }

fun sendMessage(msgType: Int, localUri: Uri? = null) {
if (serviceMessenger == null || replyMessenger == null) {
errorMessage = "Service not connected"
return
}

isLoading = true
errorMessage = null
progressMessages = emptyList()
commandId++

val msg = Message.obtain(null, msgType, commandId, 0)
msg.replyTo = replyMessenger

if (localUri != null) {
val data = Bundle()
data.putString(BuildEnvironmentService.EXTRA_LOCAL_ROOTFS_URI, localUri.toString())
msg.data = data
}

try {
serviceMessenger?.send(msg)
} catch (e: Exception) {
Log.e("RootfsScreen", "Error sending message: ${e.message}")
isLoading = false
errorMessage = "Failed to send command: ${e.message}"
}
}

val localFilePicker = rememberLauncherForActivityResult(ActivityResultContracts.OpenDocument()) { uri: Uri? ->
if (uri != null) {
sendMessage(BuildEnvironmentService.MSG_INSTALL_ROOTFS, uri)
}
}

DisposableEffect(context) {
val connection = object : ServiceConnection {
override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
Expand Down Expand Up @@ -202,29 +239,6 @@ fun RootfsInstallOrDeleteButton(
}
}

fun sendMessage(msgType: Int) {
if (serviceMessenger == null || replyMessenger == null) {
errorMessage = "Service not connected"
return
}

isLoading = true
errorMessage = null
progressMessages = emptyList()
commandId++

val msg = Message.obtain(null, msgType, commandId, 0)
msg.replyTo = replyMessenger

try {
serviceMessenger?.send(msg)
} catch (e: Exception) {
Log.e("RootfsScreen", "Error sending message: ${e.message}")
isLoading = false
errorMessage = "Failed to send command: ${e.message}"
}
}

when {
isLoading -> {
CircularProgressIndicator()
Expand Down Expand Up @@ -262,13 +276,19 @@ fun RootfsInstallOrDeleteButton(
}

!fileExists -> {
Text(stringResource(R.string.missing_rootfs_message))
Text(stringResource(R.string.missing_rootfs_message), modifier = Modifier.padding(16.dp))
Spacer(modifier = Modifier.height(20.dp))
Button(onClick = {
sendMessage(BuildEnvironmentService.MSG_INSTALL_ROOTFS)
}) {
Text(stringResource(R.string.install_rootfs_button))
}
Spacer(modifier = Modifier.height(8.dp))
OutlinedButton(onClick = {
localFilePicker.launch(arrayOf("application/x-xz"))
}) {
Text(stringResource(R.string.install_rootfs_local_button))
}
}

else -> {
Expand Down
1 change: 1 addition & 0 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
<string name="app_name">Godot Android Build Environment</string>
<string name="app_launcher_name">GABE</string>
<string name="install_rootfs_button">Install Rootfs</string>
<string name="install_rootfs_local_button">Install from local file</string>
<string name="delete_rootfs_button">Delete Rootfs</string>
<string name="installing_rootfs_message">Installing rootfs...\nThis may take several minutes.</string>
<string name="deleting_rootfs_message">Deleting rootfs...</string>
Expand Down
Loading