mirror of
https://github.com/awfixers-stuff/OwnDroid.git
synced 2026-03-26 03:56:00 +00:00
Add Privilege class
This commit is contained in:
4
.github/workflows/build.yml
vendored
4
.github/workflows/build.yml
vendored
@@ -3,7 +3,7 @@ name: Build APK
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
branches: ["master"]
|
||||
branches: ["dev"]
|
||||
paths-ignore:
|
||||
- '**.md'
|
||||
tags-ignore:
|
||||
@@ -24,7 +24,7 @@ jobs:
|
||||
- name: Set up JDK 21
|
||||
uses: actions/setup-java@v4
|
||||
with:
|
||||
distribution: 'adopt'
|
||||
distribution: 'temurin'
|
||||
java-version: '21'
|
||||
|
||||
- name: Get short commit SHA
|
||||
|
||||
@@ -80,6 +80,7 @@ import kotlinx.coroutines.flow.update
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import java.net.URLDecoder
|
||||
import androidx.core.net.toUri
|
||||
|
||||
class AppInstallerActivity:FragmentActivity() {
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
@@ -116,11 +117,11 @@ private fun AppInstaller(
|
||||
installing: Boolean = false,
|
||||
options: SessionParamsOptions = SessionParamsOptions(),
|
||||
onOptionsChange: (SessionParamsOptions) -> Unit = {},
|
||||
packages: Set<Uri> = setOf(Uri.parse("https://example.com")),
|
||||
packages: Set<Uri> = setOf("https://example.com".toUri()),
|
||||
onPackageRemove: (Uri) -> Unit = {},
|
||||
onPackageChoose: (List<Uri>) -> Unit = {},
|
||||
onStartInstall: () -> Unit = {},
|
||||
writtenPackages: Set<Uri> = setOf(Uri.parse("https://example.com")),
|
||||
writtenPackages: Set<Uri> = setOf("https://example.com".toUri()),
|
||||
writingPackage: Uri? = null,
|
||||
result: Intent? = null,
|
||||
onResultDialogClose: () -> Unit = {}
|
||||
@@ -309,7 +310,7 @@ class AppInstallerViewModel(application: Application): AndroidViewModel(applicat
|
||||
intent.getParcelableExtra<Uri>(Intent.EXTRA_STREAM)?.let { uri -> packages.update { it + uri } }
|
||||
intent.getParcelableArrayExtra(Intent.EXTRA_STREAM)?.forEach { uri -> packages.update { it + (uri as Uri) } }
|
||||
intent.clipData?.let { clipData ->
|
||||
for(i in 0..(clipData.itemCount - 1)) {
|
||||
for(i in 0..clipData.itemCount) {
|
||||
packages.update { it + clipData.getItemAt(i).uri }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,9 +35,6 @@ import androidx.compose.runtime.DisposableEffect
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
@@ -108,8 +105,6 @@ import com.bintianqi.owndroid.dpm.DelegatedAdmins
|
||||
import com.bintianqi.owndroid.dpm.DelegatedAdminsScreen
|
||||
import com.bintianqi.owndroid.dpm.DeleteWorkProfile
|
||||
import com.bintianqi.owndroid.dpm.DeleteWorkProfileScreen
|
||||
import com.bintianqi.owndroid.dpm.DeviceAdmin
|
||||
import com.bintianqi.owndroid.dpm.DeviceAdminScreen
|
||||
import com.bintianqi.owndroid.dpm.DeviceInfo
|
||||
import com.bintianqi.owndroid.dpm.DeviceInfoScreen
|
||||
import com.bintianqi.owndroid.dpm.DeviceOwner
|
||||
@@ -241,9 +236,6 @@ import com.bintianqi.owndroid.dpm.dhizukuErrorStatus
|
||||
import com.bintianqi.owndroid.dpm.dhizukuPermissionGranted
|
||||
import com.bintianqi.owndroid.dpm.getDPM
|
||||
import com.bintianqi.owndroid.dpm.getReceiver
|
||||
import com.bintianqi.owndroid.dpm.isDeviceAdmin
|
||||
import com.bintianqi.owndroid.dpm.isDeviceOwner
|
||||
import com.bintianqi.owndroid.dpm.isProfileOwner
|
||||
import com.bintianqi.owndroid.dpm.setDefaultAffiliationID
|
||||
import com.bintianqi.owndroid.ui.Animations
|
||||
import com.bintianqi.owndroid.ui.theme.OwnDroidTheme
|
||||
@@ -259,7 +251,6 @@ val backToHomeStateFlow = MutableStateFlow(false)
|
||||
@ExperimentalMaterial3Api
|
||||
class MainActivity : FragmentActivity() {
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
registerActivityResult(this)
|
||||
enableEdgeToEdge()
|
||||
WindowCompat.setDecorFitsSystemWindows(window, false)
|
||||
super.onCreate(savedInstanceState)
|
||||
@@ -288,6 +279,7 @@ class MainActivity : FragmentActivity() {
|
||||
dhizukuErrorStatus.value = 1
|
||||
}
|
||||
}
|
||||
updatePrivilege(this)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -325,9 +317,8 @@ fun Home(vm: MyViewModel) {
|
||||
composable<Permissions> {
|
||||
PermissionsScreen(::navigateUp, { navController.navigate(it) }) { navController.navigate(ShizukuScreen, it) }
|
||||
}
|
||||
composable<ShizukuScreen> { ShizukuScreen(it.arguments!!, ::navigateUp) { navController.navigate(it) } }
|
||||
composable<ShizukuScreen> { ShizukuScreen(it.arguments!!, ::navigateUp) { dest -> navController.navigate(dest) } }
|
||||
composable<Accounts>(mapOf(serializableNavTypePair<List<Accounts.Account>>())) { AccountsScreen(it.toRoute(), ::navigateUp) }
|
||||
composable<DeviceAdmin> { DeviceAdminScreen(::navigateUp) }
|
||||
composable<ProfileOwner> { ProfileOwnerScreen(::navigateUp) }
|
||||
composable<DeviceOwner> { DeviceOwnerScreen(::navigateUp) }
|
||||
composable<DelegatedAdmins> { DelegatedAdminsScreen(::navigateUp, ::navigate) }
|
||||
@@ -385,8 +376,8 @@ fun Home(vm: MyViewModel) {
|
||||
composable<DeleteWorkProfile> { DeleteWorkProfileScreen(::navigateUp) }
|
||||
|
||||
composable<ApplicationsList> {
|
||||
AppChooserScreen(it.toRoute(), {
|
||||
if(it == null) navigateUp() else navigate(ApplicationDetails(it))
|
||||
AppChooserScreen(it.toRoute(), { dest ->
|
||||
if(dest == null) navigateUp() else navigate(ApplicationDetails(dest))
|
||||
}, {
|
||||
SharedPrefs(context).applicationsListView = false
|
||||
navController.navigate(ApplicationsFeatures) {
|
||||
@@ -489,7 +480,7 @@ fun Home(vm: MyViewModel) {
|
||||
LaunchedEffect(Unit) {
|
||||
val dpm = context.getDPM()
|
||||
val sp = SharedPrefs(context)
|
||||
val profileNotActivated = !sp.managedProfileActivated && context.isProfileOwner && (VERSION.SDK_INT < 24 || dpm.isManagedProfile(receiver))
|
||||
val profileNotActivated = !sp.managedProfileActivated && myPrivilege.value.work
|
||||
if(profileNotActivated) {
|
||||
dpm.setProfileEnabled(receiver)
|
||||
sp.managedProfileActivated = true
|
||||
@@ -505,24 +496,14 @@ fun Home(vm: MyViewModel) {
|
||||
private fun HomeScreen(onNavigate: (Any) -> Unit) {
|
||||
val context = LocalContext.current
|
||||
val dpm = context.getDPM()
|
||||
val receiver = context.getReceiver()
|
||||
var activated by remember { mutableStateOf(false) }
|
||||
var activateType by remember { mutableStateOf("") }
|
||||
val deviceAdmin = context.isDeviceAdmin
|
||||
val deviceOwner = context.isDeviceOwner
|
||||
val profileOwner = context.isProfileOwner
|
||||
val refreshStatus by dhizukuErrorStatus.collectAsState()
|
||||
LaunchedEffect(refreshStatus) {
|
||||
activated = context.isProfileOwner || context.isDeviceOwner
|
||||
activateType = if(SharedPrefs(context).dhizuku) context.getString(R.string.dhizuku) + " - " else ""
|
||||
activateType += context.getString(
|
||||
if(deviceOwner) { R.string.device_owner }
|
||||
else if(profileOwner) {
|
||||
if(VERSION.SDK_INT >= 24 && dpm.isManagedProfile(receiver)) R.string.work_profile_owner else R.string.profile_owner
|
||||
}
|
||||
else if(deviceAdmin) R.string.device_admin else R.string.click_to_activate
|
||||
)
|
||||
}
|
||||
val privilege by myPrivilege.collectAsStateWithLifecycle()
|
||||
val activateType = (if(privilege.dhizuku) context.getString(R.string.dhizuku) + " - " else "") +
|
||||
context.getString(
|
||||
if(privilege.device) R.string.device_owner
|
||||
else if(privilege.work) R.string.work_profile_owner
|
||||
else if(privilege.profile) R.string.profile_owner
|
||||
else R.string.click_to_activate
|
||||
)
|
||||
Scaffold {
|
||||
Column(modifier = Modifier.padding(it).verticalScroll(rememberScrollState())) {
|
||||
Spacer(Modifier.padding(vertical = 25.dp))
|
||||
@@ -541,6 +522,7 @@ private fun HomeScreen(onNavigate: (Any) -> Unit) {
|
||||
.padding(vertical = 16.dp),
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
val activated = privilege.device || privilege.profile
|
||||
Icon(
|
||||
painterResource(if(activated) R.drawable.check_circle_fill1 else R.drawable.block_fill0), null,
|
||||
Modifier.padding(start = 14.dp), colorScheme.onPrimary
|
||||
@@ -555,23 +537,32 @@ private fun HomeScreen(onNavigate: (Any) -> Unit) {
|
||||
if(activateType != "") { Text(text = activateType, color = colorScheme.onPrimary) }
|
||||
}
|
||||
}
|
||||
HomePageItem(R.string.system, R.drawable.android_fill0) { onNavigate(SystemManager) }
|
||||
if(deviceOwner || profileOwner) { HomePageItem(R.string.network, R.drawable.wifi_fill0) { onNavigate(Network) } }
|
||||
if(privilege.device || privilege.profile) {
|
||||
HomePageItem(R.string.system, R.drawable.android_fill0) { onNavigate(SystemManager) }
|
||||
HomePageItem(R.string.network, R.drawable.wifi_fill0) { onNavigate(Network) }
|
||||
}
|
||||
if(
|
||||
(VERSION.SDK_INT < 24 && !deviceOwner) || (dpm.isProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE) ||
|
||||
(profileOwner && dpm.isManagedProfile(receiver))
|
||||
)
|
||||
privilege.work || (VERSION.SDK_INT < 24 && !privilege.device) ||
|
||||
dpm.isProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE)
|
||||
) {
|
||||
HomePageItem(R.string.work_profile, R.drawable.work_fill0) { onNavigate(WorkProfile) }
|
||||
HomePageItem(R.string.work_profile, R.drawable.work_fill0) {
|
||||
onNavigate(
|
||||
if(VERSION.SDK_INT < 24 ||
|
||||
dpm.isProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE)
|
||||
) WorkProfile else CreateWorkProfile
|
||||
)
|
||||
}
|
||||
}
|
||||
if(deviceOwner || profileOwner) HomePageItem(R.string.applications, R.drawable.apps_fill0) {
|
||||
onNavigate(if(SharedPrefs(context).applicationsListView) ApplicationsList(true) else ApplicationsFeatures)
|
||||
if(privilege.device || privilege.profile) {
|
||||
HomePageItem(R.string.applications, R.drawable.apps_fill0) {
|
||||
onNavigate(if(SharedPrefs(context).applicationsListView) ApplicationsList(true) else ApplicationsFeatures)
|
||||
}
|
||||
if(VERSION.SDK_INT >= 24) {
|
||||
HomePageItem(R.string.user_restriction, R.drawable.person_off) { onNavigate(UserRestriction) }
|
||||
}
|
||||
HomePageItem(R.string.users,R.drawable.manage_accounts_fill0) { onNavigate(Users) }
|
||||
HomePageItem(R.string.password_and_keyguard, R.drawable.password_fill0) { onNavigate(Password) }
|
||||
}
|
||||
if(VERSION.SDK_INT >= 24 && (profileOwner || deviceOwner)) {
|
||||
HomePageItem(R.string.user_restriction, R.drawable.person_off) { onNavigate(UserRestriction) }
|
||||
}
|
||||
HomePageItem(R.string.users,R.drawable.manage_accounts_fill0) { onNavigate(Users) }
|
||||
if(deviceOwner || profileOwner) HomePageItem(R.string.password_and_keyguard, R.drawable.password_fill0) { onNavigate(Password) }
|
||||
HomePageItem(R.string.settings, R.drawable.settings_fill0) { onNavigate(Settings) }
|
||||
Spacer(Modifier.padding(vertical = 20.dp))
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ import androidx.fragment.app.FragmentActivity
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.bintianqi.owndroid.ui.theme.OwnDroidTheme
|
||||
import kotlin.system.exitProcess
|
||||
import androidx.core.content.edit
|
||||
|
||||
class ManageSpaceActivity: FragmentActivity() {
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
@@ -62,7 +63,7 @@ class ManageSpaceActivity: FragmentActivity() {
|
||||
dataDir.resolve("shared_prefs").deleteRecursively()
|
||||
} else {
|
||||
val sharedPref = applicationContext.getSharedPreferences("data", MODE_PRIVATE)
|
||||
sharedPref.edit().clear().apply()
|
||||
sharedPref.edit { clear() }
|
||||
}
|
||||
this.showOperationResultToast(true)
|
||||
finish()
|
||||
|
||||
39
app/src/main/java/com/bintianqi/owndroid/Privilege.kt
Normal file
39
app/src/main/java/com/bintianqi/owndroid/Privilege.kt
Normal file
@@ -0,0 +1,39 @@
|
||||
package com.bintianqi.owndroid
|
||||
|
||||
import android.content.Context
|
||||
import android.os.Binder
|
||||
import android.os.Build
|
||||
import com.bintianqi.owndroid.dpm.getDPM
|
||||
import com.bintianqi.owndroid.dpm.getReceiver
|
||||
import com.bintianqi.owndroid.dpm.isDeviceOwner
|
||||
import com.bintianqi.owndroid.dpm.isProfileOwner
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
|
||||
class Privilege(
|
||||
val device: Boolean = false, // Device owner
|
||||
val profile: Boolean = false, // Profile owner
|
||||
val dhizuku: Boolean = false,
|
||||
val work: Boolean = false, // Work profile
|
||||
val org: Boolean = false, // Organization-owned work profile
|
||||
val affiliated: Boolean = false
|
||||
) {
|
||||
val primary = Binder.getCallingUid() / 100000 == 0 // Primary user
|
||||
}
|
||||
|
||||
val myPrivilege = MutableStateFlow(Privilege())
|
||||
|
||||
fun updatePrivilege(context: Context) {
|
||||
val dpm = context.getDPM()
|
||||
val receiver = context.getReceiver()
|
||||
val profile = context.isProfileOwner
|
||||
val work = profile && Build.VERSION.SDK_INT >= 24 && dpm.isManagedProfile(receiver)
|
||||
myPrivilege.value = Privilege(
|
||||
device = context.isDeviceOwner,
|
||||
profile = profile,
|
||||
dhizuku = SharedPrefs(context).dhizuku,
|
||||
work = work,
|
||||
org = work && Build.VERSION.SDK_INT >= 30 && dpm.isOrganizationOwnedDeviceWithManagedProfile,
|
||||
affiliated = Build.VERSION.SDK_INT >= 28 && dpm.isAffiliatedUser
|
||||
)
|
||||
}
|
||||
|
||||
@@ -6,21 +6,15 @@ import android.app.admin.DeviceAdminReceiver
|
||||
import android.content.ComponentName
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.pm.ShortcutInfo
|
||||
import android.content.pm.ShortcutManager
|
||||
import android.graphics.drawable.Icon
|
||||
import android.os.Build.VERSION
|
||||
import android.os.PersistableBundle
|
||||
import android.os.UserHandle
|
||||
import android.os.UserManager
|
||||
import android.widget.Toast
|
||||
import androidx.core.app.NotificationCompat
|
||||
import androidx.core.graphics.drawable.toBitmap
|
||||
import com.bintianqi.owndroid.dpm.handleNetworkLogs
|
||||
import com.bintianqi.owndroid.dpm.isDeviceOwner
|
||||
import com.bintianqi.owndroid.dpm.isProfileOwner
|
||||
import com.bintianqi.owndroid.dpm.handlePrivilegeChange
|
||||
import com.bintianqi.owndroid.dpm.processSecurityLogs
|
||||
import com.bintianqi.owndroid.dpm.setDefaultAffiliationID
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
@@ -38,35 +32,18 @@ class Receiver : DeviceAdminReceiver() {
|
||||
dpm.setLockTaskPackages(receiver, arrayOf())
|
||||
dpm.setLockTaskPackages(receiver, packages)
|
||||
}
|
||||
if(!context.isDeviceOwner && !context.isProfileOwner) SharedPrefs(context).isApiEnabled = false
|
||||
}
|
||||
|
||||
override fun onEnabled(context: Context, intent: Intent) {
|
||||
super.onEnabled(context, intent)
|
||||
if(context.isProfileOwner || context.isDeviceOwner){
|
||||
setDefaultAffiliationID(context)
|
||||
Toast.makeText(context, context.getString(R.string.onEnabled), Toast.LENGTH_SHORT).show()
|
||||
if(VERSION.SDK_INT >= 25) {
|
||||
val sm = context.getSystemService(ShortcutManager::class.java)
|
||||
val lockIntent = Intent("com.bintianqi.owndroid.action.LOCK")
|
||||
.setComponent(ComponentName(context, ShortcutsReceiverActivity::class.java))
|
||||
val shortcut = ShortcutInfo.Builder(context, "LockScreen")
|
||||
.setShortLabel(context.getString(R.string.lock_now))
|
||||
.setIcon(Icon.createWithBitmap(context.getDrawable(R.drawable.screen_lock_portrait_fill0)?.toBitmap()))
|
||||
.setIntent(lockIntent)
|
||||
sm.addDynamicShortcuts(listOf(shortcut.build()))
|
||||
}
|
||||
}
|
||||
updatePrivilege(context)
|
||||
handlePrivilegeChange(context)
|
||||
}
|
||||
|
||||
override fun onDisabled(context: Context, intent: Intent) {
|
||||
super.onDisabled(context, intent)
|
||||
Toast.makeText(context, R.string.onDisabled, Toast.LENGTH_SHORT).show()
|
||||
SharedPrefs(context).isDefaultAffiliationIdSet = false
|
||||
if(VERSION.SDK_INT >= 25) {
|
||||
val sm = context.getSystemService(ShortcutManager::class.java)
|
||||
sm.removeDynamicShortcuts(listOf("LockScreen"))
|
||||
}
|
||||
updatePrivilege(context)
|
||||
handlePrivilegeChange(context)
|
||||
}
|
||||
|
||||
override fun onProfileProvisioningComplete(context: Context, intent: Intent) {
|
||||
|
||||
@@ -2,7 +2,6 @@ package com.bintianqi.owndroid
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.os.Build.VERSION
|
||||
import androidx.activity.compose.rememberLauncherForActivityResult
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
@@ -45,6 +44,7 @@ import androidx.compose.ui.text.input.KeyboardType
|
||||
import androidx.compose.ui.unit.DpOffset
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.core.content.edit
|
||||
import androidx.core.net.toUri
|
||||
import com.bintianqi.owndroid.ui.FunctionItem
|
||||
import com.bintianqi.owndroid.ui.MyScaffold
|
||||
import com.bintianqi.owndroid.ui.Notes
|
||||
@@ -285,7 +285,7 @@ fun AboutScreen(onNavigateUp: () -> Unit) {
|
||||
}
|
||||
|
||||
fun shareLink(inputContext: Context, link: String) {
|
||||
val uri = Uri.parse(link)
|
||||
val uri = link.toUri()
|
||||
val intent = Intent(Intent.ACTION_VIEW, uri)
|
||||
inputContext.startActivity(Intent.createChooser(intent, "Open in browser"), null)
|
||||
}
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
package com.bintianqi.owndroid
|
||||
|
||||
import android.content.Context
|
||||
import android.content.SharedPreferences
|
||||
import android.os.Build
|
||||
import androidx.core.content.edit
|
||||
import kotlin.properties.ReadWriteProperty
|
||||
import kotlin.reflect.KProperty
|
||||
|
||||
class SharedPrefs(context: Context) {
|
||||
val sharedPrefs = context.getSharedPreferences("data", Context.MODE_PRIVATE)
|
||||
val sharedPrefs: SharedPreferences = context.getSharedPreferences("data", Context.MODE_PRIVATE)
|
||||
var managedProfileActivated by BooleanSharedPref("managed_profile_activated")
|
||||
var dhizuku by BooleanSharedPref("dhizuku_mode")
|
||||
var isDefaultAffiliationIdSet by BooleanSharedPref("default_affiliation_id_set")
|
||||
|
||||
@@ -1,25 +1,20 @@
|
||||
package com.bintianqi.owndroid
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.admin.DevicePolicyManager
|
||||
import android.content.ClipData
|
||||
import android.content.ClipboardManager
|
||||
import android.content.ComponentName
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.widget.Toast
|
||||
import androidx.activity.ComponentActivity
|
||||
import androidx.activity.result.contract.ActivityResultContract
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.annotation.RequiresApi
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.navigation.NavHostController
|
||||
import androidx.navigation.NavType
|
||||
import com.bintianqi.owndroid.dpm.addDeviceAdmin
|
||||
import kotlinx.serialization.encodeToString
|
||||
import kotlinx.serialization.json.Json
|
||||
import java.io.FileNotFoundException
|
||||
@@ -60,15 +55,6 @@ fun writeClipBoard(context: Context, string: String):Boolean{
|
||||
return true
|
||||
}
|
||||
|
||||
fun registerActivityResult(context: ComponentActivity) {
|
||||
addDeviceAdmin = context.registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
|
||||
val dpm = context.applicationContext.getSystemService(Context.DEVICE_POLICY_SERVICE) as DevicePolicyManager
|
||||
if(dpm.isAdminActive(ComponentName(context.applicationContext, Receiver::class.java))) {
|
||||
backToHomeStateFlow.value = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun formatFileSize(bytes: Long): String {
|
||||
val kb = 1024
|
||||
val mb = kb * 1024
|
||||
@@ -91,15 +77,11 @@ fun parseTimestamp(timestamp: Long): String {
|
||||
return formatter.format(instant)
|
||||
}
|
||||
|
||||
fun parseDate(date: Date)
|
||||
= SimpleDateFormat("yyyy/MM/dd HH:mm:ss", Locale.getDefault()).format(date)
|
||||
fun parseDate(date: Date): String = SimpleDateFormat("yyyy/MM/dd HH:mm:ss", Locale.getDefault()).format(date)
|
||||
|
||||
val Long.humanReadableDate: String
|
||||
get() = SimpleDateFormat("yyyy/MM/dd", Locale.getDefault()).format(Date(this))
|
||||
|
||||
val Long.humanReadableDateTime: String
|
||||
get() = SimpleDateFormat("yyyy/MM/dd HH:mm:ss", Locale.getDefault()).format(Date(this))
|
||||
|
||||
fun formatDate(pattern: String, value: Long): String
|
||||
= SimpleDateFormat(pattern, Locale.getDefault()).format(Date(value))
|
||||
|
||||
|
||||
@@ -76,6 +76,7 @@ import androidx.compose.ui.text.input.ImeAction
|
||||
import androidx.compose.ui.text.input.KeyboardType
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.bintianqi.owndroid.AppInfo
|
||||
import com.bintianqi.owndroid.AppInstallerActivity
|
||||
import com.bintianqi.owndroid.AppInstallerViewModel
|
||||
@@ -84,6 +85,7 @@ import com.bintianqi.owndroid.HorizontalPadding
|
||||
import com.bintianqi.owndroid.R
|
||||
import com.bintianqi.owndroid.getInstalledAppsFlags
|
||||
import com.bintianqi.owndroid.installedApps
|
||||
import com.bintianqi.owndroid.myPrivilege
|
||||
import com.bintianqi.owndroid.showOperationResultToast
|
||||
import com.bintianqi.owndroid.ui.ErrorDialog
|
||||
import com.bintianqi.owndroid.ui.FullWidthRadioButtonItem
|
||||
@@ -179,14 +181,11 @@ fun ApplicationsFeaturesScreen(onNavigateUp: () -> Unit, onNavigate: (Any) -> Un
|
||||
.verticalScroll(rememberScrollState())
|
||||
.padding(bottom = 80.dp)
|
||||
) {
|
||||
val dpm = context.getDPM()
|
||||
val receiver = context.getReceiver()
|
||||
val deviceOwner = context.isDeviceOwner
|
||||
val profileOwner = context.isProfileOwner
|
||||
val privilege by myPrivilege.collectAsStateWithLifecycle()
|
||||
if(VERSION.SDK_INT >= 24) FunctionItem(R.string.suspend, icon = R.drawable.block_fill0) { onNavigate(Suspend) }
|
||||
FunctionItem(R.string.hide, icon = R.drawable.visibility_off_fill0) { onNavigate(Hide) }
|
||||
FunctionItem(R.string.block_uninstall, icon = R.drawable.delete_forever_fill0) { onNavigate(BlockUninstall) }
|
||||
if(VERSION.SDK_INT >= 30 && (deviceOwner || (VERSION.SDK_INT >= 33 && profileOwner))) {
|
||||
if(VERSION.SDK_INT >= 30 && (privilege.device || (VERSION.SDK_INT >= 33 && privilege.profile))) {
|
||||
FunctionItem(R.string.disable_user_control, icon = R.drawable.do_not_touch_fill0) { onNavigate(DisableUserControl) }
|
||||
}
|
||||
if(VERSION.SDK_INT >= 23) {
|
||||
@@ -202,19 +201,19 @@ fun ApplicationsFeaturesScreen(onNavigateUp: () -> Unit, onNavigate: (Any) -> Un
|
||||
context.startActivity(Intent(context, AppInstallerActivity::class.java))
|
||||
}
|
||||
FunctionItem(R.string.uninstall_app, icon = R.drawable.delete_fill0) { onNavigate(UninstallApp) }
|
||||
if(VERSION.SDK_INT >= 28 && deviceOwner) {
|
||||
if(VERSION.SDK_INT >= 28 && privilege.device) {
|
||||
FunctionItem(R.string.keep_uninstalled_packages, icon = R.drawable.delete_fill0) { onNavigate(KeepUninstalledPackages) }
|
||||
}
|
||||
if(VERSION.SDK_INT >= 28) FunctionItem(R.string.install_existing_app, icon = R.drawable.install_mobile_fill0) {
|
||||
onNavigate(InstallExistingApp)
|
||||
}
|
||||
if(VERSION.SDK_INT >= 30 && profileOwner && dpm.isManagedProfile(receiver)) {
|
||||
if(VERSION.SDK_INT >= 30 && privilege.work) {
|
||||
FunctionItem(R.string.cross_profile_apps, icon = R.drawable.work_fill0) { onNavigate(CrossProfilePackages) }
|
||||
}
|
||||
if(profileOwner) {
|
||||
if(privilege.work) {
|
||||
FunctionItem(R.string.cross_profile_widget, icon = R.drawable.widgets_fill0) { onNavigate(CrossProfileWidgetProviders) }
|
||||
}
|
||||
if(VERSION.SDK_INT >= 34 && deviceOwner) {
|
||||
if(VERSION.SDK_INT >= 34 && privilege.device) {
|
||||
FunctionItem(R.string.credential_manager_policy, icon = R.drawable.license_fill0) { onNavigate(CredentialManagerPolicy) }
|
||||
}
|
||||
FunctionItem(R.string.permitted_accessibility_services, icon = R.drawable.settings_accessibility_fill0) {
|
||||
@@ -222,7 +221,7 @@ fun ApplicationsFeaturesScreen(onNavigateUp: () -> Unit, onNavigate: (Any) -> Un
|
||||
}
|
||||
FunctionItem(R.string.permitted_ime, icon = R.drawable.keyboard_fill0) { onNavigate(PermittedInputMethods) }
|
||||
FunctionItem(R.string.enable_system_app, icon = R.drawable.enable_fill0) { onNavigate(EnableSystemApp) }
|
||||
if(VERSION.SDK_INT >= 34 && (deviceOwner || dpm.isOrgProfile(receiver))) {
|
||||
if(VERSION.SDK_INT >= 34 && (privilege.device || privilege.work)) {
|
||||
FunctionItem(R.string.set_default_dialer, icon = R.drawable.call_fill0) { onNavigate(SetDefaultDialer) }
|
||||
}
|
||||
}
|
||||
@@ -445,9 +444,9 @@ fun DisableUserControlScreen(onNavigateUp: () -> Unit) {
|
||||
}
|
||||
LaunchedEffect(Unit) { refresh() }
|
||||
MyLazyScaffold(R.string.disable_user_control, onNavigateUp) {
|
||||
items(packages, { it.name }) {
|
||||
ApplicationItem(it) {
|
||||
dpm.setUserControlDisabledPackages(receiver, packages.minus(it).map { it.name })
|
||||
items(packages, { it.name }) { info ->
|
||||
ApplicationItem(info) {
|
||||
dpm.setUserControlDisabledPackages(receiver, packages.minus(info).map { it.name })
|
||||
refresh()
|
||||
}
|
||||
}
|
||||
@@ -477,6 +476,7 @@ fun PermissionsManagerScreen(onNavigateUp: () -> Unit, param: PermissionsManager
|
||||
val context = LocalContext.current
|
||||
val dpm = context.getDPM()
|
||||
val receiver = context.getReceiver()
|
||||
val privilege by myPrivilege.collectAsStateWithLifecycle()
|
||||
var packageName by remember { mutableStateOf(packageNameParam ?: "") }
|
||||
var selectedPermission by remember { mutableStateOf<PermissionItem?>(null) }
|
||||
val statusMap = remember { mutableStateMapOf<String, Int>() }
|
||||
@@ -551,7 +551,7 @@ fun PermissionsManagerScreen(onNavigateUp: () -> Unit, param: PermissionsManager
|
||||
Column {
|
||||
Text(selectedPermission!!.permission)
|
||||
Spacer(Modifier.padding(vertical = 4.dp))
|
||||
if(!(VERSION.SDK_INT >= 31 && selectedPermission!!.profileOwnerRestricted && context.isProfileOwner)) {
|
||||
if(!(VERSION.SDK_INT >= 31 && selectedPermission!!.profileOwnerRestricted && privilege.profile)) {
|
||||
GrantPermissionItem(R.string.granted, PERMISSION_GRANT_STATE_GRANTED)
|
||||
}
|
||||
GrantPermissionItem(R.string.denied, PERMISSION_GRANT_STATE_DENIED)
|
||||
@@ -581,9 +581,9 @@ fun DisableMeteredDataScreen(onNavigateUp: () -> Unit) {
|
||||
}
|
||||
LaunchedEffect(Unit) { refresh() }
|
||||
MyLazyScaffold(R.string.disable_metered_data, onNavigateUp) {
|
||||
items(packages, { it.name }) {
|
||||
ApplicationItem(it) {
|
||||
dpm.setMeteredDataDisabledPackages(receiver, packages.minus(it).map { it.name })
|
||||
items(packages, { it.name }) { info ->
|
||||
ApplicationItem(info) {
|
||||
dpm.setMeteredDataDisabledPackages(receiver, packages.minus(info).map { it.name })
|
||||
refresh()
|
||||
}
|
||||
}
|
||||
@@ -732,9 +732,9 @@ fun KeepUninstalledPackagesScreen(onNavigateUp: () -> Unit) {
|
||||
}
|
||||
LaunchedEffect(Unit) { refresh() }
|
||||
MyLazyScaffold(R.string.keep_uninstalled_packages, onNavigateUp) {
|
||||
items(packages, { it.name }) {
|
||||
ApplicationItem(it) {
|
||||
dpm.setKeepUninstalledPackages(receiver, packages.minus(it).map { it.name })
|
||||
items(packages, { it.name }) { info ->
|
||||
ApplicationItem(info) {
|
||||
dpm.setKeepUninstalledPackages(receiver, packages.minus(info).map { it.name })
|
||||
refresh()
|
||||
}
|
||||
}
|
||||
@@ -798,9 +798,9 @@ fun CrossProfilePackagesScreen(onNavigateUp: () -> Unit) {
|
||||
}
|
||||
LaunchedEffect(Unit) { refresh() }
|
||||
MyLazyScaffold(R.string.cross_profile_apps, onNavigateUp) {
|
||||
items(packages, { it.name }) {
|
||||
ApplicationItem(it) {
|
||||
dpm.setCrossProfilePackages(receiver, packages.minus(it).map { it.name }.toSet())
|
||||
items(packages, { it.name }) { info ->
|
||||
ApplicationItem(info) {
|
||||
dpm.setCrossProfilePackages(receiver, packages.minus(info).map { it.name }.toSet())
|
||||
refresh()
|
||||
}
|
||||
}
|
||||
@@ -1062,6 +1062,7 @@ fun EnableSystemAppScreen(onNavigateUp: () -> Unit) {
|
||||
) {
|
||||
Text(stringResource(R.string.enable))
|
||||
}
|
||||
Notes(R.string.enable_system_app)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -14,17 +14,21 @@ import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.pm.IPackageInstaller
|
||||
import android.content.pm.PackageInstaller
|
||||
import android.content.pm.ShortcutInfo
|
||||
import android.content.pm.ShortcutManager
|
||||
import android.graphics.drawable.Icon
|
||||
import android.os.Build.VERSION
|
||||
import android.os.UserManager
|
||||
import android.util.Log
|
||||
import androidx.activity.result.ActivityResultLauncher
|
||||
import androidx.annotation.DrawableRes
|
||||
import androidx.annotation.RequiresApi
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.core.graphics.drawable.toBitmap
|
||||
import com.bintianqi.owndroid.R
|
||||
import com.bintianqi.owndroid.Receiver
|
||||
import com.bintianqi.owndroid.SharedPrefs
|
||||
import com.bintianqi.owndroid.ShortcutsReceiverActivity
|
||||
import com.bintianqi.owndroid.backToHomeStateFlow
|
||||
import com.bintianqi.owndroid.myPrivilege
|
||||
import com.rosan.dhizuku.api.Dhizuku
|
||||
import com.rosan.dhizuku.api.Dhizuku.binderWrapper
|
||||
import com.rosan.dhizuku.api.DhizukuBinderWrapper
|
||||
@@ -39,8 +43,6 @@ import kotlinx.serialization.json.put
|
||||
import kotlinx.serialization.json.putJsonArray
|
||||
import java.io.OutputStream
|
||||
|
||||
lateinit var addDeviceAdmin: ActivityResultLauncher<Intent>
|
||||
|
||||
val Context.isDeviceOwner: Boolean
|
||||
get() {
|
||||
val dpm = getSystemService(Context.DEVICE_POLICY_SERVICE) as DevicePolicyManager
|
||||
@@ -59,11 +61,6 @@ val Context.isProfileOwner: Boolean
|
||||
return dpm.isProfileOwnerApp("com.bintianqi.owndroid")
|
||||
}
|
||||
|
||||
val Context.isDeviceAdmin: Boolean
|
||||
get() {
|
||||
return getDPM().isAdminActive(getReceiver())
|
||||
}
|
||||
|
||||
val Context.dpcPackageName: String
|
||||
get() {
|
||||
return if(SharedPrefs(this).dhizuku) {
|
||||
@@ -73,10 +70,6 @@ val Context.dpcPackageName: String
|
||||
}
|
||||
}
|
||||
|
||||
fun DevicePolicyManager.isOrgProfile(receiver: ComponentName): Boolean {
|
||||
return VERSION.SDK_INT >= 30 && this.isProfileOwnerApp("com.bintianqi.owndroid") && isManagedProfile(receiver) && isOrganizationOwnedDeviceWithManagedProfile
|
||||
}
|
||||
|
||||
@SuppressLint("PrivateApi")
|
||||
private fun binderWrapperDevicePolicyManager(appContext: Context): DevicePolicyManager? {
|
||||
try {
|
||||
@@ -544,10 +537,10 @@ fun parseSecurityEventData(event: SecurityLog.SecurityEvent): JsonElement? {
|
||||
fun setDefaultAffiliationID(context: Context) {
|
||||
if(VERSION.SDK_INT < 26) return
|
||||
val sp = SharedPrefs(context)
|
||||
val privilege = myPrivilege.value
|
||||
if(!sp.isDefaultAffiliationIdSet) {
|
||||
try {
|
||||
val um = context.getSystemService(Context.USER_SERVICE) as UserManager
|
||||
if(context.isDeviceOwner || (!um.isSystemUser && context.isProfileOwner)) {
|
||||
if(privilege.device || (!privilege.primary && privilege.profile)) {
|
||||
val dpm = context.getDPM()
|
||||
val receiver = context.getReceiver()
|
||||
val affiliationIDs = dpm.getAffiliationIds(receiver)
|
||||
@@ -596,3 +589,31 @@ fun parsePackageInstallerMessage(context: Context, result: Intent): String {
|
||||
else -> ""
|
||||
} + statusMessage.let { if(it == null) "" else "\n$it" }
|
||||
}
|
||||
|
||||
|
||||
fun handlePrivilegeChange(context: Context) {
|
||||
val privilege = myPrivilege.value
|
||||
val activated = privilege.device || privilege.profile
|
||||
if(activated) {
|
||||
if(!privilege.dhizuku) {
|
||||
setDefaultAffiliationID(context)
|
||||
if(VERSION.SDK_INT >= 25) {
|
||||
val sm = context.getSystemService(ShortcutManager::class.java)
|
||||
val lockIntent = Intent("com.bintianqi.owndroid.action.LOCK")
|
||||
.setComponent(ComponentName(context, ShortcutsReceiverActivity::class.java))
|
||||
val shortcut = ShortcutInfo.Builder(context, "LockScreen")
|
||||
.setShortLabel(context.getString(R.string.lock_now))
|
||||
.setIcon(Icon.createWithBitmap(context.getDrawable(R.drawable.screen_lock_portrait_fill0)?.toBitmap()))
|
||||
.setIntent(lockIntent)
|
||||
sm.addDynamicShortcuts(listOf(shortcut.build()))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
SharedPrefs(context).isDefaultAffiliationIdSet = false
|
||||
if(VERSION.SDK_INT >= 25) {
|
||||
val sm = context.getSystemService(ShortcutManager::class.java)
|
||||
sm.removeDynamicShortcuts(listOf("LockScreen"))
|
||||
}
|
||||
SharedPrefs(context).isApiEnabled = false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,7 +26,6 @@ import android.net.IpConfiguration
|
||||
import android.net.LinkAddress
|
||||
import android.net.ProxyInfo
|
||||
import android.net.StaticIpConfiguration
|
||||
import android.net.Uri
|
||||
import android.net.wifi.WifiConfiguration
|
||||
import android.net.wifi.WifiManager
|
||||
import android.net.wifi.WifiSsid
|
||||
@@ -124,14 +123,16 @@ import androidx.compose.ui.text.input.ImeAction
|
||||
import androidx.compose.ui.text.input.KeyboardType
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.core.net.toUri
|
||||
import androidx.core.os.bundleOf
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.bintianqi.owndroid.ChoosePackageContract
|
||||
import com.bintianqi.owndroid.HorizontalPadding
|
||||
import com.bintianqi.owndroid.R
|
||||
import com.bintianqi.owndroid.SharedPrefs
|
||||
import com.bintianqi.owndroid.formatDate
|
||||
import com.bintianqi.owndroid.formatFileSize
|
||||
import com.bintianqi.owndroid.humanReadableDate
|
||||
import com.bintianqi.owndroid.myPrivilege
|
||||
import com.bintianqi.owndroid.showOperationResultToast
|
||||
import com.bintianqi.owndroid.ui.CheckBoxItem
|
||||
import com.bintianqi.owndroid.ui.ErrorDialog
|
||||
@@ -163,29 +164,24 @@ import kotlin.reflect.jvm.jvmErasure
|
||||
|
||||
@Composable
|
||||
fun NetworkScreen(onNavigateUp: () -> Unit, onNavigate: (Any) -> Unit) {
|
||||
val context = LocalContext.current
|
||||
val dpm = context.getDPM()
|
||||
val receiver = context.getReceiver()
|
||||
val deviceOwner = context.isDeviceOwner
|
||||
val profileOwner = context.isProfileOwner
|
||||
val dhizuku = SharedPrefs(context).dhizuku
|
||||
val privilege by myPrivilege.collectAsStateWithLifecycle()
|
||||
MyScaffold(R.string.network, onNavigateUp, 0.dp) {
|
||||
if(!dhizuku) FunctionItem(R.string.wifi, icon = R.drawable.wifi_fill0) { onNavigate(WiFi) }
|
||||
if(!privilege.dhizuku) FunctionItem(R.string.wifi, icon = R.drawable.wifi_fill0) { onNavigate(WiFi) }
|
||||
if(VERSION.SDK_INT >= 30) {
|
||||
FunctionItem(R.string.options, icon = R.drawable.tune_fill0) { onNavigate(NetworkOptions) }
|
||||
}
|
||||
if(VERSION.SDK_INT >= 23 && !dhizuku && (deviceOwner || profileOwner))
|
||||
if(VERSION.SDK_INT >= 23 && !privilege.dhizuku && (privilege.device || privilege.profile))
|
||||
FunctionItem(R.string.network_stats, icon = R.drawable.query_stats_fill0) { onNavigate(QueryNetworkStats) }
|
||||
if(VERSION.SDK_INT >= 29 && deviceOwner) {
|
||||
if(VERSION.SDK_INT >= 29 && privilege.device) {
|
||||
FunctionItem(R.string.private_dns, icon = R.drawable.dns_fill0) { onNavigate(PrivateDns) }
|
||||
}
|
||||
if(VERSION.SDK_INT >= 24) {
|
||||
FunctionItem(R.string.always_on_vpn, icon = R.drawable.vpn_key_fill0) { onNavigate(AlwaysOnVpnPackage) }
|
||||
}
|
||||
if(deviceOwner) {
|
||||
if(privilege.device) {
|
||||
FunctionItem(R.string.recommended_global_proxy, icon = R.drawable.vpn_key_fill0) { onNavigate(RecommendedGlobalProxy) }
|
||||
}
|
||||
if(VERSION.SDK_INT >= 26 && !dhizuku && (deviceOwner || (profileOwner && dpm.isManagedProfile(receiver)))) {
|
||||
if(VERSION.SDK_INT >= 26 && !privilege.dhizuku && (privilege.device || privilege.work)) {
|
||||
FunctionItem(R.string.network_logging, icon = R.drawable.description_fill0) { onNavigate(NetworkLogging) }
|
||||
}
|
||||
if(VERSION.SDK_INT >= 31) {
|
||||
@@ -194,7 +190,7 @@ fun NetworkScreen(onNavigateUp: () -> Unit, onNavigate: (Any) -> Unit) {
|
||||
if(VERSION.SDK_INT >= 33) {
|
||||
FunctionItem(R.string.preferential_network_service, icon = R.drawable.globe_fill0) { onNavigate(PreferentialNetworkService) }
|
||||
}
|
||||
if(VERSION.SDK_INT >= 28 && deviceOwner) {
|
||||
if(VERSION.SDK_INT >= 28 && privilege.device) {
|
||||
FunctionItem(R.string.override_apn, icon = R.drawable.cell_tower_fill0) { onNavigate(OverrideApn) }
|
||||
}
|
||||
}
|
||||
@@ -207,10 +203,10 @@ fun NetworkOptionsScreen(onNavigateUp: () -> Unit) {
|
||||
val context = LocalContext.current
|
||||
val dpm = context.getDPM()
|
||||
val receiver = context.getReceiver()
|
||||
val deviceOwner = context.isDeviceOwner
|
||||
val privilege by myPrivilege.collectAsStateWithLifecycle()
|
||||
var dialog by remember { mutableIntStateOf(0) }
|
||||
MyScaffold(R.string.options, onNavigateUp, 0.dp) {
|
||||
if(VERSION.SDK_INT>=30 && (deviceOwner || dpm.isOrgProfile(receiver))) {
|
||||
if(VERSION.SDK_INT >= 30 && (privilege.device || privilege.org)) {
|
||||
SwitchItem(R.string.lockdown_admin_configured_network, icon = R.drawable.wifi_password_fill0,
|
||||
getState = { dpm.hasLockdownAdminConfiguredNetworks(receiver) }, onCheckedChange = { dpm.setConfiguredNetworksLockdownState(receiver,it) },
|
||||
onClickBlank = { dialog = 1 }
|
||||
@@ -265,9 +261,8 @@ fun WifiScreen(onNavigateUp: () -> Unit, onNavigate: (Any) -> Unit, onNavigateTo
|
||||
}
|
||||
HorizontalPager(state = pagerState, verticalAlignment = Alignment.Top) { page ->
|
||||
if(page == 0) {
|
||||
val wm = context.getSystemService(Context.WIFI_SERVICE) as WifiManager
|
||||
val deviceOwner = context.isDeviceOwner
|
||||
val orgProfileOwner = context.getDPM().isOrgProfile(context.getReceiver())
|
||||
val wm = context.applicationContext.getSystemService(Context.WIFI_SERVICE) as WifiManager
|
||||
val privilege by myPrivilege.collectAsStateWithLifecycle()
|
||||
@Suppress("DEPRECATION") Column(
|
||||
modifier = Modifier.fillMaxSize().padding(top = 12.dp)
|
||||
) {
|
||||
@@ -299,10 +294,10 @@ fun WifiScreen(onNavigateUp: () -> Unit, onNavigate: (Any) -> Unit, onNavigateTo
|
||||
Text(stringResource(R.string.reconnect))
|
||||
}
|
||||
}
|
||||
if(VERSION.SDK_INT >= 24 && (deviceOwner || orgProfileOwner)) {
|
||||
if(VERSION.SDK_INT >= 24 && (privilege.device || privilege.org)) {
|
||||
FunctionItem(R.string.wifi_mac_address) { wifiMacDialog = true }
|
||||
}
|
||||
if(VERSION.SDK_INT >= 33 && (deviceOwner || orgProfileOwner)) {
|
||||
if(VERSION.SDK_INT >= 33 && (privilege.device || privilege.org)) {
|
||||
FunctionItem(R.string.min_wifi_security_level) { onNavigate(WifiSecurityLevel) }
|
||||
FunctionItem(R.string.wifi_ssid_policy) { onNavigate(WifiSsidPolicyScreen) }
|
||||
}
|
||||
@@ -315,7 +310,6 @@ fun WifiScreen(onNavigateUp: () -> Unit, onNavigate: (Any) -> Unit, onNavigateTo
|
||||
}
|
||||
}
|
||||
if(wifiMacDialog && VERSION.SDK_INT >= 24) {
|
||||
val context = LocalContext.current
|
||||
val dpm = context.getDPM()
|
||||
val receiver = context.getReceiver()
|
||||
AlertDialog(
|
||||
@@ -344,7 +338,7 @@ fun WifiScreen(onNavigateUp: () -> Unit, onNavigate: (Any) -> Unit, onNavigateTo
|
||||
@Composable
|
||||
private fun SavedNetworks(onNavigateToUpdateNetwork: (Bundle) -> Unit) {
|
||||
val context = LocalContext.current
|
||||
val wm = context.getSystemService(Context.WIFI_SERVICE) as WifiManager
|
||||
val wm = context.applicationContext.getSystemService(Context.WIFI_SERVICE) as WifiManager
|
||||
val configuredNetworks = remember { mutableStateListOf<WifiConfiguration>() }
|
||||
var networkDetailsDialog by remember { mutableIntStateOf(-1) } // -1:Hidden, 0+:Index of configuredNetworks
|
||||
val coroutine = rememberCoroutineScope()
|
||||
@@ -688,7 +682,7 @@ private fun AddNetworkScreen(wifiConfig: WifiConfiguration? = null, onNavigateUp
|
||||
}
|
||||
Button(
|
||||
onClick = {
|
||||
val wm = context.getSystemService(Context.WIFI_SERVICE) as WifiManager
|
||||
val wm = context.applicationContext.getSystemService(Context.WIFI_SERVICE) as WifiManager
|
||||
try {
|
||||
val config = WifiConfiguration()
|
||||
config.status = status
|
||||
@@ -899,7 +893,7 @@ fun NetworkStats.toBucketList(): List<NetworkStats.Bucket> {
|
||||
@Composable
|
||||
fun NetworkStatsScreen(onNavigateUp: () -> Unit, onNavigateToViewer: (NetworkStatsViewer) -> Unit) {
|
||||
val context = LocalContext.current
|
||||
val deviceOwner = context.isDeviceOwner
|
||||
val privilege by myPrivilege.collectAsStateWithLifecycle()
|
||||
val fm = LocalFocusManager.current
|
||||
val nsm = context.getSystemService(NetworkStatsManager::class.java)
|
||||
val coroutine = rememberCoroutineScope()
|
||||
@@ -971,7 +965,7 @@ fun NetworkStatsScreen(onNavigateUp: () -> Unit, onNavigateToViewer: (NetworkSta
|
||||
NetworkStatsTarget.entries.forEach {
|
||||
if(
|
||||
VERSION.SDK_INT >= it.minApi &&
|
||||
(deviceOwner || it != NetworkStatsTarget.Device) &&
|
||||
(privilege.device || it != NetworkStatsTarget.Device) &&
|
||||
((queryType == 1 && (it == NetworkStatsTarget.Device || it == NetworkStatsTarget.User)) ||
|
||||
(queryType == 2 && (it == NetworkStatsTarget.Uid || it == NetworkStatsTarget.UidTag || it == NetworkStatsTarget.UidTagState)))
|
||||
) DropdownMenuItem(
|
||||
@@ -1120,7 +1114,7 @@ fun NetworkStatsScreen(onNavigateUp: () -> Unit, onNavigateToViewer: (NetworkSta
|
||||
if(VERSION.SDK_INT >= 24 && (target == NetworkStatsTarget.UidTag || target == NetworkStatsTarget.UidTagState))
|
||||
ExposedDropdownMenuBox(
|
||||
activeTextField == NetworkStatsActiveTextField.Tag,
|
||||
{ activeTextField == if(it) NetworkStatsActiveTextField.Tag else NetworkStatsActiveTextField.None }
|
||||
{ activeTextField = if(it) NetworkStatsActiveTextField.Tag else NetworkStatsActiveTextField.None }
|
||||
) {
|
||||
var tagText by rememberSaveable { mutableStateOf(context.getString(R.string.all)) }
|
||||
var readOnly by rememberSaveable { mutableStateOf(true) }
|
||||
@@ -1596,7 +1590,7 @@ fun RecommendedGlobalProxyScreen(onNavigateUp: () -> Unit) {
|
||||
Toast.makeText(context, R.string.invalid_config, Toast.LENGTH_SHORT).show()
|
||||
return@Button
|
||||
}
|
||||
val uri = Uri.parse(proxyUri)
|
||||
val uri = proxyUri.toUri()
|
||||
val port: Int
|
||||
try {
|
||||
port = proxyPort.toInt()
|
||||
@@ -1827,8 +1821,8 @@ fun AddPreferentialNetworkServiceConfigScreen(route: AddPreferentialNetworkServi
|
||||
title = R.string.block_non_matching_networks,
|
||||
state = blockNonMatching, onCheckedChange = { blockNonMatching = it }, padding = false
|
||||
)
|
||||
val includedUidsLegal = includedUids.lines().filter { it.isNotBlank() }.let {
|
||||
it.isEmpty() || (it.all { it.toIntOrNull() != null } && excludedUids.isBlank())
|
||||
val includedUidsLegal = includedUids.lines().filter { it.isNotBlank() }.let { uid ->
|
||||
uid.isEmpty() || (uid.all { it.toIntOrNull() != null } && excludedUids.isBlank())
|
||||
}
|
||||
OutlinedTextField(
|
||||
value = includedUids, onValueChange = { includedUids = it }, minLines = 2,
|
||||
@@ -1837,8 +1831,8 @@ fun AddPreferentialNetworkServiceConfigScreen(route: AddPreferentialNetworkServi
|
||||
isError = !includedUidsLegal,
|
||||
modifier = Modifier.fillMaxWidth().padding(bottom = 6.dp)
|
||||
)
|
||||
val excludedUidsLegal = excludedUids.lines().filter { it.isNotBlank() }.let {
|
||||
it.isEmpty() || (it.all { it.toIntOrNull() != null } && includedUids.isBlank())
|
||||
val excludedUidsLegal = excludedUids.lines().filter { it.isNotBlank() }.let { uid ->
|
||||
uid.isEmpty() || (uid.all { it.toIntOrNull() != null } && includedUids.isBlank())
|
||||
}
|
||||
OutlinedTextField(
|
||||
value = excludedUids, onValueChange = { excludedUids = it }, minLines = 2,
|
||||
@@ -1852,7 +1846,7 @@ fun AddPreferentialNetworkServiceConfigScreen(route: AddPreferentialNetworkServi
|
||||
try {
|
||||
val config = PreferentialNetworkServiceConfig.Builder().apply {
|
||||
setEnabled(enabled)
|
||||
if(enabled) setNetworkId(id.toInt())
|
||||
if(enabled) setNetworkId(id)
|
||||
setFallbackToDefaultConnectionAllowed(allowFallback)
|
||||
setExcludedUids(excludedUids.lines().filter { it.isNotBlank() }.map { it.toInt() }.toIntArray())
|
||||
setIncludedUids(includedUids.lines().filter { it.isNotBlank() }.map { it.toInt() }.toIntArray())
|
||||
@@ -1957,7 +1951,7 @@ private val apnTypes = listOf(
|
||||
|
||||
@Serializable object AddApnSetting
|
||||
|
||||
@OptIn(ExperimentalLayoutApi::class, ExperimentalMaterial3Api::class)
|
||||
@OptIn(ExperimentalLayoutApi::class)
|
||||
@RequiresApi(28)
|
||||
@Composable
|
||||
fun AddApnSettingScreen(origin: ApnSetting?, onNavigateUp: () -> Unit) {
|
||||
@@ -2099,14 +2093,14 @@ fun AddApnSettingScreen(origin: ApnSetting?, onNavigateUp: () -> Unit) {
|
||||
OutlinedTextField(
|
||||
mtuV4, { mtuV4 = it }, Modifier.fillMaxWidth(0.49F),
|
||||
label = { Text("MTU (IPv4)") },
|
||||
isError = !mtuV4.isEmpty() && mtuV4.toIntOrNull() == null,
|
||||
isError = mtuV4.isNotEmpty() && mtuV4.toIntOrNull() == null,
|
||||
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number, imeAction = ImeAction.Next),
|
||||
keyboardActions = KeyboardActions { fr.requestFocus() }
|
||||
)
|
||||
OutlinedTextField(
|
||||
mtuV6, { mtuV6 = it }, Modifier.focusRequester(fr).fillMaxWidth(0.96F),
|
||||
label = { Text("MTU (IPv6)") },
|
||||
isError = !mtuV6.isEmpty() && mtuV6.toIntOrNull() == null,
|
||||
isError = mtuV6.isNotEmpty() && mtuV6.toIntOrNull() == null,
|
||||
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number, imeAction = ImeAction.Done),
|
||||
keyboardActions = KeyboardActions { fm.clearFocus() }
|
||||
)
|
||||
@@ -2194,7 +2188,7 @@ fun AddApnSettingScreen(origin: ApnSetting?, onNavigateUp: () -> Unit) {
|
||||
setMmsProxyAddress(mmsProxyAddress)
|
||||
mmsProxyPort.toIntOrNull()?.let { setMmsProxyPort(it) }
|
||||
}
|
||||
setMmsc(Uri.parse(mmsc))
|
||||
setMmsc(mmsc.toUri())
|
||||
if(VERSION.SDK_INT >= 33) {
|
||||
mtuV4.toIntOrNull()?.let { setMtuV4(it) }
|
||||
mtuV6.toIntOrNull()?.let { setMtuV6(it) }
|
||||
@@ -2238,7 +2232,7 @@ fun AddApnSettingScreen(origin: ApnSetting?, onNavigateUp: () -> Unit) {
|
||||
AlertDialog(
|
||||
title = { Text(if(dialog == 1) "Proxy" else "MMS proxy") },
|
||||
text = {
|
||||
val fm = LocalFocusManager.current
|
||||
val focusManager = LocalFocusManager.current
|
||||
Column {
|
||||
OutlinedTextField(
|
||||
address, { address = it }, Modifier.fillMaxWidth().padding(bottom = 4.dp),
|
||||
@@ -2253,7 +2247,7 @@ fun AddApnSettingScreen(origin: ApnSetting?, onNavigateUp: () -> Unit) {
|
||||
isError = port.isNotEmpty() && port.toIntOrNull() == null,
|
||||
label = { Text(stringResource(R.string.port)) },
|
||||
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number, imeAction = ImeAction.Done),
|
||||
keyboardActions = KeyboardActions { fm.clearFocus() }
|
||||
keyboardActions = KeyboardActions { focusManager.clearFocus() }
|
||||
)
|
||||
}
|
||||
},
|
||||
|
||||
@@ -65,9 +65,11 @@ import androidx.compose.ui.text.input.KeyboardType
|
||||
import androidx.compose.ui.text.input.PasswordVisualTransformation
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.core.content.ContextCompat.startActivity
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.bintianqi.owndroid.HorizontalPadding
|
||||
import com.bintianqi.owndroid.R
|
||||
import com.bintianqi.owndroid.SharedPrefs
|
||||
import com.bintianqi.owndroid.myPrivilege
|
||||
import com.bintianqi.owndroid.showOperationResultToast
|
||||
import com.bintianqi.owndroid.ui.CheckBoxItem
|
||||
import com.bintianqi.owndroid.ui.FullWidthCheckBoxItem
|
||||
@@ -86,38 +88,30 @@ import kotlinx.serialization.Serializable
|
||||
@Composable
|
||||
fun PasswordScreen(onNavigateUp: () -> Unit, onNavigate: (Any) -> Unit) {
|
||||
val context = LocalContext.current
|
||||
val deviceAdmin = context.isDeviceAdmin
|
||||
val deviceOwner = context.isDeviceOwner
|
||||
val profileOwner = context.isProfileOwner
|
||||
val privilege by myPrivilege.collectAsStateWithLifecycle()
|
||||
var dialog by remember { mutableIntStateOf(0) }
|
||||
MyScaffold(R.string.password_and_keyguard, onNavigateUp, 0.dp) {
|
||||
FunctionItem(R.string.password_info, icon = R.drawable.info_fill0) { onNavigate(PasswordInfo) }
|
||||
if(SharedPrefs(context).displayDangerousFeatures) {
|
||||
if(VERSION.SDK_INT >= 26 && (deviceOwner || profileOwner)) {
|
||||
if(VERSION.SDK_INT >= 26) {
|
||||
FunctionItem(R.string.reset_password_token, icon = R.drawable.key_vertical_fill0) { onNavigate(ResetPasswordToken) }
|
||||
}
|
||||
if(deviceAdmin || deviceOwner || profileOwner) {
|
||||
FunctionItem(R.string.reset_password, icon = R.drawable.lock_reset_fill0) { onNavigate(ResetPassword) }
|
||||
}
|
||||
FunctionItem(R.string.reset_password, icon = R.drawable.lock_reset_fill0) { onNavigate(ResetPassword) }
|
||||
}
|
||||
if(VERSION.SDK_INT >= 31 && (deviceOwner || profileOwner)) {
|
||||
if(VERSION.SDK_INT >= 31) {
|
||||
FunctionItem(R.string.required_password_complexity, icon = R.drawable.password_fill0) { onNavigate(RequiredPasswordComplexity) }
|
||||
}
|
||||
if(deviceAdmin) {
|
||||
FunctionItem(R.string.disable_keyguard_features, icon = R.drawable.screen_lock_portrait_fill0) { onNavigate(KeyguardDisabledFeatures) }
|
||||
}
|
||||
if(deviceOwner) {
|
||||
FunctionItem(R.string.disable_keyguard_features, icon = R.drawable.screen_lock_portrait_fill0) { onNavigate(KeyguardDisabledFeatures) }
|
||||
if(privilege.device) {
|
||||
FunctionItem(R.string.max_time_to_lock, icon = R.drawable.schedule_fill0) { dialog = 1 }
|
||||
FunctionItem(R.string.pwd_expiration_timeout, icon = R.drawable.lock_clock_fill0) { dialog = 3 }
|
||||
FunctionItem(R.string.max_pwd_fail, icon = R.drawable.no_encryption_fill0) { dialog = 4 }
|
||||
}
|
||||
if(VERSION.SDK_INT >= 26 && (deviceOwner || profileOwner)) {
|
||||
if(VERSION.SDK_INT >= 26) {
|
||||
FunctionItem(R.string.required_strong_auth_timeout, icon = R.drawable.fingerprint_off_fill0) { dialog = 2 }
|
||||
}
|
||||
if(deviceAdmin){
|
||||
FunctionItem(R.string.pwd_history, icon = R.drawable.history_fill0) { dialog = 5 }
|
||||
}
|
||||
if(VERSION.SDK_INT < 31 && (deviceOwner || profileOwner)) {
|
||||
FunctionItem(R.string.pwd_history, icon = R.drawable.history_fill0) { dialog = 5 }
|
||||
if(VERSION.SDK_INT < 31) {
|
||||
FunctionItem(R.string.required_password_quality, icon = R.drawable.password_fill0) { onNavigate(RequiredPasswordQuality) }
|
||||
}
|
||||
}
|
||||
@@ -217,8 +211,7 @@ fun PasswordInfoScreen(onNavigateUp: () -> Unit) {
|
||||
val context = LocalContext.current
|
||||
val dpm = context.getDPM()
|
||||
val receiver = context.getReceiver()
|
||||
val deviceOwner = context.isDeviceOwner
|
||||
val profileOwner = context.isProfileOwner
|
||||
val privilege by myPrivilege.collectAsStateWithLifecycle()
|
||||
var dialog by remember { mutableIntStateOf(0) } // 0:none, 1:password complexity
|
||||
MyScaffold(R.string.password_info, onNavigateUp, 0.dp) {
|
||||
if(VERSION.SDK_INT >= 29) {
|
||||
@@ -231,10 +224,8 @@ fun PasswordInfoScreen(onNavigateUp: () -> Unit) {
|
||||
}
|
||||
InfoItem(R.string.current_password_complexity, text, true) { dialog = 1 }
|
||||
}
|
||||
if(deviceOwner || profileOwner) {
|
||||
InfoItem(R.string.password_sufficient, dpm.isActivePasswordSufficient.yesOrNo)
|
||||
}
|
||||
if(VERSION.SDK_INT >= 28 && profileOwner && dpm.isManagedProfile(receiver)) {
|
||||
InfoItem(R.string.password_sufficient, dpm.isActivePasswordSufficient.yesOrNo)
|
||||
if(VERSION.SDK_INT >= 28 && privilege.work) {
|
||||
InfoItem(R.string.unified_password, dpm.isUsingUnifiedPassword(receiver).yesOrNo)
|
||||
}
|
||||
}
|
||||
@@ -367,7 +358,7 @@ fun ResetPasswordScreen(onNavigateUp: () -> Unit) {
|
||||
focusMgr.clearFocus()
|
||||
},
|
||||
colors = ButtonDefaults.buttonColors(containerColor = colorScheme.error, contentColor = colorScheme.onError),
|
||||
enabled = tokenByteArray.size >=32 && password.length !in 1..3 && (context.isDeviceOwner || context.isProfileOwner),
|
||||
enabled = tokenByteArray.size >=32 && password.length !in 1..3,
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
) {
|
||||
Text(stringResource(R.string.reset_password_with_token))
|
||||
|
||||
@@ -1,18 +1,14 @@
|
||||
package com.bintianqi.owndroid.dpm
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.admin.DevicePolicyManager
|
||||
import android.content.ActivityNotFoundException
|
||||
import android.content.ComponentName
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.pm.PackageManager
|
||||
import android.os.Binder
|
||||
import android.os.Build.VERSION
|
||||
import android.os.Bundle
|
||||
import android.os.IBinder
|
||||
import android.os.RemoteException
|
||||
import android.os.UserManager
|
||||
import android.widget.Toast
|
||||
import androidx.activity.compose.rememberLauncherForActivityResult
|
||||
import androidx.annotation.Keep
|
||||
@@ -21,7 +17,6 @@ import androidx.annotation.StringRes
|
||||
import androidx.compose.animation.AnimatedVisibility
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.text.KeyboardActions
|
||||
import androidx.compose.foundation.text.KeyboardOptions
|
||||
import androidx.compose.foundation.text.selection.SelectionContainer
|
||||
@@ -43,13 +38,16 @@ import androidx.compose.ui.text.input.KeyboardType
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.window.Dialog
|
||||
import androidx.core.os.bundleOf
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.bintianqi.owndroid.ChoosePackageContract
|
||||
import com.bintianqi.owndroid.HorizontalPadding
|
||||
import com.bintianqi.owndroid.R
|
||||
import com.bintianqi.owndroid.SharedPrefs
|
||||
import com.bintianqi.owndroid.backToHomeStateFlow
|
||||
import com.bintianqi.owndroid.myPrivilege
|
||||
import com.bintianqi.owndroid.showOperationResultToast
|
||||
import com.bintianqi.owndroid.ui.*
|
||||
import com.bintianqi.owndroid.updatePrivilege
|
||||
import com.bintianqi.owndroid.writeClipBoard
|
||||
import com.bintianqi.owndroid.yesOrNo
|
||||
import com.rosan.dhizuku.api.Dhizuku
|
||||
@@ -61,19 +59,15 @@ import rikka.sui.Sui
|
||||
|
||||
@Serializable object Permissions
|
||||
|
||||
@SuppressLint("NewApi")
|
||||
@Composable
|
||||
fun PermissionsScreen(onNavigateUp: () -> Unit, onNavigate: (Any) -> Unit, onNavigateToShizuku: (Bundle) -> Unit) {
|
||||
val context = LocalContext.current
|
||||
val dpm = context.getDPM()
|
||||
val receiver = context.getReceiver()
|
||||
val deviceAdmin = context.isDeviceAdmin
|
||||
val deviceOwner = context.isDeviceOwner
|
||||
val profileOwner = context.isProfileOwner
|
||||
val userManager = context.getSystemService(Context.USER_SERVICE) as UserManager
|
||||
val privilege by myPrivilege.collectAsStateWithLifecycle()
|
||||
var dialog by remember { mutableIntStateOf(0) }
|
||||
var bindingShizuku by remember { mutableStateOf(false) }
|
||||
val enrollmentSpecificId = if(VERSION.SDK_INT >= 31 && (deviceOwner || profileOwner)) dpm.enrollmentSpecificId else ""
|
||||
val enrollmentSpecificId = if(VERSION.SDK_INT >= 31 && (privilege.device || privilege.profile)) dpm.enrollmentSpecificId else ""
|
||||
MyScaffold(R.string.permissions, onNavigateUp, 0.dp) {
|
||||
if(!dpm.isDeviceOwnerApp(context.packageName)) {
|
||||
SwitchItem(
|
||||
@@ -83,19 +77,15 @@ fun PermissionsScreen(onNavigateUp: () -> Unit, onNavigate: (Any) -> Unit, onNav
|
||||
onClickBlank = { dialog = 4 }
|
||||
)
|
||||
}
|
||||
FunctionItem(
|
||||
R.string.device_admin, stringResource(if(deviceAdmin) R.string.activated else R.string.deactivated),
|
||||
operation = { onNavigate(DeviceAdmin) }
|
||||
)
|
||||
if(profileOwner || !userManager.isSystemUser) {
|
||||
if(privilege.profile || !privilege.primary) {
|
||||
FunctionItem(
|
||||
R.string.profile_owner, stringResource(if(profileOwner) R.string.activated else R.string.deactivated),
|
||||
R.string.profile_owner, stringResource(if(privilege.profile) R.string.activated else R.string.deactivated),
|
||||
operation = { onNavigate(ProfileOwner) }
|
||||
)
|
||||
}
|
||||
if(!profileOwner && userManager.isSystemUser) {
|
||||
if(!privilege.profile && privilege.primary) {
|
||||
FunctionItem(
|
||||
R.string.device_owner, stringResource(if(deviceOwner) R.string.activated else R.string.deactivated),
|
||||
R.string.device_owner, stringResource(if(privilege.device) R.string.activated else R.string.deactivated),
|
||||
operation = { onNavigate(DeviceOwner) }
|
||||
)
|
||||
}
|
||||
@@ -130,25 +120,24 @@ fun PermissionsScreen(onNavigateUp: () -> Unit, onNavigate: (Any) -> Unit, onNav
|
||||
Toast.makeText(context, R.string.shizuku_not_started, Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
if(VERSION.SDK_INT >= 26 && (deviceOwner || profileOwner))
|
||||
FunctionItem(R.string.delegated_admins) { onNavigate(DelegatedAdmins) }
|
||||
if(VERSION.SDK_INT >= 26) FunctionItem(R.string.delegated_admins) { onNavigate(DelegatedAdmins) }
|
||||
FunctionItem(R.string.device_info, icon = R.drawable.perm_device_information_fill0) { onNavigate(DeviceInfo) }
|
||||
if(VERSION.SDK_INT >= 24 && (profileOwner || (VERSION.SDK_INT >= 26 && deviceOwner))) {
|
||||
if(VERSION.SDK_INT >= 24 && (privilege.profile || (VERSION.SDK_INT >= 26 && privilege.device))) {
|
||||
FunctionItem(R.string.org_name, icon = R.drawable.corporate_fare_fill0) { dialog = 2 }
|
||||
}
|
||||
if(VERSION.SDK_INT >= 31 && (profileOwner || deviceOwner)) {
|
||||
if(VERSION.SDK_INT >= 31) {
|
||||
FunctionItem(R.string.org_id, icon = R.drawable.corporate_fare_fill0) { dialog = 3 }
|
||||
}
|
||||
if(enrollmentSpecificId != "") {
|
||||
FunctionItem(R.string.enrollment_specific_id, icon = R.drawable.id_card_fill0) { dialog = 1 }
|
||||
}
|
||||
if(VERSION.SDK_INT >= 24 && (deviceOwner || dpm.isOrgProfile(receiver))) {
|
||||
if(VERSION.SDK_INT >= 24 && (privilege.device || privilege.org)) {
|
||||
FunctionItem(R.string.lock_screen_info, icon = R.drawable.screen_lock_portrait_fill0) { onNavigate(LockScreenInfo) }
|
||||
}
|
||||
if(VERSION.SDK_INT >= 24 && deviceAdmin) {
|
||||
if(VERSION.SDK_INT >= 24) {
|
||||
FunctionItem(R.string.support_messages, icon = R.drawable.chat_fill0) { onNavigate(SupportMessage) }
|
||||
}
|
||||
if(VERSION.SDK_INT >= 28 && (deviceOwner || profileOwner)) {
|
||||
if(VERSION.SDK_INT >= 28) {
|
||||
FunctionItem(R.string.transfer_ownership, icon = R.drawable.admin_panel_settings_fill0) { onNavigate(TransferOwnership) }
|
||||
}
|
||||
}
|
||||
@@ -174,7 +163,7 @@ fun PermissionsScreen(onNavigateUp: () -> Unit, onNavigate: (Any) -> Unit, onNav
|
||||
text = {
|
||||
val focusMgr = LocalFocusManager.current
|
||||
LaunchedEffect(Unit) {
|
||||
if(dialog == 1) input = dpm.enrollmentSpecificId
|
||||
if(dialog == 1 && VERSION.SDK_INT >= 31) input = dpm.enrollmentSpecificId
|
||||
}
|
||||
Column {
|
||||
if(dialog != 4) OutlinedTextField(
|
||||
@@ -220,8 +209,8 @@ fun PermissionsScreen(onNavigateUp: () -> Unit, onNavigate: (Any) -> Unit, onNav
|
||||
TextButton(
|
||||
onClick = {
|
||||
try {
|
||||
if(dialog == 2) dpm.setOrganizationName(receiver, input)
|
||||
if(dialog == 3) dpm.setOrganizationId(input)
|
||||
if(dialog == 2 && VERSION.SDK_INT >= 24) dpm.setOrganizationName(receiver, input)
|
||||
if(dialog == 3 && VERSION.SDK_INT >= 31) dpm.setOrganizationId(input)
|
||||
dialog = 0
|
||||
} catch(_: IllegalStateException) {
|
||||
Toast.makeText(context, R.string.failed, Toast.LENGTH_SHORT).show()
|
||||
@@ -250,6 +239,7 @@ private fun toggleDhizukuMode(status: Boolean, context: Context) {
|
||||
if(dhizukuPermissionGranted()) {
|
||||
sp.dhizuku = true
|
||||
Dhizuku.init(context)
|
||||
updatePrivilege(context)
|
||||
backToHomeStateFlow.value = true
|
||||
} else {
|
||||
Dhizuku.requestPermission(object: DhizukuRequestPermissionListener() {
|
||||
@@ -258,6 +248,7 @@ private fun toggleDhizukuMode(status: Boolean, context: Context) {
|
||||
if(grantResult == PackageManager.PERMISSION_GRANTED) {
|
||||
sp.dhizuku = true
|
||||
Dhizuku.init(context)
|
||||
updatePrivilege(context)
|
||||
backToHomeStateFlow.value = true
|
||||
} else {
|
||||
dhizukuErrorStatus.value = 2
|
||||
@@ -311,65 +302,6 @@ fun LockScreenInfoScreen(onNavigateUp: () -> Unit) {
|
||||
}
|
||||
}
|
||||
|
||||
@Serializable object DeviceAdmin
|
||||
|
||||
@Composable
|
||||
fun DeviceAdminScreen(onNavigateUp: () -> Unit) {
|
||||
val context = LocalContext.current
|
||||
val dpm = context.getDPM()
|
||||
val receiver = context.getReceiver()
|
||||
var deactivateDialog by remember { mutableStateOf(false) }
|
||||
val deviceAdmin = context.isDeviceAdmin
|
||||
MyScaffold(R.string.device_admin, onNavigateUp) {
|
||||
Text(text = stringResource(if(context.isDeviceAdmin) R.string.activated else R.string.deactivated), style = typography.titleLarge)
|
||||
Spacer(Modifier.padding(vertical = 5.dp))
|
||||
AnimatedVisibility(deviceAdmin) {
|
||||
Button(
|
||||
onClick = { deactivateDialog = true },
|
||||
enabled = !context.isProfileOwner && !context.isDeviceOwner,
|
||||
colors = ButtonDefaults.buttonColors(containerColor = colorScheme.error, contentColor = colorScheme.onError)
|
||||
) {
|
||||
Text(stringResource(R.string.deactivate))
|
||||
}
|
||||
}
|
||||
AnimatedVisibility(!deviceAdmin) {
|
||||
Column {
|
||||
Button(onClick = { activateDeviceAdmin(context, receiver) }, modifier = Modifier.fillMaxWidth()) {
|
||||
Text(stringResource(R.string.activate_jump))
|
||||
}
|
||||
Spacer(Modifier.padding(vertical = 5.dp))
|
||||
SelectionContainer {
|
||||
Text(text = stringResource(R.string.activate_device_admin_command))
|
||||
}
|
||||
CopyTextButton(R.string.copy_command, stringResource(R.string.activate_device_admin_command))
|
||||
}
|
||||
}
|
||||
}
|
||||
if(deactivateDialog) {
|
||||
AlertDialog(
|
||||
title = { Text(stringResource(R.string.deactivate)) },
|
||||
onDismissRequest = { deactivateDialog = false },
|
||||
dismissButton = {
|
||||
TextButton(
|
||||
onClick = { deactivateDialog = false }
|
||||
) {
|
||||
Text(stringResource(R.string.cancel))
|
||||
}
|
||||
},
|
||||
confirmButton = {
|
||||
TextButton(
|
||||
onClick = {
|
||||
dpm.removeActiveAdmin(receiver)
|
||||
deactivateDialog = false
|
||||
}
|
||||
) {
|
||||
Text(stringResource(R.string.confirm))
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Serializable object ProfileOwner
|
||||
|
||||
@Composable
|
||||
@@ -378,7 +310,8 @@ fun ProfileOwnerScreen(onNavigateUp: () -> Unit) {
|
||||
val dpm = context.getDPM()
|
||||
val receiver = context.getReceiver()
|
||||
var deactivateDialog by remember { mutableStateOf(false) }
|
||||
val profileOwner = context.isProfileOwner
|
||||
val privilege by myPrivilege.collectAsStateWithLifecycle()
|
||||
val profileOwner = privilege.profile
|
||||
MyScaffold(R.string.profile_owner, onNavigateUp) {
|
||||
Text(stringResource(if(profileOwner) R.string.activated else R.string.deactivated), style = typography.titleLarge)
|
||||
Spacer(Modifier.padding(vertical = 5.dp))
|
||||
@@ -432,7 +365,8 @@ fun DeviceOwnerScreen(onNavigateUp: () -> Unit) {
|
||||
val context = LocalContext.current
|
||||
val dpm = context.getDPM()
|
||||
var deactivateDialog by remember { mutableStateOf(false) }
|
||||
val deviceOwner = context.isDeviceOwner
|
||||
val privilege by myPrivilege.collectAsStateWithLifecycle()
|
||||
val deviceOwner = privilege.device
|
||||
MyScaffold(R.string.device_owner, onNavigateUp) {
|
||||
Text(text = stringResource(if(deviceOwner) R.string.activated else R.string.deactivated), style = typography.titleLarge)
|
||||
Spacer(Modifier.padding(vertical = 5.dp))
|
||||
@@ -644,15 +578,15 @@ fun AddDelegatedAdminScreen(data: AddDelegatedAdmin, onNavigateUp: () -> Unit) {
|
||||
fun DeviceInfoScreen(onNavigateUp: () -> Unit) {
|
||||
val context = LocalContext.current
|
||||
val dpm = context.getDPM()
|
||||
val receiver = context.getReceiver()
|
||||
val privilege by myPrivilege.collectAsStateWithLifecycle()
|
||||
var dialog by remember { mutableIntStateOf(0) }
|
||||
MyScaffold(R.string.device_info, onNavigateUp, 0.dp) {
|
||||
if(VERSION.SDK_INT>=34 && (context.isDeviceOwner || dpm.isOrgProfile(receiver))) {
|
||||
if(VERSION.SDK_INT>=34 && (privilege.device || privilege.org)) {
|
||||
InfoItem(R.string.financed_device, dpm.isDeviceFinanced.yesOrNo)
|
||||
}
|
||||
if(VERSION.SDK_INT >= 33) {
|
||||
val dpmRole = dpm.devicePolicyManagementRoleHolderPackage
|
||||
InfoItem(R.string.dpmrh, if(dpmRole == null) stringResource(R.string.none) else dpmRole)
|
||||
InfoItem(R.string.dpmrh, dpmRole ?: stringResource(R.string.none))
|
||||
}
|
||||
val encryptionStatus = mutableMapOf(
|
||||
DevicePolicyManager.ENCRYPTION_STATUS_INACTIVE to R.string.es_inactive,
|
||||
@@ -670,7 +604,7 @@ fun DeviceInfoScreen(onNavigateUp: () -> Unit) {
|
||||
}
|
||||
val adminList = dpm.activeAdmins
|
||||
if(adminList != null) {
|
||||
InfoItem(R.string.activated_device_admin, adminList.map { it.flattenToShortString() }.joinToString("\n"))
|
||||
InfoItem(R.string.activated_device_admin, adminList.joinToString("\n") { it.flattenToShortString() })
|
||||
}
|
||||
}
|
||||
if(dialog != 0) AlertDialog(
|
||||
@@ -766,6 +700,7 @@ fun SupportMessageScreen(onNavigateUp: () -> Unit) {
|
||||
@Composable
|
||||
fun TransferOwnershipScreen(onNavigateUp: () -> Unit) {
|
||||
val context = LocalContext.current
|
||||
val privilege by myPrivilege.collectAsStateWithLifecycle()
|
||||
val focusMgr = LocalFocusManager.current
|
||||
var input by remember { mutableStateOf("") }
|
||||
val componentName = ComponentName.unflattenFromString(input)
|
||||
@@ -793,7 +728,7 @@ fun TransferOwnershipScreen(onNavigateUp: () -> Unit) {
|
||||
text = {
|
||||
Text(stringResource(
|
||||
R.string.transfer_ownership_warning,
|
||||
stringResource(if(context.isDeviceOwner) R.string.device_owner else R.string.profile_owner),
|
||||
stringResource(if(privilege.device) R.string.device_owner else R.string.profile_owner),
|
||||
ComponentName.unflattenFromString(input)!!.packageName
|
||||
))
|
||||
},
|
||||
@@ -805,11 +740,12 @@ fun TransferOwnershipScreen(onNavigateUp: () -> Unit) {
|
||||
try {
|
||||
dpm.transferOwnership(receiver, componentName!!, null)
|
||||
context.showOperationResultToast(true)
|
||||
updatePrivilege(context)
|
||||
dialog = false
|
||||
backToHomeStateFlow.value = true
|
||||
onNavigateUp()
|
||||
} catch(e: Exception) {
|
||||
e.printStackTrace()
|
||||
Toast.makeText(context, R.string.failed, Toast.LENGTH_SHORT).show()
|
||||
context.showOperationResultToast(false)
|
||||
}
|
||||
},
|
||||
colors = ButtonDefaults.textButtonColors(contentColor = colorScheme.error)
|
||||
@@ -825,14 +761,3 @@ fun TransferOwnershipScreen(onNavigateUp: () -> Unit) {
|
||||
onDismissRequest = { dialog = false }
|
||||
)
|
||||
}
|
||||
|
||||
private fun activateDeviceAdmin(inputContext:Context,inputComponent:ComponentName) {
|
||||
try {
|
||||
val intent = Intent(DevicePolicyManager.ACTION_ADD_DEVICE_ADMIN)
|
||||
intent.putExtra(DevicePolicyManager.EXTRA_DEVICE_ADMIN, inputComponent)
|
||||
intent.putExtra(DevicePolicyManager.EXTRA_ADD_EXPLANATION, inputContext.getString(R.string.activate_device_admin_here))
|
||||
addDeviceAdmin.launch(intent)
|
||||
} catch(_:ActivityNotFoundException) {
|
||||
Toast.makeText(inputContext, R.string.unsupported, Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,7 +19,6 @@ import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.foundation.text.selection.SelectionContainer
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
@@ -36,9 +35,12 @@ import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.bintianqi.owndroid.IUserService
|
||||
import com.bintianqi.owndroid.R
|
||||
import com.bintianqi.owndroid.myPrivilege
|
||||
import com.bintianqi.owndroid.ui.MySmallTitleScaffold
|
||||
import com.bintianqi.owndroid.updatePrivilege
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.serialization.Serializable
|
||||
@@ -46,17 +48,13 @@ import rikka.shizuku.Shizuku
|
||||
|
||||
@Serializable object ShizukuScreen
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun ShizukuScreen(navArgs: Bundle, onNavigateUp: () -> Unit, onNavigateToAccountsViewer: (Accounts) -> Unit) {
|
||||
val context = LocalContext.current
|
||||
val dpm = context.getDPM()
|
||||
val receiver = context.getReceiver()
|
||||
val coScope = rememberCoroutineScope()
|
||||
val privilege by myPrivilege.collectAsStateWithLifecycle()
|
||||
val coroutine = rememberCoroutineScope()
|
||||
val outputTextScrollState = rememberScrollState()
|
||||
var outputText by rememberSaveable { mutableStateOf("") }
|
||||
var showDeviceOwnerButton by remember { mutableStateOf(!context.isDeviceOwner) }
|
||||
var showOrgProfileOwnerButton by remember { mutableStateOf(true) }
|
||||
val binder = navArgs.getBinder("binder")!!
|
||||
var service by remember { mutableStateOf<IUserService?>(null) }
|
||||
LaunchedEffect(Unit) {
|
||||
@@ -70,7 +68,7 @@ fun ShizukuScreen(navArgs: Bundle, onNavigateUp: () -> Unit, onNavigateToAccount
|
||||
|
||||
Button(
|
||||
onClick = {
|
||||
coScope.launch{
|
||||
coroutine.launch{
|
||||
outputText = service!!.execute("dpm list-owners")
|
||||
outputTextScrollState.animateScrollTo(0)
|
||||
}
|
||||
@@ -81,7 +79,7 @@ fun ShizukuScreen(navArgs: Bundle, onNavigateUp: () -> Unit, onNavigateToAccount
|
||||
}
|
||||
Button(
|
||||
onClick = {
|
||||
coScope.launch{
|
||||
coroutine.launch{
|
||||
outputText = service!!.execute("pm list users")
|
||||
outputTextScrollState.animateScrollTo(0)
|
||||
}
|
||||
@@ -100,7 +98,7 @@ fun ShizukuScreen(navArgs: Bundle, onNavigateUp: () -> Unit, onNavigateToAccount
|
||||
onNavigateToAccountsViewer(Accounts(accounts))
|
||||
} catch(_: Exception) {
|
||||
outputText = service!!.execute("dumpsys account")
|
||||
coScope.launch{
|
||||
coroutine.launch{
|
||||
outputTextScrollState.animateScrollTo(0)
|
||||
}
|
||||
}
|
||||
@@ -111,39 +109,37 @@ fun ShizukuScreen(navArgs: Bundle, onNavigateUp: () -> Unit, onNavigateToAccount
|
||||
}
|
||||
Spacer(Modifier.padding(vertical = 5.dp))
|
||||
|
||||
AnimatedVisibility(showDeviceOwnerButton, modifier = Modifier.align(Alignment.CenterHorizontally)) {
|
||||
AnimatedVisibility(!privilege.device, modifier = Modifier.align(Alignment.CenterHorizontally)) {
|
||||
Button(
|
||||
onClick = {
|
||||
coScope.launch{
|
||||
coroutine.launch{
|
||||
outputText = service!!.execute(context.getString(R.string.dpm_activate_do_command))
|
||||
outputTextScrollState.animateScrollTo(0)
|
||||
delay(500)
|
||||
showDeviceOwnerButton = !context.isDeviceOwner
|
||||
updatePrivilege(context)
|
||||
}
|
||||
}
|
||||
) {
|
||||
Text(text = stringResource(R.string.activate_device_owner))
|
||||
}
|
||||
}
|
||||
|
||||
if(VERSION.SDK_INT >= 30 && context.isProfileOwner && dpm.isManagedProfile(receiver) && !dpm.isOrganizationOwnedDeviceWithManagedProfile) {
|
||||
AnimatedVisibility(showOrgProfileOwnerButton) {
|
||||
Button(
|
||||
onClick = {
|
||||
coScope.launch{
|
||||
val userID = Binder.getCallingUid() / 100000
|
||||
outputText = service!!.execute(
|
||||
"dpm mark-profile-owner-on-organization-owned-device --user $userID com.bintianqi.owndroid/com.bintianqi.owndroid.Receiver"
|
||||
)
|
||||
outputTextScrollState.animateScrollTo(0)
|
||||
delay(500)
|
||||
showOrgProfileOwnerButton = !dpm.isOrganizationOwnedDeviceWithManagedProfile
|
||||
}
|
||||
},
|
||||
modifier = Modifier.align(Alignment.CenterHorizontally)
|
||||
) {
|
||||
Text(text = stringResource(R.string.activate_org_profile))
|
||||
}
|
||||
|
||||
AnimatedVisibility(VERSION.SDK_INT >= 30 && privilege.work && !privilege.org) {
|
||||
Button(
|
||||
onClick = {
|
||||
coroutine.launch{
|
||||
val userID = Binder.getCallingUid() / 100000
|
||||
outputText = service!!.execute(
|
||||
"dpm mark-profile-owner-on-organization-owned-device --user $userID com.bintianqi.owndroid/com.bintianqi.owndroid.Receiver"
|
||||
)
|
||||
outputTextScrollState.animateScrollTo(0)
|
||||
delay(500)
|
||||
updatePrivilege(context)
|
||||
}
|
||||
},
|
||||
modifier = Modifier.align(Alignment.CenterHorizontally)
|
||||
) {
|
||||
Text(text = stringResource(R.string.activate_org_profile))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -116,6 +116,7 @@ import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.input.ImeAction
|
||||
import androidx.compose.ui.text.input.KeyboardType
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.bintianqi.owndroid.ChoosePackageContract
|
||||
import com.bintianqi.owndroid.HorizontalPadding
|
||||
import com.bintianqi.owndroid.NotificationUtils
|
||||
@@ -123,6 +124,7 @@ import com.bintianqi.owndroid.R
|
||||
import com.bintianqi.owndroid.SharedPrefs
|
||||
import com.bintianqi.owndroid.formatFileSize
|
||||
import com.bintianqi.owndroid.humanReadableDate
|
||||
import com.bintianqi.owndroid.myPrivilege
|
||||
import com.bintianqi.owndroid.parseDate
|
||||
import com.bintianqi.owndroid.showOperationResultToast
|
||||
import com.bintianqi.owndroid.ui.CheckBoxItem
|
||||
@@ -160,62 +162,54 @@ fun SystemManagerScreen(onNavigateUp: () -> Unit, onNavigate: (Any) -> Unit) {
|
||||
val dpm = context.getDPM()
|
||||
val receiver = context.getReceiver()
|
||||
val sp = SharedPrefs(context)
|
||||
val dhizuku = sp.dhizuku
|
||||
val deviceOwner = context.isDeviceOwner
|
||||
val profileOwner = context.isProfileOwner
|
||||
val privilege by myPrivilege.collectAsStateWithLifecycle()
|
||||
var dialog by remember { mutableIntStateOf(0) }
|
||||
MyScaffold(R.string.system, onNavigateUp, 0.dp) {
|
||||
if(deviceOwner || profileOwner) {
|
||||
FunctionItem(R.string.options, icon = R.drawable.tune_fill0) { onNavigate(SystemOptions) }
|
||||
}
|
||||
FunctionItem(R.string.options, icon = R.drawable.tune_fill0) { onNavigate(SystemOptions) }
|
||||
FunctionItem(R.string.keyguard, icon = R.drawable.screen_lock_portrait_fill0) { onNavigate(Keyguard) }
|
||||
if(VERSION.SDK_INT >= 24 && deviceOwner && !dhizuku)
|
||||
if(VERSION.SDK_INT >= 24 && privilege.device && !privilege.dhizuku)
|
||||
FunctionItem(R.string.hardware_monitor, icon = R.drawable.memory_fill0) { onNavigate(HardwareMonitor) }
|
||||
if(VERSION.SDK_INT >= 24 && deviceOwner) {
|
||||
if(VERSION.SDK_INT >= 24 && privilege.device) {
|
||||
FunctionItem(R.string.reboot, icon = R.drawable.restart_alt_fill0) { dialog = 1 }
|
||||
}
|
||||
if(deviceOwner && VERSION.SDK_INT >= 24 && (VERSION.SDK_INT < 28 || dpm.isAffiliatedUser)) {
|
||||
if(VERSION.SDK_INT >= 24 && privilege.device && (VERSION.SDK_INT < 28 || dpm.isAffiliatedUser)) {
|
||||
FunctionItem(R.string.bug_report, icon = R.drawable.bug_report_fill0) { dialog = 2 }
|
||||
}
|
||||
if(VERSION.SDK_INT >= 28 && (deviceOwner || dpm.isOrgProfile(receiver))) {
|
||||
if(VERSION.SDK_INT >= 28 && (privilege.device || privilege.org)) {
|
||||
FunctionItem(R.string.change_time, icon = R.drawable.schedule_fill0) { onNavigate(ChangeTime) }
|
||||
FunctionItem(R.string.change_timezone, icon = R.drawable.schedule_fill0) { onNavigate(ChangeTimeZone) }
|
||||
}
|
||||
/*if(VERSION.SDK_INT >= 28 && (deviceOwner || profileOwner))
|
||||
FunctionItem(R.string.key_pairs, icon = R.drawable.key_vertical_fill0) { navCtrl.navigate("KeyPairs") }*/
|
||||
if(VERSION.SDK_INT >= 35 && (deviceOwner || (profileOwner && dpm.isAffiliatedUser)))
|
||||
if(VERSION.SDK_INT >= 35 && (privilege.device || (privilege.profile && privilege.affiliated)))
|
||||
FunctionItem(R.string.content_protection_policy, icon = R.drawable.search_fill0) { onNavigate(ContentProtectionPolicy) }
|
||||
if(VERSION.SDK_INT >= 23 && (deviceOwner || profileOwner)) {
|
||||
if(VERSION.SDK_INT >= 23) {
|
||||
FunctionItem(R.string.permission_policy, icon = R.drawable.key_fill0) { onNavigate(PermissionPolicy) }
|
||||
}
|
||||
if(VERSION.SDK_INT >= 34 && deviceOwner) {
|
||||
if(VERSION.SDK_INT >= 34 && privilege.device) {
|
||||
FunctionItem(R.string.mte_policy, icon = R.drawable.memory_fill0) { onNavigate(MtePolicy) }
|
||||
}
|
||||
if(VERSION.SDK_INT >= 31 && (deviceOwner || profileOwner)) {
|
||||
if(VERSION.SDK_INT >= 31) {
|
||||
FunctionItem(R.string.nearby_streaming_policy, icon = R.drawable.share_fill0) { onNavigate(NearbyStreamingPolicy) }
|
||||
}
|
||||
if(VERSION.SDK_INT >= 28 && deviceOwner) {
|
||||
if(VERSION.SDK_INT >= 28 && privilege.device) {
|
||||
FunctionItem(R.string.lock_task_mode, icon = R.drawable.lock_fill0) { onNavigate(LockTaskMode) }
|
||||
}
|
||||
if(deviceOwner || profileOwner) {
|
||||
FunctionItem(R.string.ca_cert, icon = R.drawable.license_fill0) { onNavigate(CaCert) }
|
||||
}
|
||||
if(VERSION.SDK_INT >= 26 && !dhizuku && (deviceOwner || dpm.isOrgProfile(receiver))) {
|
||||
FunctionItem(R.string.ca_cert, icon = R.drawable.license_fill0) { onNavigate(CaCert) }
|
||||
if(VERSION.SDK_INT >= 26 && !privilege.dhizuku && (privilege.device || privilege.org)) {
|
||||
FunctionItem(R.string.security_logging, icon = R.drawable.description_fill0) { onNavigate(SecurityLogging) }
|
||||
}
|
||||
if(deviceOwner || profileOwner) {
|
||||
FunctionItem(R.string.disable_account_management, icon = R.drawable.account_circle_fill0) { onNavigate(DisableAccountManagement) }
|
||||
}
|
||||
if(VERSION.SDK_INT >= 23 && (deviceOwner || dpm.isOrgProfile(receiver))) {
|
||||
FunctionItem(R.string.disable_account_management, icon = R.drawable.account_circle_fill0) { onNavigate(DisableAccountManagement) }
|
||||
if(VERSION.SDK_INT >= 23 && (privilege.device || privilege.org)) {
|
||||
FunctionItem(R.string.system_update_policy, icon = R.drawable.system_update_fill0) { onNavigate(SetSystemUpdatePolicy) }
|
||||
}
|
||||
if(VERSION.SDK_INT >= 29 && (deviceOwner || dpm.isOrgProfile(receiver))) {
|
||||
if(VERSION.SDK_INT >= 29 && (privilege.device || privilege.org)) {
|
||||
FunctionItem(R.string.install_system_update, icon = R.drawable.system_update_fill0) { onNavigate(InstallSystemUpdate) }
|
||||
}
|
||||
if(VERSION.SDK_INT >= 30 && (deviceOwner || dpm.isOrgProfile(receiver))) {
|
||||
if(VERSION.SDK_INT >= 30 && (privilege.device || privilege.org)) {
|
||||
FunctionItem(R.string.frp_policy, icon = R.drawable.device_reset_fill0) { onNavigate(FrpPolicy) }
|
||||
}
|
||||
if(sp.displayDangerousFeatures && context.isDeviceAdmin && !(VERSION.SDK_INT >= 24 && profileOwner && dpm.isManagedProfile(receiver))) {
|
||||
if(sp.displayDangerousFeatures && !privilege.work) {
|
||||
FunctionItem(R.string.wipe_data, icon = R.drawable.device_reset_fill0) { onNavigate(WipeData) }
|
||||
}
|
||||
}
|
||||
@@ -253,27 +247,21 @@ fun SystemOptionsScreen(onNavigateUp: () -> Unit) {
|
||||
val context = LocalContext.current
|
||||
val dpm = context.getDPM()
|
||||
val receiver = context.getReceiver()
|
||||
val deviceOwner = context.isDeviceOwner
|
||||
val profileOwner = context.isProfileOwner
|
||||
val um = context.getSystemService(Context.USER_SERVICE) as UserManager
|
||||
val privilege by myPrivilege.collectAsStateWithLifecycle()
|
||||
var dialog by remember { mutableIntStateOf(0) }
|
||||
MyScaffold(R.string.options, onNavigateUp, 0.dp) {
|
||||
if(deviceOwner || profileOwner) {
|
||||
SwitchItem(R.string.disable_cam, icon = R.drawable.photo_camera_fill0,
|
||||
getState = { dpm.getCameraDisabled(null) }, onCheckedChange = { dpm.setCameraDisabled(receiver,it) }
|
||||
)
|
||||
}
|
||||
if(deviceOwner || profileOwner) {
|
||||
SwitchItem(R.string.disable_screen_capture, icon = R.drawable.screenshot_fill0,
|
||||
getState = { dpm.getScreenCaptureDisabled(null) }, onCheckedChange = { dpm.setScreenCaptureDisabled(receiver,it) }
|
||||
)
|
||||
}
|
||||
if(VERSION.SDK_INT >= 34 && (deviceOwner || (profileOwner && dpm.isAffiliatedUser))) {
|
||||
SwitchItem(R.string.disable_cam, icon = R.drawable.photo_camera_fill0,
|
||||
getState = { dpm.getCameraDisabled(null) }, onCheckedChange = { dpm.setCameraDisabled(receiver,it) }
|
||||
)
|
||||
SwitchItem(R.string.disable_screen_capture, icon = R.drawable.screenshot_fill0,
|
||||
getState = { dpm.getScreenCaptureDisabled(null) }, onCheckedChange = { dpm.setScreenCaptureDisabled(receiver,it) }
|
||||
)
|
||||
if(VERSION.SDK_INT >= 34 && (privilege.device || (privilege.profile && privilege.affiliated))) {
|
||||
SwitchItem(R.string.disable_status_bar, icon = R.drawable.notifications_fill0,
|
||||
getState = { dpm.isStatusBarDisabled}, onCheckedChange = { dpm.setStatusBarDisabled(receiver,it) }
|
||||
)
|
||||
}
|
||||
if(deviceOwner || (VERSION.SDK_INT >= 23 && profileOwner && um.isSystemUser) || dpm.isOrgProfile(receiver)) {
|
||||
if(privilege.device || privilege.org) {
|
||||
if(VERSION.SDK_INT >= 30) {
|
||||
SwitchItem(R.string.auto_time, icon = R.drawable.schedule_fill0,
|
||||
getState = { dpm.getAutoTimeEnabled(receiver) }, onCheckedChange = { dpm.setAutoTimeEnabled(receiver,it) }
|
||||
@@ -286,30 +274,28 @@ fun SystemOptionsScreen(onNavigateUp: () -> Unit) {
|
||||
getState = { dpm.autoTimeRequired }, onCheckedChange = { dpm.setAutoTimeRequired(receiver,it) }, padding = false)
|
||||
}
|
||||
}
|
||||
if(deviceOwner || profileOwner) {
|
||||
SwitchItem(R.string.master_mute, icon = R.drawable.volume_off_fill0,
|
||||
getState = { dpm.isMasterVolumeMuted(receiver) }, onCheckedChange = { dpm.setMasterVolumeMuted(receiver,it) }
|
||||
)
|
||||
}
|
||||
if(VERSION.SDK_INT >= 26 && (deviceOwner || profileOwner)) {
|
||||
SwitchItem(R.string.master_mute, icon = R.drawable.volume_off_fill0,
|
||||
getState = { dpm.isMasterVolumeMuted(receiver) }, onCheckedChange = { dpm.setMasterVolumeMuted(receiver,it) }
|
||||
)
|
||||
if(VERSION.SDK_INT >= 26) {
|
||||
SwitchItem(R.string.backup_service, icon = R.drawable.backup_fill0,
|
||||
getState = { dpm.isBackupServiceEnabled(receiver) }, onCheckedChange = { dpm.setBackupServiceEnabled(receiver,it) },
|
||||
onClickBlank = { dialog = 1 }
|
||||
)
|
||||
}
|
||||
if(VERSION.SDK_INT >= 24 && profileOwner && dpm.isManagedProfile(receiver)) {
|
||||
if(VERSION.SDK_INT >= 24 && privilege.work) {
|
||||
SwitchItem(R.string.disable_bt_contact_share, icon = R.drawable.account_circle_fill0,
|
||||
getState = { dpm.getBluetoothContactSharingDisabled(receiver) },
|
||||
onCheckedChange = { dpm.setBluetoothContactSharingDisabled(receiver,it) }
|
||||
)
|
||||
}
|
||||
if(VERSION.SDK_INT >= 30 && deviceOwner) {
|
||||
if(VERSION.SDK_INT >= 30 && privilege.device) {
|
||||
SwitchItem(R.string.common_criteria_mode , icon =R.drawable.security_fill0,
|
||||
getState = { dpm.isCommonCriteriaModeEnabled(receiver) }, onCheckedChange = { dpm.setCommonCriteriaModeEnabled(receiver,it) },
|
||||
onClickBlank = { dialog = 2 }
|
||||
)
|
||||
}
|
||||
if(VERSION.SDK_INT >= 31 && (deviceOwner || dpm.isOrgProfile(receiver)) && dpm.canUsbDataSignalingBeDisabled()) {
|
||||
if(VERSION.SDK_INT >= 31 && (privilege.device || privilege.org) && dpm.canUsbDataSignalingBeDisabled()) {
|
||||
SwitchItem(
|
||||
R.string.disable_usb_signal, icon = R.drawable.usb_fill0, getState = { !dpm.isUsbDataSignalingEnabled },
|
||||
onCheckedChange = { dpm.isUsbDataSignalingEnabled = !it },
|
||||
@@ -340,24 +326,21 @@ fun KeyguardScreen(onNavigateUp: () -> Unit) {
|
||||
val context = LocalContext.current
|
||||
val dpm = context.getDPM()
|
||||
val receiver = context.getReceiver()
|
||||
val deviceOwner = context.isDeviceOwner
|
||||
val profileOwner = context.isProfileOwner
|
||||
val privilege by myPrivilege.collectAsStateWithLifecycle()
|
||||
MyScaffold(R.string.keyguard, onNavigateUp) {
|
||||
if(VERSION.SDK_INT >= 23) {
|
||||
if(VERSION.SDK_INT >= 23 && (privilege.device || (VERSION.SDK_INT >= 28 && privilege.profile && privilege.affiliated))) {
|
||||
Row(
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
) {
|
||||
Button(
|
||||
onClick = { context.showOperationResultToast(dpm.setKeyguardDisabled(receiver, true)) },
|
||||
enabled = deviceOwner || (VERSION.SDK_INT >= 28 && profileOwner && dpm.isAffiliatedUser),
|
||||
modifier = Modifier.fillMaxWidth(0.49F)
|
||||
) {
|
||||
Text(stringResource(R.string.disable))
|
||||
}
|
||||
Button(
|
||||
onClick = { context.showOperationResultToast(dpm.setKeyguardDisabled(receiver, false)) },
|
||||
enabled = deviceOwner || (VERSION.SDK_INT >= 28 && profileOwner && dpm.isAffiliatedUser),
|
||||
modifier = Modifier.fillMaxWidth(0.96F)
|
||||
) {
|
||||
Text(stringResource(R.string.enable))
|
||||
@@ -369,7 +352,7 @@ fun KeyguardScreen(onNavigateUp: () -> Unit) {
|
||||
if(VERSION.SDK_INT >= 23) Text(text = stringResource(R.string.lock_now), style = typography.headlineLarge)
|
||||
Spacer(Modifier.padding(vertical = 2.dp))
|
||||
var flag by remember { mutableIntStateOf(0) }
|
||||
if(VERSION.SDK_INT >= 26 && profileOwner && dpm.isManagedProfile(receiver)) {
|
||||
if(VERSION.SDK_INT >= 26 && privilege.work) {
|
||||
CheckBoxItem(
|
||||
R.string.evict_credential_encryption_key,
|
||||
flag and FLAG_EVICT_CREDENTIAL_ENCRYPTION_KEY != 0
|
||||
@@ -380,12 +363,11 @@ fun KeyguardScreen(onNavigateUp: () -> Unit) {
|
||||
onClick = {
|
||||
if(VERSION.SDK_INT >= 26) dpm.lockNow(flag) else dpm.lockNow()
|
||||
},
|
||||
enabled = context.isDeviceAdmin,
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
) {
|
||||
Text(stringResource(R.string.lock_now))
|
||||
}
|
||||
if(VERSION.SDK_INT >= 26 && profileOwner && dpm.isManagedProfile(receiver)) {
|
||||
if(VERSION.SDK_INT >= 26 && privilege.work) {
|
||||
Notes(R.string.info_evict_credential_encryption_key)
|
||||
}
|
||||
}
|
||||
@@ -393,7 +375,6 @@ fun KeyguardScreen(onNavigateUp: () -> Unit) {
|
||||
|
||||
@Serializable object HardwareMonitor
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@RequiresApi(24)
|
||||
@Composable
|
||||
fun HardwareMonitorScreen(onNavigateUp: () -> Unit) {
|
||||
@@ -1332,7 +1313,7 @@ fun CaCertScreen(onNavigateUp: () -> Unit) {
|
||||
text = {
|
||||
if(dialog == 3) Text(stringResource(R.string.uninstall_all_user_ca_cert))
|
||||
else {
|
||||
var text = ""
|
||||
var text: String
|
||||
val sha256 = MessageDigest.getInstance("SHA-256").digest(caCertByteArray).toHexString()
|
||||
try {
|
||||
val cf = CertificateFactory.getInstance("X.509")
|
||||
@@ -1634,6 +1615,7 @@ fun WipeDataScreen(onNavigateUp: () -> Unit) {
|
||||
val context = LocalContext.current
|
||||
val userManager = context.getSystemService(Context.USER_SERVICE) as UserManager
|
||||
val dpm = context.getDPM()
|
||||
val privilege by myPrivilege.collectAsStateWithLifecycle()
|
||||
val focusMgr = LocalFocusManager.current
|
||||
var flag by remember { mutableIntStateOf(0) }
|
||||
var warning by remember { mutableStateOf(false) }
|
||||
@@ -1642,7 +1624,7 @@ fun WipeDataScreen(onNavigateUp: () -> Unit) {
|
||||
var reason by remember { mutableStateOf("") }
|
||||
MyScaffold(R.string.wipe_data, onNavigateUp) {
|
||||
CheckBoxItem(R.string.wipe_external_storage, flag and WIPE_EXTERNAL_STORAGE != 0) { flag = flag xor WIPE_EXTERNAL_STORAGE }
|
||||
if(VERSION.SDK_INT >= 22 && context.isDeviceOwner) CheckBoxItem(
|
||||
if(VERSION.SDK_INT >= 22 && privilege.device) CheckBoxItem(
|
||||
R.string.wipe_reset_protection_data, flag and WIPE_RESET_PROTECTION_DATA != 0) { flag = flag xor WIPE_RESET_PROTECTION_DATA }
|
||||
if(VERSION.SDK_INT >= 28) CheckBoxItem(R.string.wipe_euicc, flag and WIPE_EUICC != 0) { flag = flag xor WIPE_EUICC }
|
||||
if(VERSION.SDK_INT >= 29) CheckBoxItem(R.string.wipe_silently, silent) { silent = it }
|
||||
@@ -1667,7 +1649,7 @@ fun WipeDataScreen(onNavigateUp: () -> Unit) {
|
||||
Text("WipeData")
|
||||
}
|
||||
}
|
||||
if (VERSION.SDK_INT >= 34 && context.isDeviceOwner) {
|
||||
if (VERSION.SDK_INT >= 34 && privilege.device) {
|
||||
Button(
|
||||
onClick = {
|
||||
focusMgr.clearFocus()
|
||||
|
||||
@@ -10,11 +10,13 @@ import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.bintianqi.owndroid.R
|
||||
import com.bintianqi.owndroid.myPrivilege
|
||||
import com.bintianqi.owndroid.ui.FunctionItem
|
||||
import com.bintianqi.owndroid.ui.MyScaffold
|
||||
import com.bintianqi.owndroid.ui.SwitchItem
|
||||
@@ -33,14 +35,12 @@ data class Restriction(
|
||||
@RequiresApi(24)
|
||||
@Composable
|
||||
fun UserRestrictionScreen(onNavigateUp: () -> Unit, onNavigate: (Int, List<Restriction>) -> Unit) {
|
||||
val context = LocalContext.current
|
||||
val dpm = context.getDPM()
|
||||
val receiver = context.getReceiver()
|
||||
val privilege by myPrivilege.collectAsStateWithLifecycle()
|
||||
MyScaffold(R.string.user_restriction, onNavigateUp, 0.dp) {
|
||||
Spacer(Modifier.padding(vertical = 2.dp))
|
||||
Text(text = stringResource(R.string.switch_to_disable_feature), modifier = Modifier.padding(start = 16.dp))
|
||||
if(context.isProfileOwner) { Text(text = stringResource(R.string.profile_owner_is_restricted), modifier = Modifier.padding(start = 16.dp)) }
|
||||
if(context.isProfileOwner && dpm.isManagedProfile(receiver)) {
|
||||
if(privilege.profile) { Text(text = stringResource(R.string.profile_owner_is_restricted), modifier = Modifier.padding(start = 16.dp)) }
|
||||
if(privilege.work) {
|
||||
Text(text = stringResource(R.string.some_features_invalid_in_work_profile), modifier = Modifier.padding(start = 16.dp))
|
||||
}
|
||||
Spacer(Modifier.padding(vertical = 2.dp))
|
||||
|
||||
@@ -64,8 +64,10 @@ import androidx.compose.ui.text.input.KeyboardType
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.window.Dialog
|
||||
import androidx.compose.ui.window.DialogProperties
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.bintianqi.owndroid.HorizontalPadding
|
||||
import com.bintianqi.owndroid.R
|
||||
import com.bintianqi.owndroid.myPrivilege
|
||||
import com.bintianqi.owndroid.parseTimestamp
|
||||
import com.bintianqi.owndroid.showOperationResultToast
|
||||
import com.bintianqi.owndroid.ui.FullWidthCheckBoxItem
|
||||
@@ -89,28 +91,25 @@ fun UsersScreen(onNavigateUp: () -> Unit, onNavigate: (Any) -> Unit) {
|
||||
val context = LocalContext.current
|
||||
val dpm = context.getDPM()
|
||||
val receiver = context.getReceiver()
|
||||
val deviceOwner = context.isDeviceOwner
|
||||
val profileOwner = context.isProfileOwner
|
||||
val privilege by myPrivilege.collectAsStateWithLifecycle()
|
||||
var dialog by remember { mutableIntStateOf(0) }
|
||||
MyScaffold(R.string.users, onNavigateUp, 0.dp) {
|
||||
if(VERSION.SDK_INT >= 28 && profileOwner && dpm.isAffiliatedUser) {
|
||||
if(VERSION.SDK_INT >= 28 && privilege.profile && privilege.affiliated) {
|
||||
FunctionItem(R.string.logout, icon = R.drawable.logout_fill0) { dialog = 2 }
|
||||
}
|
||||
FunctionItem(R.string.user_info, icon = R.drawable.person_fill0) { onNavigate(UserInfo) }
|
||||
if(deviceOwner && VERSION.SDK_INT >= 28) {
|
||||
if(VERSION.SDK_INT >= 28 && privilege.device) {
|
||||
FunctionItem(R.string.secondary_users, icon = R.drawable.list_fill0) { dialog = 1 }
|
||||
FunctionItem(R.string.options, icon = R.drawable.tune_fill0) { onNavigate(UsersOptions) }
|
||||
}
|
||||
if(deviceOwner) {
|
||||
if(privilege.device) {
|
||||
FunctionItem(R.string.user_operation, icon = R.drawable.sync_alt_fill0) { onNavigate(UserOperation) }
|
||||
}
|
||||
if(VERSION.SDK_INT >= 24 && deviceOwner) {
|
||||
if(VERSION.SDK_INT >= 24 && privilege.device) {
|
||||
FunctionItem(R.string.create_user, icon = R.drawable.person_add_fill0) { onNavigate(CreateUser) }
|
||||
}
|
||||
if(deviceOwner || profileOwner) {
|
||||
FunctionItem(R.string.change_username, icon = R.drawable.edit_fill0) { onNavigate(ChangeUsername) }
|
||||
}
|
||||
if(VERSION.SDK_INT >= 23 && (deviceOwner || profileOwner)) {
|
||||
FunctionItem(R.string.change_username, icon = R.drawable.edit_fill0) { onNavigate(ChangeUsername) }
|
||||
if(VERSION.SDK_INT >= 23) {
|
||||
var changeUserIconDialog by remember { mutableStateOf(false) }
|
||||
var bitmap: Bitmap? by remember { mutableStateOf(null) }
|
||||
val launcher = rememberLauncherForActivityResult(ActivityResultContracts.GetContent()) {
|
||||
@@ -123,12 +122,12 @@ fun UsersScreen(onNavigateUp: () -> Unit, onNavigate: (Any) -> Unit) {
|
||||
Toast.makeText(context, R.string.select_an_image, Toast.LENGTH_SHORT).show()
|
||||
launcher.launch("image/*")
|
||||
}
|
||||
if(changeUserIconDialog == true) ChangeUserIconDialog(bitmap!!) { changeUserIconDialog = false }
|
||||
if(changeUserIconDialog) ChangeUserIconDialog(bitmap!!) { changeUserIconDialog = false }
|
||||
}
|
||||
if(VERSION.SDK_INT >= 28 && deviceOwner) {
|
||||
if(VERSION.SDK_INT >= 28 && privilege.device) {
|
||||
FunctionItem(R.string.user_session_msg, icon = R.drawable.notifications_fill0) { onNavigate(UserSessionMessage) }
|
||||
}
|
||||
if(VERSION.SDK_INT >= 26 && (deviceOwner || profileOwner)) {
|
||||
if(VERSION.SDK_INT >= 26) {
|
||||
FunctionItem(R.string.affiliation_id, icon = R.drawable.id_card_fill0) { onNavigate(AffiliationId) }
|
||||
}
|
||||
}
|
||||
@@ -190,6 +189,7 @@ fun UserInfoScreen(onNavigateUp: () -> Unit) {
|
||||
val context = LocalContext.current
|
||||
val dpm = context.getDPM()
|
||||
val receiver = context.getReceiver()
|
||||
val privilege by myPrivilege.collectAsStateWithLifecycle()
|
||||
val userManager = context.getSystemService(Context.USER_SERVICE) as UserManager
|
||||
val user = Process.myUserHandle()
|
||||
var infoDialog by remember { mutableIntStateOf(0) }
|
||||
@@ -205,10 +205,8 @@ fun UserInfoScreen(onNavigateUp: () -> Unit) {
|
||||
}
|
||||
if (VERSION.SDK_INT >= 28) {
|
||||
InfoItem(R.string.logout_enabled, dpm.isLogoutEnabled.yesOrNo)
|
||||
if(context.isDeviceOwner || context.isProfileOwner) {
|
||||
InfoItem(R.string.ephemeral_user, dpm.isEphemeralUser(receiver).yesOrNo)
|
||||
}
|
||||
InfoItem(R.string.affiliated_user, dpm.isAffiliatedUser.yesOrNo)
|
||||
InfoItem(R.string.ephemeral_user, dpm.isEphemeralUser(receiver).yesOrNo)
|
||||
InfoItem(R.string.affiliated_user, privilege.affiliated.yesOrNo)
|
||||
}
|
||||
InfoItem(R.string.user_id, (Binder.getCallingUid() / 100000).toString())
|
||||
InfoItem(R.string.user_serial_number, userManager.getSerialNumberForUser(Process.myUserHandle()).toString())
|
||||
@@ -447,7 +445,7 @@ fun AffiliationIdScreen(onNavigateUp: () -> Unit) {
|
||||
Spacer(Modifier.padding(vertical = 5.dp))
|
||||
Button(
|
||||
onClick = {
|
||||
list.removeAll(listOf(""))
|
||||
list.removeAll(setOf(""))
|
||||
dpm.setAffiliationIds(receiver, list.toSet())
|
||||
context.showOperationResultToast(true)
|
||||
refreshIds()
|
||||
|
||||
@@ -53,7 +53,9 @@ import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.input.ImeAction
|
||||
import androidx.compose.ui.text.input.KeyboardType
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.bintianqi.owndroid.R
|
||||
import com.bintianqi.owndroid.myPrivilege
|
||||
import com.bintianqi.owndroid.showOperationResultToast
|
||||
import com.bintianqi.owndroid.ui.CheckBoxItem
|
||||
import com.bintianqi.owndroid.ui.CopyTextButton
|
||||
@@ -69,26 +71,16 @@ import kotlinx.serialization.Serializable
|
||||
|
||||
@Composable
|
||||
fun WorkProfileScreen(onNavigateUp: () -> Unit, onNavigate: (Any) -> Unit) {
|
||||
val context = LocalContext.current
|
||||
val dpm = context.getDPM()
|
||||
val receiver = context.getReceiver()
|
||||
val profileOwner = context.isProfileOwner
|
||||
val privilege by myPrivilege.collectAsStateWithLifecycle()
|
||||
MyScaffold(R.string.work_profile, onNavigateUp, 0.dp) {
|
||||
if(VERSION.SDK_INT >= 30 && profileOwner && dpm.isManagedProfile(receiver)) {
|
||||
if(VERSION.SDK_INT >= 30) {
|
||||
FunctionItem(R.string.org_owned_work_profile, icon = R.drawable.corporate_fare_fill0) { onNavigate(OrganizationOwnedProfile) }
|
||||
}
|
||||
if(VERSION.SDK_INT < 24 || dpm.isProvisioningAllowed(ACTION_PROVISION_MANAGED_PROFILE)) {
|
||||
FunctionItem(R.string.create_work_profile, icon = R.drawable.work_fill0) { onNavigate(CreateWorkProfile) }
|
||||
}
|
||||
if(dpm.isOrgProfile(receiver)) {
|
||||
if(privilege.org) {
|
||||
FunctionItem(R.string.suspend_personal_app, icon = R.drawable.block_fill0) { onNavigate(SuspendPersonalApp) }
|
||||
}
|
||||
if(profileOwner && (VERSION.SDK_INT < 24 || dpm.isManagedProfile(receiver))) {
|
||||
FunctionItem(R.string.intent_filter, icon = R.drawable.filter_alt_fill0) { onNavigate(CrossProfileIntentFilter) }
|
||||
}
|
||||
if(profileOwner && (VERSION.SDK_INT < 24 || dpm.isManagedProfile(receiver))) {
|
||||
FunctionItem(R.string.delete_work_profile, icon = R.drawable.delete_forever_fill0) { onNavigate(DeleteWorkProfile) }
|
||||
}
|
||||
FunctionItem(R.string.intent_filter, icon = R.drawable.filter_alt_fill0) { onNavigate(CrossProfileIntentFilter) }
|
||||
FunctionItem(R.string.delete_work_profile, icon = R.drawable.delete_forever_fill0) { onNavigate(DeleteWorkProfile) }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -73,8 +73,6 @@
|
||||
|
||||
<!--Разрешения-->
|
||||
<string name="click_to_activate">Нажмите для активации</string>
|
||||
<string name="device_admin">Администратор устройства</string>
|
||||
<string name="activate_jump" tools:ignore="TypographyEllipsis">Активировать...</string>
|
||||
<string name="profile_owner">Владелец профиля</string>
|
||||
<string name="device_owner">Владелец устройства</string>
|
||||
<string name="delegated_admins">Делегированные администраторы</string>
|
||||
@@ -116,9 +114,7 @@
|
||||
<string name="activate_device_admin_here">Активируйте администратора устройства здесь.</string>
|
||||
|
||||
<!--Приемник-->
|
||||
<string name="onEnabled">OwnDroid: Включено</string>
|
||||
<string name="onDisabled">OwnDroid: Отключено</string>
|
||||
<string name="create_work_profile_success">OwnDroid: Рабочий профиль успешно создан</string>
|
||||
<string name="create_work_profile_success">Рабочий профиль успешно создан</string>
|
||||
|
||||
<!--Dhizuku-->
|
||||
<string name="failed_to_init_dhizuku">Не удалось инициализировать Dhizuku</string>
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||
<!--Global-->
|
||||
<string name="app_name" translatable="false">OwnDroid</string>
|
||||
<string name="place_holder" translatable="false"/>
|
||||
<string name="disabled">Devre Dışı</string>
|
||||
<string name="enabled">Etkin</string>
|
||||
<string name="disable">Devre Dışı Bırak</string>
|
||||
@@ -64,7 +62,6 @@
|
||||
<string name="alias">Takma Ad</string>
|
||||
<string name="unknown_error">Bilinmeyen Hata</string>
|
||||
<string name="permission_denied">İzin Reddedildi</string>
|
||||
<string name="api" translatable="false">API</string>
|
||||
<string name="error">Hata</string>
|
||||
<string name="status">Durum</string>
|
||||
<string name="edit">Düzenle</string>
|
||||
@@ -75,8 +72,6 @@
|
||||
|
||||
<!--Permissions-->
|
||||
<string name="click_to_activate">Etkinleştirmek için Tıklayın</string>
|
||||
<string name="device_admin">Cihaz Yöneticisi</string>
|
||||
<string name="activate_jump" tools:ignore="TypographyEllipsis">Etkinleştir...</string>
|
||||
<string name="profile_owner">Profil Sahibi</string>
|
||||
<string name="device_owner">Cihaz Sahibi</string>
|
||||
<string name="delegated_admins">Yetkilendirilmiş Yöneticiler</string>
|
||||
@@ -91,9 +86,6 @@
|
||||
<string name="add_delegated_admin">Yetkilendirilmiş Yönetici Ekle</string>
|
||||
<string name="dhizuku_will_be_deactivated">Dhizuku Devre Dışı Bırakılacak</string>
|
||||
<string name="reset_device_policy">Cihaz Politikasını Sıfırla</string>
|
||||
<string name="activate_device_admin_command" translatable="false">dpm set-active-admin com.bintianqi.owndroid/com.bintianqi.owndroid.Receiver</string>
|
||||
<string name="activate_profile_owner_command" translatable="false">dpm set-profile-owner --user %1$s com.bintianqi.owndroid/com.bintianqi.owndroid.Receiver</string>
|
||||
<string name="activate_device_owner_command" translatable="false">dpm set-device-owner com.bintianqi.owndroid/com.bintianqi.owndroid.Receiver</string>
|
||||
<string name="device_info">Cihaz Bilgisi</string>
|
||||
<string name="support_device_id_attestation">Cihaz Kimliği Doğrulamasını Destekler</string>
|
||||
<string name="support_unique_device_attestation">Benzersiz Cihaz Doğrulamasını Destekler</string>
|
||||
@@ -121,22 +113,17 @@
|
||||
<string name="activate_device_admin_here">Cihaz Yöneticisini Burada Etkinleştir.</string>
|
||||
|
||||
<!--Receiver-->
|
||||
<string name="onEnabled">OwnDroid: Etkin</string>
|
||||
<string name="onDisabled">OwnDroid: Devre Dışı</string>
|
||||
<string name="create_work_profile_success">OwnDroid: İş Profili Başarıyla Oluşturuldu</string>
|
||||
<string name="create_work_profile_success">İş Profili Başarıyla Oluşturuldu</string>
|
||||
|
||||
<!--Dhizuku-->
|
||||
<string name="dhizuku" translatable="false">Dhizuku</string>
|
||||
<string name="failed_to_init_dhizuku">Dhizuku Başlatılamadı</string>
|
||||
<string name="dhizuku_permission_not_granted">Dhizuku İzni Verilmedi</string>
|
||||
<string name="dhizuku_mode_disabled">Dhizuku Modu Devre Dışı</string>
|
||||
<!--Shizuku-->
|
||||
<string name="shizuku" translatable="false">Shizuku</string>
|
||||
<string name="list_owners">Sahip Listesi</string>
|
||||
<string name="list_users">Kullanıcı Listesi</string>
|
||||
<string name="list_accounts">Hesap Listesi</string>
|
||||
<string name="shizuku_not_started">Shizuku Başlatılmadı.</string>
|
||||
<string name="dpm_activate_do_command" translatable="false">dpm set-device-owner com.bintianqi.owndroid/com.bintianqi.owndroid.Receiver</string>
|
||||
<string name="activate_device_owner">Cihaz Sahibini Etkinleştir</string>
|
||||
<string name="activate_org_profile">Kuruluşa Ait İş Profilini Etkinleştir</string>
|
||||
<string name="accounts">Hesaplar</string>
|
||||
@@ -246,7 +233,6 @@
|
||||
<!--Network-->
|
||||
<string name="network">Ağ</string>
|
||||
<string name="wifi_mac_address">Wi-Fi MAC Adresi</string>
|
||||
<string name="wifi" translatable="false">Wi-Fi</string>
|
||||
<string name="disconnect">Bağlantıyı Kes</string>
|
||||
<string name="reconnect">Yeniden Bağlan</string>
|
||||
<string name="saved_networks">Kayıtlı Ağlar</string>
|
||||
@@ -277,13 +263,11 @@
|
||||
<string name="target">Hedef</string>
|
||||
<string name="device">Cihaz</string>
|
||||
<string name="user">Kullanıcı</string>
|
||||
<string name="uid" translatable="false">UID</string>
|
||||
<string name="uid_tag">UID Etiketi</string>
|
||||
<string name="uid_tag_state">UID Etiket Durumu</string>
|
||||
<string name="network_type">Ağ Türü</string>
|
||||
<string name="mobile">Mobil</string>
|
||||
<string name="ethernet">Ethernet</string>
|
||||
<string name="vpn" translatable="false">VPN</string>
|
||||
<string name="subscriber_id">Abone Kimliği</string>
|
||||
<string name="all">Tümü</string>
|
||||
<string name="uninstalled">Kaldırılmış</string>
|
||||
@@ -357,9 +341,6 @@
|
||||
<string name="account_name">Hesap Adı</string>
|
||||
<string name="keep_account">Hesabı Koru</string>
|
||||
<string name="org_owned_work_profile">Kuruluşa Ait İş Profili</string>
|
||||
<string name="activate_org_profile_command" tools:ignore="TypographyDashes" translatable="false">
|
||||
dpm mark-profile-owner-on-organization-owned-device --user %1$s com.bintianqi.owndroid/com.bintianqi.owndroid.Receiver
|
||||
</string>
|
||||
<string name="skip_encryption">Şifrelemeyi Atla</string>
|
||||
<string name="create">Oluştur</string>
|
||||
<string name="suspend_personal_app">Kişisel Uygulamayı Askıya Al</string>
|
||||
@@ -440,7 +421,6 @@
|
||||
<string name="bt_share">Bluetooth Paylaşımı</string>
|
||||
<string name="share_location">Konumu Paylaş</string>
|
||||
<string name="config_location">Konumu Yapılandır</string>
|
||||
<string name="nfc" translatable="false">NFC</string>
|
||||
<string name="outgoing_beam">Giden Işın</string>
|
||||
<string name="usb_file_transfer">USB Dosya Aktarımı</string>
|
||||
<string name="mount_physical_media">Fiziksel Medyayı Bağla</string>
|
||||
@@ -501,7 +481,6 @@
|
||||
<string name="logout_enabled">Çıkış Yapma Etkin</string>
|
||||
<string name="ephemeral_user">Geçici Kullanıcı</string>
|
||||
<string name="affiliated_user">Bağlı Kullanıcı</string>
|
||||
<string name="user_id" translatable="false">User ID</string>
|
||||
<string name="user_serial_number">Kullanıcı Seri Numarası</string>
|
||||
<string name="secondary_users">İkincil Kullanıcılar</string>
|
||||
<string name="no_secondary_users">İkincil Kullanıcı Yok</string>
|
||||
|
||||
@@ -70,8 +70,6 @@
|
||||
|
||||
<!--Permissions-->
|
||||
<string name="click_to_activate">点击以激活</string>
|
||||
<string name="device_admin">Device admin</string>
|
||||
<string name="activate_jump" tools:ignore="TypographyEllipsis">激活...</string>
|
||||
<string name="profile_owner">Profile owner</string>
|
||||
<string name="device_owner">Device owner</string>
|
||||
<string name="delegated_admins">委托管理员</string>
|
||||
@@ -112,9 +110,7 @@
|
||||
<string name="activate_device_admin_here">在这里激活Device admin</string>
|
||||
|
||||
<!--Receiver-->
|
||||
<string name="onEnabled">OwnDroid:已启用</string>
|
||||
<string name="onDisabled">OwnDroid:已禁用</string>
|
||||
<string name="create_work_profile_success">OwnDroid:创建工作资料成功</string>
|
||||
<string name="create_work_profile_success">创建工作资料成功</string>
|
||||
|
||||
<!--Dhizuku-->
|
||||
<string name="failed_to_init_dhizuku">Dhizuku初始化失败</string>
|
||||
|
||||
@@ -75,8 +75,6 @@
|
||||
|
||||
<!--Permissions-->
|
||||
<string name="click_to_activate">Click to activate</string>
|
||||
<string name="device_admin">Device admin</string>
|
||||
<string name="activate_jump" tools:ignore="TypographyEllipsis">Activate...</string>
|
||||
<string name="profile_owner">Profile owner</string>
|
||||
<string name="device_owner">Device owner</string>
|
||||
<string name="delegated_admins">Delegated admins</string>
|
||||
@@ -91,7 +89,6 @@
|
||||
<string name="add_delegated_admin">Add delegated admin</string>
|
||||
<string name="dhizuku_will_be_deactivated">Dhizuku will be deactivated</string>
|
||||
<string name="reset_device_policy">Reset device policy</string>
|
||||
<string name="activate_device_admin_command" translatable="false">dpm set-active-admin com.bintianqi.owndroid/com.bintianqi.owndroid.Receiver</string>
|
||||
<string name="activate_profile_owner_command" translatable="false">dpm set-profile-owner --user %1$s com.bintianqi.owndroid/com.bintianqi.owndroid.Receiver</string>
|
||||
<string name="activate_device_owner_command" translatable="false">dpm set-device-owner com.bintianqi.owndroid/com.bintianqi.owndroid.Receiver</string>
|
||||
<string name="device_info">Device info</string>
|
||||
@@ -121,9 +118,7 @@
|
||||
<string name="activate_device_admin_here">Activate Device admin here.</string>
|
||||
|
||||
<!--Receiver-->
|
||||
<string name="onEnabled">OwnDroid: Enabled</string>
|
||||
<string name="onDisabled">OwnDroid: Disabled</string>
|
||||
<string name="create_work_profile_success">OwnDroid: Create work profile success</string>
|
||||
<string name="create_work_profile_success">Create work profile success</string>
|
||||
|
||||
<!--Dhizuku-->
|
||||
<string name="dhizuku" translatable="false">Dhizuku</string>
|
||||
|
||||
Reference in New Issue
Block a user