mirror of
https://github.com/awfixers-stuff/OwnDroid.git
synced 2026-03-23 19:15:58 +00:00
ViewModel refactoring: Permissions part
Add MyDbHelper and MyRepository, use database to store dhizuku clients, fix #168
This commit is contained in:
@@ -7,7 +7,6 @@ import androidx.activity.viewModels
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.fragment.app.FragmentActivity
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.bintianqi.owndroid.ui.AppInstaller
|
||||
import com.bintianqi.owndroid.ui.theme.OwnDroidTheme
|
||||
|
||||
@@ -15,11 +14,10 @@ class AppInstallerActivity:FragmentActivity() {
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
enableEdgeToEdge()
|
||||
super.onCreate(savedInstanceState)
|
||||
val myVm by viewModels<MyViewModel>()
|
||||
val vm by viewModels<AppInstallerViewModel>()
|
||||
vm.initialize(intent)
|
||||
val theme = ThemeSettings(SP.materialYou, SP.darkTheme, SP.blackTheme)
|
||||
setContent {
|
||||
val theme by myVm.theme.collectAsStateWithLifecycle()
|
||||
OwnDroidTheme(theme) {
|
||||
val uiState by vm.uiState.collectAsState()
|
||||
AppInstaller(
|
||||
|
||||
@@ -9,7 +9,6 @@ import android.util.Log
|
||||
import androidx.activity.ComponentActivity
|
||||
import androidx.activity.compose.setContent
|
||||
import androidx.activity.enableEdgeToEdge
|
||||
import androidx.activity.viewModels
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.material3.AlertDialog
|
||||
@@ -24,7 +23,6 @@ import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.bintianqi.owndroid.ui.theme.OwnDroidTheme
|
||||
import com.google.accompanist.drawablepainter.rememberDrawablePainter
|
||||
import com.rosan.dhizuku.aidl.IDhizukuClient
|
||||
@@ -34,12 +32,9 @@ import com.rosan.dhizuku.server_api.DhizukuService
|
||||
import com.rosan.dhizuku.shared.DhizukuVariables
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.json.Json
|
||||
|
||||
private const val TAG = "DhizukuServer"
|
||||
|
||||
const val DHIZUKU_CLIENTS_FILE = "dhizuku_clients.json"
|
||||
|
||||
class MyDhizukuProvider(): DhizukuProvider() {
|
||||
override fun onCreateService(client: IDhizukuClient): DhizukuService? {
|
||||
Log.d(TAG, "Creating MyDhizukuService")
|
||||
@@ -56,8 +51,6 @@ class MyDhizukuService(context: Context, admin: ComponentName, client: IDhizukuC
|
||||
pm.getNameForUid(callingUid) ?: return false,
|
||||
if (Build.VERSION.SDK_INT >= 28) PackageManager.GET_SIGNING_CERTIFICATES else PackageManager.GET_SIGNATURES
|
||||
)
|
||||
val file = mContext.filesDir.resolve(DHIZUKU_CLIENTS_FILE)
|
||||
val clients = Json.decodeFromString<List<DhizukuClientInfo>>(file.readText())
|
||||
val signature = getPackageSignature(packageInfo)
|
||||
val requiredPermission = when (func) {
|
||||
"remote_transact", "remote_process" -> func
|
||||
@@ -65,9 +58,10 @@ class MyDhizukuService(context: Context, admin: ComponentName, client: IDhizukuC
|
||||
"get_delegated_scopes", "set_delegated_scopes" -> "delegated_scopes"
|
||||
else -> "other"
|
||||
}
|
||||
val hasPermission = clients.find {
|
||||
callingUid == it.uid && signature == it.signature && requiredPermission in it.permissions
|
||||
} != null
|
||||
val hasPermission = (mContext.applicationContext as MyApplication).myRepo
|
||||
.checkDhizukuClientPermission(
|
||||
callingUid, signature, requiredPermission
|
||||
)
|
||||
Log.d(TAG, "UID $callingUid, PID $callingPid, required permission: $requiredPermission, has permission: $hasPermission")
|
||||
return hasPermission
|
||||
}
|
||||
@@ -97,26 +91,19 @@ class DhizukuActivity : ComponentActivity() {
|
||||
val icon = appInfo.loadIcon(packageManager)
|
||||
val label = appInfo.loadLabel(packageManager).toString()
|
||||
fun close(grantPermission: Boolean) {
|
||||
val file = filesDir.resolve(DHIZUKU_CLIENTS_FILE)
|
||||
val json = Json { ignoreUnknownKeys = true }
|
||||
val clients = json.decodeFromString<MutableList<DhizukuClientInfo>>(file.readText())
|
||||
val index = clients.indexOfFirst { it.uid == uid }
|
||||
val clientInfo = DhizukuClientInfo(
|
||||
uid, getPackageSignature(packageInfo), if (grantPermission) DhizukuPermissions else emptyList()
|
||||
)
|
||||
if (index == -1) clients += clientInfo
|
||||
else clients[index] = clientInfo
|
||||
file.writeText(Json.encodeToString(clients))
|
||||
(application as MyApplication).myRepo.setDhizukuClient(clientInfo)
|
||||
finish()
|
||||
listener.onRequestPermission(
|
||||
if (grantPermission) PackageManager.PERMISSION_GRANTED else PackageManager.PERMISSION_DENIED
|
||||
)
|
||||
}
|
||||
val vm by viewModels<MyViewModel>()
|
||||
enableEdgeToEdge()
|
||||
val theme = ThemeSettings(SP.materialYou, SP.darkTheme, SP.blackTheme)
|
||||
setContent {
|
||||
var appLockDialog by remember { mutableStateOf(false) }
|
||||
val theme by vm.theme.collectAsStateWithLifecycle()
|
||||
OwnDroidTheme(theme) {
|
||||
if (!appLockDialog) AlertDialog(
|
||||
icon = {
|
||||
|
||||
@@ -293,23 +293,40 @@ fun Home(vm: MyViewModel, onLock: () -> Unit) {
|
||||
) {
|
||||
composable<Home> { HomeScreen(::navigate) }
|
||||
composable<WorkModes> {
|
||||
WorkModesScreen(it.toRoute(), ::navigateUp, {
|
||||
WorkModesScreen(vm, it.toRoute(), ::navigateUp, {
|
||||
navController.navigate(Home) {
|
||||
popUpTo<WorkModes> { inclusive = true }
|
||||
}
|
||||
}, {
|
||||
navController.navigate(WorkModes(false)) {
|
||||
popUpTo(Home) { inclusive = true }
|
||||
}
|
||||
}, ::navigate)
|
||||
}
|
||||
composable<DhizukuServerSettings> { DhizukuServerSettingsScreen(::navigateUp) }
|
||||
|
||||
composable<DelegatedAdmins> { DelegatedAdminsScreen(::navigateUp, ::navigate) }
|
||||
composable<AddDelegatedAdmin>{
|
||||
AddDelegatedAdminScreen(vm.chosenPackage, ::choosePackage, it.toRoute(), ::navigateUp)
|
||||
composable<DhizukuServerSettings> {
|
||||
DhizukuServerSettingsScreen(vm.dhizukuClients, vm::getDhizukuClients,
|
||||
vm::updateDhizukuClient, vm::getDhizukuServerEnabled, vm::setDhizukuServerEnabled,
|
||||
::navigateUp)
|
||||
}
|
||||
|
||||
composable<DelegatedAdmins> {
|
||||
DelegatedAdminsScreen(vm.delegatedAdmins, vm::getDelegatedAdmins, ::navigateUp, ::navigate)
|
||||
}
|
||||
composable<AddDelegatedAdmin>{
|
||||
AddDelegatedAdminScreen(vm.chosenPackage, ::choosePackage, it.toRoute(),
|
||||
vm::setDelegatedAdmin, ::navigateUp)
|
||||
}
|
||||
composable<DeviceInfo> { DeviceInfoScreen(vm, ::navigateUp) }
|
||||
composable<LockScreenInfo> {
|
||||
LockScreenInfoScreen(vm::getLockScreenInfo, vm::setLockScreenInfo, ::navigateUp)
|
||||
}
|
||||
composable<SupportMessage> {
|
||||
SupportMessageScreen(vm::getShortSupportMessage, vm::getLongSupportMessage,
|
||||
vm::setShortSupportMessage, vm::setLongSupportMessage, ::navigateUp)
|
||||
}
|
||||
composable<DeviceInfo> { DeviceInfoScreen(::navigateUp) }
|
||||
composable<LockScreenInfo> { LockScreenInfoScreen(::navigateUp) }
|
||||
composable<SupportMessage> { SupportMessageScreen(::navigateUp) }
|
||||
composable<TransferOwnership> {
|
||||
TransferOwnershipScreen(::navigateUp) {
|
||||
TransferOwnershipScreen(vm.deviceAdminReceivers, vm::getDeviceAdminReceivers,
|
||||
vm::transferOwnership, ::navigateUp) {
|
||||
navController.navigate(WorkModes(false)) {
|
||||
popUpTo(Home) { inclusive = true }
|
||||
}
|
||||
|
||||
@@ -5,12 +5,14 @@ import android.os.Build.VERSION
|
||||
import org.lsposed.hiddenapibypass.HiddenApiBypass
|
||||
|
||||
class MyApplication : Application() {
|
||||
lateinit var myRepo: MyRepository
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
if (VERSION.SDK_INT >= 28) HiddenApiBypass.setHiddenApiExemptions("")
|
||||
SP = SharedPrefs(applicationContext)
|
||||
val dbHelper = MyDbHelper(this)
|
||||
myRepo = MyRepository(dbHelper)
|
||||
Privilege.initialize(applicationContext)
|
||||
Privilege.updateStatus()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
15
app/src/main/java/com/bintianqi/owndroid/MyDbHelper.kt
Normal file
15
app/src/main/java/com/bintianqi/owndroid/MyDbHelper.kt
Normal file
@@ -0,0 +1,15 @@
|
||||
package com.bintianqi.owndroid
|
||||
|
||||
import android.content.Context
|
||||
import android.database.sqlite.SQLiteDatabase
|
||||
import android.database.sqlite.SQLiteOpenHelper
|
||||
|
||||
class MyDbHelper(context: Context): SQLiteOpenHelper(context, "data", null, 1) {
|
||||
override fun onCreate(db: SQLiteDatabase) {
|
||||
db.execSQL("CREATE TABLE dhizuku_clients (uid INTEGER PRIMARY KEY," +
|
||||
"signature TEXT, permissions TEXT)")
|
||||
}
|
||||
override fun onUpgrade(db: SQLiteDatabase?, oldVersion: Int, newVersion: Int) {
|
||||
|
||||
}
|
||||
}
|
||||
46
app/src/main/java/com/bintianqi/owndroid/MyRepository.kt
Normal file
46
app/src/main/java/com/bintianqi/owndroid/MyRepository.kt
Normal file
@@ -0,0 +1,46 @@
|
||||
package com.bintianqi.owndroid
|
||||
|
||||
import android.content.ContentValues
|
||||
import android.database.sqlite.SQLiteDatabase
|
||||
|
||||
class MyRepository(val dbHelper: MyDbHelper) {
|
||||
fun getDhizukuClients(): List<DhizukuClientInfo> {
|
||||
val list = mutableListOf<DhizukuClientInfo>()
|
||||
dbHelper.readableDatabase.rawQuery("SELECT * FROM dhizuku_clients", null).use { cursor ->
|
||||
while (cursor.moveToNext()) {
|
||||
list += DhizukuClientInfo(
|
||||
cursor.getInt(0), cursor.getString(1),
|
||||
cursor.getString(2).split(",").filter { it.isNotEmpty() }
|
||||
)
|
||||
}
|
||||
}
|
||||
return list
|
||||
}
|
||||
fun checkDhizukuClientPermission(uid: Int, signature: String?, permission: String): Boolean {
|
||||
val cursor = if (signature == null) {
|
||||
dbHelper.readableDatabase.rawQuery(
|
||||
"SELECT permissions FROM dhizuku_clients WHERE uid = $uid AND signature IS NULL",
|
||||
null
|
||||
)
|
||||
} else {
|
||||
dbHelper.readableDatabase.rawQuery(
|
||||
"SELECT permissions FROM dhizuku_clients WHERE uid = $uid AND signature = ?",
|
||||
arrayOf(signature)
|
||||
)
|
||||
}
|
||||
return cursor.use {
|
||||
it.moveToNext() && permission in it.getString(0).split(",")
|
||||
}
|
||||
}
|
||||
fun setDhizukuClient(info: DhizukuClientInfo) {
|
||||
val cv = ContentValues()
|
||||
cv.put("uid", info.uid)
|
||||
cv.put("signature", info.signature)
|
||||
cv.put("permissions", info.permissions.joinToString(","))
|
||||
dbHelper.writableDatabase.insertWithOnConflict("dhizuku_clients", null, cv,
|
||||
SQLiteDatabase.CONFLICT_REPLACE)
|
||||
}
|
||||
fun deleteDhizukuClient(info: DhizukuClientInfo) {
|
||||
dbHelper.writableDatabase.delete("dhizuku_clients", "uid = ${info.uid}", null)
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,8 @@ package com.bintianqi.owndroid
|
||||
import android.app.ActivityOptions
|
||||
import android.app.Application
|
||||
import android.app.PendingIntent
|
||||
import android.app.admin.DeviceAdminInfo
|
||||
import android.app.admin.DeviceAdminReceiver
|
||||
import android.app.admin.DevicePolicyManager
|
||||
import android.app.admin.DevicePolicyManager.InstallSystemUpdateCallback
|
||||
import android.app.admin.FactoryResetProtectionPolicy
|
||||
@@ -30,18 +32,25 @@ import androidx.lifecycle.application
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.bintianqi.owndroid.Privilege.DAR
|
||||
import com.bintianqi.owndroid.Privilege.DPM
|
||||
import com.bintianqi.owndroid.dpm.ACTIVATE_DEVICE_OWNER_COMMAND
|
||||
import com.bintianqi.owndroid.dpm.AppStatus
|
||||
import com.bintianqi.owndroid.dpm.CaCertInfo
|
||||
import com.bintianqi.owndroid.dpm.DelegatedAdmin
|
||||
import com.bintianqi.owndroid.dpm.DeviceAdmin
|
||||
import com.bintianqi.owndroid.dpm.FrpPolicyInfo
|
||||
import com.bintianqi.owndroid.dpm.HardwareProperties
|
||||
import com.bintianqi.owndroid.dpm.PendingSystemUpdateInfo
|
||||
import com.bintianqi.owndroid.dpm.SystemOptionsStatus
|
||||
import com.bintianqi.owndroid.dpm.SystemUpdatePolicyInfo
|
||||
import com.bintianqi.owndroid.dpm.delegatedScopesList
|
||||
import com.bintianqi.owndroid.dpm.getPackageInstaller
|
||||
import com.bintianqi.owndroid.dpm.isValidPackageName
|
||||
import com.bintianqi.owndroid.dpm.parsePackageInstallerMessage
|
||||
import com.bintianqi.owndroid.dpm.permissionList
|
||||
import com.bintianqi.owndroid.dpm.temperatureTypes
|
||||
import com.rosan.dhizuku.api.Dhizuku
|
||||
import com.rosan.dhizuku.api.DhizukuRequestPermissionListener
|
||||
import com.topjohnwu.superuser.Shell
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.channels.BufferOverflow
|
||||
import kotlinx.coroutines.channels.Channel
|
||||
@@ -56,6 +65,7 @@ import java.security.cert.X509Certificate
|
||||
import java.util.concurrent.Executors
|
||||
|
||||
class MyViewModel(application: Application): AndroidViewModel(application) {
|
||||
val myRepo = getApplication<MyApplication>().myRepo
|
||||
val PM = application.packageManager
|
||||
val theme = MutableStateFlow(ThemeSettings(SP.materialYou, SP.darkTheme, SP.blackTheme))
|
||||
fun changeTheme(newTheme: ThemeSettings) {
|
||||
@@ -787,6 +797,205 @@ class MyViewModel(application: Application): AndroidViewModel(application) {
|
||||
}
|
||||
DPM.installSystemUpdate(DAR, uri, application.mainExecutor, callback)
|
||||
}
|
||||
|
||||
@RequiresApi(24)
|
||||
fun isCreatingWorkProfileAllowed(): Boolean {
|
||||
return DPM.isProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE)
|
||||
}
|
||||
fun activateDoByShizuku(callback: (Boolean, String?) -> Unit) {
|
||||
viewModelScope.launch {
|
||||
useShizuku(application) { service ->
|
||||
try {
|
||||
val result = IUserService.Stub.asInterface(service)
|
||||
.execute(ACTIVATE_DEVICE_OWNER_COMMAND)
|
||||
if (result == null || result.getInt("code", -1) != 0) {
|
||||
callback(false, null)
|
||||
} else {
|
||||
Privilege.updateStatus()
|
||||
callback(
|
||||
true, result.getString("output") + "\n" + result.getString("error")
|
||||
)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
callback(false, null)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
fun activateDoByRoot(callback: (Boolean, String?) -> Unit) {
|
||||
Shell.getShell { shell ->
|
||||
if(shell.isRoot) {
|
||||
val result = Shell.cmd(ACTIVATE_DEVICE_OWNER_COMMAND).exec()
|
||||
val output = result.out.joinToString("\n") + "\n" + result.err.joinToString("\n")
|
||||
Privilege.updateStatus()
|
||||
callback(result.isSuccess, output)
|
||||
} else {
|
||||
callback(false, application.getString(R.string.permission_denied))
|
||||
}
|
||||
}
|
||||
}
|
||||
@RequiresApi(28)
|
||||
fun activateDoByDhizuku(callback: (Boolean, String?) -> Unit) {
|
||||
DPM.transferOwnership(DAR, MyAdminComponent, null)
|
||||
SP.dhizuku = false
|
||||
Privilege.initialize(application)
|
||||
callback(true, null)
|
||||
}
|
||||
fun activateDhizukuMode(callback: (Boolean, String?) -> Unit) {
|
||||
fun onSucceed() {
|
||||
SP.dhizuku = true
|
||||
Privilege.initialize(application)
|
||||
callback(true, null)
|
||||
}
|
||||
if (Dhizuku.init(application)) {
|
||||
if (Dhizuku.isPermissionGranted()) {
|
||||
onSucceed()
|
||||
} else {
|
||||
Dhizuku.requestPermission(object : DhizukuRequestPermissionListener() {
|
||||
override fun onRequestPermission(grantResult: Int) {
|
||||
if(grantResult == PackageManager.PERMISSION_GRANTED) onSucceed()
|
||||
}
|
||||
})
|
||||
}
|
||||
} else {
|
||||
callback(false, application.getString(R.string.failed_to_init_dhizuku))
|
||||
}
|
||||
}
|
||||
fun clearDeviceOwner() {
|
||||
DPM.clearDeviceOwnerApp(application.packageName)
|
||||
}
|
||||
@RequiresApi(24)
|
||||
fun clearProfileOwner() {
|
||||
DPM.clearProfileOwner(MyAdminComponent)
|
||||
}
|
||||
fun deactivateDhizukuMode() {
|
||||
SP.dhizuku = false
|
||||
Privilege.initialize(application)
|
||||
}
|
||||
val dhizukuClients = MutableStateFlow(emptyList<Pair<DhizukuClientInfo, AppInfo>>())
|
||||
fun getDhizukuClients() {
|
||||
viewModelScope.launch {
|
||||
dhizukuClients.value = myRepo.getDhizukuClients().mapNotNull {
|
||||
val packageName = PM.getNameForUid(it.uid)
|
||||
if (packageName == null) {
|
||||
myRepo.deleteDhizukuClient(it)
|
||||
null
|
||||
} else {
|
||||
it to getAppInfo(packageName)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
fun getDhizukuServerEnabled(): Boolean {
|
||||
return SP.dhizukuServer
|
||||
}
|
||||
fun setDhizukuServerEnabled(status: Boolean) {
|
||||
SP.dhizukuServer = status
|
||||
}
|
||||
fun updateDhizukuClient(info: DhizukuClientInfo) {
|
||||
myRepo.setDhizukuClient(info)
|
||||
dhizukuClients.update { list ->
|
||||
val ml = list.toMutableList()
|
||||
val index = ml.indexOfFirst { it.first.uid == info.uid }
|
||||
ml[index] = info to ml[index].second
|
||||
ml
|
||||
}
|
||||
}
|
||||
@RequiresApi(24)
|
||||
fun getLockScreenInfo(): String {
|
||||
return DPM.deviceOwnerLockScreenInfo?.toString() ?: ""
|
||||
}
|
||||
@RequiresApi(24)
|
||||
fun setLockScreenInfo(text: String) {
|
||||
DPM.setDeviceOwnerLockScreenInfo(DAR, text)
|
||||
}
|
||||
val delegatedAdmins = MutableStateFlow(emptyList<DelegatedAdmin>())
|
||||
@RequiresApi(26)
|
||||
fun getDelegatedAdmins() {
|
||||
val list = mutableListOf<DelegatedAdmin>()
|
||||
delegatedScopesList.forEach { scope ->
|
||||
DPM.getDelegatePackages(DAR, scope.id)?.forEach { pkg ->
|
||||
val index = list.indexOfFirst { it.app.name == pkg }
|
||||
if (index == -1) {
|
||||
list += DelegatedAdmin(getAppInfo(pkg), listOf(scope.id))
|
||||
} else {
|
||||
list[index] = DelegatedAdmin(list[index].app, list[index].scopes + scope.id)
|
||||
}
|
||||
}
|
||||
}
|
||||
delegatedAdmins.value = list
|
||||
}
|
||||
@RequiresApi(26)
|
||||
fun setDelegatedAdmin(name: String, scopes: List<String>) {
|
||||
DPM.setDelegatedScopes(DAR, name, scopes)
|
||||
getDelegatedAdmins()
|
||||
}
|
||||
@RequiresApi(34)
|
||||
fun getDeviceFinanced(): Boolean {
|
||||
return DPM.isDeviceFinanced
|
||||
}
|
||||
@RequiresApi(33)
|
||||
fun getDpmRh(): String? {
|
||||
return DPM.devicePolicyManagementRoleHolderPackage
|
||||
}
|
||||
fun getStorageEncryptionStatus(): Int {
|
||||
return DPM.storageEncryptionStatus
|
||||
}
|
||||
@RequiresApi(28)
|
||||
fun getDeviceIdAttestationSupported(): Boolean {
|
||||
return DPM.isDeviceIdAttestationSupported
|
||||
}
|
||||
@RequiresApi(30)
|
||||
fun getUniqueDeviceAttestationSupported(): Boolean {
|
||||
return DPM.isUniqueDeviceAttestationSupported
|
||||
}
|
||||
fun getActiveAdmins(): String {
|
||||
return DPM.activeAdmins?.joinToString("\n") {
|
||||
it.flattenToShortString()
|
||||
} ?: application.getString(R.string.none)
|
||||
}
|
||||
@RequiresApi(24)
|
||||
fun getShortSupportMessage(): String {
|
||||
return DPM.getShortSupportMessage(DAR)?.toString() ?: ""
|
||||
}
|
||||
@RequiresApi(24)
|
||||
fun getLongSupportMessage(): String {
|
||||
return DPM.getLongSupportMessage(DAR)?.toString() ?: ""
|
||||
}
|
||||
@RequiresApi(24)
|
||||
fun setShortSupportMessage(text: String?) {
|
||||
DPM.setShortSupportMessage(DAR, text)
|
||||
}
|
||||
@RequiresApi(24)
|
||||
fun setLongSupportMessage(text: String?) {
|
||||
DPM.setLongSupportMessage(DAR, text)
|
||||
}
|
||||
val deviceAdminReceivers = MutableStateFlow(emptyList<DeviceAdmin>())
|
||||
fun getDeviceAdminReceivers() {
|
||||
viewModelScope.launch {
|
||||
deviceAdminReceivers.value = PM.queryBroadcastReceivers(
|
||||
Intent(DeviceAdminReceiver.ACTION_DEVICE_ADMIN_ENABLED),
|
||||
PackageManager.GET_META_DATA
|
||||
).mapNotNull {
|
||||
try {
|
||||
DeviceAdminInfo(application, it)
|
||||
} catch(_: Exception) {
|
||||
null
|
||||
}
|
||||
}.filter {
|
||||
it.isVisible && it.packageName != "com.bintianqi.owndroid" &&
|
||||
it.activityInfo.applicationInfo.flags and ApplicationInfo.FLAG_SYSTEM == 0
|
||||
}.map {
|
||||
DeviceAdmin(getAppInfo(it.packageName), it.component)
|
||||
}
|
||||
}
|
||||
}
|
||||
@RequiresApi(28)
|
||||
fun transferOwnership(component: ComponentName) {
|
||||
DPM.transferOwnership(DAR, component, null)
|
||||
Privilege.updateStatus()
|
||||
}
|
||||
}
|
||||
|
||||
data class ThemeSettings(
|
||||
|
||||
@@ -31,6 +31,7 @@ object Privilege {
|
||||
}
|
||||
DPM = context.getSystemService(Context.DEVICE_POLICY_SERVICE) as DevicePolicyManager
|
||||
DAR = MyAdminComponent
|
||||
updateStatus()
|
||||
}
|
||||
lateinit var DPM: DevicePolicyManager
|
||||
private set
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -16,7 +16,6 @@ import android.app.admin.DevicePolicyManager.WIPE_EUICC
|
||||
import android.app.admin.DevicePolicyManager.WIPE_EXTERNAL_STORAGE
|
||||
import android.app.admin.DevicePolicyManager.WIPE_RESET_PROTECTION_DATA
|
||||
import android.app.admin.DevicePolicyManager.WIPE_SILENTLY
|
||||
import android.app.admin.SystemUpdateInfo
|
||||
import android.app.admin.SystemUpdatePolicy.TYPE_INSTALL_AUTOMATIC
|
||||
import android.app.admin.SystemUpdatePolicy.TYPE_INSTALL_WINDOWED
|
||||
import android.app.admin.SystemUpdatePolicy.TYPE_POSTPONE
|
||||
@@ -135,7 +134,6 @@ import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.serialization.Serializable
|
||||
import java.io.ByteArrayOutputStream
|
||||
import java.util.Date
|
||||
import java.util.TimeZone
|
||||
import kotlin.math.roundToLong
|
||||
|
||||
|
||||
@@ -259,7 +259,7 @@ fun InfoItem(title: Int, text: String, withInfo: Boolean = false, onClick: () ->
|
||||
Modifier.fillMaxWidth().padding(vertical = 6.dp).padding(start = HorizontalPadding, end = 8.dp),
|
||||
Arrangement.SpaceBetween, Alignment.CenterVertically
|
||||
) {
|
||||
Column {
|
||||
Column(Modifier.weight(1F)) {
|
||||
Text(stringResource(title), style = typography.titleLarge)
|
||||
Text(text, Modifier.alpha(0.8F))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user