Skip to content

Commit

Permalink
Move AlwaysOnVpn from App manager to Network
Browse files Browse the repository at this point in the history
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
  • Loading branch information
BinTianqi committed Aug 13, 2024
1 parent b452005 commit 32f43ce
Show file tree
Hide file tree
Showing 8 changed files with 202 additions and 83 deletions.
22 changes: 11 additions & 11 deletions app/src/main/java/com/bintianqi/owndroid/Setting.kt
Original file line number Diff line number Diff line change
Expand Up @@ -67,27 +67,27 @@ 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
)
}
}

@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()) {
Expand All @@ -97,7 +97,7 @@ private fun ThemeSettings(materialYou:MutableState<Boolean>, blackTheme:MutableS
{
sharedPref.edit().putBoolean("black_theme", it).apply()
blackTheme.value = it
}
}, padding = false
)
}
}
Expand All @@ -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
)
}
}
Expand Down
46 changes: 0 additions & 46 deletions app/src/main/java/com/bintianqi/owndroid/dpm/ApplicationManage.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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) }
Expand Down Expand Up @@ -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") }
}
Expand Down Expand Up @@ -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
Expand Down
91 changes: 87 additions & 4 deletions app/src/main/java/com/bintianqi/owndroid/dpm/Network.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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() }
Expand Down Expand Up @@ -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") }
}
Expand All @@ -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
)
}
}
Expand Down Expand Up @@ -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
Expand Down
22 changes: 22 additions & 0 deletions app/src/main/java/com/bintianqi/owndroid/dpm/ShizukuActivate.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
Loading

0 comments on commit 32f43ce

Please sign in to comment.