Move AlwaysOnVpn from App manager to Network

Use Shizuku to list users and list accounts
Add package selector for Lock task mode
Specify an Activity before start lock task mode
Improve UI design
This commit is contained in:
BinTianqi
2024-08-13 21:03:03 +08:00
parent b452005ada
commit 32f43ce801
8 changed files with 202 additions and 83 deletions

View File

@@ -67,11 +67,11 @@ private fun Home(navCtrl: NavHostController) {
@Composable
private fun Options() {
val sharedPref = LocalContext.current.getSharedPreferences("data", Context.MODE_PRIVATE)
Column(modifier = Modifier.fillMaxSize().verticalScroll(rememberScrollState())) {
Column(modifier = Modifier.fillMaxSize().verticalScroll(rememberScrollState()).padding(start = 20.dp, end = 16.dp)) {
SwitchItem(
R.string.show_dangerous_features, "", R.drawable.warning_fill0,
{ sharedPref.getBoolean("dangerous_features", false) },
{ sharedPref.edit().putBoolean("dangerous_features", it).apply() }
{ sharedPref.edit().putBoolean("dangerous_features", it).apply() }, padding = false
)
}
}
@@ -79,15 +79,15 @@ private fun Options() {
@Composable
private fun ThemeSettings(materialYou:MutableState<Boolean>, blackTheme:MutableState<Boolean>) {
val sharedPref = LocalContext.current.getSharedPreferences("data", Context.MODE_PRIVATE)
Column(modifier = Modifier.fillMaxSize().verticalScroll(rememberScrollState())) {
if(VERSION.SDK_INT>=31) {
Column(modifier = Modifier.fillMaxSize().verticalScroll(rememberScrollState()).padding(start = 20.dp, end = 16.dp)) {
if(VERSION.SDK_INT >= 31) {
SwitchItem(
R.string.material_you_color, stringResource(R.string.dynamic_color_desc), null,
{ sharedPref.getBoolean("material_you",true) },
{
sharedPref.edit().putBoolean("material_you", it).apply()
materialYou.value = it
}
}, padding = false
)
}
if(isSystemInDarkTheme()) {
@@ -97,7 +97,7 @@ private fun ThemeSettings(materialYou:MutableState<Boolean>, blackTheme:MutableS
{
sharedPref.edit().putBoolean("black_theme", it).apply()
blackTheme.value = it
}
}, padding = false
)
}
}
@@ -107,30 +107,30 @@ private fun ThemeSettings(materialYou:MutableState<Boolean>, blackTheme:MutableS
private fun AuthSettings() {
val sharedPref = LocalContext.current.getSharedPreferences("data", Context.MODE_PRIVATE)
var auth by remember{ mutableStateOf(sharedPref.getBoolean("auth",false)) }
Column(modifier = Modifier.fillMaxSize().verticalScroll(rememberScrollState())) {
Column(modifier = Modifier.fillMaxSize().verticalScroll(rememberScrollState()).padding(start = 20.dp, end = 16.dp)) {
SwitchItem(
R.string.lock_owndroid, "", null, auth,
{
sharedPref.edit().putBoolean("auth", it).apply()
auth = sharedPref.getBoolean("auth", false)
}
}, padding = false
)
if(auth) {
SwitchItem(
R.string.enable_bio_auth, "", null,
{ sharedPref.getBoolean("bio_auth", false) },
{ sharedPref.edit().putBoolean("bio_auth", it).apply() }
{ sharedPref.edit().putBoolean("bio_auth", it).apply() }, padding = false
)
SwitchItem(
R.string.lock_in_background, stringResource(R.string.developing), null,
{ sharedPref.getBoolean("lock_in_background", false) },
{ sharedPref.edit().putBoolean("lock_in_background", it).apply() }
{ sharedPref.edit().putBoolean("lock_in_background", it).apply() }, padding = false
)
}
SwitchItem(
R.string.protect_storage, "", null,
{ sharedPref.getBoolean("protect_storage", false) },
{ sharedPref.edit().putBoolean("protect_storage", it).apply() }
{ sharedPref.edit().putBoolean("protect_storage", it).apply() }, padding = false
)
}
}

View File

@@ -147,7 +147,6 @@ fun ApplicationManage(navCtrl:NavHostController, dialogStatus: MutableIntState)
composable(route = "Home") {
Home(localNavCtrl, pkgName, dialogStatus)
}
composable(route = "AlwaysOnVpn") { AlwaysOnVPNPackage(pkgName) }
composable(route = "UserControlDisabled") { UserCtrlDisabledPkg(pkgName) }
composable(route = "PermissionManage") { PermissionManage(pkgName) }
composable(route = "CrossProfilePackage") { CrossProfilePkg(pkgName) }
@@ -245,9 +244,6 @@ private fun Home(
onClickBlank = { appControlAction = 3; appControlDialog = true }
)
}
if(VERSION.SDK_INT >= 24 && (deviceOwner || profileOwner)) {
SubPageItem(R.string.always_on_vpn, "", R.drawable.vpn_key_fill0) { navCtrl.navigate("AlwaysOnVpn") }
}
if((VERSION.SDK_INT >= 33 && profileOwner) || (VERSION.SDK_INT >= 30 && deviceOwner)) {
SubPageItem(R.string.ucd, "", R.drawable.do_not_touch_fill0) { navCtrl.navigate("UserControlDisabled") }
}
@@ -349,48 +345,6 @@ private fun Home(
}
}
@SuppressLint("NewApi")
@Composable
fun AlwaysOnVPNPackage(pkgName: String) {
val context = LocalContext.current
val dpm = context.getDPM()
val receiver = context.getReceiver()
var lockdown by remember { mutableStateOf(false) }
var pkg by remember { mutableStateOf<String?>("") }
val refresh = { pkg = dpm.getAlwaysOnVpnPackage(receiver) }
LaunchedEffect(Unit) { refresh() }
val setAlwaysOnVpn: (String?, Boolean)->Unit = { vpnPkg: String?, lockdownEnabled: Boolean ->
try {
dpm.setAlwaysOnVpnPackage(receiver, vpnPkg, lockdownEnabled)
Toast.makeText(context, R.string.success, Toast.LENGTH_SHORT).show()
} catch(e: UnsupportedOperationException) {
Toast.makeText(context, R.string.unsupported, Toast.LENGTH_SHORT).show()
} catch(e: NameNotFoundException) {
Toast.makeText(context, R.string.not_installed, Toast.LENGTH_SHORT).show()
}
}
Column(modifier = Modifier.fillMaxSize().verticalScroll(rememberScrollState()).padding(horizontal = 8.dp)) {
Spacer(Modifier.padding(vertical = 10.dp))
Text(text = stringResource(R.string.always_on_vpn), style = typography.headlineLarge, modifier = Modifier.padding(vertical = 8.dp))
Text(text = stringResource(R.string.current_app_is) + pkg, modifier = Modifier.padding(vertical = 8.dp))
SwitchItem(R.string.enable_lockdown, "", null, lockdown, { lockdown = it }, padding = false)
Spacer(Modifier.padding(vertical = 5.dp))
Button(
onClick = { setAlwaysOnVpn(pkgName, lockdown); refresh() },
modifier = Modifier.fillMaxWidth()
) {
Text(stringResource(R.string.apply))
}
Spacer(Modifier.padding(vertical = 5.dp))
Button(
onClick = { setAlwaysOnVpn(null, false); refresh() },
modifier = Modifier.fillMaxWidth()
) {
Text(stringResource(R.string.clear_current_config))
}
Spacer(Modifier.padding(vertical = 30.dp))
}
}
@SuppressLint("NewApi")
@Composable

View File

@@ -16,6 +16,7 @@ import android.app.admin.WifiSsidPolicy
import android.app.admin.WifiSsidPolicy.WIFI_SSID_POLICY_TYPE_ALLOWLIST
import android.app.admin.WifiSsidPolicy.WIFI_SSID_POLICY_TYPE_DENYLIST
import android.content.Context
import android.content.pm.PackageManager.NameNotFoundException
import android.net.ProxyInfo
import android.net.Uri
import android.net.wifi.WifiSsid
@@ -42,6 +43,7 @@ import android.widget.Toast
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.animateContentSize
import androidx.compose.foundation.ScrollState
import androidx.compose.foundation.clickable
import androidx.compose.foundation.horizontalScroll
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
@@ -50,15 +52,16 @@ import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.offset
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.RoundedCornerShape
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.AlertDialog
import androidx.compose.material3.Button
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme.typography
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Scaffold
@@ -69,17 +72,21 @@ import androidx.compose.material3.TextField
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.MutableState
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.mutableStateListOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.alpha
import androidx.compose.ui.draw.clip
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.input.KeyboardType
@@ -91,6 +98,7 @@ import androidx.navigation.compose.composable
import androidx.navigation.compose.currentBackStackEntryAsState
import androidx.navigation.compose.rememberNavController
import com.bintianqi.owndroid.R
import com.bintianqi.owndroid.selectedPackage
import com.bintianqi.owndroid.toText
import com.bintianqi.owndroid.ui.Animations
import com.bintianqi.owndroid.ui.CheckBoxItem
@@ -130,6 +138,7 @@ fun Network(navCtrl: NavHostController) {
composable(route = "MinWifiSecurityLevel") { WifiSecLevel() }
composable(route = "WifiSsidPolicy") { WifiSsidPolicy() }
composable(route = "PrivateDNS") { PrivateDNS() }
composable(route = "AlwaysOnVpn") { AlwaysOnVPNPackage(navCtrl) }
composable(route = "RecommendedGlobalProxy") { RecommendedGlobalProxy() }
composable(route = "NetworkLog") { NetworkLog() }
composable(route = "WifiAuthKeypair") { WifiAuthKeypair() }
@@ -178,6 +187,9 @@ private fun Home(navCtrl:NavHostController, scrollState: ScrollState, wifiMacDia
if(VERSION.SDK_INT >= 29 && deviceOwner) {
SubPageItem(R.string.private_dns, "", R.drawable.dns_fill0) { navCtrl.navigate("PrivateDNS") }
}
if(VERSION.SDK_INT >= 24 && (deviceOwner || profileOwner)) {
SubPageItem(R.string.always_on_vpn, "", R.drawable.vpn_key_fill0) { navCtrl.navigate("AlwaysOnVpn") }
}
if(deviceOwner) {
SubPageItem(R.string.recommended_global_proxy, "", R.drawable.vpn_key_fill0) { navCtrl.navigate("RecommendedGlobalProxy") }
}
@@ -200,17 +212,17 @@ private fun Switches() {
val dpm = context.getDPM()
val receiver = context.getReceiver()
val deviceOwner = context.isDeviceOwner
Column(modifier = Modifier.fillMaxSize()) {
Column(modifier = Modifier.fillMaxSize().padding(start = 20.dp, end = 16.dp)) {
Spacer(Modifier.padding(vertical = 5.dp))
if(VERSION.SDK_INT >= 33 && deviceOwner) {
SwitchItem(
R.string.preferential_network_service, stringResource(R.string.developing), R.drawable.globe_fill0,
{ dpm.isPreferentialNetworkServiceEnabled }, { dpm.isPreferentialNetworkServiceEnabled = it }
{ dpm.isPreferentialNetworkServiceEnabled }, { dpm.isPreferentialNetworkServiceEnabled = it }, padding = false
)
}
if(VERSION.SDK_INT>=30 && (deviceOwner || dpm.isOrgProfile(receiver))) {
SwitchItem(R.string.lockdown_admin_configured_network, "", R.drawable.wifi_password_fill0,
{ dpm.hasLockdownAdminConfiguredNetworks(receiver) }, { dpm.setConfiguredNetworksLockdownState(receiver,it) }
{ dpm.hasLockdownAdminConfiguredNetworks(receiver) }, { dpm.setConfiguredNetworksLockdownState(receiver,it) }, padding = false
)
}
}
@@ -438,6 +450,77 @@ private fun PrivateDNS() {
}
}
@SuppressLint("NewApi")
@Composable
fun AlwaysOnVPNPackage(navCtrl: NavHostController) {
val context = LocalContext.current
val dpm = context.getDPM()
val receiver = context.getReceiver()
var lockdown by rememberSaveable { mutableStateOf(false) }
var pkgName by rememberSaveable { mutableStateOf("") }
val focusMgr = LocalFocusManager.current
val refresh = { pkgName = dpm.getAlwaysOnVpnPackage(receiver) ?: "" }
LaunchedEffect(Unit) { refresh() }
val updatePackage by selectedPackage.collectAsState()
LaunchedEffect(updatePackage) {
if(selectedPackage.value != "") {
pkgName = selectedPackage.value
selectedPackage.value = ""
}
}
val setAlwaysOnVpn: (String?, Boolean)->Boolean = { vpnPkg: String?, lockdownEnabled: Boolean ->
try {
dpm.setAlwaysOnVpnPackage(receiver, vpnPkg, lockdownEnabled)
Toast.makeText(context, R.string.success, Toast.LENGTH_SHORT).show()
true
} catch(e: UnsupportedOperationException) {
Toast.makeText(context, R.string.unsupported, Toast.LENGTH_SHORT).show()
false
} catch(e: NameNotFoundException) {
Toast.makeText(context, R.string.not_installed, Toast.LENGTH_SHORT).show()
false
}
}
Column(modifier = Modifier.fillMaxSize().verticalScroll(rememberScrollState()).padding(horizontal = 8.dp)) {
Spacer(Modifier.padding(vertical = 10.dp))
Text(text = stringResource(R.string.always_on_vpn), style = typography.headlineLarge, modifier = Modifier.padding(vertical = 8.dp))
OutlinedTextField(
value = pkgName,
onValueChange = { pkgName = it },
label = { Text(stringResource(R.string.package_name)) },
keyboardOptions = KeyboardOptions(imeAction = ImeAction.Done),
keyboardActions = KeyboardActions(onDone = { focusMgr.clearFocus() }),
trailingIcon = {
Icon(painter = painterResource(R.drawable.checklist_fill0), contentDescription = null,
modifier = Modifier
.clip(RoundedCornerShape(50))
.clickable(onClick = {
focusMgr.clearFocus()
navCtrl.navigate("PackageSelector")
})
.padding(3.dp))
},
modifier = Modifier.fillMaxWidth().padding(vertical = 3.dp)
)
SwitchItem(R.string.enable_lockdown, "", null, lockdown, { lockdown = it }, padding = false)
Spacer(Modifier.padding(vertical = 5.dp))
Button(
onClick = { if(setAlwaysOnVpn(pkgName, lockdown)) refresh() },
modifier = Modifier.fillMaxWidth()
) {
Text(stringResource(R.string.apply))
}
Spacer(Modifier.padding(vertical = 5.dp))
Button(
onClick = { if(setAlwaysOnVpn(null, false)) refresh() },
modifier = Modifier.fillMaxWidth()
) {
Text(stringResource(R.string.clear_current_config))
}
Spacer(Modifier.padding(vertical = 30.dp))
}
}
@Composable
private fun RecommendedGlobalProxy() {
val context = LocalContext.current

View File

@@ -114,6 +114,28 @@ fun ShizukuActivate() {
) {
Text(text = stringResource(R.string.list_owners))
}
Button(
onClick = {
coScope.launch{
outputText = service!!.execute("pm list users")
outputTextScrollState.animateScrollTo(0)
}
},
enabled = enabled
) {
Text(text = stringResource(R.string.list_users))
}
Button(
onClick = {
coScope.launch{
outputText = service!!.execute("dumpsys account")
outputTextScrollState.animateScrollTo(0)
}
},
enabled = enabled
) {
Text(text = stringResource(R.string.list_accounts))
}
Spacer(Modifier.padding(vertical = 5.dp))
AnimatedVisibility(showDeviceAdminButton && showDeviceOwnerButton) {

View File

@@ -35,6 +35,7 @@ import android.app.admin.SystemUpdatePolicy
import android.app.admin.SystemUpdatePolicy.TYPE_INSTALL_AUTOMATIC
import android.app.admin.SystemUpdatePolicy.TYPE_INSTALL_WINDOWED
import android.app.admin.SystemUpdatePolicy.TYPE_POSTPONE
import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.net.Uri
@@ -45,16 +46,17 @@ import android.widget.Toast
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.animateContentSize
import androidx.compose.foundation.ScrollState
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.offset
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.foundation.text.selection.SelectionContainer
@@ -62,6 +64,7 @@ import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.AlertDialog
import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme.colorScheme
import androidx.compose.material3.MaterialTheme.typography
import androidx.compose.material3.OutlinedTextField
@@ -79,12 +82,15 @@ import androidx.compose.runtime.mutableStateListOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.alpha
import androidx.compose.ui.draw.clip
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.input.KeyboardType
@@ -100,6 +106,7 @@ import com.bintianqi.owndroid.StopLockTaskModeReceiver
import com.bintianqi.owndroid.fileUriFlow
import com.bintianqi.owndroid.getFile
import com.bintianqi.owndroid.prepareForNotification
import com.bintianqi.owndroid.selectedPackage
import com.bintianqi.owndroid.toText
import com.bintianqi.owndroid.toggle
import com.bintianqi.owndroid.ui.Animations
@@ -117,7 +124,7 @@ import java.util.concurrent.Executors
import kotlin.math.pow
@Composable
fun SystemManage(navCtrl:NavHostController) {
fun SystemManage(navCtrl: NavHostController) {
val localNavCtrl = rememberNavController()
val backStackEntry by localNavCtrl.currentBackStackEntryAsState()
val scrollState = rememberScrollState()
@@ -151,7 +158,7 @@ fun SystemManage(navCtrl:NavHostController) {
composable(route = "PermissionPolicy") { PermissionPolicy() }
composable(route = "MTEPolicy") { MTEPolicy() }
composable(route = "NearbyStreamingPolicy") { NearbyStreamingPolicy() }
composable(route = "LockTaskMode") { LockTaskMode() }
composable(route = "LockTaskMode") { LockTaskMode(navCtrl) }
composable(route = "CaCert") { CaCert() }
composable(route = "SecurityLogs") { SecurityLogs() }
composable(route = "SystemUpdatePolicy") { SysUpdatePolicy() }
@@ -239,53 +246,53 @@ private fun Switches() {
val receiver = context.getReceiver()
val deviceOwner = context.isDeviceOwner
val profileOwner = context.isProfileOwner
Column(modifier = Modifier.fillMaxSize().verticalScroll(rememberScrollState())) {
Column(modifier = Modifier.fillMaxSize().verticalScroll(rememberScrollState()).padding(start = 20.dp, end = 16.dp)) {
Spacer(Modifier.padding(vertical = 10.dp))
if(deviceOwner || profileOwner) {
SwitchItem(R.string.disable_cam,"", R.drawable.photo_camera_fill0,
{ dpm.getCameraDisabled(null) }, { dpm.setCameraDisabled(receiver,it) }
{ dpm.getCameraDisabled(null) }, { dpm.setCameraDisabled(receiver,it) }, padding = false
)
}
if(deviceOwner || profileOwner) {
SwitchItem(R.string.disable_screen_capture, "", R.drawable.screenshot_fill0,
{ dpm.getScreenCaptureDisabled(null) }, { dpm.setScreenCaptureDisabled(receiver,it) }
{ dpm.getScreenCaptureDisabled(null) }, { dpm.setScreenCaptureDisabled(receiver,it) }, padding = false
)
}
if(VERSION.SDK_INT >= 34 && (deviceOwner || (profileOwner && dpm.isAffiliatedUser))) {
SwitchItem(R.string.disable_status_bar, "", R.drawable.notifications_fill0,
{ dpm.isStatusBarDisabled}, { dpm.setStatusBarDisabled(receiver,it) }
{ dpm.isStatusBarDisabled}, { dpm.setStatusBarDisabled(receiver,it) }, padding = false
)
}
if(deviceOwner || dpm.isOrgProfile(receiver)) {
if(VERSION.SDK_INT >= 30) {
SwitchItem(R.string.auto_time, "", R.drawable.schedule_fill0,
{ dpm.getAutoTimeEnabled(receiver) }, { dpm.setAutoTimeEnabled(receiver,it) }
{ dpm.getAutoTimeEnabled(receiver) }, { dpm.setAutoTimeEnabled(receiver,it) }, padding = false
)
SwitchItem(R.string.auto_timezone, "", R.drawable.globe_fill0,
{ dpm.getAutoTimeZoneEnabled(receiver) }, { dpm.setAutoTimeZoneEnabled(receiver,it) }
{ dpm.getAutoTimeZoneEnabled(receiver) }, { dpm.setAutoTimeZoneEnabled(receiver,it) }, padding = false
)
}else{
SwitchItem(R.string.require_auto_time, "", R.drawable.schedule_fill0, { dpm.autoTimeRequired}, { dpm.setAutoTimeRequired(receiver,it) })
SwitchItem(R.string.require_auto_time, "", R.drawable.schedule_fill0, { dpm.autoTimeRequired}, { dpm.setAutoTimeRequired(receiver,it) }, padding = false)
}
}
if(deviceOwner || profileOwner) {
SwitchItem(R.string.master_mute, "", R.drawable.volume_up_fill0,
{ dpm.isMasterVolumeMuted(receiver) }, { dpm.setMasterVolumeMuted(receiver,it) }
{ dpm.isMasterVolumeMuted(receiver) }, { dpm.setMasterVolumeMuted(receiver,it) }, padding = false
)
}
if(VERSION.SDK_INT >= 26 && (deviceOwner || profileOwner)) {
SwitchItem(R.string.backup_service, "", R.drawable.backup_fill0,
{ dpm.isBackupServiceEnabled(receiver) }, { dpm.setBackupServiceEnabled(receiver,it) }
{ dpm.isBackupServiceEnabled(receiver) }, { dpm.setBackupServiceEnabled(receiver,it) }, padding = false
)
}
if(VERSION.SDK_INT >= 23 && (deviceOwner || profileOwner)) {
SwitchItem(R.string.disable_bt_contact_share, "", R.drawable.account_circle_fill0,
{ dpm.getBluetoothContactSharingDisabled(receiver) }, { dpm.setBluetoothContactSharingDisabled(receiver,it) }
{ dpm.getBluetoothContactSharingDisabled(receiver) }, { dpm.setBluetoothContactSharingDisabled(receiver,it) }, padding = false
)
}
if(VERSION.SDK_INT >= 30 && deviceOwner) {
SwitchItem(R.string.common_criteria_mode , "",R.drawable.security_fill0,
{ dpm.isCommonCriteriaModeEnabled(receiver) }, { dpm.setCommonCriteriaModeEnabled(receiver,it) }
{ dpm.isCommonCriteriaModeEnabled(receiver) }, { dpm.setCommonCriteriaModeEnabled(receiver,it) }, padding = false
)
}
if(VERSION.SDK_INT >= 31 && (deviceOwner || dpm.isOrgProfile(receiver))) {
@@ -297,7 +304,7 @@ private fun Switches() {
} else {
Toast.makeText(context, R.string.unsupported, Toast.LENGTH_SHORT).show()
}
}
}, padding = false
)
}
Spacer(Modifier.padding(vertical = 30.dp))
@@ -657,15 +664,16 @@ private fun NearbyStreamingPolicy() {
@SuppressLint("NewApi")
@Composable
private fun LockTaskMode() {
private fun LockTaskMode(navCtrl: NavHostController) {
val context = LocalContext.current
val dpm = context.getDPM()
val receiver = context.getReceiver()
val focusMgr = LocalFocusManager.current
val coroutine = rememberCoroutineScope()
var appSelectorRequest by rememberSaveable { mutableIntStateOf(0) }
Column(modifier = Modifier.fillMaxSize().padding(horizontal = 8.dp).verticalScroll(rememberScrollState())) {
val lockTaskFeatures = remember { mutableStateListOf<Int>() }
var custom by remember { mutableStateOf(false) }
var custom by rememberSaveable { mutableStateOf(false) }
val refreshFeature = {
var calculate = dpm.getLockTaskFeatures(receiver)
lockTaskFeatures.clear()
@@ -756,7 +764,7 @@ private fun LockTaskMode() {
}
val lockTaskPackages = remember { mutableStateListOf<String>() }
var inputLockTaskPkg by remember { mutableStateOf("") }
var inputLockTaskPkg by rememberSaveable { mutableStateOf("") }
LaunchedEffect(Unit) { lockTaskPackages.addAll(dpm.getLockTaskPackages(receiver)) }
Spacer(Modifier.padding(vertical = 10.dp))
Text(text = stringResource(R.string.lock_task_packages), style = typography.headlineLarge)
@@ -772,6 +780,17 @@ private fun LockTaskMode() {
label = { Text(stringResource(R.string.package_name)) },
keyboardOptions = KeyboardOptions(imeAction = ImeAction.Done),
keyboardActions = KeyboardActions(onDone = { focusMgr.clearFocus() }),
trailingIcon = {
Icon(painter = painterResource(R.drawable.checklist_fill0), contentDescription = null,
modifier = Modifier
.clip(RoundedCornerShape(50))
.clickable(onClick = {
focusMgr.clearFocus()
appSelectorRequest = 1
navCtrl.navigate("PackageSelector")
})
.padding(3.dp))
},
modifier = Modifier.fillMaxWidth().padding(vertical = 3.dp)
)
Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween) {
@@ -797,7 +816,16 @@ private fun LockTaskMode() {
) {
Text(stringResource(R.string.apply))
}
var startLockTaskApp by remember { mutableStateOf("") }
var startLockTaskApp by rememberSaveable { mutableStateOf("") }
var startLockTaskActivity by rememberSaveable { mutableStateOf("") }
var specifyActivity by rememberSaveable { mutableStateOf(false) }
val updatePackage by selectedPackage.collectAsState()
LaunchedEffect(updatePackage) {
if(updatePackage != "") {
if(appSelectorRequest == 1) inputLockTaskPkg = updatePackage else startLockTaskApp = updatePackage
selectedPackage.value = ""
}
}
Spacer(Modifier.padding(vertical = 10.dp))
Text(text = stringResource(R.string.start_lock_task_mode), style = typography.headlineLarge)
Spacer(Modifier.padding(vertical = 5.dp))
@@ -807,8 +835,30 @@ private fun LockTaskMode() {
label = { Text(stringResource(R.string.package_name)) },
keyboardOptions = KeyboardOptions(imeAction = ImeAction.Done),
keyboardActions = KeyboardActions(onDone = { focusMgr.clearFocus() }),
trailingIcon = {
Icon(painter = painterResource(R.drawable.checklist_fill0), contentDescription = null,
modifier = Modifier
.clip(RoundedCornerShape(50))
.clickable(onClick = {
focusMgr.clearFocus()
appSelectorRequest = 2
navCtrl.navigate("PackageSelector")
})
.padding(3.dp))
},
modifier = Modifier.fillMaxWidth().padding(vertical = 3.dp)
)
CheckBoxItem(R.string.specify_activity, specifyActivity, { specifyActivity = it })
AnimatedVisibility(specifyActivity) {
OutlinedTextField(
value = startLockTaskActivity,
onValueChange = { startLockTaskActivity = it },
label = { Text("Activity") },
keyboardOptions = KeyboardOptions(imeAction = ImeAction.Done),
keyboardActions = KeyboardActions(onDone = { focusMgr.clearFocus() }),
modifier = Modifier.fillMaxWidth().padding(bottom = 5.dp)
)
}
Button(
modifier = Modifier.fillMaxWidth(),
onClick = {
@@ -818,7 +868,8 @@ private fun LockTaskMode() {
}
val options = ActivityOptions.makeBasic().setLockTaskEnabled(true)
val packageManager = context.packageManager
val launchIntent = packageManager.getLaunchIntentForPackage(startLockTaskApp)
val launchIntent = if(specifyActivity) Intent().setComponent(ComponentName(startLockTaskApp, startLockTaskActivity))
else packageManager.getLaunchIntentForPackage(startLockTaskApp)
if (launchIntent != null) {
coroutine.launch {
prepareForNotification(context) {

View File

@@ -109,6 +109,8 @@
<!--Shizuku-->
<string name="check_shizuku">İzni Kontrol Et</string>
<string name="list_owners">Sahipleri Listele</string>
<string name="list_users">List users</string> <!--TODO-->
<string name="list_accounts">List accounts</string> <!--TODO-->
<string name="shizuku_not_started">Shizuku Başlatılmadı. </string>
<string name="shizuku_activated_shell">İzin Verildi (Kabuk)</string>
<string name="shizuku_activated_root">İzin Verildi (Root)</string>
@@ -160,8 +162,9 @@
<string name="lock_task_mode">Lock task mode</string> <!--TODO-->
<string name="lock_task_feature">Görev kilitleme özelliği</string>
<string name="lock_task_packages">Lock task packages</string> <!--TODO-->
<string name="specify_activity">Specify Activity</string> <!--TODO-->
<string name="start_lock_task_mode">Start lock task mode</string> <!--TODO-->
<string name="app_not_allowed">App not allowed</string> <!--TODO-->
<string name="app_not_allowed">App is not allowed</string> <!--TODO-->
<string name="disable_all">Hepsini devre dışı bırak</string>
<!--ltf: lock task feature-->

View File

@@ -104,6 +104,8 @@
<!--Shizuku-->
<string name="check_shizuku">检查Shizuku</string>
<string name="list_owners">列出Owners</string>
<string name="list_users">列出用户</string>
<string name="list_accounts">列出账号</string>
<string name="shizuku_not_started">服务未启动</string>
<string name="shizuku_activated_shell">已授权Shell</string>
<string name="shizuku_activated_root">已授权Root</string>
@@ -155,6 +157,7 @@
<string name="lock_task_mode">锁定任务模式</string>
<string name="lock_task_feature">锁定任务功能</string>
<string name="lock_task_packages">锁定任务应用</string>
<string name="specify_activity">指定Activity</string>
<string name="start_lock_task_mode">启动锁定任务模式</string>
<string name="app_not_allowed">应用未被允许</string>
<string name="disable_all">禁用全部</string>

View File

@@ -111,6 +111,8 @@
<string name="shizuku" translatable="false">Shizuku</string>
<string name="check_shizuku">Check permission</string>
<string name="list_owners">List owners</string>
<string name="list_users">List users</string>
<string name="list_accounts">List accounts</string>
<string name="shizuku_not_started">Shizuku not started. </string>
<string name="dpm_activate_do_command" translatable="false">dpm set-device-owner com.bintianqi.owndroid/com.bintianqi.owndroid.Receiver</string>
<string name="dpm_activate_da_command" translatable="false">dpm set-active-admin com.bintianqi.owndroid/com.bintianqi.owndroid.Receiver</string>
@@ -164,8 +166,9 @@
<string name="lock_task_mode">Lock task mode</string>
<string name="lock_task_feature">Lock task feature</string>
<string name="lock_task_packages">Lock task packages</string>
<string name="specify_activity">Specify Activity</string>
<string name="start_lock_task_mode">Start lock task mode</string>
<string name="app_not_allowed">App not allowed</string>
<string name="app_not_allowed">App is not allowed</string>
<string name="disable_all">Disable all</string>
<!--ltf: lock task feature-->
<string name="ltf_sys_info">Allow system info</string>