From 7c76cae99b627533b86c10355b6e41ec7d309b4d Mon Sep 17 00:00:00 2001 From: nift4 Date: Tue, 20 Aug 2024 17:11:23 +0200 Subject: [PATCH] somewhat cleaning up --- .../java/org/andbootmgr/app/DeviceInfo.kt | 12 +- .../java/org/andbootmgr/app/MainActivity.kt | 108 +++++++++--------- .../java/org/andbootmgr/app/WizardActivity.kt | 26 ----- .../java/org/andbootmgr/app/themes/Themes.kt | 8 +- .../andbootmgr/app/util/StayAliveService.kt | 18 ++- 5 files changed, 79 insertions(+), 93 deletions(-) diff --git a/app/src/main/java/org/andbootmgr/app/DeviceInfo.kt b/app/src/main/java/org/andbootmgr/app/DeviceInfo.kt index f1d9931b..89444210 100644 --- a/app/src/main/java/org/andbootmgr/app/DeviceInfo.kt +++ b/app/src/main/java/org/andbootmgr/app/DeviceInfo.kt @@ -6,6 +6,8 @@ import android.util.Log import com.topjohnwu.superuser.Shell import com.topjohnwu.superuser.io.SuFile import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.async +import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import org.andbootmgr.app.util.SDUtils import org.json.JSONObject @@ -102,10 +104,12 @@ class JsonDeviceInfoFactory(private val ctx: Context) { if (BuildConfig.VERSION_CODE < jsonRoot.getInt("minAppVersion")) throw IllegalStateException("please upgrade app") if (fromNet) { - val newRoot = JSONObject() - newRoot.put("deviceInfo", json) - newRoot.put("minAppVersion", jsonRoot.getInt("minAppVersion")) - File(ctx.filesDir, "abm_dd_cache.json").writeText(newRoot.toString()) + launch { + val newRoot = JSONObject() + newRoot.put("deviceInfo", json) + newRoot.put("minAppVersion", jsonRoot.getInt("minAppVersion")) + File(ctx.filesDir, "abm_dd_cache.json").writeText(newRoot.toString()) + } } if (!json.getBoolean("metaOnSd")) throw IllegalArgumentException("sd less currently not implemented") diff --git a/app/src/main/java/org/andbootmgr/app/MainActivity.kt b/app/src/main/java/org/andbootmgr/app/MainActivity.kt index b6c9873d..945bdf85 100644 --- a/app/src/main/java/org/andbootmgr/app/MainActivity.kt +++ b/app/src/main/java/org/andbootmgr/app/MainActivity.kt @@ -4,8 +4,6 @@ import android.content.Intent import android.os.Build import android.os.Bundle import android.util.Log -import android.view.View -import android.view.ViewTreeObserver import android.widget.Toast import androidx.activity.ComponentActivity import androidx.activity.compose.setContent @@ -40,6 +38,7 @@ import com.topjohnwu.superuser.Shell.FLAG_REDIRECT_STDERR import com.topjohnwu.superuser.io.SuFile import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.async import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import org.andbootmgr.app.themes.ThemeViewModel @@ -47,6 +46,8 @@ import org.andbootmgr.app.themes.Themes import org.andbootmgr.app.util.AbmTheme import org.andbootmgr.app.util.ConfigFile import org.andbootmgr.app.util.SDUtils +import org.andbootmgr.app.util.StayAliveService +import org.andbootmgr.app.util.Terminal import org.andbootmgr.app.util.Toolkit import java.io.File @@ -93,10 +94,6 @@ class MainActivityState { val theme = ThemeViewModel(this) var defaultCfg = mutableStateMapOf() var isReady = false - var navController: NavHostController? = null - var drawerState: DrawerState? = null - var scope: CoroutineScope? = null - var root = false var isOk = false var logic: DeviceLogic? = null @@ -200,14 +197,20 @@ class MainActivity : ComponentActivity() { } } if (!fail) { - Shell.getShell { shell -> - CoroutineScope(Dispatchers.IO).launch { - vm.root = shell.isRoot - if (vm.root && Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { - Shell.cmd("pm grant $packageName ${android.Manifest.permission.POST_NOTIFICATIONS}") - } - vm.deviceInfo = JsonDeviceInfoFactory(vm.activity!!).get(Build.DEVICE) - // == temp migration code start == + CoroutineScope(Dispatchers.IO).launch { + launch { + vm.noobMode = + this@MainActivity.getSharedPreferences("abm", 0) + .getBoolean("noob_mode", BuildConfig.DEFAULT_NOOB_MODE) + } + // TODO I/O on app startup is meh, but can we avoid it? + val di = async { JsonDeviceInfoFactory(vm.activity!!).get(Build.DEVICE) } + val shell = Shell.getShell() // blocking + if (shell.isRoot && Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + Shell.cmd("pm grant $packageName ${android.Manifest.permission.POST_NOTIFICATIONS}").submit() + } + // == temp migration code start == + launch { if (Shell.cmd("mountpoint -q /data/abm/bootset").exec().isSuccess) { Shell.cmd("umount /data/abm/bootset").exec() } @@ -215,35 +218,37 @@ class MainActivity : ComponentActivity() { if (it.exists()) Shell.cmd("rm -rf /data/abm").exec() } - // == temp migration code end == - if (vm.deviceInfo != null && vm.deviceInfo!!.isInstalled(vm.logic!!)) { - vm.mountBootset() - } else { - Log.i("ABM", "not installed, not trying to mount") - } - if (vm.deviceInfo != null) { - vm.isOk = ((vm.deviceInfo!!.isInstalled(vm.logic!!)) && - vm.deviceInfo!!.isBooted(vm.logic!!) && - !(!vm.logic!!.mounted || vm.deviceInfo!!.isCorrupt(vm.logic!!))) - } - withContext(Dispatchers.Main) { - setContent { - // TODO support work resumption by instantly opening Terminal with null action if work is going on + } + // == temp migration code end == + vm.deviceInfo = di.await() // blocking + val installed = vm.deviceInfo?.isInstalled(vm.logic!!) + if (installed == true) { + vm.mountBootset() + } else { + Log.i("ABM", "not installed, not trying to mount") + } + if (vm.deviceInfo != null) { + vm.isOk = installed!! && vm.deviceInfo!!.isBooted(vm.logic!!) && + !(!vm.logic!!.mounted || vm.deviceInfo!!.isCorrupt(vm.logic!!)) + } + withContext(Dispatchers.Main) { + setContent { + var terminalEnabled by remember { mutableStateOf(StayAliveService.isRunning) } + val newAction = remember { mutableStateOf<(suspend (MutableList) -> Unit)?>(null) } + val action = if (newAction.value != null) { + terminalEnabled = true + newAction.value + } else null + if (terminalEnabled) { + Terminal(null, action) + } else { val navController = rememberNavController() - val drawerState = rememberDrawerState(DrawerValue.Closed) - val scope = rememberCoroutineScope() - vm.navController = navController - vm.drawerState = drawerState - vm.scope = scope - vm.noobMode = - LocalContext.current.getSharedPreferences("abm", 0) - .getBoolean("noob_mode", BuildConfig.DEFAULT_NOOB_MODE) - AppContent(vm) { - NavGraph(vm, it) + AppContent(vm, navController) { + NavGraph(vm, navController, it) } } - vm.isReady = true } + vm.isReady = true } } } @@ -254,9 +259,10 @@ class MainActivity : ComponentActivity() { @OptIn(ExperimentalMaterial3Api::class) @Composable -fun AppContent(vm: MainActivityState, view: @Composable (PaddingValues) -> Unit) { - val drawerState = vm.drawerState!! - val scope = vm.scope!! +fun AppContent(vm: MainActivityState, navController: NavHostController, + view: @Composable (PaddingValues) -> Unit) { + val drawerState = rememberDrawerState(DrawerValue.Closed) + val scope = rememberCoroutineScope() var fabhint by remember { mutableStateOf(false) } val fab = @Composable { if (vm.noobMode && vm.isOk && vm.currentNav == "start") { @@ -275,7 +281,7 @@ fun AppContent(vm: MainActivityState, view: @Composable (PaddingValues) -> Unit) selected = vm.currentNav == "start", onClick = { scope.launch { - vm.navController!!.navigate("start") + navController.navigate("start") drawerState.close() } }, @@ -287,7 +293,7 @@ fun AppContent(vm: MainActivityState, view: @Composable (PaddingValues) -> Unit) selected = vm.currentNav == "themes", onClick = { scope.launch { - vm.navController!!.navigate("themes") + navController.navigate("themes") drawerState.close() } }, @@ -298,7 +304,7 @@ fun AppContent(vm: MainActivityState, view: @Composable (PaddingValues) -> Unit) selected = vm.currentNav == "settings", onClick = { scope.launch { - vm.navController!!.navigate("settings") + navController.navigate("settings") drawerState.close() } }, @@ -339,8 +345,8 @@ fun AppContent(vm: MainActivityState, view: @Composable (PaddingValues) -> Unit) } @Composable -private fun NavGraph(vm: MainActivityState, it: PaddingValues) { - NavHost(navController = vm.navController!!, startDestination = "start", modifier = Modifier.padding(it).fillMaxSize()) { +private fun NavGraph(vm: MainActivityState, navController: NavHostController, it: PaddingValues) { + NavHost(navController = navController, startDestination = "start", modifier = Modifier.padding(it).fillMaxSize()) { composable("start") { vm.currentNav = "start" Start(vm) @@ -1140,13 +1146,7 @@ private fun PartTool(vm: MainActivityState) { @Composable private fun Preview() { val vm = MainActivityState() - val navController = rememberNavController() - val drawerState = rememberDrawerState(DrawerValue.Closed) - val scope = rememberCoroutineScope() - vm.navController = navController - vm.drawerState = drawerState - vm.scope = scope - AppContent(vm) { + AppContent(vm, rememberNavController()) { Box(modifier = Modifier.padding(it)) { Start(vm) } diff --git a/app/src/main/java/org/andbootmgr/app/WizardActivity.kt b/app/src/main/java/org/andbootmgr/app/WizardActivity.kt index 475b248f..b455833f 100644 --- a/app/src/main/java/org/andbootmgr/app/WizardActivity.kt +++ b/app/src/main/java/org/andbootmgr/app/WizardActivity.kt @@ -22,7 +22,6 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.MutableState import androidx.compose.runtime.mutableStateOf import androidx.compose.ui.Modifier -import androidx.compose.ui.tooling.preview.Preview import androidx.core.net.toFile import androidx.navigation.NavHostController import androidx.navigation.compose.NavHost @@ -297,29 +296,4 @@ private fun BtnsRow(vm: WizardActivityState) { Text(vm.nextText.value) } } -} - -@Preview(showBackground = true) -@Composable -private fun Preview() { - val vm = WizardActivityState("null") - AbmTheme { - // A surface container using the 'background' color from the theme - Surface( - modifier = Modifier.fillMaxSize(), - color = MaterialTheme.colorScheme.background - ) { - Column { - Box( - Modifier - .fillMaxWidth() - .weight(1.0f)) { - //Select(vm) - } - Box(Modifier.fillMaxWidth()) { - BtnsRow(vm) - } - } - } - } } \ No newline at end of file diff --git a/app/src/main/java/org/andbootmgr/app/themes/Themes.kt b/app/src/main/java/org/andbootmgr/app/themes/Themes.kt index ef3021af..205051a1 100644 --- a/app/src/main/java/org/andbootmgr/app/themes/Themes.kt +++ b/app/src/main/java/org/andbootmgr/app/themes/Themes.kt @@ -327,13 +327,7 @@ class ThemeViewModel(val mvm: MainActivityState) : ViewModel() { @Composable fun ThemePreview() { val vm = MainActivityState() - val navController = rememberNavController() - val drawerState = rememberDrawerState(DrawerValue.Closed) - val scope = rememberCoroutineScope() - vm.navController = navController - vm.drawerState = drawerState - vm.scope = scope - AppContent(vm) { + AppContent(vm, rememberNavController()) { Box(modifier = Modifier.padding(it)) { Themes(vm.theme) } diff --git a/app/src/main/java/org/andbootmgr/app/util/StayAliveService.kt b/app/src/main/java/org/andbootmgr/app/util/StayAliveService.kt index 465bd3ee..ac0446ce 100644 --- a/app/src/main/java/org/andbootmgr/app/util/StayAliveService.kt +++ b/app/src/main/java/org/andbootmgr/app/util/StayAliveService.kt @@ -74,12 +74,20 @@ class StayAliveService : LifecycleService(), IStayAlive { if (!isWorkDone) { Log.e(TAG, "Warning: finishing StayAliveService before work is done.") } - destroyed = true + if (!destroyed) { + if (!isRunning) throw IllegalStateException("excepted isRunning to be true for non-destroyed service") + isRunning = false + destroyed = true + } stopSelf() } override fun onCreate() { super.onCreate() + if (isRunning) { + throw IllegalStateException("expected isRunning=false for new service") + } + isRunning = true NotificationManagerCompat.from(this).createNotificationChannel( NotificationChannelCompat.Builder(SERVICE_CHANNEL, NotificationManagerCompat.IMPORTANCE_HIGH) @@ -134,13 +142,19 @@ class StayAliveService : LifecycleService(), IStayAlive { override fun onDestroy() { super.onDestroy() - destroyed = true + if (!destroyed) { + if (!isRunning) throw IllegalStateException("excepted isRunning to be true for non-destroyed service") + isRunning = false + destroyed = true + } } companion object { private const val TAG = "ABM_StayAlive" private const val SERVICE_CHANNEL = "service" private const val FG_SERVICE_ID = 1001 + var isRunning = false + private set } }