ViewModel refactoring: UserRestriction part

fix bugs (#165)
This commit is contained in:
BinTianqi
2025-09-24 17:20:28 +08:00
parent 2c72912ea6
commit 289afb63ff
5 changed files with 168 additions and 166 deletions

View File

@@ -526,15 +526,14 @@ fun Home(vm: MyViewModel, onLock: () -> Unit) {
} }
composable<UserRestriction> { composable<UserRestriction> {
UserRestrictionScreen(::navigateUp) { UserRestrictionScreen(vm::getUserRestrictions, ::navigateUp, ::navigate)
navigate(it)
}
} }
composable<UserRestrictionEditor> { composable<UserRestrictionEditor> {
UserRestrictionEditorScreen(::navigateUp) UserRestrictionEditorScreen(vm.userRestrictions, vm::setUserRestriction, ::navigateUp)
} }
composable<UserRestrictionOptions>(mapOf(serializableNavTypePair<List<Restriction>>())) { composable<UserRestrictionOptions>(mapOf(serializableNavTypePair<List<Restriction>>())) {
UserRestrictionOptionsScreen(it.toRoute(), ::navigateUp) UserRestrictionOptionsScreen(it.toRoute(), vm.userRestrictions,
vm::setUserRestriction, ::navigateUp)
} }
composable<Users> { UsersScreen(::navigateUp, ::navigate) } composable<Users> { UsersScreen(::navigateUp, ::navigate) }

View File

