From e1df70ed1f3ffe5642dc4e39bf7e574895d52eeb Mon Sep 17 00:00:00 2001 From: GlobalTechInfo Date: Sun, 2 Aug 2026 23:25:58 +0000 Subject: [PATCH] fix shared storage access inside distros and bump to v1.0.3 - bind /sdcard, /storage and /mnt into the proot terminal session so /storage/emulated/0 is usable inside every distro - request All files access from the terminal screen (was moved to the welcome screen where it could be skipped) and re-ask until granted - swap the left/right arrow triangles in the default extra keys row - bump version to 1.0.3 and update the changelog --- CHANGELOG.md | 12 ++++ app/build.gradle.kts | 4 +- .../com/redtermapp/ui/SettingsActivity.kt | 2 +- .../com/redtermapp/ui/TerminalActivity.kt | 27 +++++++- .../java/com/redtermapp/ui/WelcomeActivity.kt | 42 ------------ .../com/redtermapp/util/StoragePermission.kt | 65 +++++++++++++++++++ 6 files changed, 106 insertions(+), 46 deletions(-) create mode 100644 app/src/main/java/com/redtermapp/util/StoragePermission.kt diff --git a/CHANGELOG.md b/CHANGELOG.md index bd5d8c4..b49089d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,18 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [v1.0.3] + +### Changed + +- **Extra keys**: swapped the positions of the left and right arrow triangles in the default second key row (`◀ ▼ ▶` instead of `▶ ▼ ◀`); Reset in Settings uses the new order too. +- Settings page shows version v1.0.3. + +### Fixed + +- **Shared storage in distros**: the terminal's proot session now binds `/sdcard`, `/storage` and `/mnt` into the distro, so `/storage/emulated/0` files are visible and usable inside every distro. +- **All files access**: the All files access request moved back to the terminal screen (where it was in earlier builds) instead of the welcome screen, where it could be skipped — the terminal re-asks until it is granted and shows a toast explaining why it is needed. + ## [v1.0.2] ### Added diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 74ff299..581cd47 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -15,8 +15,8 @@ android { applicationId = "com.redtermapp" minSdk = 24 targetSdk = 35 - versionCode = 1 - versionName = "1.0.2" + versionCode = 2 + versionName = "1.0.3" } signingConfigs { diff --git a/app/src/main/java/com/redtermapp/ui/SettingsActivity.kt b/app/src/main/java/com/redtermapp/ui/SettingsActivity.kt index 35ebe35..c51652a 100644 --- a/app/src/main/java/com/redtermapp/ui/SettingsActivity.kt +++ b/app/src/main/java/com/redtermapp/ui/SettingsActivity.kt @@ -239,7 +239,7 @@ class SettingsActivity : AppCompatActivity() { } findViewById(R.id.reset_extra_keys_btn).setOnClickListener { row1Input.setText("\u2630 ESC TAB CTRL ALT \u25B2 HOME END") - row2Input.setText("INS DEL && \u25B6 \u25BC \u25C0 \u232B") + row2Input.setText("INS DEL && \u25C0 \u25BC \u25B6 \u232B") prefs.edit() .putString("extra_keys_row1", row1Input.text.toString().trim()) .putString("extra_keys_row2", row2Input.text.toString().trim()) diff --git a/app/src/main/java/com/redtermapp/ui/TerminalActivity.kt b/app/src/main/java/com/redtermapp/ui/TerminalActivity.kt index 644c8b9..ecb3334 100644 --- a/app/src/main/java/com/redtermapp/ui/TerminalActivity.kt +++ b/app/src/main/java/com/redtermapp/ui/TerminalActivity.kt @@ -173,6 +173,22 @@ class TerminalActivity : AppCompatActivity() { super.onCreate(savedInstanceState) setContentView(R.layout.activity_terminal) + if (!com.redtermapp.util.StoragePermission.isAccessible(this)) { + Toast.makeText( + this, + "RedTerm needs All files access to use /storage/emulated/0 in the terminal", + Toast.LENGTH_LONG + ).show() + com.redtermapp.util.StoragePermission.requestAccess(this) + } + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.TIRAMISU && + androidx.core.content.ContextCompat.checkSelfPermission( + this, android.Manifest.permission.POST_NOTIFICATIONS + ) != android.content.pm.PackageManager.PERMISSION_GRANTED + ) { + requestPermissions(arrayOf(android.Manifest.permission.POST_NOTIFICATIONS), 1001) + } + distroName = intent?.getStringExtra(EXTRA_DISTRO) ?: "alpine" pendingStartDir = intent?.getStringExtra(EXTRA_START_DIR) getSharedPreferences("settings", MODE_PRIVATE) @@ -314,7 +330,7 @@ class TerminalActivity : AppCompatActivity() { private fun extraKeyLabels(): Pair, List> { val prefs = getSharedPreferences("settings", MODE_PRIVATE) val d1 = "\u2630 ESC TAB CTRL ALT \u25B2 HOME END" - val d2 = "INS DEL && \u25B6 \u25BC \u25C0 \u232B" + val d2 = "INS DEL && \u25C0 \u25BC \u25B6 \u232B" val split = { s: String -> s.trim().split(Regex("\\s+")).filter { it.isNotEmpty() } } return split(prefs.getString("extra_keys_row1", d1)!!) to split(prefs.getString("extra_keys_row2", d2)!!) @@ -578,6 +594,7 @@ ${ldr32}export PROOT_TMP_DIR=$rp/tmp mkdir -p "$rp/tmp" exec $prootBin -0 -L -r "$rp" -w ${startInner ?: "/root"} --link2symlink --sysvipc --kill-on-exit \ -b /dev -b /proc -b /sys -b /system -b /apex -b /linkerconfig/ld.config.txt \ + -b /sdcard -b /storage -b /mnt \ /system/bin/sh -i 2>&1 """) launchSh.setExecutable(true, false) @@ -923,6 +940,14 @@ exec $prootBin -0 -L -r "$rp" -w ${startInner ?: "/root"} --link2symlink --sysvi override fun onResume() { super.onResume() + if (!com.redtermapp.util.StoragePermission.isAccessible(this)) { + val prefs = getSharedPreferences("settings", MODE_PRIVATE) + val lastAsk = prefs.getLong("storage_ask_time", 0L) + if (System.currentTimeMillis() - lastAsk > 8000) { + prefs.edit().putLong("storage_ask_time", System.currentTimeMillis()).apply() + com.redtermapp.util.StoragePermission.requestAccess(this) + } + } terminalView.requestFocus() terminalView.onScreenUpdated() titleHandler.postDelayed(titleRunnable, 1000) diff --git a/app/src/main/java/com/redtermapp/ui/WelcomeActivity.kt b/app/src/main/java/com/redtermapp/ui/WelcomeActivity.kt index 1a91fc9..9527f48 100644 --- a/app/src/main/java/com/redtermapp/ui/WelcomeActivity.kt +++ b/app/src/main/java/com/redtermapp/ui/WelcomeActivity.kt @@ -1,14 +1,8 @@ package com.redtermapp.ui -import android.Manifest import android.content.Context import android.content.Intent -import android.content.pm.PackageManager -import android.net.Uri -import android.os.Build import android.os.Bundle -import android.os.Environment -import android.provider.Settings import android.widget.Button import android.widget.LinearLayout import android.widget.ProgressBar @@ -16,7 +10,6 @@ import android.widget.TextView import android.widget.Toast import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AppCompatActivity -import androidx.core.content.ContextCompat import androidx.lifecycle.lifecycleScope import com.google.android.material.card.MaterialCardView import com.redtermapp.R @@ -75,8 +68,6 @@ class WelcomeActivity : AppCompatActivity() { private fun finishSetup() { val selectOnly = intent?.getBooleanExtra(EXTRA_SELECT_ONLY, false) ?: false - requestSetupPermissions() - if (!selectOnly && hasInstalledDistro()) { navigateToMain() return @@ -143,39 +134,6 @@ class WelcomeActivity : AppCompatActivity() { } } - private fun requestSetupPermissions() { - val toAsk = ArrayList() - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU && - ContextCompat.checkSelfPermission(this, Manifest.permission.POST_NOTIFICATIONS) - != PackageManager.PERMISSION_GRANTED - ) { - toAsk.add(Manifest.permission.POST_NOTIFICATIONS) - } - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && - ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) - != PackageManager.PERMISSION_GRANTED - ) { - toAsk.add(Manifest.permission.READ_EXTERNAL_STORAGE) - } - } - if (toAsk.isNotEmpty()) { - requestPermissions(toAsk.toTypedArray(), 1001) - } - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R && !Environment.isExternalStorageManager()) { - try { - startActivity(Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION).apply { - data = Uri.parse("package:$packageName") - }) - } catch (_: Exception) { - try { - startActivity(Intent(Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION)) - } catch (_: Exception) { - } - } - } - } - private fun refreshDistroStates() { for (distro in DistroRegistry.allDistros) { val card = distroCardMap[distro.name] ?: continue diff --git a/app/src/main/java/com/redtermapp/util/StoragePermission.kt b/app/src/main/java/com/redtermapp/util/StoragePermission.kt new file mode 100644 index 0000000..47897af --- /dev/null +++ b/app/src/main/java/com/redtermapp/util/StoragePermission.kt @@ -0,0 +1,65 @@ +package com.redtermapp.util + +import android.Manifest +import android.app.Activity +import android.content.Context +import android.content.Intent +import android.content.pm.PackageManager +import android.net.Uri +import android.os.Build +import android.os.Environment +import android.provider.Settings +import androidx.core.content.ContextCompat + +object StoragePermission { + + fun isAccessible(context: Context): Boolean { + return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { + Environment.isExternalStorageManager() + } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + val read = ContextCompat.checkSelfPermission(context, Manifest.permission.READ_EXTERNAL_STORAGE) == + PackageManager.PERMISSION_GRANTED + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { + read + } else { + val write = ContextCompat.checkSelfPermission(context, Manifest.permission.WRITE_EXTERNAL_STORAGE) == + PackageManager.PERMISSION_GRANTED + read && write + } + } else { + true + } + } + + fun requestAccess(activity: Activity) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { + try { + activity.startActivity( + Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION).apply { + data = Uri.parse("package:${activity.packageName}") + } + ) + return + } catch (_: Exception) {} + try { + activity.startActivity(Intent(Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION)) + } catch (_: Exception) {} + } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + val perms = ArrayList() + if (ContextCompat.checkSelfPermission(activity, Manifest.permission.READ_EXTERNAL_STORAGE) != + PackageManager.PERMISSION_GRANTED + ) { + perms.add(Manifest.permission.READ_EXTERNAL_STORAGE) + } + if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.P && + ContextCompat.checkSelfPermission(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE) != + PackageManager.PERMISSION_GRANTED + ) { + perms.add(Manifest.permission.WRITE_EXTERNAL_STORAGE) + } + if (perms.isNotEmpty()) { + activity.requestPermissions(perms.toTypedArray(), 2001) + } + } + } +} \ No newline at end of file