mirror of
https://github.com/awfixers-stuff/OwnDroid.git
synced 2026-03-23 19:15:58 +00:00
App manager: show a dialog when click suspend, hide, block uninstall or always-on vpn
raise pkgName state to save it
This commit is contained in:
@@ -22,7 +22,7 @@ android {
|
|||||||
versionCode = 26
|
versionCode = 26
|
||||||
versionName = "5.1"
|
versionName = "5.1"
|
||||||
multiDexEnabled = false
|
multiDexEnabled = false
|
||||||
//signingConfig = signingConfigs.getByName("testkey")
|
signingConfig = signingConfigs.getByName("testkey")
|
||||||
}
|
}
|
||||||
|
|
||||||
buildTypes {
|
buildTypes {
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package com.bintianqi.owndroid
|
package com.bintianqi.owndroid
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
import android.app.admin.DevicePolicyManager
|
import android.app.admin.DevicePolicyManager
|
||||||
import android.content.ComponentName
|
import android.content.ComponentName
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
@@ -21,8 +22,7 @@ import androidx.compose.material3.Icon
|
|||||||
import androidx.compose.material3.MaterialTheme.colorScheme
|
import androidx.compose.material3.MaterialTheme.colorScheme
|
||||||
import androidx.compose.material3.MaterialTheme.typography
|
import androidx.compose.material3.MaterialTheme.typography
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.*
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.draw.clip
|
import androidx.compose.ui.draw.clip
|
||||||
@@ -60,6 +60,7 @@ class MainActivity : ComponentActivity() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressLint("UnrememberedMutableState")
|
||||||
@ExperimentalMaterial3Api
|
@ExperimentalMaterial3Api
|
||||||
@Composable
|
@Composable
|
||||||
fun MyScaffold(){
|
fun MyScaffold(){
|
||||||
@@ -69,6 +70,8 @@ fun MyScaffold(){
|
|||||||
val myComponent = ComponentName(myContext,Receiver::class.java)
|
val myComponent = ComponentName(myContext,Receiver::class.java)
|
||||||
val sharedPref = LocalContext.current.getSharedPreferences("data", Context.MODE_PRIVATE)
|
val sharedPref = LocalContext.current.getSharedPreferences("data", Context.MODE_PRIVATE)
|
||||||
val focusMgr = LocalFocusManager.current
|
val focusMgr = LocalFocusManager.current
|
||||||
|
val pkgName = mutableStateOf("")
|
||||||
|
val dialogStatus = mutableIntStateOf(0)
|
||||||
SetDarkTheme()
|
SetDarkTheme()
|
||||||
LaunchedEffect(Unit){
|
LaunchedEffect(Unit){
|
||||||
while(true){
|
while(true){
|
||||||
@@ -89,17 +92,17 @@ fun MyScaffold(){
|
|||||||
popEnterTransition = Animations.navHostPopEnterTransition,
|
popEnterTransition = Animations.navHostPopEnterTransition,
|
||||||
popExitTransition = Animations.navHostPopExitTransition
|
popExitTransition = Animations.navHostPopExitTransition
|
||||||
){
|
){
|
||||||
composable(route = "HomePage", content = { HomePage(navCtrl)})
|
composable(route = "HomePage", content = { HomePage(navCtrl, pkgName)})
|
||||||
composable(route = "SystemManage", content = { SystemManage(navCtrl) })
|
composable(route = "SystemManage", content = { SystemManage(navCtrl) })
|
||||||
composable(route = "ManagedProfile", content = {ManagedProfile(navCtrl)})
|
composable(route = "ManagedProfile", content = {ManagedProfile(navCtrl)})
|
||||||
composable(route = "Permissions", content = { DpmPermissions(navCtrl)})
|
composable(route = "Permissions", content = { DpmPermissions(navCtrl)})
|
||||||
composable(route = "ApplicationManage", content = { ApplicationManage(navCtrl)})
|
composable(route = "ApplicationManage", content = { ApplicationManage(navCtrl, pkgName, dialogStatus)})
|
||||||
composable(route = "UserRestriction", content = { UserRestriction(navCtrl)})
|
composable(route = "UserRestriction", content = { UserRestriction(navCtrl)})
|
||||||
composable(route = "UserManage", content = { UserManage(navCtrl)})
|
composable(route = "UserManage", content = { UserManage(navCtrl)})
|
||||||
composable(route = "Password", content = { Password(navCtrl)})
|
composable(route = "Password", content = { Password(navCtrl)})
|
||||||
composable(route = "AppSetting", content = { AppSetting(navCtrl)})
|
composable(route = "AppSetting", content = { AppSetting(navCtrl)})
|
||||||
composable(route = "Network", content = {Network(navCtrl)})
|
composable(route = "Network", content = {Network(navCtrl)})
|
||||||
composable(route = "PackageSelector"){PackageSelector(navCtrl)}
|
composable(route = "PackageSelector"){PackageSelector(navCtrl, pkgName)}
|
||||||
composable(route = "PermissionPicker"){PermissionPicker(navCtrl)}
|
composable(route = "PermissionPicker"){PermissionPicker(navCtrl)}
|
||||||
}
|
}
|
||||||
LaunchedEffect(Unit){
|
LaunchedEffect(Unit){
|
||||||
@@ -114,7 +117,7 @@ fun MyScaffold(){
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun HomePage(navCtrl:NavHostController){
|
private fun HomePage(navCtrl:NavHostController, pkgName: MutableState<String>){
|
||||||
val myContext = LocalContext.current
|
val myContext = LocalContext.current
|
||||||
val myDpm = myContext.getSystemService(ComponentActivity.DEVICE_POLICY_SERVICE) as DevicePolicyManager
|
val myDpm = myContext.getSystemService(ComponentActivity.DEVICE_POLICY_SERVICE) as DevicePolicyManager
|
||||||
val myComponent = ComponentName(myContext,Receiver::class.java)
|
val myComponent = ComponentName(myContext,Receiver::class.java)
|
||||||
@@ -125,6 +128,7 @@ private fun HomePage(navCtrl:NavHostController){
|
|||||||
}
|
}
|
||||||
else if(myDpm.isAdminActive(myComponent)){R.string.device_admin}else{R.string.click_to_activate}
|
else if(myDpm.isAdminActive(myComponent)){R.string.device_admin}else{R.string.click_to_activate}
|
||||||
)
|
)
|
||||||
|
LaunchedEffect(Unit){ pkgName.value = "" }
|
||||||
Column(modifier = Modifier.statusBarsPadding().verticalScroll(rememberScrollState())) {
|
Column(modifier = Modifier.statusBarsPadding().verticalScroll(rememberScrollState())) {
|
||||||
Spacer(Modifier.padding(vertical = 25.dp))
|
Spacer(Modifier.padding(vertical = 25.dp))
|
||||||
Text(text = stringResource(R.string.app_name), style = typography.headlineLarge, modifier = Modifier.padding(start = 10.dp), color = colorScheme.onBackground)
|
Text(text = stringResource(R.string.app_name), style = typography.headlineLarge, modifier = Modifier.padding(start = 10.dp), color = colorScheme.onBackground)
|
||||||
|
|||||||
@@ -21,8 +21,6 @@ import androidx.compose.ui.res.painterResource
|
|||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.navigation.NavHostController
|
import androidx.navigation.NavHostController
|
||||||
import com.bintianqi.owndroid.dpm.applySelectedPackage
|
|
||||||
import com.bintianqi.owndroid.dpm.selectedPackage
|
|
||||||
import com.bintianqi.owndroid.ui.NavIcon
|
import com.bintianqi.owndroid.ui.NavIcon
|
||||||
import com.bintianqi.owndroid.ui.theme.bgColor
|
import com.bintianqi.owndroid.ui.theme.bgColor
|
||||||
import com.google.accompanist.drawablepainter.rememberDrawablePainter
|
import com.google.accompanist.drawablepainter.rememberDrawablePainter
|
||||||
@@ -40,7 +38,7 @@ private val pkgs = mutableListOf<PkgInfo>()
|
|||||||
|
|
||||||
@OptIn(ExperimentalMaterial3Api::class, ExperimentalFoundationApi::class)
|
@OptIn(ExperimentalMaterial3Api::class, ExperimentalFoundationApi::class)
|
||||||
@Composable
|
@Composable
|
||||||
fun PackageSelector(navCtrl:NavHostController){
|
fun PackageSelector(navCtrl:NavHostController, pkgName: MutableState<String>){
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
val pm = context.packageManager
|
val pm = context.packageManager
|
||||||
val apps = pm.getInstalledApplications(0)
|
val apps = pm.getInstalledApplications(0)
|
||||||
@@ -144,7 +142,7 @@ fun PackageSelector(navCtrl:NavHostController){
|
|||||||
if(show) {
|
if(show) {
|
||||||
items(pkgs) {
|
items(pkgs) {
|
||||||
if(filter==it.type){
|
if(filter==it.type){
|
||||||
PackageItem(it, navCtrl)
|
PackageItem(it, navCtrl, pkgName)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
items(1){Spacer(Modifier.padding(vertical = 30.dp))}
|
items(1){Spacer(Modifier.padding(vertical = 30.dp))}
|
||||||
@@ -163,12 +161,12 @@ fun PackageSelector(navCtrl:NavHostController){
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun PackageItem(pkg: PkgInfo, navCtrl: NavHostController){
|
private fun PackageItem(pkg: PkgInfo, navCtrl: NavHostController, pkgName: MutableState<String>){
|
||||||
Row(
|
Row(
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.clickable{selectedPackage =pkg.pkgName;applySelectedPackage =true;navCtrl.navigateUp()}
|
.clickable{ pkgName.value = pkg.pkgName; navCtrl.navigateUp()}
|
||||||
.padding(vertical = 3.dp)
|
.padding(vertical = 3.dp)
|
||||||
){
|
){
|
||||||
Spacer(Modifier.padding(start = 15.dp))
|
Spacer(Modifier.padding(start = 15.dp))
|
||||||
|
|||||||
@@ -32,7 +32,6 @@ import androidx.compose.foundation.text.selection.SelectionContainer
|
|||||||
import androidx.compose.material3.*
|
import androidx.compose.material3.*
|
||||||
import androidx.compose.material3.MaterialTheme.typography
|
import androidx.compose.material3.MaterialTheme.typography
|
||||||
import androidx.compose.runtime.*
|
import androidx.compose.runtime.*
|
||||||
import androidx.compose.runtime.saveable.rememberSaveable
|
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.draw.clip
|
import androidx.compose.ui.draw.clip
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
@@ -43,6 +42,7 @@ import androidx.compose.ui.text.input.ImeAction
|
|||||||
import androidx.compose.ui.text.input.KeyboardType
|
import androidx.compose.ui.text.input.KeyboardType
|
||||||
import androidx.compose.ui.text.style.TextAlign
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.compose.ui.window.Dialog
|
||||||
import androidx.core.content.ContextCompat.startActivity
|
import androidx.core.content.ContextCompat.startActivity
|
||||||
import androidx.navigation.NavHostController
|
import androidx.navigation.NavHostController
|
||||||
import androidx.navigation.compose.NavHost
|
import androidx.navigation.compose.NavHost
|
||||||
@@ -64,10 +64,13 @@ private var keepUninstallPkg = mutableListOf<String>()
|
|||||||
private var permittedIme = mutableListOf<String>()
|
private var permittedIme = mutableListOf<String>()
|
||||||
private var permittedAccessibility = mutableListOf<String>()
|
private var permittedAccessibility = mutableListOf<String>()
|
||||||
|
|
||||||
|
private var dialogConfirmButtonAction = {}
|
||||||
|
private var dialogDismissButtonAction = {}
|
||||||
|
private var dialogGetStatus = { false }
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun ApplicationManage(navCtrl:NavHostController){
|
fun ApplicationManage(navCtrl:NavHostController, pkgName: MutableState<String>, dialogStatus: MutableIntState){
|
||||||
val focusMgr = LocalFocusManager.current
|
val focusMgr = LocalFocusManager.current
|
||||||
var pkgName by rememberSaveable{ mutableStateOf("") }
|
|
||||||
val localNavCtrl = rememberNavController()
|
val localNavCtrl = rememberNavController()
|
||||||
val backStackEntry by localNavCtrl.currentBackStackEntryAsState()
|
val backStackEntry by localNavCtrl.currentBackStackEntryAsState()
|
||||||
val titleMap = mapOf(
|
val titleMap = mapOf(
|
||||||
@@ -96,16 +99,10 @@ fun ApplicationManage(navCtrl:NavHostController){
|
|||||||
}
|
}
|
||||||
){ paddingValues->
|
){ paddingValues->
|
||||||
Column(modifier = Modifier.fillMaxSize().padding(top = paddingValues.calculateTopPadding())){
|
Column(modifier = Modifier.fillMaxSize().padding(top = paddingValues.calculateTopPadding())){
|
||||||
LaunchedEffect(Unit) {
|
|
||||||
while(true){
|
|
||||||
if(applySelectedPackage){ pkgName = selectedPackage; applySelectedPackage = false; applySelectedPermission = true}
|
|
||||||
delay(100)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(backStackEntry?.destination?.route!="InstallApp"){
|
if(backStackEntry?.destination?.route!="InstallApp"){
|
||||||
TextField(
|
TextField(
|
||||||
value = pkgName,
|
value = pkgName.value,
|
||||||
onValueChange = { pkgName = it },
|
onValueChange = { pkgName.value = it },
|
||||||
label = { Text(stringResource(R.string.package_name)) },
|
label = { Text(stringResource(R.string.package_name)) },
|
||||||
modifier = Modifier.fillMaxWidth(),
|
modifier = Modifier.fillMaxWidth(),
|
||||||
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Ascii, imeAction = ImeAction.Done),
|
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Ascii, imeAction = ImeAction.Done),
|
||||||
@@ -128,27 +125,30 @@ fun ApplicationManage(navCtrl:NavHostController){
|
|||||||
popExitTransition = Animations.navHostPopExitTransition,
|
popExitTransition = Animations.navHostPopExitTransition,
|
||||||
modifier = Modifier.background(bgColor)
|
modifier = Modifier.background(bgColor)
|
||||||
){
|
){
|
||||||
composable(route = "Home"){Home(localNavCtrl,pkgName)}
|
composable(route = "Home"){Home(localNavCtrl, pkgName.value, dialogStatus)}
|
||||||
composable(route = "BlockUninstall"){BlockUninstall(pkgName)}
|
composable(route = "UserControlDisabled"){UserCtrlDisabledPkg(pkgName.value)}
|
||||||
composable(route = "UserControlDisabled"){UserCtrlDisabledPkg(pkgName)}
|
composable(route = "PermissionManage"){PermissionManage(pkgName.value, navCtrl)}
|
||||||
composable(route = "PermissionManage"){PermissionManage(pkgName,navCtrl)}
|
composable(route = "CrossProfilePackage"){CrossProfilePkg(pkgName.value)}
|
||||||
composable(route = "CrossProfilePackage"){CrossProfilePkg(pkgName)}
|
composable(route = "CrossProfileWidget"){CrossProfileWidget(pkgName.value)}
|
||||||
composable(route = "CrossProfileWidget"){CrossProfileWidget(pkgName)}
|
composable(route = "CredentialManagePolicy"){CredentialManagePolicy(pkgName.value)}
|
||||||
composable(route = "CredentialManagePolicy"){CredentialManagePolicy(pkgName)}
|
composable(route = "Accessibility"){PermittedAccessibility(pkgName.value)}
|
||||||
composable(route = "Accessibility"){PermittedAccessibility(pkgName)}
|
composable(route = "IME"){PermittedIME(pkgName.value)}
|
||||||
composable(route = "IME"){PermittedIME(pkgName)}
|
composable(route = "KeepUninstalled"){KeepUninstalledApp(pkgName.value)}
|
||||||
composable(route = "KeepUninstalled"){KeepUninstalledApp(pkgName)}
|
|
||||||
composable(route = "InstallApp"){InstallApp()}
|
composable(route = "InstallApp"){InstallApp()}
|
||||||
composable(route = "UninstallApp"){UninstallApp(pkgName)}
|
composable(route = "UninstallApp"){UninstallApp(pkgName.value)}
|
||||||
composable(route = "ClearAppData"){ClearAppData(pkgName)}
|
composable(route = "ClearAppData"){ClearAppData(pkgName.value)}
|
||||||
composable(route = "DefaultDialer"){DefaultDialerApp(pkgName)}
|
composable(route = "DefaultDialer"){DefaultDialerApp(pkgName.value)}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if(dialogStatus.intValue!=0){
|
||||||
|
LocalFocusManager.current.clearFocus()
|
||||||
|
AppControlDialog(dialogStatus)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun Home(navCtrl:NavHostController, pkgName: String){
|
private fun Home(navCtrl:NavHostController, pkgName: String, dialogStatus: MutableIntState){
|
||||||
Column(modifier = Modifier.fillMaxSize().verticalScroll(rememberScrollState())){
|
Column(modifier = Modifier.fillMaxSize().verticalScroll(rememberScrollState())){
|
||||||
val myContext = LocalContext.current
|
val myContext = LocalContext.current
|
||||||
val myDpm = myContext.getSystemService(ComponentActivity.DEVICE_POLICY_SERVICE) as DevicePolicyManager
|
val myDpm = myContext.getSystemService(ComponentActivity.DEVICE_POLICY_SERVICE) as DevicePolicyManager
|
||||||
@@ -163,26 +163,51 @@ private fun Home(navCtrl:NavHostController, pkgName: String){
|
|||||||
startActivity(myContext,intent,null)
|
startActivity(myContext,intent,null)
|
||||||
}
|
}
|
||||||
if(VERSION.SDK_INT>=24&&(isDeviceOwner(myDpm)||isProfileOwner(myDpm))){
|
if(VERSION.SDK_INT>=24&&(isDeviceOwner(myDpm)||isProfileOwner(myDpm))){
|
||||||
SwitchItem(
|
val getSuspendStatus = {
|
||||||
R.string.suspend,"",R.drawable.block_fill0,
|
|
||||||
{
|
|
||||||
try{ myDpm.isPackageSuspended(myComponent, pkgName) }
|
try{ myDpm.isPackageSuspended(myComponent, pkgName) }
|
||||||
catch(e:NameNotFoundException){ false }
|
catch(e:NameNotFoundException){ false }
|
||||||
catch(e:IllegalArgumentException){ false }
|
catch(e:IllegalArgumentException){ false }
|
||||||
},
|
}
|
||||||
{myDpm.setPackagesSuspended(myComponent, arrayOf(pkgName), it)}
|
SwitchItem(
|
||||||
|
title = R.string.suspend, desc = "", icon = R.drawable.block_fill0,
|
||||||
|
getState = getSuspendStatus,
|
||||||
|
onCheckedChange = { myDpm.setPackagesSuspended(myComponent, arrayOf(pkgName), it) },
|
||||||
|
onClickBlank = {
|
||||||
|
dialogGetStatus = getSuspendStatus
|
||||||
|
dialogConfirmButtonAction = { myDpm.setPackagesSuspended(myComponent, arrayOf(pkgName), true) }
|
||||||
|
dialogDismissButtonAction = { myDpm.setPackagesSuspended(myComponent, arrayOf(pkgName), false) }
|
||||||
|
dialogStatus.intValue = 1
|
||||||
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
if(isDeviceOwner(myDpm)||isProfileOwner(myDpm)){
|
if(isDeviceOwner(myDpm)||isProfileOwner(myDpm)){
|
||||||
SwitchItem(
|
SwitchItem(
|
||||||
R.string.hide, stringResource(R.string.isapphidden_desc),R.drawable.visibility_off_fill0,
|
title = R.string.hide, desc = stringResource(R.string.isapphidden_desc), icon = R.drawable.visibility_off_fill0,
|
||||||
{myDpm.isApplicationHidden(myComponent,pkgName)},{myDpm.setApplicationHidden(myComponent, pkgName, it)}
|
getState = { myDpm.isApplicationHidden(myComponent,pkgName) },
|
||||||
|
onCheckedChange = { myDpm.setApplicationHidden(myComponent, pkgName, it) },
|
||||||
|
onClickBlank = {
|
||||||
|
dialogGetStatus = { myDpm.isApplicationHidden(myComponent,pkgName) }
|
||||||
|
dialogConfirmButtonAction = { myDpm.setApplicationHidden(myComponent, pkgName, true) }
|
||||||
|
dialogDismissButtonAction = { myDpm.setApplicationHidden(myComponent, pkgName, false) }
|
||||||
|
dialogStatus.intValue = 2
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
if(isDeviceOwner(myDpm)||isProfileOwner(myDpm)){
|
||||||
|
SwitchItem(
|
||||||
|
title = R.string.block_uninstall, desc = "", icon = R.drawable.delete_forever_fill0,
|
||||||
|
getState = { myDpm.isUninstallBlocked(myComponent,pkgName) },
|
||||||
|
onCheckedChange = { myDpm.setUninstallBlocked(myComponent,pkgName,it) },
|
||||||
|
onClickBlank = {
|
||||||
|
dialogGetStatus = { myDpm.isUninstallBlocked(myComponent,pkgName) }
|
||||||
|
dialogConfirmButtonAction = { myDpm.setUninstallBlocked(myComponent,pkgName,true) }
|
||||||
|
dialogDismissButtonAction = { myDpm.setUninstallBlocked(myComponent,pkgName,false) }
|
||||||
|
dialogStatus.intValue = 3
|
||||||
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
if(VERSION.SDK_INT>=24&&(isDeviceOwner(myDpm)||isProfileOwner(myDpm))){
|
if(VERSION.SDK_INT>=24&&(isDeviceOwner(myDpm)||isProfileOwner(myDpm))){
|
||||||
SwitchItem(
|
val setAlwaysOnVpn: (Boolean)->Unit = {
|
||||||
R.string.always_on_vpn,"",R.drawable.vpn_key_fill0,{pkgName == myDpm.getAlwaysOnVpnPackage(myComponent)},
|
|
||||||
{
|
|
||||||
try {
|
try {
|
||||||
myDpm.setAlwaysOnVpnPackage(myComponent, pkgName, it)
|
myDpm.setAlwaysOnVpnPackage(myComponent, pkgName, it)
|
||||||
} catch(e: UnsupportedOperationException) {
|
} catch(e: UnsupportedOperationException) {
|
||||||
@@ -191,10 +216,17 @@ private fun Home(navCtrl:NavHostController, pkgName: String){
|
|||||||
Toast.makeText(myContext, R.string.not_installed, Toast.LENGTH_SHORT).show()
|
Toast.makeText(myContext, R.string.not_installed, Toast.LENGTH_SHORT).show()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
SwitchItem(
|
||||||
|
title = R.string.always_on_vpn, desc = "", icon = R.drawable.vpn_key_fill0,
|
||||||
|
getState = {pkgName == myDpm.getAlwaysOnVpnPackage(myComponent)},
|
||||||
|
onCheckedChange = setAlwaysOnVpn,
|
||||||
|
onClickBlank = {
|
||||||
|
dialogGetStatus = { pkgName == myDpm.getAlwaysOnVpnPackage(myComponent) }
|
||||||
|
dialogConfirmButtonAction = { setAlwaysOnVpn(true) }
|
||||||
|
dialogDismissButtonAction = { setAlwaysOnVpn(false) }
|
||||||
|
dialogStatus.intValue = 4
|
||||||
}
|
}
|
||||||
if(isDeviceOwner(myDpm)||isProfileOwner(myDpm)){
|
)
|
||||||
SubPageItem(R.string.block_uninstall,"",R.drawable.delete_forever_fill0){navCtrl.navigate("BlockUninstall")}
|
|
||||||
}
|
}
|
||||||
if((VERSION.SDK_INT>=33&&isProfileOwner(myDpm))||(VERSION.SDK_INT>=30&&isDeviceOwner(myDpm))){
|
if((VERSION.SDK_INT>=33&&isProfileOwner(myDpm))||(VERSION.SDK_INT>=30&&isDeviceOwner(myDpm))){
|
||||||
SubPageItem(R.string.ucd,"",R.drawable.do_not_touch_fill0){navCtrl.navigate("UserControlDisabled")}
|
SubPageItem(R.string.ucd,"",R.drawable.do_not_touch_fill0){navCtrl.navigate("UserControlDisabled")}
|
||||||
@@ -300,49 +332,6 @@ private fun UserCtrlDisabledPkg(pkgName:String){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
|
||||||
private fun BlockUninstall(pkgName: String){
|
|
||||||
val myContext = LocalContext.current
|
|
||||||
val myDpm = myContext.getSystemService(ComponentActivity.DEVICE_POLICY_SERVICE) as DevicePolicyManager
|
|
||||||
val myComponent = ComponentName(myContext,Receiver::class.java)
|
|
||||||
val focusMgr = LocalFocusManager.current
|
|
||||||
Column(modifier = Modifier.fillMaxSize().padding(horizontal = 8.dp).verticalScroll(rememberScrollState())){
|
|
||||||
var state by remember{mutableStateOf(myDpm.isUninstallBlocked(myComponent,pkgName))}
|
|
||||||
Spacer(Modifier.padding(vertical = 10.dp))
|
|
||||||
Text(text = stringResource(R.string.block_uninstall), style = typography.headlineLarge)
|
|
||||||
Spacer(Modifier.padding(vertical = 5.dp))
|
|
||||||
Text(stringResource(R.string.current_state, stringResource(if(state){R.string.enabled}else{R.string.disabled})))
|
|
||||||
Spacer(Modifier.padding(vertical = 3.dp))
|
|
||||||
Text(text = stringResource(R.string.sometimes_get_wrong_block_uninstall_state))
|
|
||||||
Spacer(Modifier.padding(vertical = 5.dp))
|
|
||||||
Row(horizontalArrangement = Arrangement.SpaceBetween, modifier = Modifier.fillMaxWidth()) {
|
|
||||||
Button(
|
|
||||||
onClick = {
|
|
||||||
focusMgr.clearFocus()
|
|
||||||
myDpm.setUninstallBlocked(myComponent,pkgName,true)
|
|
||||||
Toast.makeText(myContext, R.string.success, Toast.LENGTH_SHORT).show()
|
|
||||||
state = myDpm.isUninstallBlocked(myComponent,pkgName)
|
|
||||||
},
|
|
||||||
modifier = Modifier.fillMaxWidth(0.49F)
|
|
||||||
) {
|
|
||||||
Text(stringResource(R.string.enable))
|
|
||||||
}
|
|
||||||
Button(
|
|
||||||
onClick = {
|
|
||||||
focusMgr.clearFocus()
|
|
||||||
myDpm.setUninstallBlocked(myComponent,pkgName,false)
|
|
||||||
Toast.makeText(myContext, R.string.success, Toast.LENGTH_SHORT).show()
|
|
||||||
state = myDpm.isUninstallBlocked(myComponent,pkgName)
|
|
||||||
},
|
|
||||||
modifier = Modifier.fillMaxWidth(0.96F)
|
|
||||||
){
|
|
||||||
Text(stringResource(R.string.disable))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Spacer(Modifier.padding(vertical = 30.dp))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressLint("NewApi")
|
@SuppressLint("NewApi")
|
||||||
@Composable
|
@Composable
|
||||||
private fun PermissionManage(pkgName: String, navCtrl: NavHostController){
|
private fun PermissionManage(pkgName: String, navCtrl: NavHostController){
|
||||||
@@ -899,6 +888,62 @@ private fun DefaultDialerApp(pkgName: String){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun AppControlDialog(status: MutableIntState){
|
||||||
|
val enabled = dialogGetStatus()
|
||||||
|
Dialog(
|
||||||
|
onDismissRequest = { status.intValue = 0 }
|
||||||
|
) {
|
||||||
|
Card(
|
||||||
|
modifier = Modifier.fillMaxWidth()
|
||||||
|
){
|
||||||
|
Column(
|
||||||
|
modifier = Modifier.fillMaxWidth().padding(15.dp)
|
||||||
|
){
|
||||||
|
Text(
|
||||||
|
text = stringResource(
|
||||||
|
when(status.intValue){
|
||||||
|
1 -> R.string.suspend
|
||||||
|
2 -> R.string.hide
|
||||||
|
3 -> R.string.block_uninstall
|
||||||
|
4 -> R.string.always_on_vpn
|
||||||
|
else -> R.string.unknown
|
||||||
|
}
|
||||||
|
),
|
||||||
|
style = typography.headlineMedium,
|
||||||
|
modifier = Modifier.padding(start = 5.dp)
|
||||||
|
)
|
||||||
|
Text(
|
||||||
|
text = stringResource(R.string.current_status_is) + stringResource(if(enabled){R.string.enabled}else{R.string.disabled}),
|
||||||
|
modifier = Modifier.padding(start = 5.dp, top = 5.dp, bottom = 5.dp)
|
||||||
|
)
|
||||||
|
Row(
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
horizontalArrangement = Arrangement.SpaceBetween
|
||||||
|
){
|
||||||
|
TextButton(
|
||||||
|
onClick = { status.intValue = 0 }
|
||||||
|
){
|
||||||
|
Text(text = stringResource(R.string.cancel))
|
||||||
|
}
|
||||||
|
Row{
|
||||||
|
TextButton(
|
||||||
|
onClick = { dialogDismissButtonAction(); status.intValue = 0 }
|
||||||
|
){
|
||||||
|
Text(text = stringResource(R.string.disable))
|
||||||
|
}
|
||||||
|
TextButton(
|
||||||
|
onClick = { dialogConfirmButtonAction(); status.intValue = 0 }
|
||||||
|
){
|
||||||
|
Text(text = stringResource(R.string.enable))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Throws(IOException::class)
|
@Throws(IOException::class)
|
||||||
private fun installPackage(context: Context, inputStream: InputStream){
|
private fun installPackage(context: Context, inputStream: InputStream){
|
||||||
val packageInstaller = context.packageManager.packageInstaller
|
val packageInstaller = context.packageManager.packageInstaller
|
||||||
|
|||||||
@@ -5,8 +5,6 @@ import android.content.Intent
|
|||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import androidx.activity.result.ActivityResultLauncher
|
import androidx.activity.result.ActivityResultLauncher
|
||||||
|
|
||||||
var selectedPackage = ""
|
|
||||||
var applySelectedPackage = false
|
|
||||||
var selectedPermission = ""
|
var selectedPermission = ""
|
||||||
var applySelectedPermission = false
|
var applySelectedPermission = false
|
||||||
lateinit var createManagedProfile: ActivityResultLauncher<Intent>
|
lateinit var createManagedProfile: ActivityResultLauncher<Intent>
|
||||||
|
|||||||
@@ -5,7 +5,9 @@ import android.widget.Toast
|
|||||||
import androidx.annotation.DrawableRes
|
import androidx.annotation.DrawableRes
|
||||||
import androidx.annotation.StringRes
|
import androidx.annotation.StringRes
|
||||||
import androidx.compose.animation.animateContentSize
|
import androidx.compose.animation.animateContentSize
|
||||||
|
import androidx.compose.foundation.LocalIndication
|
||||||
import androidx.compose.foundation.clickable
|
import androidx.compose.foundation.clickable
|
||||||
|
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||||
import androidx.compose.foundation.layout.*
|
import androidx.compose.foundation.layout.*
|
||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
import androidx.compose.material3.*
|
import androidx.compose.material3.*
|
||||||
@@ -128,12 +130,21 @@ fun SwitchItem(
|
|||||||
@DrawableRes icon: Int?,
|
@DrawableRes icon: Int?,
|
||||||
getState: ()->Boolean,
|
getState: ()->Boolean,
|
||||||
onCheckedChange: (Boolean)->Unit,
|
onCheckedChange: (Boolean)->Unit,
|
||||||
enable:Boolean=true
|
enable:Boolean = true,
|
||||||
|
onClickBlank: (() -> Unit)? = null
|
||||||
){
|
){
|
||||||
var checked by remember{mutableStateOf(false)}
|
var checked by remember{mutableStateOf(false)}
|
||||||
checked = getState()
|
checked = getState()
|
||||||
Box(modifier = Modifier.fillMaxWidth().padding(vertical = 5.dp)) {
|
Box(
|
||||||
Row(verticalAlignment = Alignment.CenterVertically, modifier = Modifier.align(Alignment.CenterStart)){
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.clickable(enabled = onClickBlank!=null, onClick = onClickBlank?:{})
|
||||||
|
.padding(vertical = 5.dp)
|
||||||
|
) {
|
||||||
|
Row(
|
||||||
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
modifier = Modifier.align(Alignment.CenterStart)
|
||||||
|
){
|
||||||
Spacer(Modifier.padding(start = 30.dp))
|
Spacer(Modifier.padding(start = 30.dp))
|
||||||
if(icon!=null){
|
if(icon!=null){
|
||||||
Icon(painter = painterResource(icon),contentDescription = null)
|
Icon(painter = painterResource(icon),contentDescription = null)
|
||||||
|
|||||||
@@ -45,6 +45,7 @@
|
|||||||
<string name="copy">复制</string>
|
<string name="copy">复制</string>
|
||||||
<string name="file_not_exist">文件不存在</string>
|
<string name="file_not_exist">文件不存在</string>
|
||||||
<string name="io_exception">IO异常</string>
|
<string name="io_exception">IO异常</string>
|
||||||
|
<string name="current_status_is">当前状态:</string>
|
||||||
|
|
||||||
<!--Permissions-->
|
<!--Permissions-->
|
||||||
<string name="click_to_activate">点击以激活</string>
|
<string name="click_to_activate">点击以激活</string>
|
||||||
@@ -256,7 +257,6 @@
|
|||||||
<string name="app_info">应用详情</string>
|
<string name="app_info">应用详情</string>
|
||||||
<string name="not_installed">未安装</string>
|
<string name="not_installed">未安装</string>
|
||||||
<string name="block_uninstall">防卸载</string>
|
<string name="block_uninstall">防卸载</string>
|
||||||
<string name="sometimes_get_wrong_block_uninstall_state">有时候无法正确获取防卸载状态</string>
|
|
||||||
<string name="ucd">禁止用户控制</string>
|
<string name="ucd">禁止用户控制</string>
|
||||||
<string name="ucd_desc">用户将无法清除应用的存储空间和缓存</string>
|
<string name="ucd_desc">用户将无法清除应用的存储空间和缓存</string>
|
||||||
<string name="app_list_is">应用列表:</string>
|
<string name="app_list_is">应用列表:</string>
|
||||||
|
|||||||
@@ -48,6 +48,7 @@
|
|||||||
<string name="copy">Copy</string>
|
<string name="copy">Copy</string>
|
||||||
<string name="file_not_exist">File not exist</string>
|
<string name="file_not_exist">File not exist</string>
|
||||||
<string name="io_exception">IO Exception</string>
|
<string name="io_exception">IO Exception</string>
|
||||||
|
<string name="current_status_is">Current status: </string>
|
||||||
|
|
||||||
<!--Permissions-->
|
<!--Permissions-->
|
||||||
<string name="click_to_activate">Click to activate</string>
|
<string name="click_to_activate">Click to activate</string>
|
||||||
@@ -269,7 +270,6 @@
|
|||||||
<string name="app_info">App info</string>
|
<string name="app_info">App info</string>
|
||||||
<string name="not_installed">Not installed</string>
|
<string name="not_installed">Not installed</string>
|
||||||
<string name="block_uninstall">Block uninstall</string>
|
<string name="block_uninstall">Block uninstall</string>
|
||||||
<string name="sometimes_get_wrong_block_uninstall_state">Sometimes it shows a wrong status</string>
|
|
||||||
<!--ucd: user control disabled-->
|
<!--ucd: user control disabled-->
|
||||||
<string name="ucd">Disable user control</string>
|
<string name="ucd">Disable user control</string>
|
||||||
<string name="ucd_desc">If you set this, you cannot clear storage or cache of the app. </string>
|
<string name="ucd_desc">If you set this, you cannot clear storage or cache of the app. </string>
|
||||||
|
|||||||
Reference in New Issue
Block a user