@@ -996,6 +996,25 @@ class MyViewModel(application: Application): AndroidViewModel(application) {
DPM.transferOwnership(DAR, component, null) DPM.transferOwnership(DAR, component, null)
Privilege.updateStatus() Privilege.updateStatus()
} }
val userRestrictions = MutableStateFlow(emptyMap<String, Boolean>())
@RequiresApi(24)
fun getUserRestrictions() {
val bundle = DPM.getUserRestrictions(DAR)
userRestrictions.value = bundle.keySet().associateWith { bundle.getBoolean(it) }
}
fun setUserRestriction(name: String, state: Boolean): Boolean {
return try {
if (state) {
DPM.addUserRestriction(DAR, name)
} else {
DPM.clearUserRestriction(DAR, name)
}
userRestrictions.update { it.plus(name to state) }
true
} catch (_: SecurityException) {
false
}
}
} }
data class ThemeSettings( data class ThemeSettings(

View File

@@ -24,6 +24,7 @@ object Privilege {
if (dhizukuDpm != null) { if (dhizukuDpm != null) {
DPM = dhizukuDpm DPM = dhizukuDpm
DAR = Dhizuku.getOwnerComponent() DAR = Dhizuku.getOwnerComponent()
updateStatus()
return return
} }
} }

View File

@@ -0,0 +1,110 @@
package com.bintianqi.owndroid
import android.os.Build
import android.os.UserManager
import com.bintianqi.owndroid.dpm.Restriction
@Suppress("InlinedApi")
object UserRestrictionsRepository {
val network = listOf(
Restriction(UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS, R.string.config_mobile_network, R.drawable.signal_cellular_alt_fill0),
Restriction(UserManager.DISALLOW_CONFIG_WIFI, R.string.config_wifi, R.drawable.wifi_fill0),
Restriction(UserManager.DISALLOW_DATA_ROAMING, R.string.data_roaming, R.drawable.network_cell_fill0, 24),
Restriction(UserManager.DISALLOW_CELLULAR_2G, R.string.cellular_2g, R.drawable.network_cell_fill0, 34),
Restriction(UserManager.DISALLOW_ULTRA_WIDEBAND_RADIO, R.string.ultra_wideband_radio, R.drawable.wifi_tethering_fill0, 34),
Restriction(UserManager.DISALLOW_ADD_WIFI_CONFIG, R.string.add_wifi_conf, R.drawable.wifi_fill0, 33),
Restriction(UserManager.DISALLOW_CHANGE_WIFI_STATE, R.string.change_wifi_state, R.drawable.wifi_fill0, 33),
Restriction(UserManager.DISALLOW_WIFI_DIRECT, R.string.wifi_direct, R.drawable.wifi_tethering_fill0),
Restriction(UserManager.DISALLOW_WIFI_TETHERING, R.string.wifi_tethering, R.drawable.wifi_tethering_fill0, 33),
Restriction(UserManager.DISALLOW_SHARING_ADMIN_CONFIGURED_WIFI, R.string.share_admin_wifi, R.drawable.share_fill0, 33),
Restriction(UserManager.DISALLOW_NETWORK_RESET, R.string.network_reset, R.drawable.reset_wrench_fill0, 23),
Restriction(UserManager.DISALLOW_CONFIG_TETHERING, R.string.config_tethering, R.drawable.wifi_tethering_fill0),
Restriction(UserManager.DISALLOW_CONFIG_VPN, R.string.config_vpn, R.drawable.vpn_key_fill0),
Restriction(UserManager.DISALLOW_CONFIG_PRIVATE_DNS, R.string.config_private_dns, R.drawable.dns_fill0, 29),
Restriction(UserManager.DISALLOW_AIRPLANE_MODE, R.string.airplane_mode, R.drawable.airplanemode_active_fill0, 28),
Restriction(UserManager.DISALLOW_CONFIG_CELL_BROADCASTS, R.string.config_cell_broadcasts, R.drawable.cell_tower_fill0),
Restriction(UserManager.DISALLOW_SMS, R.string.sms, R.drawable.sms_fill0),
Restriction(UserManager.DISALLOW_OUTGOING_CALLS, R.string.outgoing_calls, R.drawable.phone_forwarded_fill0),
Restriction(UserManager.DISALLOW_SIM_GLOBALLY, R.string.download_esim, R.drawable.sim_card_download_fill0),
Restriction(UserManager.DISALLOW_THREAD_NETWORK, R.string.thread_network, R.drawable.router_fill0, 36)
)
val connectivity = listOf(
Restriction(UserManager.DISALLOW_BLUETOOTH, R.string.bluetooth, R.drawable.bluetooth_fill0, 26),
Restriction(UserManager.DISALLOW_BLUETOOTH_SHARING, R.string.bt_share, R.drawable.bluetooth_searching_fill0, 26),
Restriction(UserManager.DISALLOW_SHARE_LOCATION, R.string.share_location, R.drawable.location_on_fill0),
Restriction(UserManager.DISALLOW_CONFIG_LOCATION, R.string.config_location, R.drawable.location_on_fill0, 28),
Restriction(UserManager.DISALLOW_NEAR_FIELD_COMMUNICATION_RADIO, R.string.nfc, R.drawable.nfc_fill0, 35),
Restriction(UserManager.DISALLOW_OUTGOING_BEAM, R.string.outgoing_beam, R.drawable.nfc_fill0, 22),
Restriction(UserManager.DISALLOW_USB_FILE_TRANSFER, R.string.usb_file_transfer, R.drawable.usb_fill0),
Restriction(UserManager.DISALLOW_MOUNT_PHYSICAL_MEDIA, R.string.mount_physical_media, R.drawable.sd_card_fill0),
Restriction(UserManager.DISALLOW_PRINTING, R.string.printing, R.drawable.print_fill0, 28)
)
val applications = listOf(
Restriction(UserManager.DISALLOW_INSTALL_APPS, R.string.install_app, R.drawable.android_fill0),
Restriction(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES_GLOBALLY, R.string.install_unknown_src_globally, R.drawable.android_fill0, 29),
Restriction(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES, R.string.inst_unknown_src, R.drawable.android_fill0),
Restriction(UserManager.DISALLOW_UNINSTALL_APPS, R.string.uninstall_app, R.drawable.delete_fill0),
Restriction(UserManager.DISALLOW_APPS_CONTROL, R.string.apps_ctrl, R.drawable.apps_fill0),
Restriction(UserManager.DISALLOW_CONFIG_DEFAULT_APPS, R.string.config_default_apps, R.drawable.apps_fill0, 34)
)
val media = listOf(
Restriction(UserManager.DISALLOW_CONFIG_BRIGHTNESS, R.string.config_brightness, R.drawable.brightness_5_fill0, 28),
Restriction(UserManager.DISALLOW_CONFIG_SCREEN_TIMEOUT, R.string.config_scr_timeout, R.drawable.screen_lock_portrait_fill0, 28),
Restriction(UserManager.DISALLOW_AMBIENT_DISPLAY, R.string.ambient_display, R.drawable.brightness_5_fill0, 28),
Restriction(UserManager.DISALLOW_ADJUST_VOLUME, R.string.adjust_volume, R.drawable.volume_up_fill0),
Restriction(UserManager.DISALLOW_UNMUTE_MICROPHONE, R.string.unmute_microphone, R.drawable.mic_fill0),
Restriction(UserManager.DISALLOW_CAMERA_TOGGLE, R.string.camera_toggle, R.drawable.cameraswitch_fill0, 31),
Restriction(UserManager.DISALLOW_MICROPHONE_TOGGLE, R.string.microphone_toggle, R.drawable.mic_fill0, 31)
)
val users = listOf(
Restriction(UserManager.DISALLOW_ADD_USER, R.string.add_user, R.drawable.account_circle_fill0),
Restriction(UserManager.DISALLOW_REMOVE_USER, R.string.remove_user, R.drawable.account_circle_fill0),
Restriction(UserManager.DISALLOW_USER_SWITCH, R.string.switch_user, R.drawable.account_circle_fill0, 28),
Restriction(UserManager.DISALLOW_ADD_MANAGED_PROFILE, R.string.create_work_profile, R.drawable.work_fill0, 26),
Restriction(UserManager.DISALLOW_REMOVE_MANAGED_PROFILE, R.string.delete_work_profile, R.drawable.delete_forever_fill0, 26),
Restriction(UserManager.DISALLOW_ADD_PRIVATE_PROFILE, R.string.create_private_space, R.drawable.lock_fill0, 35),
Restriction(UserManager.DISALLOW_SET_USER_ICON, R.string.set_user_icon, R.drawable.account_circle_fill0, 24),
Restriction(UserManager.DISALLOW_CROSS_PROFILE_COPY_PASTE, R.string.cross_profile_copy, R.drawable.content_paste_fill0),
Restriction(UserManager.DISALLOW_SHARE_INTO_MANAGED_PROFILE, R.string.share_into_managed_profile, R.drawable.share_fill0, 28),
Restriction(UserManager.DISALLOW_UNIFIED_PASSWORD, R.string.unified_pwd, R.drawable.work_fill0, 28)
)
val other = listOf(
Restriction(UserManager.DISALLOW_AUTOFILL, R.string.autofill, R.drawable.password_fill0, 26),
Restriction(UserManager.DISALLOW_CONFIG_CREDENTIALS, R.string.config_credentials, R.drawable.android_fill0),
Restriction(UserManager.DISALLOW_CONTENT_CAPTURE, R.string.content_capture, R.drawable.screenshot_fill0, 29),
Restriction(UserManager.DISALLOW_CONTENT_SUGGESTIONS, R.string.content_suggestions, R.drawable.sms_fill0, 29),
Restriction(UserManager.DISALLOW_ASSIST_CONTENT, R.string.assist_content, R.drawable.info_fill0, 35),
Restriction(UserManager.DISALLOW_CREATE_WINDOWS, R.string.create_windows, R.drawable.web_asset),
Restriction(UserManager.DISALLOW_SET_WALLPAPER, R.string.set_wallpaper, R.drawable.wallpaper_fill0, 24),
Restriction(UserManager.DISALLOW_GRANT_ADMIN, R.string.grant_admin, R.drawable.security_fill0, 34),
Restriction(UserManager.DISALLOW_FUN, R.string.`fun`, R.drawable.stadia_controller_fill0, 23),
Restriction(UserManager.DISALLOW_MODIFY_ACCOUNTS, R.string.modify_accounts, R.drawable.manage_accounts_fill0),
Restriction(UserManager.DISALLOW_CONFIG_LOCALE, R.string.config_locale, R.drawable.language_fill0, 28),
Restriction(UserManager.DISALLOW_CONFIG_DATE_TIME, R.string.config_date_time, R.drawable.schedule_fill0, 28),
Restriction(UserManager.DISALLOW_SYSTEM_ERROR_DIALOGS, R.string.sys_err_dialog, R.drawable.warning_fill0, 28),
Restriction(UserManager.DISALLOW_FACTORY_RESET, R.string.factory_reset, R.drawable.android_fill0),
Restriction(UserManager.DISALLOW_SAFE_BOOT, R.string.safe_boot, R.drawable.security_fill0, 23),
Restriction(UserManager.DISALLOW_DEBUGGING_FEATURES, R.string.debug_features, R.drawable.adb_fill0)
)
fun getData(id: String): Pair<Int, List<Restriction>> {
val category = UserRestrictionCategory.entries.find { it.id == id }!!
return category.title to when (category) {
UserRestrictionCategory.Network -> network
UserRestrictionCategory.Connectivity -> connectivity
UserRestrictionCategory.Applications -> applications
UserRestrictionCategory.Media -> media
UserRestrictionCategory.Users -> users
UserRestrictionCategory.Other -> other
}.filter { Build.VERSION.SDK_INT >= it.requiresApi }
}
}
enum class UserRestrictionCategory(val id: String, val title: Int, val icon: Int) {
Network("network", R.string.network, R.drawable.language_fill0),
Connectivity("connectivity", R.string.connectivity, R.drawable.devices_other_fill0),
Applications("applications", R.string.applications, R.drawable.apps_fill0),
Media("media", R.string.media, R.drawable.volume_up_fill0),
Users("users", R.string.users, R.drawable.manage_accounts_fill0),
Other("other", R.string.other, R.drawable.more_horiz_fill0)
}

View File

@@ -1,10 +1,6 @@
package com.bintianqi.owndroid.dpm package com.bintianqi.owndroid.dpm
import android.os.Build
import android.os.UserManager
import androidx.annotation.DrawableRes
import androidx.annotation.RequiresApi import androidx.annotation.RequiresApi
import androidx.annotation.StringRes
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Row
@@ -12,6 +8,7 @@ import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.WindowInsets import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.ime import androidx.compose.foundation.layout.ime
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyColumn
@@ -39,8 +36,6 @@ import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateListOf
import androidx.compose.runtime.mutableStateMapOf
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
@@ -57,17 +52,20 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.bintianqi.owndroid.HorizontalPadding import com.bintianqi.owndroid.HorizontalPadding
import com.bintianqi.owndroid.Privilege import com.bintianqi.owndroid.Privilege
import com.bintianqi.owndroid.R import com.bintianqi.owndroid.R
import com.bintianqi.owndroid.UserRestrictionCategory
import com.bintianqi.owndroid.UserRestrictionsRepository
import com.bintianqi.owndroid.showOperationResultToast import com.bintianqi.owndroid.showOperationResultToast
import com.bintianqi.owndroid.ui.FunctionItem import com.bintianqi.owndroid.ui.FunctionItem
import com.bintianqi.owndroid.ui.MyLazyScaffold import com.bintianqi.owndroid.ui.MyLazyScaffold
import com.bintianqi.owndroid.ui.NavIcon import com.bintianqi.owndroid.ui.NavIcon
import kotlinx.coroutines.flow.StateFlow
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
@Serializable @Serializable
data class Restriction( data class Restriction(
val id: String, val id: String,
@StringRes val name: Int, val name: Int,
@DrawableRes val icon: Int, val icon: Int,
val requiresApi: Int = 0 val requiresApi: Int = 0
) )
@@ -76,12 +74,12 @@ data class Restriction(
@OptIn(ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterial3Api::class)
@RequiresApi(24) @RequiresApi(24)
@Composable @Composable
fun UserRestrictionScreen(onNavigateUp: () -> Unit, onNavigate: (Any) -> Unit) { fun UserRestrictionScreen(
getRestrictions: () -> Unit,onNavigateUp: () -> Unit, onNavigate: (Any) -> Unit
) {
val privilege by Privilege.status.collectAsStateWithLifecycle() val privilege by Privilege.status.collectAsStateWithLifecycle()
val sb = TopAppBarDefaults.exitUntilCollapsedScrollBehavior() val sb = TopAppBarDefaults.exitUntilCollapsedScrollBehavior()
fun navigateToOptions(title: Int, items: List<Restriction>) { LaunchedEffect(Unit) { getRestrictions() }
onNavigate(UserRestrictionOptions(title, items))
}
Scaffold( Scaffold(
Modifier.nestedScroll(sb.nestedScrollConnection), Modifier.nestedScroll(sb.nestedScrollConnection),
topBar = { topBar = {
@@ -114,49 +112,29 @@ fun UserRestrictionScreen(onNavigateUp: () -> Unit, onNavigate: (Any) -> Unit) {
Text(text = stringResource(R.string.some_features_invalid_in_work_profile), modifier = Modifier.padding(start = 16.dp)) Text(text = stringResource(R.string.some_features_invalid_in_work_profile), modifier = Modifier.padding(start = 16.dp))
} }
Spacer(Modifier.padding(vertical = 2.dp)) Spacer(Modifier.padding(vertical = 2.dp))
FunctionItem(R.string.network, icon = R.drawable.language_fill0) { UserRestrictionCategory.entries.forEach {
navigateToOptions(R.string.network, RestrictionData.internet) FunctionItem(it.title, icon = it.icon) {
} onNavigate(UserRestrictionOptions(it.id))
FunctionItem(R.string.connectivity, icon = R.drawable.devices_other_fill0) { }
navigateToOptions(R.string.connectivity, RestrictionData.connectivity)
}
FunctionItem(R.string.applications, icon = R.drawable.apps_fill0) {
navigateToOptions(R.string.applications, RestrictionData.applications)
}
FunctionItem(R.string.users, icon = R.drawable.account_circle_fill0) {
navigateToOptions(R.string.users, RestrictionData.users)
}
FunctionItem(R.string.media, icon = R.drawable.volume_up_fill0) {
navigateToOptions(R.string.media, RestrictionData.media)
}
FunctionItem(R.string.other, icon = R.drawable.more_horiz_fill0) {
navigateToOptions(R.string.other, RestrictionData.other)
} }
} }
} }
} }
@Serializable @Serializable
data class UserRestrictionOptions( data class UserRestrictionOptions(val id: String)
val title: Int, val items: List<Restriction>
)
@RequiresApi(24) @RequiresApi(24)
@Composable @Composable
fun UserRestrictionOptionsScreen( fun UserRestrictionOptionsScreen(
data: UserRestrictionOptions, onNavigateUp: () -> Unit args: UserRestrictionOptions, userRestrictions: StateFlow<Map<String, Boolean>>,
setRestriction: (String, Boolean) -> Boolean, onNavigateUp: () -> Unit
) { ) {
val context = LocalContext.current val context = LocalContext.current
val status = remember { mutableStateMapOf<String, Boolean>() } val status by userRestrictions.collectAsStateWithLifecycle()
fun refresh() { val (title, items) = UserRestrictionsRepository.getData(args.id)
val restrictions = Privilege.DPM.getUserRestrictions(Privilege.DAR) MyLazyScaffold(title, onNavigateUp) {
data.items.forEach { items(items) { restriction ->
status.put(it.id, restrictions.getBoolean(it.id))
}
}
LaunchedEffect(Unit) { refresh() }
MyLazyScaffold(data.title, onNavigateUp) {
items(data.items.filter { Build.VERSION.SDK_INT >= it.requiresApi }) { restriction ->
Row( Row(
Modifier.fillMaxWidth().padding(15.dp, 6.dp), Modifier.fillMaxWidth().padding(15.dp, 6.dp),
Arrangement.SpaceBetween, Alignment.CenterVertically Arrangement.SpaceBetween, Alignment.CenterVertically
@@ -174,18 +152,11 @@ fun UserRestrictionOptionsScreen(
Switch( Switch(
status[restriction.id] == true, status[restriction.id] == true,
{ {
try { if (!setRestriction(restriction.id, it)) {
if (it) {
Privilege.DPM.addUserRestriction(Privilege.DAR, restriction.id)
} else {
Privilege.DPM.clearUserRestriction(Privilege.DAR, restriction.id)
}
} catch (e: Exception) {
e.printStackTrace()
context.showOperationResultToast(false) context.showOperationResultToast(false)
} }
refresh() },
} Modifier.padding(start = 8.dp)
) )
} }
} }
@@ -195,104 +166,18 @@ fun UserRestrictionOptionsScreen(
} }
} }
@Suppress("InlinedApi")
object RestrictionData {
val internet = listOf(
Restriction(UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS, R.string.config_mobile_network, R.drawable.signal_cellular_alt_fill0),
Restriction(UserManager.DISALLOW_CONFIG_WIFI, R.string.config_wifi, R.drawable.wifi_fill0),
Restriction(UserManager.DISALLOW_DATA_ROAMING, R.string.data_roaming, R.drawable.network_cell_fill0, 24),
Restriction(UserManager.DISALLOW_CELLULAR_2G, R.string.cellular_2g, R.drawable.network_cell_fill0, 34),
Restriction(UserManager.DISALLOW_ULTRA_WIDEBAND_RADIO, R.string.ultra_wideband_radio, R.drawable.wifi_tethering_fill0, 34),
Restriction(UserManager.DISALLOW_ADD_WIFI_CONFIG, R.string.add_wifi_conf, R.drawable.wifi_fill0, 33),
Restriction(UserManager.DISALLOW_CHANGE_WIFI_STATE, R.string.change_wifi_state, R.drawable.wifi_fill0, 33),
Restriction(UserManager.DISALLOW_WIFI_DIRECT, R.string.wifi_direct, R.drawable.wifi_tethering_fill0),
Restriction(UserManager.DISALLOW_WIFI_TETHERING, R.string.wifi_tethering, R.drawable.wifi_tethering_fill0, 33),
Restriction(UserManager.DISALLOW_SHARING_ADMIN_CONFIGURED_WIFI, R.string.share_admin_wifi, R.drawable.share_fill0, 33),
Restriction(UserManager.DISALLOW_NETWORK_RESET, R.string.network_reset, R.drawable.reset_wrench_fill0, 23),
Restriction(UserManager.DISALLOW_CONFIG_TETHERING, R.string.config_tethering, R.drawable.wifi_tethering_fill0),
Restriction(UserManager.DISALLOW_CONFIG_VPN, R.string.config_vpn, R.drawable.vpn_key_fill0),
Restriction(UserManager.DISALLOW_CONFIG_PRIVATE_DNS, R.string.config_private_dns, R.drawable.dns_fill0, 29),
Restriction(UserManager.DISALLOW_AIRPLANE_MODE, R.string.airplane_mode, R.drawable.airplanemode_active_fill0, 28),
Restriction(UserManager.DISALLOW_CONFIG_CELL_BROADCASTS, R.string.config_cell_broadcasts, R.drawable.cell_tower_fill0),
Restriction(UserManager.DISALLOW_SMS, R.string.sms, R.drawable.sms_fill0),
Restriction(UserManager.DISALLOW_OUTGOING_CALLS, R.string.outgoing_calls, R.drawable.phone_forwarded_fill0),
Restriction(UserManager.DISALLOW_SIM_GLOBALLY, R.string.download_esim, R.drawable.sim_card_download_fill0),
Restriction(UserManager.DISALLOW_THREAD_NETWORK, R.string.thread_network, R.drawable.router_fill0, 36)
)
val connectivity = listOf(
Restriction(UserManager.DISALLOW_BLUETOOTH, R.string.bluetooth, R.drawable.bluetooth_fill0, 26),
Restriction(UserManager.DISALLOW_BLUETOOTH_SHARING, R.string.bt_share, R.drawable.bluetooth_searching_fill0, 26),
Restriction(UserManager.DISALLOW_SHARE_LOCATION, R.string.share_location, R.drawable.location_on_fill0),
Restriction(UserManager.DISALLOW_CONFIG_LOCATION, R.string.config_location, R.drawable.location_on_fill0, 28),
Restriction(UserManager.DISALLOW_NEAR_FIELD_COMMUNICATION_RADIO, R.string.nfc, R.drawable.nfc_fill0, 35),
Restriction(UserManager.DISALLOW_OUTGOING_BEAM, R.string.outgoing_beam, R.drawable.nfc_fill0, 22),
Restriction(UserManager.DISALLOW_USB_FILE_TRANSFER, R.string.usb_file_transfer, R.drawable.usb_fill0),
Restriction(UserManager.DISALLOW_MOUNT_PHYSICAL_MEDIA, R.string.mount_physical_media, R.drawable.sd_card_fill0),
Restriction(UserManager.DISALLOW_PRINTING, R.string.printing, R.drawable.print_fill0, 28)
)
val applications = listOf(
Restriction(UserManager.DISALLOW_INSTALL_APPS, R.string.install_app, R.drawable.android_fill0),
Restriction(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES_GLOBALLY, R.string.install_unknown_src_globally, R.drawable.android_fill0, 29),
Restriction(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES, R.string.inst_unknown_src, R.drawable.android_fill0),
Restriction(UserManager.DISALLOW_UNINSTALL_APPS, R.string.uninstall_app, R.drawable.delete_fill0),
Restriction(UserManager.DISALLOW_APPS_CONTROL, R.string.apps_ctrl, R.drawable.apps_fill0),
Restriction(UserManager.DISALLOW_CONFIG_DEFAULT_APPS, R.string.config_default_apps, R.drawable.apps_fill0, 34)
)
val media = listOf(
Restriction(UserManager.DISALLOW_CONFIG_BRIGHTNESS, R.string.config_brightness, R.drawable.brightness_5_fill0, 28),
Restriction(UserManager.DISALLOW_CONFIG_SCREEN_TIMEOUT, R.string.config_scr_timeout, R.drawable.screen_lock_portrait_fill0, 28),
Restriction(UserManager.DISALLOW_AMBIENT_DISPLAY, R.string.ambient_display, R.drawable.brightness_5_fill0, 28),
Restriction(UserManager.DISALLOW_ADJUST_VOLUME, R.string.adjust_volume, R.drawable.volume_up_fill0),
Restriction(UserManager.DISALLOW_UNMUTE_MICROPHONE, R.string.unmute_microphone, R.drawable.mic_fill0),
Restriction(UserManager.DISALLOW_CAMERA_TOGGLE, R.string.camera_toggle, R.drawable.cameraswitch_fill0, 31),
Restriction(UserManager.DISALLOW_MICROPHONE_TOGGLE, R.string.microphone_toggle, R.drawable.mic_fill0, 31)
)
val users = listOf(
Restriction(UserManager.DISALLOW_ADD_USER, R.string.add_user, R.drawable.account_circle_fill0),
Restriction(UserManager.DISALLOW_REMOVE_USER, R.string.remove_user, R.drawable.account_circle_fill0),
Restriction(UserManager.DISALLOW_USER_SWITCH, R.string.switch_user, R.drawable.account_circle_fill0, 28),
Restriction(UserManager.DISALLOW_ADD_MANAGED_PROFILE, R.string.create_work_profile, R.drawable.work_fill0, 26),
Restriction(UserManager.DISALLOW_REMOVE_MANAGED_PROFILE, R.string.delete_work_profile, R.drawable.delete_forever_fill0, 26),
Restriction(UserManager.DISALLOW_ADD_PRIVATE_PROFILE, R.string.create_private_space, R.drawable.lock_fill0, 35),
Restriction(UserManager.DISALLOW_SET_USER_ICON, R.string.set_user_icon, R.drawable.account_circle_fill0, 24),
Restriction(UserManager.DISALLOW_CROSS_PROFILE_COPY_PASTE, R.string.cross_profile_copy, R.drawable.content_paste_fill0),
Restriction(UserManager.DISALLOW_SHARE_INTO_MANAGED_PROFILE, R.string.share_into_managed_profile, R.drawable.share_fill0, 28),
Restriction(UserManager.DISALLOW_UNIFIED_PASSWORD, R.string.unified_pwd, R.drawable.work_fill0, 28)
)
val other = listOf(
Restriction(UserManager.DISALLOW_AUTOFILL, R.string.autofill, R.drawable.password_fill0, 26),
Restriction(UserManager.DISALLOW_CONFIG_CREDENTIALS, R.string.config_credentials, R.drawable.android_fill0),
Restriction(UserManager.DISALLOW_CONTENT_CAPTURE, R.string.content_capture, R.drawable.screenshot_fill0, 29),
Restriction(UserManager.DISALLOW_CONTENT_SUGGESTIONS, R.string.content_suggestions, R.drawable.sms_fill0, 29),
Restriction(UserManager.DISALLOW_ASSIST_CONTENT, R.string.assist_content, R.drawable.info_fill0, 35),
Restriction(UserManager.DISALLOW_CREATE_WINDOWS, R.string.create_windows, R.drawable.web_asset),
Restriction(UserManager.DISALLOW_SET_WALLPAPER, R.string.set_wallpaper, R.drawable.wallpaper_fill0, 24),
Restriction(UserManager.DISALLOW_GRANT_ADMIN, R.string.grant_admin, R.drawable.security_fill0, 34),
Restriction(UserManager.DISALLOW_FUN, R.string.`fun`, R.drawable.stadia_controller_fill0, 23),
Restriction(UserManager.DISALLOW_MODIFY_ACCOUNTS, R.string.modify_accounts, R.drawable.manage_accounts_fill0),
Restriction(UserManager.DISALLOW_CONFIG_LOCALE, R.string.config_locale, R.drawable.language_fill0, 28),
Restriction(UserManager.DISALLOW_CONFIG_DATE_TIME, R.string.config_date_time, R.drawable.schedule_fill0, 28),
Restriction(UserManager.DISALLOW_SYSTEM_ERROR_DIALOGS, R.string.sys_err_dialog, R.drawable.warning_fill0, 28),
Restriction(UserManager.DISALLOW_FACTORY_RESET, R.string.factory_reset, R.drawable.android_fill0),
Restriction(UserManager.DISALLOW_SAFE_BOOT, R.string.safe_boot, R.drawable.security_fill0, 23),
Restriction(UserManager.DISALLOW_DEBUGGING_FEATURES, R.string.debug_features, R.drawable.adb_fill0)
)
}
@Serializable object UserRestrictionEditor @Serializable object UserRestrictionEditor
@OptIn(ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterial3Api::class)
@RequiresApi(24) @RequiresApi(24)
@Composable @Composable
fun UserRestrictionEditorScreen(onNavigateUp: () -> Unit) { fun UserRestrictionEditorScreen(
restrictions: StateFlow<Map<String, Boolean>>, setRestriction: (String, Boolean) -> Boolean,
onNavigateUp: () -> Unit
) {
val context = LocalContext.current val context = LocalContext.current
val list = remember { mutableStateListOf<String>() } val map by restrictions.collectAsStateWithLifecycle()
fun refresh() { val list = map.filter { it.value }.map { it.key }
val restrictions = Privilege.DPM.getUserRestrictions(Privilege.DAR)
list.clear()
list.addAll(restrictions.keySet().filter { restrictions.getBoolean(it) })
}
LaunchedEffect(Unit) { refresh() }
Scaffold( Scaffold(
topBar = { topBar = {
TopAppBar( TopAppBar(
@@ -310,13 +195,7 @@ fun UserRestrictionEditorScreen(onNavigateUp: () -> Unit) {
) { ) {
Text(it) Text(it)
IconButton({ IconButton({
try { if (!setRestriction(it, false)) context.showOperationResultToast(false)
Privilege.DPM.clearUserRestriction(Privilege.DAR, it)
} catch (e: Exception) {
e.printStackTrace()
context.showOperationResultToast(false)
}
refresh()
}) { }) {
Icon(Icons.Outlined.Delete, null) Icon(Icons.Outlined.Delete, null)
} }
@@ -325,17 +204,10 @@ fun UserRestrictionEditorScreen(onNavigateUp: () -> Unit) {
item { item {
var input by remember { mutableStateOf("") } var input by remember { mutableStateOf("") }
fun add() { fun add() {
try { if (!setRestriction(input, false)) context.showOperationResultToast(false)
Privilege.DPM.addUserRestriction(Privilege.DAR, input)
input = ""
} catch (e: Exception) {
e.printStackTrace()
context.showOperationResultToast(false)
}
refresh()
} }
OutlinedTextField( OutlinedTextField(
input, { input = it }, Modifier.fillMaxWidth().padding(HorizontalPadding, 20.dp), input, { input = it }, Modifier.fillMaxWidth().padding(HorizontalPadding, 8.dp),
label = { Text("id") }, label = { Text("id") },
trailingIcon = { trailingIcon = {
IconButton(::add, enabled = input.isNotBlank()) { IconButton(::add, enabled = input.isNotBlank()) {
@@ -345,6 +217,7 @@ fun UserRestrictionEditorScreen(onNavigateUp: () -> Unit) {
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Ascii, imeAction = ImeAction.Done), keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Ascii, imeAction = ImeAction.Done),
keyboardActions = KeyboardActions { add() } keyboardActions = KeyboardActions { add() }
) )
Spacer(Modifier.height(40.dp))
} }
} }
} }