diff --git a/app/src/main/java/com/bintianqi/owndroid/MainActivity.kt b/app/src/main/java/com/bintianqi/owndroid/MainActivity.kt index c0564fb..f510707 100644 --- a/app/src/main/java/com/bintianqi/owndroid/MainActivity.kt +++ b/app/src/main/java/com/bintianqi/owndroid/MainActivity.kt @@ -42,9 +42,10 @@ import com.bintianqi.owndroid.dpm.* import com.bintianqi.owndroid.ui.Animations import com.bintianqi.owndroid.ui.theme.OwnDroidTheme import kotlinx.coroutines.delay +import kotlinx.coroutines.flow.MutableStateFlow import java.util.Locale -var backToHome = false +var backToHomeStateFlow = MutableStateFlow(false) @ExperimentalMaterial3Api class MainActivity : FragmentActivity() { private val showAuth = mutableStateOf(false) @@ -98,11 +99,9 @@ fun Home(materialYou:MutableState, blackTheme:MutableState){ val focusMgr = LocalFocusManager.current val pkgName = mutableStateOf("") val dialogStatus = mutableIntStateOf(0) + val backToHome by backToHomeStateFlow.collectAsState() LaunchedEffect(Unit){ - while(true){ - if(backToHome){ navCtrl.navigateUp(); backToHome=false } - delay(200) - } + if(backToHome) { navCtrl.navigateUp(); backToHomeStateFlow.value = false } } NavHost( navController = navCtrl, diff --git a/app/src/main/java/com/bintianqi/owndroid/PermissionPicker.kt b/app/src/main/java/com/bintianqi/owndroid/PermissionPicker.kt index d98e11a..d8999d5 100644 --- a/app/src/main/java/com/bintianqi/owndroid/PermissionPicker.kt +++ b/app/src/main/java/com/bintianqi/owndroid/PermissionPicker.kt @@ -38,7 +38,7 @@ fun PermissionPicker(navCtrl: NavHostController){ .fillMaxWidth() .clickable{ selectedPermission = it.first - applySelectedPermission = true + applySelectedPermission.value = true navCtrl.navigateUp() } .padding(vertical = 6.dp, horizontal = 8.dp) diff --git a/app/src/main/java/com/bintianqi/owndroid/PkgSelector.kt b/app/src/main/java/com/bintianqi/owndroid/PkgSelector.kt index 55d05cd..88b512a 100644 --- a/app/src/main/java/com/bintianqi/owndroid/PkgSelector.kt +++ b/app/src/main/java/com/bintianqi/owndroid/PkgSelector.kt @@ -3,7 +3,10 @@ package com.bintianqi.owndroid import android.graphics.drawable.Drawable import android.widget.Toast import androidx.compose.animation.AnimatedVisibility -import androidx.compose.foundation.* +import androidx.compose.foundation.ExperimentalFoundationApi +import androidx.compose.foundation.Image +import androidx.compose.foundation.clickable +import androidx.compose.foundation.combinedClickable import androidx.compose.foundation.layout.* import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items @@ -24,8 +27,10 @@ import androidx.compose.ui.unit.dp import androidx.navigation.NavHostController import com.bintianqi.owndroid.ui.NavIcon import com.google.accompanist.drawablepainter.rememberDrawablePainter +import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.delay import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext private data class PkgInfo( val pkgName: String, @@ -48,7 +53,7 @@ fun PackageSelector(navCtrl:NavHostController, pkgName: MutableState){ var filter by remember{mutableStateOf("data")} val scrollState = rememberLazyListState() val co = rememberCoroutineScope() - val getPkgList:suspend ()->Unit = { + val getPkgList: suspend ()->Unit = { show = false progress = 0 hideProgress = false @@ -65,11 +70,10 @@ fun PackageSelector(navCtrl:NavHostController, pkgName: MutableState){ else if(srcDir.contains("apex")){"apex"} else{"system"} ) - progress+=1 - delay(1) + withContext(Dispatchers.Main) { progress += 1 } } show = true - delay(300) + delay(500) hideProgress = true } Scaffold( @@ -114,7 +118,6 @@ fun PackageSelector(navCtrl:NavHostController, pkgName: MutableState){ .clip(RoundedCornerShape(50)) .clickable{ co.launch{ - delay(100) getPkgList() } } @@ -153,9 +156,8 @@ fun PackageSelector(navCtrl:NavHostController, pkgName: MutableState){ } } } - LaunchedEffect(Unit){ - delay(250) - if(pkgs.size==0){getPkgList()} + LaunchedEffect(Unit) { + if(pkgs.size==0) { getPkgList() } } } } diff --git a/app/src/main/java/com/bintianqi/owndroid/Utils.kt b/app/src/main/java/com/bintianqi/owndroid/Utils.kt index d6d215d..1ea983e 100644 --- a/app/src/main/java/com/bintianqi/owndroid/Utils.kt +++ b/app/src/main/java/com/bintianqi/owndroid/Utils.kt @@ -9,12 +9,13 @@ import androidx.activity.result.ActivityResultLauncher import androidx.activity.result.contract.ActivityResultContracts import com.bintianqi.owndroid.dpm.addDeviceAdmin import com.bintianqi.owndroid.dpm.createManagedProfile +import kotlinx.coroutines.flow.MutableStateFlow import java.io.FileNotFoundException import java.io.IOException import java.io.InputStream lateinit var getFile: ActivityResultLauncher -var fileUri: Uri? = null +val fileUriFlow = MutableStateFlow(Uri.parse("")) var zhCN = true @@ -71,7 +72,7 @@ fun registerActivityResult(context: ComponentActivity){ if(it==null){ Toast.makeText(context.applicationContext, R.string.file_not_exist, Toast.LENGTH_SHORT).show() }else{ - fileUri = it.data + fileUriFlow.value = it.data } } } @@ -79,7 +80,7 @@ fun registerActivityResult(context: ComponentActivity){ addDeviceAdmin = context.registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { val dpm = context.applicationContext.getSystemService(ComponentActivity.DEVICE_POLICY_SERVICE) as DevicePolicyManager if(dpm.isAdminActive(ComponentName(context.applicationContext, Receiver::class.java))){ - backToHome = true + backToHomeStateFlow.value = true } } } diff --git a/app/src/main/java/com/bintianqi/owndroid/dpm/ApplicationManage.kt b/app/src/main/java/com/bintianqi/owndroid/dpm/ApplicationManage.kt index aeb6e48..1e19d6b 100644 --- a/app/src/main/java/com/bintianqi/owndroid/dpm/ApplicationManage.kt +++ b/app/src/main/java/com/bintianqi/owndroid/dpm/ApplicationManage.kt @@ -52,7 +52,6 @@ import androidx.navigation.compose.rememberNavController import com.bintianqi.owndroid.* import com.bintianqi.owndroid.R import com.bintianqi.owndroid.ui.* -import kotlinx.coroutines.delay import java.io.IOException import java.io.InputStream import java.util.concurrent.Executors @@ -263,9 +262,7 @@ private fun Home(navCtrl:NavHostController, pkgName: String, dialogStatus: Mutab SubPageItem(R.string.set_default_dialer,"",R.drawable.call_fill0){navCtrl.navigate("DefaultDialer")} } Spacer(Modifier.padding(vertical = 30.dp)) - LaunchedEffect(Unit) { - fileUri = null - } + LaunchedEffect(Unit) { fileUriFlow.value = Uri.parse("") } } } @@ -348,10 +345,10 @@ private fun PermissionManage(pkgName: String, navCtrl: NavHostController){ PERMISSION_GRANT_STATE_GRANTED to stringResource(R.string.granted), PERMISSION_GRANT_STATE_DENIED to stringResource(R.string.denied) ) - LaunchedEffect(Unit) { - while(true){ - if(applySelectedPermission){inputPermission = selectedPermission; applySelectedPermission = false} - delay(100) + LaunchedEffect(applySelectedPermission.collectAsState()) { + if(applySelectedPermission.value) { + inputPermission = selectedPermission + applySelectedPermission.value = false } } LaunchedEffect(pkgName) { @@ -794,6 +791,7 @@ private fun UninstallApp(pkgName: String){ private fun InstallApp(){ val context = LocalContext.current val focusMgr = LocalFocusManager.current + val selected = fileUriFlow.collectAsState().value != Uri.parse("") Column(modifier = Modifier.fillMaxSize().padding(horizontal = 8.dp).verticalScroll(rememberScrollState())){ Spacer(Modifier.padding(vertical = 10.dp)) Text(text = stringResource(R.string.install_app), style = typography.headlineLarge) @@ -810,13 +808,11 @@ private fun InstallApp(){ ) { Text(stringResource(R.string.select_apk)) } - var selected by remember{mutableStateOf(false)} - LaunchedEffect(selected){while(true){ delay(800); selected = fileUri!=null}} AnimatedVisibility(selected) { Spacer(Modifier.padding(vertical = 3.dp)) Column(modifier = Modifier.fillMaxWidth()){ Button( - onClick = { uriToStream(context, fileUri){stream -> installPackage(context,stream)} }, + onClick = { uriToStream(context, fileUriFlow.value){stream -> installPackage(context,stream)} }, modifier = Modifier.fillMaxWidth() ) { Text(stringResource(R.string.silent_install)) @@ -824,7 +820,7 @@ private fun InstallApp(){ Button( onClick = { val intent = Intent(Intent.ACTION_INSTALL_PACKAGE) - intent.setData(fileUri) + intent.setData(fileUriFlow.value) intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) context.startActivity(intent) }, diff --git a/app/src/main/java/com/bintianqi/owndroid/dpm/DPM.kt b/app/src/main/java/com/bintianqi/owndroid/dpm/DPM.kt index ad09faa..5831fa1 100644 --- a/app/src/main/java/com/bintianqi/owndroid/dpm/DPM.kt +++ b/app/src/main/java/com/bintianqi/owndroid/dpm/DPM.kt @@ -2,11 +2,11 @@ package com.bintianqi.owndroid.dpm import android.app.admin.DevicePolicyManager import android.content.Intent -import android.net.Uri import androidx.activity.result.ActivityResultLauncher +import kotlinx.coroutines.flow.MutableStateFlow var selectedPermission = "" -var applySelectedPermission = false +var applySelectedPermission = MutableStateFlow(false) lateinit var createManagedProfile: ActivityResultLauncher lateinit var addDeviceAdmin: ActivityResultLauncher diff --git a/app/src/main/java/com/bintianqi/owndroid/dpm/ShizukuActivate.kt b/app/src/main/java/com/bintianqi/owndroid/dpm/ShizukuActivate.kt index e05adf2..a8c1678 100644 --- a/app/src/main/java/com/bintianqi/owndroid/dpm/ShizukuActivate.kt +++ b/app/src/main/java/com/bintianqi/owndroid/dpm/ShizukuActivate.kt @@ -129,7 +129,7 @@ fun ShizukuActivate(){ coScope.launch{ outputText = service!!.execute(context.getString(R.string.dpm_activate_po_command)) outputTextScrollState.animateScrollTo(0, scrollAnim()) - delay(600) + delay(500) showProfileOwnerButton = !isProfileOwner(dpm) } }, diff --git a/app/src/main/java/com/bintianqi/owndroid/dpm/SystemManager.kt b/app/src/main/java/com/bintianqi/owndroid/dpm/SystemManager.kt index 5e32b38..3c3b56e 100644 --- a/app/src/main/java/com/bintianqi/owndroid/dpm/SystemManager.kt +++ b/app/src/main/java/com/bintianqi/owndroid/dpm/SystemManager.kt @@ -11,6 +11,7 @@ import android.app.admin.SystemUpdatePolicy.TYPE_POSTPONE import android.content.ComponentName import android.content.Context import android.content.Intent +import android.net.Uri import android.os.Binder import android.os.Build.VERSION import android.os.UserManager @@ -19,11 +20,14 @@ import android.widget.Toast import androidx.activity.ComponentActivity import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.animateContentSize -import androidx.compose.foundation.* +import androidx.compose.foundation.ScrollState +import androidx.compose.foundation.focusable import androidx.compose.foundation.layout.* +import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.text.KeyboardActions import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.foundation.text.selection.SelectionContainer +import androidx.compose.foundation.verticalScroll import androidx.compose.material3.* import androidx.compose.material3.MaterialTheme.colorScheme import androidx.compose.material3.MaterialTheme.typography @@ -44,7 +48,6 @@ import androidx.navigation.compose.rememberNavController import com.bintianqi.owndroid.* import com.bintianqi.owndroid.R import com.bintianqi.owndroid.ui.* -import kotlinx.coroutines.delay import java.util.Date @Composable @@ -150,7 +153,7 @@ private fun Home(navCtrl: NavHostController,scrollState: ScrollState){ } SubPageItem(R.string.wipe_data,"",R.drawable.warning_fill0){navCtrl.navigate("WipeData")} Spacer(Modifier.padding(vertical = 30.dp)) - LaunchedEffect(Unit){fileUri=null} + LaunchedEffect(Unit){ fileUriFlow.value = Uri.parse("") } } } @@ -593,26 +596,23 @@ private fun CaCert(){ val context = LocalContext.current val dpm = context.getSystemService(ComponentActivity.DEVICE_POLICY_SERVICE) as DevicePolicyManager val receiver = ComponentName(context,Receiver::class.java) + val uri by fileUriFlow.collectAsState() var exist by remember{mutableStateOf(false)} - var uriPath by remember{mutableStateOf("")} - var caCertByteArray = byteArrayOf() - val refresh = { - if(uriPath!=fileUri?.path){ - if(caCertByteArray.isEmpty()){ - uriToStream(context, fileUri){ - val array = it.readBytes() - caCertByteArray = if(array.size<10000){ - array - }else{ - byteArrayOf() - } + val uriPath = uri.path ?: "" + var caCertByteArray by remember{ mutableStateOf(byteArrayOf()) } + LaunchedEffect(uri) { + if(uri != Uri.parse("")) { + uriToStream(context, uri){ + val array = it.readBytes() + caCertByteArray = if(array.size<10000){ + array + }else{ + byteArrayOf() } - exist = dpm.hasCaCertInstalled(receiver, caCertByteArray) } - uriPath = fileUri?.path?:"" + exist = dpm.hasCaCertInstalled(receiver, caCertByteArray) } } - LaunchedEffect(exist){ while(true){ refresh();delay(500) } } Column(modifier = Modifier.fillMaxSize().padding(horizontal = 8.dp).verticalScroll(rememberScrollState())){ Spacer(Modifier.padding(vertical = 10.dp)) Text(text = stringResource(R.string.ca_cert), style = typography.headlineLarge) @@ -642,7 +642,7 @@ private fun CaCert(){ onClick = { val result = dpm.installCaCert(receiver, caCertByteArray) Toast.makeText(context, if(result){R.string.success}else{R.string.fail}, Toast.LENGTH_SHORT).show() - refresh() + exist = dpm.hasCaCertInstalled(receiver, caCertByteArray) }, modifier = Modifier.fillMaxWidth(0.49F) ) { diff --git a/app/src/main/java/com/bintianqi/owndroid/dpm/UserManager.kt b/app/src/main/java/com/bintianqi/owndroid/dpm/UserManager.kt index 9c63f01..2455e75 100644 --- a/app/src/main/java/com/bintianqi/owndroid/dpm/UserManager.kt +++ b/app/src/main/java/com/bintianqi/owndroid/dpm/UserManager.kt @@ -6,6 +6,7 @@ import android.content.ComponentName import android.content.Context import android.content.Intent import android.graphics.BitmapFactory +import android.net.Uri import android.os.Binder import android.os.Build.VERSION import android.os.Process @@ -119,9 +120,7 @@ private fun Home(navCtrl: NavHostController,scrollState: ScrollState){ SubPageItem(R.string.affiliation_id,"",R.drawable.id_card_fill0){navCtrl.navigate("AffiliationID")} } Spacer(Modifier.padding(vertical = 30.dp)) - LaunchedEffect(Unit) { - fileUri = null - } + LaunchedEffect(Unit) { fileUriFlow.value = Uri.parse("") } } } @@ -495,7 +494,7 @@ private fun UserIcon(){ val dpm = context.getSystemService(ComponentActivity.DEVICE_POLICY_SERVICE) as DevicePolicyManager val receiver = ComponentName(context,Receiver::class.java) var getContent by remember{mutableStateOf(false)} - var canApply by remember{mutableStateOf(false)} + val canApply = fileUriFlow.collectAsState().value != Uri.parse("") Column(modifier = Modifier.fillMaxSize().padding(horizontal = 8.dp).verticalScroll(rememberScrollState())){ Spacer(Modifier.padding(vertical = 10.dp)) Text(text = stringResource(R.string.change_user_icon), style = typography.headlineLarge) @@ -515,11 +514,10 @@ private fun UserIcon(){ ) { Text(stringResource(R.string.select_picture)) } - LaunchedEffect(Unit){ delay(600); canApply = fileUri!=null } AnimatedVisibility(canApply) { Button( onClick = { - uriToStream(context, fileUri){stream -> + uriToStream(context, fileUriFlow.value){stream -> val bitmap = BitmapFactory.decodeStream(stream) dpm.setUserIcon(receiver,bitmap) Toast.makeText(context, R.string.success, Toast.LENGTH_SHORT).show()