Fix CA certs manager and User restrictions manager

Add authentication to app installer
Change version to 6.4 (36)
This commit is contained in:
BinTianqi
2025-02-08 19:07:23 +08:00
parent 5e109d74b1
commit 9528d3eb8d
9 changed files with 119 additions and 112 deletions

View File

@@ -137,7 +137,6 @@ import com.bintianqi.owndroid.ui.NavIcon
import com.bintianqi.owndroid.ui.RadioButtonItem
import com.bintianqi.owndroid.ui.SwitchItem
import com.bintianqi.owndroid.uriToStream
import com.bintianqi.owndroid.yesOrNo
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import java.io.ByteArrayOutputStream
@@ -1227,63 +1226,24 @@ fun CACert(navCtrl: NavHostController) {
val context = LocalContext.current
val dpm = context.getDPM()
val receiver = context.getReceiver()
var exist by remember { mutableStateOf(false) }
var fileUri by remember { mutableStateOf<Uri?>(null) }
var caCertByteArray by remember { mutableStateOf(ByteArray(100000)) }
val getFileLauncher = rememberLauncherForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
result.data?.data?.let { uri ->
uriToStream(context, uri) {
val array = it.readBytes()
caCertByteArray = if(array.size < 10000) {
array
} else {
byteArrayOf()
}
}
var dialog by remember { mutableStateOf(false) }
var caCertByteArray = remember { byteArrayOf() }
val getFileLauncher = rememberLauncherForActivityResult(ActivityResultContracts.GetContent()) { uri ->
uri ?: return@rememberLauncherForActivityResult
uriToStream(context, uri) {
caCertByteArray = it.readBytes()
}
dialog = true
}
MyScaffold(R.string.ca_cert, 8.dp, navCtrl) {
Text(
text = if(fileUri == null) { stringResource(R.string.please_select_ca_cert) }
else { stringResource(R.string.cert_installed, stringResource(exist.yesOrNo)) },
modifier = Modifier.animateContentSize()
)
Spacer(Modifier.padding(vertical = 5.dp))
Button(
onClick = {
val caCertIntent = Intent(Intent.ACTION_GET_CONTENT)
caCertIntent.setType("*/*")
caCertIntent.addCategory(Intent.CATEGORY_OPENABLE)
getFileLauncher.launch(caCertIntent)
getFileLauncher.launch("*/*")
},
modifier = Modifier.fillMaxWidth()
modifier = Modifier.fillMaxWidth().padding(vertical = 8.dp)
) {
Text(stringResource(R.string.select_ca_cert))
}
AnimatedVisibility(fileUri != null) {
Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween) {
Button(
onClick = {
context.showOperationResultToast(dpm.installCaCert(receiver, caCertByteArray))
exist = dpm.hasCaCertInstalled(receiver, caCertByteArray)
},
modifier = Modifier.fillMaxWidth(0.49F)
) {
Text(stringResource(R.string.install))
}
Button(
onClick = {
dpm.uninstallCaCert(receiver, caCertByteArray)
exist = dpm.hasCaCertInstalled(receiver, caCertByteArray)
context.showOperationResultToast(true)
},
enabled = exist,
modifier = Modifier.fillMaxWidth(0.96F)
) {
Text(stringResource(R.string.uninstall))
}
}
}
Button(
onClick = {
dpm.uninstallAllUserCaCerts(receiver)
@@ -1293,6 +1253,28 @@ fun CACert(navCtrl: NavHostController) {
) {
Text(stringResource(R.string.uninstall_all_user_ca_cert))
}
if(dialog) {
val exist = dpm.hasCaCertInstalled(receiver, caCertByteArray)
AlertDialog(
confirmButton = {
TextButton({
if(exist) {
dpm.uninstallCaCert(receiver, caCertByteArray)
} else {
val result = dpm.installCaCert(receiver, caCertByteArray)
context.showOperationResultToast(result)
}
dialog = false
}) {
Text(stringResource(if(exist) R.string.uninstall else R.string.install))
}
},
dismissButton = {
TextButton({ dialog = false }) { Text(stringResource(R.string.cancel)) }
},
onDismissRequest = { dialog = false }
)
}
}
}

View File

@@ -1,22 +1,20 @@
package com.bintianqi.owndroid.dpm
import android.os.Build.VERSION
import android.os.Build
import android.os.Bundle
import android.os.UserManager
import android.widget.Toast
import androidx.annotation.DrawableRes
import androidx.annotation.RequiresApi
import androidx.annotation.StringRes
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.navigation.NavHostController
import com.bintianqi.owndroid.MyViewModel
import com.bintianqi.owndroid.R
@@ -31,15 +29,19 @@ data class Restriction(
val requiresApi: Int = 0
)
@RequiresApi(24)
@Composable
fun UserRestriction(navCtrl:NavHostController) {
fun UserRestriction(navCtrl:NavHostController, vm: MyViewModel) {
val context = LocalContext.current
val dpm = context.getDPM()
val receiver = context.getReceiver()
LaunchedEffect(Unit) {
vm.userRestrictions.value = dpm.getUserRestrictions(receiver)
}
MyScaffold(R.string.user_restriction, 0.dp, navCtrl) {
Text(text = stringResource(R.string.switch_to_disable_feature), modifier = Modifier.padding(start = 16.dp))
if(context.isProfileOwner) { Text(text = stringResource(R.string.profile_owner_is_restricted), modifier = Modifier.padding(start = 16.dp)) }
if(context.isProfileOwner && (VERSION.SDK_INT < 24 || dpm.isManagedProfile(receiver))) {
if(context.isProfileOwner && dpm.isManagedProfile(receiver)) {
Text(text = stringResource(R.string.some_features_invalid_in_work_profile), modifier = Modifier.padding(start = 16.dp))
}
Spacer(Modifier.padding(vertical = 2.dp))
@@ -54,30 +56,19 @@ fun UserRestriction(navCtrl:NavHostController) {
@RequiresApi(24)
@Composable
fun UserRestrictionItem(restriction: Restriction, vm: MyViewModel) {
val context = LocalContext.current
val userRestrictions by vm.userRestrictions.collectAsStateWithLifecycle()
Box(modifier = Modifier.padding(start = 22.dp, end = 16.dp)) {
SwitchItem(
restriction.name, restriction.id, restriction.icon,
userRestrictions.getBoolean(restriction.id),
{
val dpm = context.getDPM()
val receiver = context.getReceiver()
try {
if(it) {
dpm.addUserRestriction(receiver, restriction.id)
} else {
dpm.clearUserRestriction(receiver, restriction.id)
}
vm.userRestrictions.value = dpm.getUserRestrictions(receiver)
} catch(_: SecurityException) {
if(context.isProfileOwner) {
Toast.makeText(context, R.string.require_device_owner, Toast.LENGTH_SHORT).show()
}
}
}, padding = false
)
fun UserRestrictionScreen(
title: Int, items: List<Restriction>, restrictions: Bundle,
onRestrictionChange: (String, Boolean) -> Unit, onNavigateUp: () -> Unit
) {
MyScaffold(title, 0.dp, onNavigateUp, false) {
items.filter { Build.VERSION.SDK_INT >= it.requiresApi }.forEach { restriction ->
SwitchItem(
restriction.name, restriction.id, restriction.icon,
restrictions.getBoolean(restriction.id), { onRestrictionChange(restriction.id, it) }, padding = true
)
/*Box(modifier = Modifier.padding(start = 22.dp, end = 16.dp)) {
}*/
}
}
}