feat: refactor navigation, use navigation3 library

Fix global settings crash (#237)
This commit is contained in:
BinTianqi
2026-02-16 23:16:10 +08:00
parent f31e38f596
commit 2cd2ce4449
24 changed files with 1262 additions and 1205 deletions

View File

@@ -89,12 +89,13 @@ gradle.taskGraph.whenReady {
dependencies { dependencies {
implementation(libs.androidx.activity.compose) implementation(libs.androidx.activity.compose)
implementation(platform(libs.androidx.compose.bom)) implementation(platform(libs.androidx.compose.bom))
implementation(libs.androidx.nav3.runtime)
implementation(libs.androidx.nav3.ui)
implementation(libs.androidx.compose.ui.tooling.preview) implementation(libs.androidx.compose.ui.tooling.preview)
debugImplementation(libs.androidx.compose.ui.tooling) debugImplementation(libs.androidx.compose.ui.tooling)
implementation(libs.accompanist.drawablepainter) implementation(libs.accompanist.drawablepainter)
implementation(libs.accompanist.permissions) implementation(libs.accompanist.permissions)
implementation(libs.androidx.material3) implementation(libs.androidx.material3)
implementation(libs.androidx.navigation.compose)
implementation(libs.material.icons.core) implementation(libs.material.icons.core)
implementation(libs.shizuku.provider) implementation(libs.shizuku.provider)
implementation(libs.shizuku.api) implementation(libs.shizuku.api)

View File

@@ -9,30 +9,13 @@ import androidx.activity.enableEdgeToEdge
import androidx.activity.result.contract.ActivityResultContracts import androidx.activity.result.contract.ActivityResultContracts
import androidx.activity.viewModels import androidx.activity.viewModels
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.gestures.detectTapGestures
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Settings
import androidx.compose.material3.AlertDialog import androidx.compose.material3.AlertDialog
import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.IconButton
import androidx.compose.material3.LargeTopAppBar
import androidx.compose.material3.MaterialTheme.colorScheme
import androidx.compose.material3.MaterialTheme.typography
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.material3.TextButton import androidx.compose.material3.TextButton
import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.LaunchedEffect
@@ -41,207 +24,21 @@ import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.DialogProperties import androidx.compose.ui.window.DialogProperties
import androidx.fragment.app.FragmentActivity import androidx.fragment.app.FragmentActivity
import androidx.lifecycle.Lifecycle import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleEventObserver import androidx.lifecycle.LifecycleEventObserver
import androidx.lifecycle.compose.LocalLifecycleOwner import androidx.lifecycle.compose.LocalLifecycleOwner
import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.navigation.compose.NavHost import androidx.navigation3.runtime.rememberNavBackStack
import androidx.navigation.compose.composable import androidx.navigation3.ui.NavDisplay
import androidx.navigation.compose.rememberNavController
import androidx.navigation.toRoute
import com.bintianqi.owndroid.dpm.AddApnSetting
import com.bintianqi.owndroid.dpm.AddApnSettingScreen
import com.bintianqi.owndroid.dpm.AddDelegatedAdmin
import com.bintianqi.owndroid.dpm.AddDelegatedAdminScreen
import com.bintianqi.owndroid.dpm.AddPreferentialNetworkServiceConfig
import com.bintianqi.owndroid.dpm.AddPreferentialNetworkServiceConfigScreen
import com.bintianqi.owndroid.dpm.AffiliationId
import com.bintianqi.owndroid.dpm.AffiliationIdScreen
import com.bintianqi.owndroid.dpm.AlwaysOnVpnPackage
import com.bintianqi.owndroid.dpm.AlwaysOnVpnPackageScreen
import com.bintianqi.owndroid.dpm.ApplicationDetails
import com.bintianqi.owndroid.dpm.ApplicationDetailsScreen
import com.bintianqi.owndroid.dpm.ApplicationsFeatures
import com.bintianqi.owndroid.dpm.ApplicationsFeaturesScreen
import com.bintianqi.owndroid.dpm.AutoTimePolicy
import com.bintianqi.owndroid.dpm.AutoTimePolicyScreen
import com.bintianqi.owndroid.dpm.AutoTimeZonePolicy
import com.bintianqi.owndroid.dpm.AutoTimeZonePolicyScreen
import com.bintianqi.owndroid.dpm.BlockUninstall
import com.bintianqi.owndroid.dpm.CaCert
import com.bintianqi.owndroid.dpm.CaCertScreen
import com.bintianqi.owndroid.dpm.ChangeTime
import com.bintianqi.owndroid.dpm.ChangeTimeScreen
import com.bintianqi.owndroid.dpm.ChangeTimeZone
import com.bintianqi.owndroid.dpm.ChangeTimeZoneScreen
import com.bintianqi.owndroid.dpm.ChangeUsername
import com.bintianqi.owndroid.dpm.ChangeUsernameScreen
import com.bintianqi.owndroid.dpm.ClearAppStorage
import com.bintianqi.owndroid.dpm.ClearAppStorageScreen
import com.bintianqi.owndroid.dpm.ContentProtectionPolicy
import com.bintianqi.owndroid.dpm.ContentProtectionPolicyScreen
import com.bintianqi.owndroid.dpm.CreateUser
import com.bintianqi.owndroid.dpm.CreateUserScreen
import com.bintianqi.owndroid.dpm.CreateWorkProfile
import com.bintianqi.owndroid.dpm.CreateWorkProfileScreen
import com.bintianqi.owndroid.dpm.CredentialManagerPolicy
import com.bintianqi.owndroid.dpm.CredentialManagerPolicyScreen
import com.bintianqi.owndroid.dpm.CrossProfileIntentFilter
import com.bintianqi.owndroid.dpm.CrossProfileIntentFilterScreen
import com.bintianqi.owndroid.dpm.CrossProfilePackages
import com.bintianqi.owndroid.dpm.CrossProfileWidgetProviders
import com.bintianqi.owndroid.dpm.DefaultInputMethod
import com.bintianqi.owndroid.dpm.DefaultInputMethodScreen
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.DeviceInfo
import com.bintianqi.owndroid.dpm.DeviceInfoScreen
import com.bintianqi.owndroid.dpm.DhizukuServerSettings
import com.bintianqi.owndroid.dpm.DhizukuServerSettingsScreen
import com.bintianqi.owndroid.dpm.DisableAccountManagement
import com.bintianqi.owndroid.dpm.DisableAccountManagementScreen
import com.bintianqi.owndroid.dpm.DisableMeteredData
import com.bintianqi.owndroid.dpm.DisableUserControl
import com.bintianqi.owndroid.dpm.EditAppGroup
import com.bintianqi.owndroid.dpm.EditAppGroupScreen
import com.bintianqi.owndroid.dpm.EnableSystemApp
import com.bintianqi.owndroid.dpm.EnableSystemAppScreen
import com.bintianqi.owndroid.dpm.FrpPolicy
import com.bintianqi.owndroid.dpm.FrpPolicyScreen
import com.bintianqi.owndroid.dpm.HardwareMonitor
import com.bintianqi.owndroid.dpm.HardwareMonitorScreen
import com.bintianqi.owndroid.dpm.Hide
import com.bintianqi.owndroid.dpm.InstallExistingApp
import com.bintianqi.owndroid.dpm.InstallExistingAppScreen
import com.bintianqi.owndroid.dpm.InstallSystemUpdate
import com.bintianqi.owndroid.dpm.InstallSystemUpdateScreen
import com.bintianqi.owndroid.dpm.KeepUninstalledPackages
import com.bintianqi.owndroid.dpm.Keyguard
import com.bintianqi.owndroid.dpm.KeyguardDisabledFeatures
import com.bintianqi.owndroid.dpm.KeyguardDisabledFeaturesScreen
import com.bintianqi.owndroid.dpm.KeyguardScreen
import com.bintianqi.owndroid.dpm.LockScreenInfo
import com.bintianqi.owndroid.dpm.LockScreenInfoScreen
import com.bintianqi.owndroid.dpm.LockTaskMode
import com.bintianqi.owndroid.dpm.LockTaskModeScreen
import com.bintianqi.owndroid.dpm.ManageAppGroups
import com.bintianqi.owndroid.dpm.ManageAppGroupsScreen
import com.bintianqi.owndroid.dpm.ManagedConfiguration
import com.bintianqi.owndroid.dpm.ManagedConfigurationScreen
import com.bintianqi.owndroid.dpm.MtePolicy
import com.bintianqi.owndroid.dpm.MtePolicyScreen
import com.bintianqi.owndroid.dpm.NearbyStreamingPolicy
import com.bintianqi.owndroid.dpm.NearbyStreamingPolicyScreen
import com.bintianqi.owndroid.dpm.Network
import com.bintianqi.owndroid.dpm.NetworkLogging
import com.bintianqi.owndroid.dpm.NetworkLoggingScreen
import com.bintianqi.owndroid.dpm.NetworkOptions
import com.bintianqi.owndroid.dpm.NetworkOptionsScreen
import com.bintianqi.owndroid.dpm.NetworkScreen
import com.bintianqi.owndroid.dpm.NetworkStatsScreen
import com.bintianqi.owndroid.dpm.NetworkStatsViewer
import com.bintianqi.owndroid.dpm.NetworkStatsViewerScreen
import com.bintianqi.owndroid.dpm.OrganizationOwnedProfile
import com.bintianqi.owndroid.dpm.OrganizationOwnedProfileScreen
import com.bintianqi.owndroid.dpm.OverrideApn
import com.bintianqi.owndroid.dpm.OverrideApnScreen
import com.bintianqi.owndroid.dpm.PackageFunctionScreen
import com.bintianqi.owndroid.dpm.Password
import com.bintianqi.owndroid.dpm.PasswordInfo
import com.bintianqi.owndroid.dpm.PasswordInfoScreen
import com.bintianqi.owndroid.dpm.PasswordScreen
import com.bintianqi.owndroid.dpm.PermissionPolicy
import com.bintianqi.owndroid.dpm.PermissionPolicyScreen
import com.bintianqi.owndroid.dpm.AppPermissionsManager
import com.bintianqi.owndroid.dpm.AppPermissionsManagerScreen
import com.bintianqi.owndroid.dpm.PermissionDetail
import com.bintianqi.owndroid.dpm.PermissionDetailScreen
import com.bintianqi.owndroid.dpm.PermissionManager
import com.bintianqi.owndroid.dpm.PermissionManagerScreen
import com.bintianqi.owndroid.dpm.PermittedAccessibilityServices
import com.bintianqi.owndroid.dpm.PermittedAsAndImPackages
import com.bintianqi.owndroid.dpm.PermittedInputMethods
import com.bintianqi.owndroid.dpm.PreferentialNetworkService
import com.bintianqi.owndroid.dpm.PreferentialNetworkServiceInfo
import com.bintianqi.owndroid.dpm.PreferentialNetworkServiceScreen
import com.bintianqi.owndroid.dpm.PrivateDns
import com.bintianqi.owndroid.dpm.PrivateDnsScreen
import com.bintianqi.owndroid.dpm.QueryNetworkStats
import com.bintianqi.owndroid.dpm.RecommendedGlobalProxy
import com.bintianqi.owndroid.dpm.RecommendedGlobalProxyScreen
import com.bintianqi.owndroid.dpm.RequiredPasswordComplexity
import com.bintianqi.owndroid.dpm.RequiredPasswordComplexityScreen
import com.bintianqi.owndroid.dpm.RequiredPasswordQuality
import com.bintianqi.owndroid.dpm.RequiredPasswordQualityScreen
import com.bintianqi.owndroid.dpm.ResetPassword
import com.bintianqi.owndroid.dpm.ResetPasswordScreen
import com.bintianqi.owndroid.dpm.ResetPasswordToken
import com.bintianqi.owndroid.dpm.ResetPasswordTokenScreen
import com.bintianqi.owndroid.dpm.SecurityLogging
import com.bintianqi.owndroid.dpm.SecurityLoggingScreen
import com.bintianqi.owndroid.dpm.SetDefaultDialer
import com.bintianqi.owndroid.dpm.SetDefaultDialerScreen
import com.bintianqi.owndroid.dpm.SetSystemUpdatePolicy
import com.bintianqi.owndroid.dpm.SupportMessage
import com.bintianqi.owndroid.dpm.SupportMessageScreen
import com.bintianqi.owndroid.dpm.Suspend
import com.bintianqi.owndroid.dpm.SuspendPersonalApp
import com.bintianqi.owndroid.dpm.SuspendPersonalAppScreen
import com.bintianqi.owndroid.dpm.SystemManager
import com.bintianqi.owndroid.dpm.SystemManagerScreen
import com.bintianqi.owndroid.dpm.SystemOptions
import com.bintianqi.owndroid.dpm.SystemOptionsScreen
import com.bintianqi.owndroid.dpm.SystemUpdatePolicyScreen
import com.bintianqi.owndroid.dpm.TransferOwnership
import com.bintianqi.owndroid.dpm.TransferOwnershipScreen
import com.bintianqi.owndroid.dpm.UninstallApp
import com.bintianqi.owndroid.dpm.UninstallAppScreen
import com.bintianqi.owndroid.dpm.UpdateNetwork
import com.bintianqi.owndroid.dpm.UpdateNetworkScreen
import com.bintianqi.owndroid.dpm.UserInfo
import com.bintianqi.owndroid.dpm.UserInfoScreen
import com.bintianqi.owndroid.dpm.UserOperation
import com.bintianqi.owndroid.dpm.UserOperationScreen
import com.bintianqi.owndroid.dpm.UserRestriction
import com.bintianqi.owndroid.dpm.UserRestrictionEditor
import com.bintianqi.owndroid.dpm.UserRestrictionEditorScreen
import com.bintianqi.owndroid.dpm.UserRestrictionOptions
import com.bintianqi.owndroid.dpm.UserRestrictionOptionsScreen
import com.bintianqi.owndroid.dpm.UserRestrictionScreen
import com.bintianqi.owndroid.dpm.UserSessionMessage
import com.bintianqi.owndroid.dpm.UserSessionMessageScreen
import com.bintianqi.owndroid.dpm.Users
import com.bintianqi.owndroid.dpm.UsersOptions
import com.bintianqi.owndroid.dpm.UsersOptionsScreen
import com.bintianqi.owndroid.dpm.UsersScreen
import com.bintianqi.owndroid.dpm.WiFi
import com.bintianqi.owndroid.dpm.WifiScreen
import com.bintianqi.owndroid.dpm.WifiSecurityLevel
import com.bintianqi.owndroid.dpm.WifiSecurityLevelScreen
import com.bintianqi.owndroid.dpm.WifiSsidPolicyScreen
import com.bintianqi.owndroid.dpm.WipeData
import com.bintianqi.owndroid.dpm.WipeDataScreen
import com.bintianqi.owndroid.dpm.WorkModes
import com.bintianqi.owndroid.dpm.WorkModesScreen
import com.bintianqi.owndroid.dpm.WorkProfile
import com.bintianqi.owndroid.dpm.WorkProfileScreen
import com.bintianqi.owndroid.dpm.dhizukuErrorStatus import com.bintianqi.owndroid.dpm.dhizukuErrorStatus
import com.bintianqi.owndroid.ui.NavTransition import com.bintianqi.owndroid.ui.NavTransition
import com.bintianqi.owndroid.ui.navigation.Destination
import com.bintianqi.owndroid.ui.navigation.myEntryProvider
import com.bintianqi.owndroid.ui.theme.OwnDroidTheme import com.bintianqi.owndroid.ui.theme.OwnDroidTheme
import kotlinx.serialization.Serializable
import java.util.Locale import java.util.Locale
@ExperimentalMaterial3Api @ExperimentalMaterial3Api
@@ -267,492 +64,36 @@ class MainActivity : FragmentActivity() {
var appLockDialog by rememberSaveable { mutableStateOf(false) } var appLockDialog by rememberSaveable { mutableStateOf(false) }
val theme by vm.theme.collectAsStateWithLifecycle() val theme by vm.theme.collectAsStateWithLifecycle()
OwnDroidTheme(theme) { OwnDroidTheme(theme) {
Home(vm) { appLockDialog = true } Box(Modifier.fillMaxSize().background(MaterialTheme.colorScheme.background))
val backstack = rememberNavBackStack(Destination.Home)
NavDisplay(
backstack,
onBack = {
backstack.removeLastOrNull()
},
transitionSpec = {
NavTransition.transition
},
popTransitionSpec = {
NavTransition.popTransition
},
predictivePopTransitionSpec = {
NavTransition.popTransition
}
) {
myEntryProvider(it as Destination, backstack, vm)
}
val lifecycleOwner = LocalLifecycleOwner.current
if (appLockDialog) { if (appLockDialog) {
AppLockDialog({ appLockDialog = false }) { moveTaskToBack(true) } AppLockDialog({ appLockDialog = false }) { moveTaskToBack(true) }
} }
}
}
}
}
@ExperimentalMaterial3Api
@Composable
fun Home(vm: MyViewModel, onLock: () -> Unit) {
val navController = rememberNavController()
val context = LocalContext.current
val focusMgr = LocalFocusManager.current
val lifecycleOwner = LocalLifecycleOwner.current
fun navigateUp() { navController.navigateUp() }
fun navigate(destination: Any) {
navController.navigate(destination) {
launchSingleTop = true
}
}
fun choosePackage() {
navController.navigate(ApplicationsList(false, true))
}
fun chooseSinglePackage() {
navController.navigate(ApplicationsList(false, false))
}
fun navigateToAppGroups() {
navController.navigate(ManageAppGroups)
}
LaunchedEffect(Unit) {
if(!Privilege.status.value.activated) {
navController.navigate(WorkModes(false)) {
popUpTo<Home> { inclusive = true }
}
}
}
@Suppress("NewApi") NavHost(
navController = navController,
startDestination = Home,
modifier = Modifier
.fillMaxSize()
.background(colorScheme.background)
.pointerInput(Unit) { detectTapGestures(onTap = { focusMgr.clearFocus() }) },
enterTransition = { NavTransition.enterTransition },
exitTransition = { NavTransition.exitTransition },
popEnterTransition = { NavTransition.popEnterTransition },
popExitTransition = { NavTransition.popExitTransition }
) {
composable<Home> { HomeScreen(::navigate) }
composable<WorkModes> {
WorkModesScreen(vm, it.toRoute(), ::navigateUp, {
navController.navigate(Home) {
popUpTo<WorkModes> { inclusive = true }
}
}, {
navController.navigate(WorkModes(false)) {
popUpTo(Home) { inclusive = true }
}
}, ::navigate)
}
composable<DhizukuServerSettings> {
DhizukuServerSettingsScreen(vm.dhizukuClients, vm::getDhizukuClients,
vm::updateDhizukuClient, vm::getDhizukuServerEnabled, vm::setDhizukuServerEnabled,
::navigateUp)
}
composable<DelegatedAdmins> {
DelegatedAdminsScreen(vm.delegatedAdmins, vm::getDelegatedAdmins, ::navigateUp, ::navigate)
}
composable<AddDelegatedAdmin>{
AddDelegatedAdminScreen(vm.chosenPackage, ::chooseSinglePackage, it.toRoute(),
vm::setDelegatedAdmin, ::navigateUp)
}
composable<DeviceInfo> { DeviceInfoScreen(vm, ::navigateUp) }
composable<LockScreenInfo> {
LockScreenInfoScreen(vm::getLockScreenInfo, vm::setLockScreenInfo, ::navigateUp)
}
composable<SupportMessage> {
SupportMessageScreen(vm::getShortSupportMessage, vm::getLongSupportMessage,
vm::setShortSupportMessage, vm::setLongSupportMessage, ::navigateUp)
}
composable<TransferOwnership> {
TransferOwnershipScreen(vm.deviceAdminReceivers, vm::getDeviceAdminReceivers,
vm::transferOwnership, ::navigateUp) {
navController.navigate(WorkModes(false)) {
popUpTo(Home) { inclusive = true }
}
}
}
composable<SystemManager> { SystemManagerScreen(vm, ::navigateUp, ::navigate) }
composable<SystemOptions> { SystemOptionsScreen(vm, ::navigateUp) }
composable<Keyguard> {
KeyguardScreen(vm::setKeyguardDisabled, vm::lockScreen, ::navigateUp)
}
composable<HardwareMonitor> {
HardwareMonitorScreen(vm.hardwareProperties, vm::getHardwareProperties,
vm::setHpRefreshInterval, ::navigateUp)
}
composable<DefaultInputMethod> {
DefaultInputMethodScreen(vm::getCurrentInputMethod, vm.inputMethodList,
vm::getInputMethods, vm::setDefaultInputMethod, ::navigateUp)
}
composable<ChangeTime> { ChangeTimeScreen(vm::setTime, ::navigateUp) }
composable<ChangeTimeZone> { ChangeTimeZoneScreen(vm::setTimeZone, ::navigateUp) }
composable<AutoTimePolicy> {
AutoTimePolicyScreen(vm::getAutoTimePolicy, vm::setAutoTimePolicy, ::navigateUp)
}
composable<AutoTimeZonePolicy> {
AutoTimeZonePolicyScreen(vm::getAutoTimeZonePolicy, vm::setAutoTimeZonePolicy,
::navigateUp)
}
//composable<> { KeyPairs(::navigateUp) }
composable<ContentProtectionPolicy> {
ContentProtectionPolicyScreen(vm::getContentProtectionPolicy,
vm::setContentProtectionPolicy, ::navigateUp)
}
composable<PermissionPolicy> {
PermissionPolicyScreen(vm::getPermissionPolicy, vm::setPermissionPolicy, ::navigateUp)
}
composable<MtePolicy> {
MtePolicyScreen(vm::getMtePolicy, vm::setMtePolicy, ::navigateUp)
}
composable<NearbyStreamingPolicy> {
NearbyStreamingPolicyScreen(vm::getNsAppPolicy, vm::setNsAppPolicy,
vm::getNsNotificationPolicy, vm::setNsNotificationPolicy, ::navigateUp)
}
composable<LockTaskMode> {
LockTaskModeScreen(
vm.chosenPackage, ::chooseSinglePackage, ::choosePackage, vm.lockTaskPackages,
vm::getLockTaskPackages, vm::setLockTaskPackage, vm::startLockTaskMode,
vm:: getLockTaskFeatures, vm::setLockTaskFeatures, ::navigateUp
)
}
composable<CaCert> {
CaCertScreen(vm.installedCaCerts, vm::getCaCerts, vm.selectedCaCert, vm::selectCaCert, vm::installCaCert, vm::parseCaCert,
vm::exportCaCert, vm::uninstallCaCert, vm::uninstallAllCaCerts, ::navigateUp)
}
composable<SecurityLogging> {
SecurityLoggingScreen(vm::getSecurityLoggingEnabled, vm::setSecurityLoggingEnabled,
vm::exportSecurityLogs, vm::getSecurityLogsCount, vm::deleteSecurityLogs,
vm::getPreRebootSecurityLogs, vm::exportPreRebootSecurityLogs, ::navigateUp)
}
composable<DisableAccountManagement> {
DisableAccountManagementScreen(vm.mdAccountTypes, vm::getMdAccountTypes,
vm::setMdAccountType, ::navigateUp)
}
composable<SetSystemUpdatePolicy> {
SystemUpdatePolicyScreen(vm::getSystemUpdatePolicy, vm::setSystemUpdatePolicy,
vm::getPendingSystemUpdate, ::navigateUp)
}
composable<InstallSystemUpdate> {
InstallSystemUpdateScreen(vm::installSystemUpdate, ::navigateUp)
}
composable<FrpPolicy> {
FrpPolicyScreen(vm.getFrpPolicy(), vm::setFrpPolicy, ::navigateUp)
}
composable<WipeData> { WipeDataScreen(vm::wipeData, ::navigateUp) }
composable<Network> { NetworkScreen(::navigateUp, ::navigate) }
composable<WiFi> {
WifiScreen(vm, ::navigateUp, ::navigate) { navController.navigate(UpdateNetwork(it)) }
}
composable<NetworkOptions> {
NetworkOptionsScreen(vm::getLanEnabled, vm::setLanEnabled, ::navigateUp)
}
composable<UpdateNetwork> {
val info = vm.configuredNetworks.collectAsStateWithLifecycle().value[
(it.toRoute() as UpdateNetwork).index
]
UpdateNetworkScreen(info, vm::setWifi, ::navigateUp)
}
composable<WifiSecurityLevel> {
WifiSecurityLevelScreen(vm::getMinimumWifiSecurityLevel,
vm::setMinimumWifiSecurityLevel, ::navigateUp)
}
composable<WifiSsidPolicyScreen> {
WifiSsidPolicyScreen(vm::getSsidPolicy, vm::setSsidPolicy, ::navigateUp)
}
composable<QueryNetworkStats> {
NetworkStatsScreen(vm.chosenPackage, ::chooseSinglePackage, vm::getPackageUid,
vm::queryNetworkStats, ::navigateUp) { navController.navigate(NetworkStatsViewer) }
}
composable<NetworkStatsViewer> {
NetworkStatsViewerScreen(vm.networkStatsData, vm::clearNetworkStats, ::navigateUp)
}
composable<PrivateDns> {
PrivateDnsScreen(vm::getPrivateDns, vm::setPrivateDns, ::navigateUp)
}
composable<AlwaysOnVpnPackage> {
AlwaysOnVpnPackageScreen(vm::getAlwaysOnVpnPackage, vm::getAlwaysOnVpnLockdown,
vm::setAlwaysOnVpn, vm.chosenPackage, ::chooseSinglePackage, ::navigateUp)
}
composable<RecommendedGlobalProxy> {
RecommendedGlobalProxyScreen(vm::setRecommendedGlobalProxy, ::navigateUp)
}
composable<NetworkLogging> {
NetworkLoggingScreen(vm::getNetworkLoggingEnabled, vm::setNetworkLoggingEnabled,
vm::getNetworkLogsCount, vm::exportNetworkLogs, vm::deleteNetworkLogs, ::navigateUp)
}
//composable<WifiAuthKeypair> { WifiAuthKeypairScreen(::navigateUp) }
composable<PreferentialNetworkService> {
PreferentialNetworkServiceScreen(vm::getPnsEnabled, vm::setPnsEnabled, vm.pnsConfigs,
vm::getPnsConfigs, ::navigateUp, ::navigate)
}
composable<AddPreferentialNetworkServiceConfig> {
val info = vm.pnsConfigs.collectAsStateWithLifecycle().value.getOrNull(
it.toRoute<AddPreferentialNetworkServiceConfig>().index
) ?: PreferentialNetworkServiceInfo()
AddPreferentialNetworkServiceConfigScreen(info, vm::setPnsConfig, ::navigateUp)
}
composable<OverrideApn> {
OverrideApnScreen(vm.apnConfigs, vm::getApnConfigs, vm::getApnEnabled,
vm::setApnEnabled, ::navigateUp) { navController.navigate(AddApnSetting(it)) }
}
composable<AddApnSetting> {
val origin = vm.apnConfigs.collectAsStateWithLifecycle().value.getOrNull((it.toRoute() as AddApnSetting).index)
AddApnSettingScreen(vm::setApnConfig, vm::removeApnConfig, origin, ::navigateUp)
}
composable<WorkProfile> { WorkProfileScreen(::navigateUp, ::navigate) }
composable<OrganizationOwnedProfile> {
OrganizationOwnedProfileScreen(vm::activateOrgProfileByShizuku, ::navigateUp)
}
composable<CreateWorkProfile> {
CreateWorkProfileScreen(vm::createWorkProfile, ::navigateUp)
}
composable<SuspendPersonalApp> {
SuspendPersonalAppScreen(
vm::getPersonalAppsSuspendedReason, vm::setPersonalAppsSuspended,
vm::getProfileMaxTimeOff, vm::setProfileMaxTimeOff, ::navigateUp
)
}
composable<CrossProfileIntentFilter> {
CrossProfileIntentFilterScreen(
vm::addCrossProfileIntentFilter, vm::clearCrossProfileIntentFilters,
vm::importCrossProfileIntentFilters, vm::exportCrossProfileIntentFilters,
::navigateUp
)
}
composable<DeleteWorkProfile> { DeleteWorkProfileScreen(vm::wipeData, ::navigateUp) }
composable<ApplicationsList> {
val params = it.toRoute<ApplicationsList>()
AppChooserScreen(
params, vm.installedPackages, vm.refreshPackagesProgress, { name ->
if (params.canSwitchView) {
if (name == null) {
navigateUp()
} else {
navigate(ApplicationDetails(name))
}
} else {
if (name != null) vm.chosenPackage.trySend(name)
navigateUp()
}
}, {
SP.applicationsListView = false
navController.navigate(ApplicationsFeatures) {
popUpTo(Home)
}
}, vm::refreshPackageList, vm::setPackageSuspended, vm::setPackageHidden)
}
composable<ApplicationsFeatures> {
ApplicationsFeaturesScreen(::navigateUp, ::navigate) {
SP.applicationsListView = true
navController.navigate(ApplicationsList(true, true)) {
popUpTo(Home)
}
}
}
composable<ApplicationDetails> {
ApplicationDetailsScreen(it.toRoute(), vm, ::navigateUp, ::navigate)
}
composable<Suspend> {
PackageFunctionScreen(
R.string.suspend, vm.suspendedPackages, vm::getSuspendedPackaged,
vm::setPackageSuspended, ::navigateUp, vm.chosenPackage, ::choosePackage,
::navigateToAppGroups, vm.appGroups, R.string.info_suspend_app
)
}
composable<Hide> {
PackageFunctionScreen(
R.string.hide, vm.hiddenPackages, vm::getHiddenPackages, vm::setPackageHidden,
::navigateUp, vm.chosenPackage, ::choosePackage, ::navigateToAppGroups, vm.appGroups
)
}
composable<BlockUninstall> {
PackageFunctionScreen(
R.string.block_uninstall, vm.ubPackages, vm::getUbPackages, vm::setPackageUb,
::navigateUp, vm.chosenPackage, ::choosePackage, ::navigateToAppGroups, vm.appGroups
)
}
composable<DisableUserControl> {
PackageFunctionScreen(
R.string.disable_user_control, vm.ucdPackages, vm::getUcdPackages,
vm::setPackageUcd, ::navigateUp, vm.chosenPackage, ::choosePackage,
::navigateToAppGroups, vm.appGroups, R.string.info_disable_user_control
)
}
composable<AppPermissionsManager> {
AppPermissionsManagerScreen(
vm::getPackagePermissions, vm::setPackagePermission, ::navigateUp, it.toRoute()
)
}
composable<PermissionManager> {
PermissionManagerScreen(::navigate, ::navigateUp)
}
composable<PermissionDetail> {
PermissionDetailScreen(
it.toRoute(), vm::getPermissionPackages, vm::setPackagePermission, ::navigateUp
)
}
composable<DisableMeteredData> {
PackageFunctionScreen(
R.string.disable_metered_data, vm.mddPackages, vm::getMddPackages,
vm::setPackageMdd, ::navigateUp, vm.chosenPackage, ::choosePackage,
::navigateToAppGroups, vm.appGroups
)
}
composable<ClearAppStorage> {
ClearAppStorageScreen(
vm.chosenPackage, ::chooseSinglePackage, vm::clearAppData, ::navigateUp
)
}
composable<UninstallApp> {
UninstallAppScreen(
vm.chosenPackage, ::chooseSinglePackage, vm::uninstallPackage, ::navigateUp
)
}
composable<KeepUninstalledPackages> {
PackageFunctionScreen(
R.string.keep_uninstalled_packages, vm.kuPackages, vm::getKuPackages,
vm::setPackageKu, ::navigateUp, vm.chosenPackage, ::choosePackage,
::navigateToAppGroups, vm.appGroups, R.string.info_keep_uninstalled_apps
)
}
composable<InstallExistingApp> {
InstallExistingAppScreen(
vm.chosenPackage, ::chooseSinglePackage, vm::installExistingApp, ::navigateUp
)
}
composable<CrossProfilePackages> {
PackageFunctionScreen(
R.string.cross_profile_apps, vm.cpPackages,
vm::getCpPackages, vm::setPackageCp, ::navigateUp, vm.chosenPackage,
::choosePackage, ::navigateToAppGroups, vm.appGroups
)
}
composable<CrossProfileWidgetProviders> {
PackageFunctionScreen(R.string.cross_profile_widget, vm.cpwProviders,
vm::getCpwProviders, vm::setCpwProvider, ::navigateUp, vm.chosenPackage,
::choosePackage, ::navigateToAppGroups, vm.appGroups)
}
composable<CredentialManagerPolicy> {
CredentialManagerPolicyScreen(
vm.chosenPackage, ::choosePackage, vm.cmPackages, vm::getCmPolicy,
vm::setCmPackage, vm::setCmPolicy, ::navigateUp
)
}
composable<PermittedAccessibilityServices> {
PermittedAsAndImPackages(
R.string.permitted_accessibility_services,
R.string.system_accessibility_always_allowed, vm.chosenPackage, ::choosePackage,
vm.pasPackages, vm::getPasPackages, vm::setPasPackage, vm::setPasPolicy,
::navigateUp
)
}
composable<PermittedInputMethods> {
PermittedAsAndImPackages(
R.string.permitted_ime, R.string.system_ime_always_allowed,
vm.chosenPackage, ::choosePackage, vm.pimPackages, vm::getPimPackages,
vm::setPimPackage, vm::setPimPolicy, ::navigateUp
)
}
composable<EnableSystemApp> {
EnableSystemAppScreen(
vm.chosenPackage, ::chooseSinglePackage, vm::enableSystemApp, ::navigateUp
)
}
composable<SetDefaultDialer> {
SetDefaultDialerScreen(
vm.chosenPackage, ::chooseSinglePackage, vm::setDefaultDialer, ::navigateUp
)
}
composable<ManagedConfiguration> {
ManagedConfigurationScreen(
it.toRoute(), vm.appRestrictions, vm::setAppRestrictions,
vm::clearAppRestrictions, ::navigateUp
)
}
composable<ManageAppGroups> {
ManageAppGroupsScreen(
vm.appGroups, vm::exportAppGroups, vm::importAppGroups,
{ id, name, apps -> navController.navigate(EditAppGroup(id, name, apps)) },
::navigateUp
)
}
composable<EditAppGroup> {
EditAppGroupScreen(
it.toRoute(), vm::getAppInfo, ::navigateUp, vm::setAppGroup,
vm::deleteAppGroup, ::choosePackage, vm.chosenPackage
)
}
composable<UserRestriction> {
UserRestrictionScreen(vm::getUserRestrictions, ::navigateUp, ::navigate)
}
composable<UserRestrictionEditor> {
UserRestrictionEditorScreen(vm.userRestrictions, vm::setUserRestriction, ::navigateUp)
}
composable<UserRestrictionOptions> {
UserRestrictionOptionsScreen(it.toRoute(), vm.userRestrictions,
vm::setUserRestriction, vm::createUserRestrictionShortcut, ::navigateUp)
}
composable<Users> { UsersScreen(vm, ::navigateUp, ::navigate) }
composable<UserInfo> { UserInfoScreen(vm::getUserInformation, ::navigateUp) }
composable<UsersOptions> {
UsersOptionsScreen(vm::getLogoutEnabled, vm::setLogoutEnabled, ::navigateUp)
}
composable<UserOperation> {
UserOperationScreen(vm::getUserIdentifiers, vm::doUserOperation,
vm::createUserOperationShortcut, ::navigateUp)
}
composable<CreateUser> { CreateUserScreen(vm::createUser, ::navigateUp) }
composable<ChangeUsername> { ChangeUsernameScreen(vm::setProfileName, ::navigateUp) }
composable<UserSessionMessage> {
UserSessionMessageScreen(vm::getUserSessionMessages, vm::setStartUserSessionMessage,
vm::setEndUserSessionMessage, ::navigateUp)
}
composable<AffiliationId> {
AffiliationIdScreen(vm.affiliationIds, vm::getAffiliationIds, vm::setAffiliationId,
::navigateUp)
}
composable<Password> { PasswordScreen(vm, ::navigateUp, ::navigate) }
composable<PasswordInfo> {
PasswordInfoScreen(vm::getPasswordComplexity, vm::isPasswordComplexitySufficient,
vm::isUsingUnifiedPassword, ::navigateUp)
}
composable<ResetPasswordToken> {
ResetPasswordTokenScreen(vm::getRpTokenState, vm::setRpToken,
vm::createActivateRpTokenIntent, vm::clearRpToken, ::navigateUp)
}
composable<ResetPassword> { ResetPasswordScreen(vm::resetPassword, ::navigateUp) }
composable<RequiredPasswordComplexity> {
RequiredPasswordComplexityScreen(vm::getRequiredPasswordComplexity,
vm::setRequiredPasswordComplexity, ::navigateUp)
}
composable<KeyguardDisabledFeatures> {
KeyguardDisabledFeaturesScreen(vm::getKeyguardDisableConfig,
vm::setKeyguardDisableConfig, ::navigateUp)
}
composable<RequiredPasswordQuality> { RequiredPasswordQualityScreen(::navigateUp) }
composable<Settings> { SettingsScreen(::navigateUp, ::navigate) }
composable<SettingsOptions> {
SettingsOptionsScreen(vm::getDisplayDangerousFeatures, vm::getShortcutsEnabled,
vm::setDisplayDangerousFeatures, vm::setShortcutsEnabled, ::navigateUp)
}
composable<Appearance> {
AppearanceScreen(::navigateUp, vm.theme, vm::changeTheme)
}
composable<AppLockSettings> {
AppLockSettingsScreen(vm.getAppLockConfig(), vm::setAppLockConfig, ::navigateUp)
}
composable<ApiSettings> {
ApiSettings(vm::getApiEnabled, vm::setApiKey, ::navigateUp)
}
composable<Notifications> {
NotificationsScreen(vm.enabledNotifications, vm::getEnabledNotifications,
vm::setNotificationEnabled, ::navigateUp)
}
composable<About> { AboutScreen(::navigateUp) }
}
DisposableEffect(lifecycleOwner) { DisposableEffect(lifecycleOwner) {
val observer = LifecycleEventObserver { _, event -> val observer = LifecycleEventObserver { _, event ->
if ( if (
(event == Lifecycle.Event.ON_CREATE && !SP.lockPasswordHash.isNullOrEmpty()) || (event == Lifecycle.Event.ON_CREATE && !SP.lockPasswordHash.isNullOrEmpty()) ||
(event == Lifecycle.Event.ON_RESUME && SP.lockWhenLeaving) (event == Lifecycle.Event.ON_RESUME && SP.lockWhenLeaving)
) { ) {
onLock() appLockDialog = true
} }
} }
lifecycleOwner.lifecycle.addObserver(observer) lifecycleOwner.lifecycle.addObserver(observer)
@@ -771,85 +112,13 @@ fun Home(vm: MyViewModel, onLock: () -> Unit) {
DhizukuErrorDialog { DhizukuErrorDialog {
dhizukuErrorStatus.value = 0 dhizukuErrorStatus.value = 0
Privilege.updateStatus() Privilege.updateStatus()
navController.navigate(WorkModes(false)) { backstack += Destination.WorkingModes(false)
popUpTo<Home> { inclusive = true } repeat(backstack.size - 1) {
launchSingleTop = true backstack.removeFirstOrNull()
} }
} }
} }
@Serializable private object Home
@OptIn(ExperimentalMaterial3Api::class)
@Composable
private fun HomeScreen(onNavigate: (Any) -> Unit) {
val privilege by Privilege.status.collectAsStateWithLifecycle()
val sb = TopAppBarDefaults.exitUntilCollapsedScrollBehavior()
Scaffold(
Modifier.nestedScroll(sb.nestedScrollConnection),
topBar = {
LargeTopAppBar(
{ Text(stringResource(R.string.app_name)) },
actions = {
IconButton({ onNavigate(WorkModes(true)) }) { Icon(painterResource(R.drawable.security_fill0), null) }
IconButton({ onNavigate(Settings) }) { Icon(Icons.Default.Settings, null) }
},
scrollBehavior = sb
)
},
contentWindowInsets = adaptiveInsets()
) {
Column(Modifier
.fillMaxSize()
.padding(it)
.verticalScroll(rememberScrollState())) {
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(privilege.work) {
HomePageItem(R.string.work_profile, R.drawable.work_fill0) {
onNavigate(WorkProfile)
}
}
if(privilege.device || privilege.profile) {
HomePageItem(R.string.applications, R.drawable.apps_fill0) {
onNavigate(
if (SP.applicationsListView) ApplicationsList(true, 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) }
}
Spacer(Modifier.height(BottomPadding))
}
}
}
@Composable
fun HomePageItem(name: Int, imgVector: Int, onClick: () -> Unit) {
Row(
modifier = Modifier
.fillMaxWidth()
.clickable(onClick = onClick)
.padding(vertical = 12.dp),
verticalAlignment = Alignment.CenterVertically
) {
Spacer(Modifier.padding(start = 30.dp))
Icon(
painter = painterResource(imgVector),
contentDescription = null
)
Spacer(Modifier.padding(start = 15.dp))
Text(
text = stringResource(name),
style = typography.headlineSmall,
modifier = Modifier.padding(bottom = if(zhCN) { 2 } else { 0 }.dp)
)
} }
} }

View File

@@ -9,8 +9,8 @@ import androidx.annotation.RequiresApi
import androidx.core.database.getIntOrNull import androidx.core.database.getIntOrNull
import androidx.core.database.getLongOrNull import androidx.core.database.getLongOrNull
import androidx.core.database.getStringOrNull import androidx.core.database.getStringOrNull
import com.bintianqi.owndroid.dpm.AppGroup import com.bintianqi.owndroid.ui.screen.AppGroup
import com.bintianqi.owndroid.dpm.IntentFilterOptions import com.bintianqi.owndroid.ui.screen.IntentFilterOptions
import com.bintianqi.owndroid.dpm.NetworkLog import com.bintianqi.owndroid.dpm.NetworkLog
import com.bintianqi.owndroid.dpm.SecurityEvent import com.bintianqi.owndroid.dpm.SecurityEvent
import com.bintianqi.owndroid.dpm.SecurityEventWithData import com.bintianqi.owndroid.dpm.SecurityEventWithData

View File

@@ -60,57 +60,58 @@ import androidx.lifecycle.viewModelScope
import com.bintianqi.owndroid.Privilege.DAR import com.bintianqi.owndroid.Privilege.DAR
import com.bintianqi.owndroid.Privilege.DPM import com.bintianqi.owndroid.Privilege.DPM
import com.bintianqi.owndroid.dpm.ACTIVATE_DEVICE_OWNER_COMMAND import com.bintianqi.owndroid.dpm.ACTIVATE_DEVICE_OWNER_COMMAND
import com.bintianqi.owndroid.dpm.ApnAuthType
import com.bintianqi.owndroid.dpm.ApnConfig
import com.bintianqi.owndroid.dpm.ApnMvnoType
import com.bintianqi.owndroid.dpm.ApnProtocol
import com.bintianqi.owndroid.dpm.AppGroup
import com.bintianqi.owndroid.dpm.AppRestriction
import com.bintianqi.owndroid.dpm.AppStatus
import com.bintianqi.owndroid.dpm.BasicAppGroup
import com.bintianqi.owndroid.dpm.CaCertInfo
import com.bintianqi.owndroid.dpm.CreateUserResult
import com.bintianqi.owndroid.dpm.CreateWorkProfileOptions
import com.bintianqi.owndroid.dpm.DelegatedAdmin import com.bintianqi.owndroid.dpm.DelegatedAdmin
import com.bintianqi.owndroid.dpm.DeviceAdmin import com.bintianqi.owndroid.dpm.DeviceAdmin
import com.bintianqi.owndroid.dpm.FrpPolicyInfo
import com.bintianqi.owndroid.dpm.HardwareProperties
import com.bintianqi.owndroid.dpm.IntentFilterOptions
import com.bintianqi.owndroid.dpm.IpMode
import com.bintianqi.owndroid.dpm.KeyguardDisableConfig
import com.bintianqi.owndroid.dpm.KeyguardDisableMode
import com.bintianqi.owndroid.dpm.NetworkStatsData
import com.bintianqi.owndroid.dpm.NetworkStatsTarget
import com.bintianqi.owndroid.dpm.PasswordComplexity
import com.bintianqi.owndroid.dpm.PendingSystemUpdateInfo
import com.bintianqi.owndroid.dpm.PreferentialNetworkServiceInfo
import com.bintianqi.owndroid.dpm.PrivateDnsConfiguration
import com.bintianqi.owndroid.dpm.PrivateDnsMode
import com.bintianqi.owndroid.dpm.ProxyMode
import com.bintianqi.owndroid.dpm.ProxyType
import com.bintianqi.owndroid.dpm.QueryNetworkStatsParams
import com.bintianqi.owndroid.dpm.RecommendedProxyConf
import com.bintianqi.owndroid.dpm.RpTokenState
import com.bintianqi.owndroid.dpm.SsidPolicy
import com.bintianqi.owndroid.dpm.SsidPolicyType
import com.bintianqi.owndroid.dpm.SystemOptionsStatus
import com.bintianqi.owndroid.dpm.SystemUpdatePolicyInfo
import com.bintianqi.owndroid.dpm.UserIdentifier
import com.bintianqi.owndroid.dpm.UserInformation
import com.bintianqi.owndroid.dpm.UserOperationType
import com.bintianqi.owndroid.dpm.WifiInfo
import com.bintianqi.owndroid.dpm.WifiSecurity
import com.bintianqi.owndroid.dpm.WifiStatus
import com.bintianqi.owndroid.dpm.activateOrgProfileCommand
import com.bintianqi.owndroid.dpm.delegatedScopesList
import com.bintianqi.owndroid.dpm.doUserOperationWithContext import com.bintianqi.owndroid.dpm.doUserOperationWithContext
import com.bintianqi.owndroid.dpm.getPackageInstaller import com.bintianqi.owndroid.dpm.getPackageInstaller
import com.bintianqi.owndroid.dpm.globalSettings
import com.bintianqi.owndroid.dpm.handlePrivilegeChange import com.bintianqi.owndroid.dpm.handlePrivilegeChange
import com.bintianqi.owndroid.dpm.parsePackageInstallerMessage import com.bintianqi.owndroid.dpm.parsePackageInstallerMessage
import com.bintianqi.owndroid.dpm.runtimePermissions import com.bintianqi.owndroid.dpm.runtimePermissions
import com.bintianqi.owndroid.dpm.secureSettings import com.bintianqi.owndroid.ui.screen.ApnAuthType
import com.bintianqi.owndroid.dpm.temperatureTypes import com.bintianqi.owndroid.ui.screen.ApnConfig
import com.bintianqi.owndroid.ui.screen.ApnMvnoType
import com.bintianqi.owndroid.ui.screen.ApnProtocol
import com.bintianqi.owndroid.ui.screen.AppGroup
import com.bintianqi.owndroid.ui.screen.AppLockConfig
import com.bintianqi.owndroid.ui.screen.AppRestriction
import com.bintianqi.owndroid.ui.screen.AppStatus
import com.bintianqi.owndroid.ui.screen.BasicAppGroup
import com.bintianqi.owndroid.ui.screen.CaCertInfo
import com.bintianqi.owndroid.ui.screen.CreateUserResult
import com.bintianqi.owndroid.ui.screen.CreateWorkProfileOptions
import com.bintianqi.owndroid.ui.screen.FrpPolicyInfo
import com.bintianqi.owndroid.ui.screen.HardwareProperties
import com.bintianqi.owndroid.ui.screen.IntentFilterOptions
import com.bintianqi.owndroid.ui.screen.IpMode
import com.bintianqi.owndroid.ui.screen.KeyguardDisableConfig
import com.bintianqi.owndroid.ui.screen.KeyguardDisableMode
import com.bintianqi.owndroid.ui.screen.NetworkStatsData
import com.bintianqi.owndroid.ui.screen.NetworkStatsTarget
import com.bintianqi.owndroid.ui.screen.PasswordComplexity
import com.bintianqi.owndroid.ui.screen.PendingSystemUpdateInfo
import com.bintianqi.owndroid.ui.screen.PreferentialNetworkServiceInfo
import com.bintianqi.owndroid.ui.screen.PrivateDnsConfiguration
import com.bintianqi.owndroid.ui.screen.PrivateDnsMode
import com.bintianqi.owndroid.ui.screen.ProxyMode
import com.bintianqi.owndroid.ui.screen.ProxyType
import com.bintianqi.owndroid.ui.screen.QueryNetworkStatsParams
import com.bintianqi.owndroid.ui.screen.RecommendedProxyConf
import com.bintianqi.owndroid.ui.screen.RpTokenState
import com.bintianqi.owndroid.ui.screen.SsidPolicy
import com.bintianqi.owndroid.ui.screen.SsidPolicyType
import com.bintianqi.owndroid.ui.screen.SystemOptionsStatus
import com.bintianqi.owndroid.ui.screen.SystemUpdatePolicyInfo
import com.bintianqi.owndroid.ui.screen.UserIdentifier
import com.bintianqi.owndroid.ui.screen.UserInformation
import com.bintianqi.owndroid.ui.screen.UserOperationType
import com.bintianqi.owndroid.ui.screen.WifiInfo
import com.bintianqi.owndroid.ui.screen.WifiSecurity
import com.bintianqi.owndroid.ui.screen.WifiStatus
import com.bintianqi.owndroid.ui.screen.activateOrgProfileCommand
import com.bintianqi.owndroid.ui.screen.delegatedScopesList
import com.bintianqi.owndroid.ui.screen.globalSettings
import com.bintianqi.owndroid.ui.screen.secureSettings
import com.bintianqi.owndroid.ui.screen.temperatureTypes
import com.rosan.dhizuku.api.Dhizuku import com.rosan.dhizuku.api.Dhizuku
import com.rosan.dhizuku.api.DhizukuRequestPermissionListener import com.rosan.dhizuku.api.DhizukuRequestPermissionListener
import com.topjohnwu.superuser.Shell import com.topjohnwu.superuser.Shell
@@ -159,7 +160,9 @@ class MyViewModel(application: Application): AndroidViewModel(application) {
} }
fun getAppLockConfig(): AppLockConfig { fun getAppLockConfig(): AppLockConfig {
val passwordHash = SP.lockPasswordHash val passwordHash = SP.lockPasswordHash
return AppLockConfig(passwordHash?.ifEmpty { null }, SP.biometricsUnlock, SP.lockWhenLeaving) return AppLockConfig(
passwordHash?.ifEmpty { null }, SP.biometricsUnlock, SP.lockWhenLeaving
)
} }
fun setAppLockConfig(config: AppLockConfig) { fun setAppLockConfig(config: AppLockConfig) {
if (config.password == null) { if (config.password == null) {

View File

@@ -63,9 +63,9 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.input.ImeAction import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.bintianqi.owndroid.ui.navigation.Destination
import com.google.accompanist.drawablepainter.rememberDrawablePainter import com.google.accompanist.drawablepainter.rememberDrawablePainter
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.serialization.Serializable
data class AppInfo( data class AppInfo(
val name: String, val name: String,
@@ -77,12 +77,10 @@ data class AppInfo(
private fun searchInString(query: String, content: String) private fun searchInString(query: String, content: String)
= query.split(' ').all { content.contains(it, true) } = query.split(' ').all { content.contains(it, true) }
@Serializable data class ApplicationsList(val canSwitchView: Boolean, val multiSelect: Boolean)
@OptIn(ExperimentalMaterial3Api::class, ExperimentalFoundationApi::class) @OptIn(ExperimentalMaterial3Api::class, ExperimentalFoundationApi::class)
@Composable @Composable
fun AppChooserScreen( fun AppChooserScreen(
params: ApplicationsList, packageList: MutableStateFlow<List<AppInfo>>, params: Destination.ApplicationsList, packageList: MutableStateFlow<List<AppInfo>>,
refreshProgress: MutableStateFlow<Float>, onChoosePackage: (String?) -> Unit, refreshProgress: MutableStateFlow<Float>, onChoosePackage: (String?) -> Unit,
onSwitchView: () -> Unit, onRefresh: () -> Unit, onSwitchView: () -> Unit, onRefresh: () -> Unit,
setPackagesSuspend: (List<String>, Boolean) -> Unit, setPackagesSuspend: (List<String>, Boolean) -> Unit,

View File

@@ -5,7 +5,7 @@ import android.content.Intent
import androidx.core.content.pm.ShortcutInfoCompat import androidx.core.content.pm.ShortcutInfoCompat
import androidx.core.content.pm.ShortcutManagerCompat import androidx.core.content.pm.ShortcutManagerCompat
import androidx.core.graphics.drawable.IconCompat import androidx.core.graphics.drawable.IconCompat
import com.bintianqi.owndroid.dpm.UserOperationType import com.bintianqi.owndroid.ui.screen.UserOperationType
object ShortcutUtils { object ShortcutUtils {
fun setAllShortcuts(context: Context, enabled: Boolean) { fun setAllShortcuts(context: Context, enabled: Boolean) {

View File

@@ -3,7 +3,7 @@ package com.bintianqi.owndroid
import android.app.Activity import android.app.Activity
import android.os.Bundle import android.os.Bundle
import android.util.Log import android.util.Log
import com.bintianqi.owndroid.dpm.UserOperationType import com.bintianqi.owndroid.ui.screen.UserOperationType
import com.bintianqi.owndroid.dpm.doUserOperationWithContext import com.bintianqi.owndroid.dpm.doUserOperationWithContext
class ShortcutsReceiverActivity : Activity() { class ShortcutsReceiverActivity : Activity() {

View File

@@ -2,7 +2,7 @@ package com.bintianqi.owndroid
import android.os.Build import android.os.Build
import android.os.UserManager import android.os.UserManager
import com.bintianqi.owndroid.dpm.Restriction import com.bintianqi.owndroid.ui.screen.Restriction
@Suppress("InlinedApi") @Suppress("InlinedApi")
object UserRestrictionsRepository { object UserRestrictionsRepository {

View File

@@ -7,6 +7,7 @@ import android.app.admin.DevicePolicyManager
import android.app.admin.DnsEvent import android.app.admin.DnsEvent
import android.app.admin.IDevicePolicyManager import android.app.admin.IDevicePolicyManager
import android.app.admin.SecurityLog import android.app.admin.SecurityLog
import android.content.ComponentName
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.content.pm.IPackageInstaller import android.content.pm.IPackageInstaller
@@ -16,6 +17,7 @@ import android.os.UserHandle
import android.os.UserManager import android.os.UserManager
import android.util.Log import android.util.Log
import androidx.annotation.RequiresApi import androidx.annotation.RequiresApi
import com.bintianqi.owndroid.AppInfo
import com.bintianqi.owndroid.MyApplication import com.bintianqi.owndroid.MyApplication
import com.bintianqi.owndroid.NotificationType import com.bintianqi.owndroid.NotificationType
import com.bintianqi.owndroid.NotificationUtils import com.bintianqi.owndroid.NotificationUtils
@@ -25,6 +27,7 @@ import com.bintianqi.owndroid.Privilege.DPM
import com.bintianqi.owndroid.R import com.bintianqi.owndroid.R
import com.bintianqi.owndroid.SP import com.bintianqi.owndroid.SP
import com.bintianqi.owndroid.ShortcutUtils import com.bintianqi.owndroid.ShortcutUtils
import com.bintianqi.owndroid.ui.screen.UserOperationType
import com.rosan.dhizuku.api.Dhizuku import com.rosan.dhizuku.api.Dhizuku
import com.rosan.dhizuku.api.DhizukuBinderWrapper import com.rosan.dhizuku.api.DhizukuBinderWrapper
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
@@ -589,3 +592,9 @@ fun doUserOperationWithContext(
UserOperationType.Delete -> DPM.removeUser(DAR, handle) UserOperationType.Delete -> DPM.removeUser(DAR, handle)
} }
} }
const val ACTIVATE_DEVICE_OWNER_COMMAND = "dpm set-device-owner com.bintianqi.owndroid/.Receiver"
data class DelegatedAdmin(val app: AppInfo, val scopes: List<String>)
data class DeviceAdmin(val app: AppInfo, val admin: ComponentName)

View File

@@ -17,9 +17,12 @@ import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.LazyListScope import androidx.compose.foundation.lazy.LazyListScope
import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.foundation.verticalScroll import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.ArrowBack import androidx.compose.material.icons.automirrored.filled.ArrowBack
import androidx.compose.material.icons.automirrored.filled.List
import androidx.compose.material.icons.outlined.Info import androidx.compose.material.icons.outlined.Info
import androidx.compose.material3.AlertDialog import androidx.compose.material3.AlertDialog
import androidx.compose.material3.Card import androidx.compose.material3.Card
@@ -31,6 +34,7 @@ import androidx.compose.material3.IconButton
import androidx.compose.material3.LargeTopAppBar import androidx.compose.material3.LargeTopAppBar
import androidx.compose.material3.MaterialTheme.colorScheme import androidx.compose.material3.MaterialTheme.colorScheme
import androidx.compose.material3.MaterialTheme.typography import androidx.compose.material3.MaterialTheme.typography
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.RadioButton import androidx.compose.material3.RadioButton
import androidx.compose.material3.Scaffold import androidx.compose.material3.Scaffold
import androidx.compose.material3.Switch import androidx.compose.material3.Switch
@@ -48,14 +52,18 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.alpha import androidx.compose.ui.draw.alpha
import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.clip
import androidx.compose.ui.input.nestedscroll.nestedScroll import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource 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.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.Dialog import androidx.compose.ui.window.Dialog
import com.bintianqi.owndroid.HorizontalPadding import com.bintianqi.owndroid.HorizontalPadding
import com.bintianqi.owndroid.R import com.bintianqi.owndroid.R
import com.bintianqi.owndroid.adaptiveInsets import com.bintianqi.owndroid.adaptiveInsets
import com.bintianqi.owndroid.ui.screen.isValidPackageName
import com.bintianqi.owndroid.zhCN import com.bintianqi.owndroid.zhCN
@Composable @Composable
@@ -398,3 +406,25 @@ fun CircularProgressDialog(onDismiss: () -> Unit) {
} }
} }
} }
@Composable
fun PackageNameTextField(
value: String, onChoosePackage: () -> Unit,
modifier: Modifier = Modifier, onValueChange: (String) -> Unit
) {
val fm = LocalFocusManager.current
OutlinedTextField(
value, onValueChange, Modifier
.fillMaxWidth()
.then(modifier),
label = { Text(stringResource(R.string.package_name)) },
trailingIcon = {
IconButton(onChoosePackage) {
Icon(Icons.AutoMirrored.Default.List, null)
}
},
isError = value.isNotEmpty() && !value.isValidPackageName,
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Ascii, imeAction = ImeAction.Done),
keyboardActions = KeyboardActions { fm.clearFocus() }
)
}

View File

@@ -10,6 +10,7 @@ import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut import androidx.compose.animation.fadeOut
import androidx.compose.animation.slideInHorizontally import androidx.compose.animation.slideInHorizontally
import androidx.compose.animation.slideOutHorizontally import androidx.compose.animation.slideOutHorizontally
import androidx.compose.animation.togetherWith
/** /**
* Learned from AOSP's Activity animation * Learned from AOSP's Activity animation
@@ -42,4 +43,7 @@ object NavTransition {
) + fadeOut( ) + fadeOut(
tween(83, 35, LinearEasing) tween(83, 35, LinearEasing)
) )
val transition = enterTransition togetherWith exitTransition
val popTransition = popEnterTransition togetherWith popExitTransition
} }

View File

@@ -0,0 +1,127 @@
package com.bintianqi.owndroid.ui.navigation
import androidx.navigation3.runtime.NavKey
import kotlinx.serialization.Serializable
sealed class Destination : NavKey {
@Serializable object Home : Destination()
@Serializable class WorkingModes(val canNavigateUp: Boolean) : Destination()
@Serializable object DhizukuServerSettings : Destination()
@Serializable object DelegatedAdmins : Destination()
@Serializable class DelegatedAdminDetails(
val pkg: String, val scopes: List<String>
) : Destination()
@Serializable object TransferOwnership : Destination()
@Serializable object System : Destination()
@Serializable object SystemOptions : Destination()
@Serializable object Keyguard : Destination()
@Serializable object HardwareMonitor : Destination()
@Serializable object DefaultInputMethod : Destination()
@Serializable object ChangeTime : Destination()
@Serializable object ChangeTimezone : Destination()
@Serializable object AutoTimePolicy : Destination()
@Serializable object AutoTimezonePolicy : Destination()
@Serializable object ContentProtectionPolicy : Destination()
@Serializable object PermissionPolicy : Destination()
@Serializable object MtePolicy : Destination()
@Serializable object NearbyStreamingPolicy : Destination()
@Serializable object LockTaskMode : Destination()
@Serializable object CaCert : Destination()
@Serializable object SecurityLogging : Destination()
@Serializable object DeviceInfo : Destination()
@Serializable object LockScreenInfo : Destination()
@Serializable object SupportMessage : Destination()
@Serializable object DisableAccountManagement : Destination()
@Serializable object FrpPolicy : Destination()
@Serializable object WipeData : Destination()
@Serializable object SystemUpdatePolicy : Destination()
@Serializable object InstallSystemUpdate : Destination()
@Serializable object Network : Destination()
@Serializable object NetworkOptions : Destination()
@Serializable object WiFi : Destination()
@Serializable class UpdateNetwork(val index: Int) : Destination()
@Serializable object WifiSecurityLevel : Destination()
@Serializable object WifiSsidPolicy : Destination()
@Serializable object NetworkStats : Destination()
@Serializable object NetworkStatsViewer : Destination()
@Serializable object PrivateDns : Destination()
@Serializable object AlwaysOnVpnPackage : Destination()
@Serializable object RecommendedGlobalProxy : Destination()
@Serializable object NetworkLogging : Destination()
@Serializable object PreferentialNetworkService : Destination()
@Serializable class AddPreferentialNetworkServiceConfig(val index: Int) : Destination()
@Serializable object OverrideApn : Destination()
@Serializable data class AddApnSetting(val index: Int) : Destination()
@Serializable object WorkProfile : Destination()
@Serializable object CreateWorkProfile : Destination()
@Serializable object OrganizationOwnedProfile : Destination()
@Serializable object SuspendPersonalApp : Destination()
@Serializable object CrossProfileIntentFilter : Destination()
@Serializable object DeleteWorkProfile : Destination()
@Serializable object ApplicationFunctions : Destination()
@Serializable object Suspend : Destination()
@Serializable object Hide : Destination()
@Serializable object BlockUninstall : Destination()
@Serializable object DisableUserControl : Destination()
@Serializable object PermissionManager : Destination()
@Serializable class PermissionDetail(val permission: String) : Destination()
@Serializable object DisableMeteredData : Destination()
@Serializable object ClearAppStorage : Destination()
@Serializable object UninstallApp : Destination()
@Serializable object KeepUninstalledPackages : Destination()
@Serializable object InstallExistingApp : Destination()
@Serializable object CrossProfilePackages : Destination()
@Serializable object CrossProfileWidgetProviders : Destination()
@Serializable object CredentialManagerPolicy : Destination()
@Serializable object PermittedAccessibilityServices : Destination()
@Serializable object PermittedInputMethods : Destination()
@Serializable object EnableSystemApp : Destination()
@Serializable object SetDefaultDialer : Destination()
@Serializable object ManageAppGroups : Destination()
@Serializable class EditAppGroup(
val id: Int?, val name: String, val apps: List<String>
) : Destination()
@Serializable class ApplicationDetails(val packageName: String) : Destination()
@Serializable class AppPermissionsManager(val packageName: String) : Destination()
@Serializable class ManagedConfiguration(val packageName: String) : Destination()
@Serializable data class ApplicationsList(
val canSwitchView: Boolean, val multiSelect: Boolean
) : Destination()
@Serializable object UserRestriction : Destination()
@Serializable data class UserRestrictionOptions(val id: String) : Destination()
@Serializable object UserRestrictionEditor : Destination()
@Serializable object Users : Destination()
@Serializable object UsersOptions : Destination()
@Serializable object UserInfo : Destination()
@Serializable object UserOperation : Destination()
@Serializable object CreateUser : Destination()
@Serializable object AffiliationId : Destination()
@Serializable object ChangeUsername : Destination()
@Serializable object UserSessionMessage : Destination()
@Serializable object Password : Destination()
@Serializable object PasswordInfo : Destination()
@Serializable object ResetPasswordToken : Destination()
@Serializable object ResetPassword : Destination()
@Serializable object RequiredPasswordComplexity : Destination()
@Serializable object KeyguardDisabledFeatures : Destination()
@Serializable object RequiredPasswordQuality : Destination()
@Serializable object Settings : Destination()
@Serializable object SettingsOptions : Destination()
@Serializable object AppearanceSettings : Destination()
@Serializable object AppLockSettings : Destination()
@Serializable object ApiSettings : Destination()
@Serializable object NotificationSettings : Destination()
@Serializable object About : Destination()
}

View File

@@ -0,0 +1,557 @@
package com.bintianqi.owndroid.ui.navigation
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.navigation3.runtime.NavBackStack
import androidx.navigation3.runtime.NavEntry
import androidx.navigation3.runtime.NavKey
import androidx.navigation3.runtime.entryProvider
import com.bintianqi.owndroid.AppChooserScreen
import com.bintianqi.owndroid.MyViewModel
import com.bintianqi.owndroid.R
import com.bintianqi.owndroid.SP
import com.bintianqi.owndroid.ui.screen.AboutScreen
import com.bintianqi.owndroid.ui.screen.AddApnSettingScreen
import com.bintianqi.owndroid.ui.screen.AddDelegatedAdminScreen
import com.bintianqi.owndroid.ui.screen.AddPreferentialNetworkServiceConfigScreen
import com.bintianqi.owndroid.ui.screen.AffiliationIdScreen
import com.bintianqi.owndroid.ui.screen.AlwaysOnVpnPackageScreen
import com.bintianqi.owndroid.ui.screen.ApiSettings
import com.bintianqi.owndroid.ui.screen.AppLockSettingsScreen
import com.bintianqi.owndroid.ui.screen.AppPermissionsManagerScreen
import com.bintianqi.owndroid.ui.screen.AppearanceScreen
import com.bintianqi.owndroid.ui.screen.ApplicationDetailsScreen
import com.bintianqi.owndroid.ui.screen.ApplicationsFeaturesScreen
import com.bintianqi.owndroid.ui.screen.AutoTimePolicyScreen
import com.bintianqi.owndroid.ui.screen.AutoTimeZonePolicyScreen
import com.bintianqi.owndroid.ui.screen.CaCertScreen
import com.bintianqi.owndroid.ui.screen.ChangeTimeScreen
import com.bintianqi.owndroid.ui.screen.ChangeTimeZoneScreen
import com.bintianqi.owndroid.ui.screen.ChangeUsernameScreen
import com.bintianqi.owndroid.ui.screen.ClearAppStorageScreen
import com.bintianqi.owndroid.ui.screen.ContentProtectionPolicyScreen
import com.bintianqi.owndroid.ui.screen.CreateUserScreen
import com.bintianqi.owndroid.ui.screen.CreateWorkProfileScreen
import com.bintianqi.owndroid.ui.screen.CredentialManagerPolicyScreen
import com.bintianqi.owndroid.ui.screen.CrossProfileIntentFilterScreen
import com.bintianqi.owndroid.ui.screen.DefaultInputMethodScreen
import com.bintianqi.owndroid.ui.screen.DelegatedAdminsScreen
import com.bintianqi.owndroid.ui.screen.DeleteWorkProfileScreen
import com.bintianqi.owndroid.ui.screen.DeviceInfoScreen
import com.bintianqi.owndroid.ui.screen.DhizukuServerSettingsScreen
import com.bintianqi.owndroid.ui.screen.DisableAccountManagementScreen
import com.bintianqi.owndroid.ui.screen.EditAppGroupScreen
import com.bintianqi.owndroid.ui.screen.EnableSystemAppScreen
import com.bintianqi.owndroid.ui.screen.FrpPolicyScreen
import com.bintianqi.owndroid.ui.screen.HardwareMonitorScreen
import com.bintianqi.owndroid.ui.screen.HomeScreen
import com.bintianqi.owndroid.ui.screen.InstallExistingAppScreen
import com.bintianqi.owndroid.ui.screen.InstallSystemUpdateScreen
import com.bintianqi.owndroid.ui.screen.KeyguardDisabledFeaturesScreen
import com.bintianqi.owndroid.ui.screen.KeyguardScreen
import com.bintianqi.owndroid.ui.screen.LockScreenInfoScreen
import com.bintianqi.owndroid.ui.screen.LockTaskModeScreen
import com.bintianqi.owndroid.ui.screen.ManageAppGroupsScreen
import com.bintianqi.owndroid.ui.screen.ManagedConfigurationScreen
import com.bintianqi.owndroid.ui.screen.MtePolicyScreen
import com.bintianqi.owndroid.ui.screen.NearbyStreamingPolicyScreen
import com.bintianqi.owndroid.ui.screen.NetworkLoggingScreen
import com.bintianqi.owndroid.ui.screen.NetworkOptionsScreen
import com.bintianqi.owndroid.ui.screen.NetworkScreen
import com.bintianqi.owndroid.ui.screen.NetworkStatsScreen
import com.bintianqi.owndroid.ui.screen.NetworkStatsViewerScreen
import com.bintianqi.owndroid.ui.screen.NotificationsScreen
import com.bintianqi.owndroid.ui.screen.OrganizationOwnedProfileScreen
import com.bintianqi.owndroid.ui.screen.OverrideApnScreen
import com.bintianqi.owndroid.ui.screen.PackageFunctionScreen
import com.bintianqi.owndroid.ui.screen.PasswordInfoScreen
import com.bintianqi.owndroid.ui.screen.PasswordScreen
import com.bintianqi.owndroid.ui.screen.PermissionDetailScreen
import com.bintianqi.owndroid.ui.screen.PermissionManagerScreen
import com.bintianqi.owndroid.ui.screen.PermissionPolicyScreen
import com.bintianqi.owndroid.ui.screen.PermittedAsAndImPackages
import com.bintianqi.owndroid.ui.screen.PreferentialNetworkServiceInfo
import com.bintianqi.owndroid.ui.screen.PreferentialNetworkServiceScreen
import com.bintianqi.owndroid.ui.screen.PrivateDnsScreen
import com.bintianqi.owndroid.ui.screen.RecommendedGlobalProxyScreen
import com.bintianqi.owndroid.ui.screen.RequiredPasswordComplexityScreen
import com.bintianqi.owndroid.ui.screen.RequiredPasswordQualityScreen
import com.bintianqi.owndroid.ui.screen.ResetPasswordScreen
import com.bintianqi.owndroid.ui.screen.ResetPasswordTokenScreen
import com.bintianqi.owndroid.ui.screen.SecurityLoggingScreen
import com.bintianqi.owndroid.ui.screen.SetDefaultDialerScreen
import com.bintianqi.owndroid.ui.screen.SettingsOptionsScreen
import com.bintianqi.owndroid.ui.screen.SettingsScreen
import com.bintianqi.owndroid.ui.screen.SupportMessageScreen
import com.bintianqi.owndroid.ui.screen.SuspendPersonalAppScreen
import com.bintianqi.owndroid.ui.screen.SystemManagerScreen
import com.bintianqi.owndroid.ui.screen.SystemOptionsScreen
import com.bintianqi.owndroid.ui.screen.SystemUpdatePolicyScreen
import com.bintianqi.owndroid.ui.screen.TransferOwnershipScreen
import com.bintianqi.owndroid.ui.screen.UninstallAppScreen
import com.bintianqi.owndroid.ui.screen.UpdateNetworkScreen
import com.bintianqi.owndroid.ui.screen.UserInfoScreen
import com.bintianqi.owndroid.ui.screen.UserOperationScreen
import com.bintianqi.owndroid.ui.screen.UserRestrictionEditorScreen
import com.bintianqi.owndroid.ui.screen.UserRestrictionOptionsScreen
import com.bintianqi.owndroid.ui.screen.UserRestrictionScreen
import com.bintianqi.owndroid.ui.screen.UserSessionMessageScreen
import com.bintianqi.owndroid.ui.screen.UsersOptionsScreen
import com.bintianqi.owndroid.ui.screen.UsersScreen
import com.bintianqi.owndroid.ui.screen.WifiScreen
import com.bintianqi.owndroid.ui.screen.WifiSecurityLevelScreen
import com.bintianqi.owndroid.ui.screen.WifiSsidPolicyScreen
import com.bintianqi.owndroid.ui.screen.WipeDataScreen
import com.bintianqi.owndroid.ui.screen.WorkModesScreen
import com.bintianqi.owndroid.ui.screen.WorkProfileScreen
fun myEntryProvider(
destination: Destination, backstack: NavBackStack<NavKey>, vm: MyViewModel
) = entryProvider {
fun navigate(dest: Destination) {
backstack += dest
}
fun navigateUp() {
backstack.removeLastOrNull()
}
fun navigateToAppGroups() {
navigate(Destination.ManageAppGroups)
}
fun navigateAndPopAll(dest: Destination) {
navigate(dest)
repeat(backstack.size - 1) {
backstack.removeFirst()
}
}
fun choosePackage() {
navigate(Destination.ApplicationsList(false, true))
}
fun chooseSinglePackage() {
navigate(Destination.ApplicationsList(false, false))
}
entry<Destination.Home> {
HomeScreen(::navigate)
}
entry<Destination.WorkingModes> {
WorkModesScreen(vm, it, ::navigateUp, {
navigateAndPopAll(Destination.Home)
}, {
navigateAndPopAll(Destination.WorkingModes(false))
}, ::navigate)
}
entry<Destination.DhizukuServerSettings> {
DhizukuServerSettingsScreen(vm.dhizukuClients, vm::getDhizukuClients,
vm::updateDhizukuClient, vm::getDhizukuServerEnabled, vm::setDhizukuServerEnabled,
::navigateUp)
}
entry<Destination.DelegatedAdmins> {
DelegatedAdminsScreen(vm.delegatedAdmins, vm::getDelegatedAdmins, ::navigateUp, ::navigate)
}
entry<Destination.DelegatedAdminDetails>{
AddDelegatedAdminScreen(vm.chosenPackage, ::chooseSinglePackage, it,
vm::setDelegatedAdmin, ::navigateUp)
}
entry<Destination.DeviceInfo> { DeviceInfoScreen(vm, ::navigateUp) }
entry<Destination.LockScreenInfo> {
LockScreenInfoScreen(vm::getLockScreenInfo, vm::setLockScreenInfo, ::navigateUp)
}
entry<Destination.SupportMessage> {
SupportMessageScreen(vm::getShortSupportMessage, vm::getLongSupportMessage,
vm::setShortSupportMessage, vm::setLongSupportMessage, ::navigateUp)
}
entry<Destination.TransferOwnership> {
TransferOwnershipScreen(vm.deviceAdminReceivers, vm::getDeviceAdminReceivers,
vm::transferOwnership, ::navigateUp
) {
navigate(Destination.WorkingModes(false))
}
}
entry<Destination.System> { SystemManagerScreen(vm, ::navigateUp, ::navigate) }
entry<Destination.SystemOptions> { SystemOptionsScreen(vm, ::navigateUp) }
entry<Destination.Keyguard> {
KeyguardScreen(vm::setKeyguardDisabled, vm::lockScreen, ::navigateUp)
}
entry<Destination.HardwareMonitor> {
HardwareMonitorScreen(vm.hardwareProperties, vm::getHardwareProperties,
vm::setHpRefreshInterval, ::navigateUp)
}
entry<Destination.DefaultInputMethod> {
DefaultInputMethodScreen(vm::getCurrentInputMethod, vm.inputMethodList,
vm::getInputMethods, vm::setDefaultInputMethod, ::navigateUp)
}
entry<Destination.ChangeTime> { ChangeTimeScreen(vm::setTime, ::navigateUp) }
entry<Destination.ChangeTimezone> { ChangeTimeZoneScreen(vm::setTimeZone, ::navigateUp) }
entry<Destination.AutoTimePolicy> {
AutoTimePolicyScreen(vm::getAutoTimePolicy, vm::setAutoTimePolicy, ::navigateUp)
}
entry<Destination.AutoTimezonePolicy> {
AutoTimeZonePolicyScreen(vm::getAutoTimeZonePolicy, vm::setAutoTimeZonePolicy,
::navigateUp)
}
//entry<Destination.> { KeyPairs(::navigateUp) }
entry<Destination.ContentProtectionPolicy> {
ContentProtectionPolicyScreen(vm::getContentProtectionPolicy,
vm::setContentProtectionPolicy, ::navigateUp)
}
entry<Destination.PermissionPolicy> {
PermissionPolicyScreen(vm::getPermissionPolicy, vm::setPermissionPolicy, ::navigateUp)
}
entry<Destination.MtePolicy> {
MtePolicyScreen(vm::getMtePolicy, vm::setMtePolicy, ::navigateUp)
}
entry<Destination.NearbyStreamingPolicy> {
NearbyStreamingPolicyScreen(vm::getNsAppPolicy, vm::setNsAppPolicy,
vm::getNsNotificationPolicy, vm::setNsNotificationPolicy, ::navigateUp)
}
entry<Destination.LockTaskMode> {
LockTaskModeScreen(
vm.chosenPackage, ::chooseSinglePackage, ::choosePackage, vm.lockTaskPackages,
vm::getLockTaskPackages, vm::setLockTaskPackage, vm::startLockTaskMode,
vm:: getLockTaskFeatures, vm::setLockTaskFeatures, ::navigateUp
)
}
entry<Destination.CaCert> {
CaCertScreen(vm.installedCaCerts, vm::getCaCerts, vm.selectedCaCert, vm::selectCaCert, vm::installCaCert, vm::parseCaCert,
vm::exportCaCert, vm::uninstallCaCert, vm::uninstallAllCaCerts, ::navigateUp)
}
entry<Destination.SecurityLogging> {
SecurityLoggingScreen(vm::getSecurityLoggingEnabled, vm::setSecurityLoggingEnabled,
vm::exportSecurityLogs, vm::getSecurityLogsCount, vm::deleteSecurityLogs,
vm::getPreRebootSecurityLogs, vm::exportPreRebootSecurityLogs, ::navigateUp)
}
entry<Destination.DisableAccountManagement> {
DisableAccountManagementScreen(vm.mdAccountTypes, vm::getMdAccountTypes,
vm::setMdAccountType, ::navigateUp)
}
entry<Destination.SystemUpdatePolicy> {
SystemUpdatePolicyScreen(vm::getSystemUpdatePolicy, vm::setSystemUpdatePolicy,
vm::getPendingSystemUpdate, ::navigateUp)
}
entry<Destination.InstallSystemUpdate> {
InstallSystemUpdateScreen(vm::installSystemUpdate, ::navigateUp)
}
entry<Destination.FrpPolicy> {
FrpPolicyScreen(vm.getFrpPolicy(), vm::setFrpPolicy, ::navigateUp)
}
entry<Destination.WipeData> { WipeDataScreen(vm::wipeData, ::navigateUp) }
entry<Destination.Network> { NetworkScreen(::navigateUp, ::navigate) }
entry<Destination.WiFi> {
WifiScreen(vm, ::navigateUp, ::navigate) { navigate(Destination.UpdateNetwork(it)) }
}
entry<Destination.NetworkOptions> {
NetworkOptionsScreen(vm::getLanEnabled, vm::setLanEnabled, ::navigateUp)
}
entry<Destination.UpdateNetwork> {
val info = vm.configuredNetworks.collectAsStateWithLifecycle().value[
it.index
]
UpdateNetworkScreen(info, vm::setWifi, ::navigateUp)
}
entry<Destination.WifiSecurityLevel> {
WifiSecurityLevelScreen(vm::getMinimumWifiSecurityLevel,
vm::setMinimumWifiSecurityLevel, ::navigateUp)
}
entry<Destination.WifiSsidPolicy> {
WifiSsidPolicyScreen(vm::getSsidPolicy, vm::setSsidPolicy, ::navigateUp)
}
entry<Destination.NetworkStats> {
NetworkStatsScreen(vm.chosenPackage, ::chooseSinglePackage, vm::getPackageUid,
vm::queryNetworkStats, ::navigateUp) { navigate(Destination.NetworkStatsViewer) }
}
entry<Destination.NetworkStatsViewer> {
NetworkStatsViewerScreen(vm.networkStatsData, vm::clearNetworkStats, ::navigateUp)
}
entry<Destination.PrivateDns> {
PrivateDnsScreen(vm::getPrivateDns, vm::setPrivateDns, ::navigateUp)
}
entry<Destination.AlwaysOnVpnPackage> {
AlwaysOnVpnPackageScreen(vm::getAlwaysOnVpnPackage, vm::getAlwaysOnVpnLockdown,
vm::setAlwaysOnVpn, vm.chosenPackage, ::chooseSinglePackage, ::navigateUp)
}
entry<Destination.RecommendedGlobalProxy> {
RecommendedGlobalProxyScreen(vm::setRecommendedGlobalProxy, ::navigateUp)
}
entry<Destination.NetworkLogging> {
NetworkLoggingScreen(vm::getNetworkLoggingEnabled, vm::setNetworkLoggingEnabled,
vm::getNetworkLogsCount, vm::exportNetworkLogs, vm::deleteNetworkLogs, ::navigateUp)
}
//entry<Destination.WifiAuthKeypair> { WifiAuthKeypairScreen(::navigateUp) }
entry<Destination.PreferentialNetworkService> {
PreferentialNetworkServiceScreen(vm::getPnsEnabled, vm::setPnsEnabled, vm.pnsConfigs,
vm::getPnsConfigs, ::navigateUp, ::navigate)
}
entry<Destination.AddPreferentialNetworkServiceConfig> {
val info = vm.pnsConfigs.collectAsStateWithLifecycle().value.getOrNull(
it.index
) ?: PreferentialNetworkServiceInfo()
AddPreferentialNetworkServiceConfigScreen(info, vm::setPnsConfig, ::navigateUp)
}
entry<Destination.OverrideApn> {
OverrideApnScreen(vm.apnConfigs, vm::getApnConfigs, vm::getApnEnabled,
vm::setApnEnabled, ::navigateUp) { navigate(Destination.AddApnSetting(it)) }
}
entry<Destination.AddApnSetting> {
val origin = vm.apnConfigs.collectAsStateWithLifecycle().value.getOrNull(it.index)
AddApnSettingScreen(vm::setApnConfig, vm::removeApnConfig, origin, ::navigateUp)
}
entry<Destination.WorkProfile> { WorkProfileScreen(::navigateUp, ::navigate) }
entry<Destination.OrganizationOwnedProfile> {
OrganizationOwnedProfileScreen(vm::activateOrgProfileByShizuku, ::navigateUp)
}
entry<Destination.CreateWorkProfile> {
CreateWorkProfileScreen(vm::createWorkProfile, ::navigateUp)
}
entry<Destination.SuspendPersonalApp> {
SuspendPersonalAppScreen(
vm::getPersonalAppsSuspendedReason, vm::setPersonalAppsSuspended,
vm::getProfileMaxTimeOff, vm::setProfileMaxTimeOff, ::navigateUp
)
}
entry<Destination.CrossProfileIntentFilter> {
CrossProfileIntentFilterScreen(
vm::addCrossProfileIntentFilter, vm::clearCrossProfileIntentFilters,
vm::importCrossProfileIntentFilters, vm::exportCrossProfileIntentFilters,
::navigateUp
)
}
entry<Destination.DeleteWorkProfile> { DeleteWorkProfileScreen(vm::wipeData, ::navigateUp) }
entry<Destination.ApplicationsList> { params ->
AppChooserScreen(
params, vm.installedPackages, vm.refreshPackagesProgress, { name ->
if (params.canSwitchView) {
if (name == null) {
navigateUp()
} else {
navigate(Destination.ApplicationDetails(name))
}
} else {
if (name != null) vm.chosenPackage.trySend(name)
navigateUp()
}
}, {
SP.applicationsListView = false
navigate(Destination.ApplicationFunctions)
backstack.removeAt(backstack.size - 2)
}, vm::refreshPackageList, vm::setPackageSuspended, vm::setPackageHidden)
}
entry<Destination.ApplicationFunctions> {
ApplicationsFeaturesScreen(::navigateUp, ::navigate) {
SP.applicationsListView = true
navigate(Destination.ApplicationsList(true, true))
backstack.removeAt(backstack.size - 2)
}
}
entry<Destination.ApplicationDetails> {
ApplicationDetailsScreen(it, vm, ::navigateUp, ::navigate)
}
entry<Destination.Suspend> {
PackageFunctionScreen(
R.string.suspend, vm.suspendedPackages, vm::getSuspendedPackaged,
vm::setPackageSuspended, ::navigateUp, vm.chosenPackage, ::choosePackage,
::navigateToAppGroups, vm.appGroups, R.string.info_suspend_app
)
}
entry<Destination.Hide> {
PackageFunctionScreen(
R.string.hide, vm.hiddenPackages, vm::getHiddenPackages, vm::setPackageHidden,
::navigateUp, vm.chosenPackage, ::choosePackage, ::navigateToAppGroups, vm.appGroups
)
}
entry<Destination.BlockUninstall> {
PackageFunctionScreen(
R.string.block_uninstall, vm.ubPackages, vm::getUbPackages, vm::setPackageUb,
::navigateUp, vm.chosenPackage, ::choosePackage, ::navigateToAppGroups, vm.appGroups
)
}
entry<Destination.DisableUserControl> {
PackageFunctionScreen(
R.string.disable_user_control, vm.ucdPackages, vm::getUcdPackages,
vm::setPackageUcd, ::navigateUp, vm.chosenPackage, ::choosePackage,
::navigateToAppGroups, vm.appGroups, R.string.info_disable_user_control
)
}
entry<Destination.AppPermissionsManager> {
AppPermissionsManagerScreen(
vm::getPackagePermissions, vm::setPackagePermission, ::navigateUp, it
)
}
entry<Destination.PermissionManager> {
PermissionManagerScreen(::navigate, ::navigateUp)
}
entry<Destination.PermissionDetail> {
PermissionDetailScreen(
it, vm::getPermissionPackages, vm::setPackagePermission, ::navigateUp
)
}
entry<Destination.DisableMeteredData> {
PackageFunctionScreen(
R.string.disable_metered_data, vm.mddPackages, vm::getMddPackages,
vm::setPackageMdd, ::navigateUp, vm.chosenPackage, ::choosePackage,
::navigateToAppGroups, vm.appGroups
)
}
entry<Destination.ClearAppStorage> {
ClearAppStorageScreen(
vm.chosenPackage, ::chooseSinglePackage, vm::clearAppData, ::navigateUp
)
}
entry<Destination.UninstallApp> {
UninstallAppScreen(
vm.chosenPackage, ::chooseSinglePackage, vm::uninstallPackage, ::navigateUp
)
}
entry<Destination.KeepUninstalledPackages> {
PackageFunctionScreen(
R.string.keep_uninstalled_packages, vm.kuPackages, vm::getKuPackages,
vm::setPackageKu, ::navigateUp, vm.chosenPackage, ::choosePackage,
::navigateToAppGroups, vm.appGroups, R.string.info_keep_uninstalled_apps
)
}
entry<Destination.InstallExistingApp> {
InstallExistingAppScreen(
vm.chosenPackage, ::chooseSinglePackage, vm::installExistingApp, ::navigateUp
)
}
entry<Destination.CrossProfilePackages> {
PackageFunctionScreen(
R.string.cross_profile_apps, vm.cpPackages,
vm::getCpPackages, vm::setPackageCp, ::navigateUp, vm.chosenPackage,
::choosePackage, ::navigateToAppGroups, vm.appGroups
)
}
entry<Destination.CrossProfileWidgetProviders> {
PackageFunctionScreen(R.string.cross_profile_widget, vm.cpwProviders,
vm::getCpwProviders, vm::setCpwProvider, ::navigateUp, vm.chosenPackage,
::choosePackage, ::navigateToAppGroups, vm.appGroups)
}
entry<Destination.CredentialManagerPolicy> {
CredentialManagerPolicyScreen(
vm.chosenPackage, ::choosePackage, vm.cmPackages, vm::getCmPolicy,
vm::setCmPackage, vm::setCmPolicy, ::navigateUp
)
}
entry<Destination.PermittedAccessibilityServices> {
PermittedAsAndImPackages(
R.string.permitted_accessibility_services,
R.string.system_accessibility_always_allowed, vm.chosenPackage, ::choosePackage,
vm.pasPackages, vm::getPasPackages, vm::setPasPackage, vm::setPasPolicy,
::navigateUp
)
}
entry<Destination.PermittedInputMethods> {
PermittedAsAndImPackages(
R.string.permitted_ime, R.string.system_ime_always_allowed,
vm.chosenPackage, ::choosePackage, vm.pimPackages, vm::getPimPackages,
vm::setPimPackage, vm::setPimPolicy, ::navigateUp
)
}
entry<Destination.EnableSystemApp> {
EnableSystemAppScreen(
vm.chosenPackage, ::chooseSinglePackage, vm::enableSystemApp, ::navigateUp
)
}
entry<Destination.SetDefaultDialer> {
SetDefaultDialerScreen(
vm.chosenPackage, ::chooseSinglePackage, vm::setDefaultDialer, ::navigateUp
)
}
entry<Destination.ManagedConfiguration> {
ManagedConfigurationScreen(
it, vm.appRestrictions, vm::setAppRestrictions,
vm::clearAppRestrictions, ::navigateUp
)
}
entry<Destination.ManageAppGroups> {
ManageAppGroupsScreen(
vm.appGroups, vm::exportAppGroups, vm::importAppGroups,
{ id, name, apps -> navigate(Destination.EditAppGroup(id, name, apps)) },
::navigateUp
)
}
entry<Destination.EditAppGroup> {
EditAppGroupScreen(
it, vm::getAppInfo, ::navigateUp, vm::setAppGroup,
vm::deleteAppGroup, ::choosePackage, vm.chosenPackage
)
}
entry<Destination.UserRestriction> {
UserRestrictionScreen(vm::getUserRestrictions, ::navigateUp, ::navigate)
}
entry<Destination.UserRestrictionEditor> {
UserRestrictionEditorScreen(vm.userRestrictions, vm::setUserRestriction, ::navigateUp)
}
entry<Destination.UserRestrictionOptions> {
UserRestrictionOptionsScreen(it, vm.userRestrictions,
vm::setUserRestriction, vm::createUserRestrictionShortcut, ::navigateUp)
}
entry<Destination.Users> { UsersScreen(vm, ::navigateUp, ::navigate) }
entry<Destination.UserInfo> { UserInfoScreen(vm::getUserInformation, ::navigateUp) }
entry<Destination.UsersOptions> {
UsersOptionsScreen(vm::getLogoutEnabled, vm::setLogoutEnabled, ::navigateUp)
}
entry<Destination.UserOperation> {
UserOperationScreen(vm::getUserIdentifiers, vm::doUserOperation,
vm::createUserOperationShortcut, ::navigateUp)
}
entry<Destination.CreateUser> { CreateUserScreen(vm::createUser, ::navigateUp) }
entry<Destination.ChangeUsername> { ChangeUsernameScreen(vm::setProfileName, ::navigateUp) }
entry<Destination.UserSessionMessage> {
UserSessionMessageScreen(vm::getUserSessionMessages, vm::setStartUserSessionMessage,
vm::setEndUserSessionMessage, ::navigateUp)
}
entry<Destination.AffiliationId> {
AffiliationIdScreen(vm.affiliationIds, vm::getAffiliationIds, vm::setAffiliationId,
::navigateUp)
}
entry<Destination.Password> { PasswordScreen(vm, ::navigateUp, ::navigate) }
entry<Destination.PasswordInfo> {
PasswordInfoScreen(vm::getPasswordComplexity, vm::isPasswordComplexitySufficient,
vm::isUsingUnifiedPassword, ::navigateUp)
}
entry<Destination.ResetPasswordToken> {
ResetPasswordTokenScreen(vm::getRpTokenState, vm::setRpToken,
vm::createActivateRpTokenIntent, vm::clearRpToken, ::navigateUp)
}
entry<Destination.ResetPassword> { ResetPasswordScreen(vm::resetPassword, ::navigateUp) }
entry<Destination.RequiredPasswordComplexity> {
RequiredPasswordComplexityScreen(vm::getRequiredPasswordComplexity,
vm::setRequiredPasswordComplexity, ::navigateUp)
}
entry<Destination.KeyguardDisabledFeatures> {
KeyguardDisabledFeaturesScreen(vm::getKeyguardDisableConfig,
vm::setKeyguardDisableConfig, ::navigateUp)
}
entry<Destination.RequiredPasswordQuality> { RequiredPasswordQualityScreen(::navigateUp) }
entry<Destination.Settings> { SettingsScreen(::navigate, ::navigateUp) }
entry<Destination.SettingsOptions> {
SettingsOptionsScreen(
vm::getDisplayDangerousFeatures, vm::getShortcutsEnabled,
vm::setDisplayDangerousFeatures, vm::setShortcutsEnabled, ::navigateUp
)
}
entry<Destination.AppearanceSettings> {
AppearanceScreen(::navigateUp, vm.theme, vm::changeTheme)
}
entry<Destination.AppLockSettings> {
AppLockSettingsScreen(vm.getAppLockConfig(), vm::setAppLockConfig, ::navigateUp)
}
entry<Destination.ApiSettings> {
ApiSettings(vm::getApiEnabled, vm::setApiKey, ::navigateUp)
}
entry<Destination.NotificationSettings> {
NotificationsScreen(
vm.enabledNotifications, vm::getEnabledNotifications,
vm::setNotificationEnabled, ::navigateUp
)
}
entry<Destination.About> { AboutScreen(::navigateUp) }
}(destination) as NavEntry<NavKey>

View File

@@ -1,4 +1,4 @@
package com.bintianqi.owndroid.dpm package com.bintianqi.owndroid.ui.screen
import android.app.admin.DevicePolicyManager.PERMISSION_GRANT_STATE_DEFAULT import android.app.admin.DevicePolicyManager.PERMISSION_GRANT_STATE_DEFAULT
import android.app.admin.DevicePolicyManager.PERMISSION_GRANT_STATE_DENIED import android.app.admin.DevicePolicyManager.PERMISSION_GRANT_STATE_DENIED
@@ -33,12 +33,10 @@ import androidx.compose.foundation.lazy.itemsIndexed
import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.foundation.text.selection.SelectionContainer import androidx.compose.foundation.text.selection.SelectionContainer
import androidx.compose.foundation.verticalScroll import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.List
import androidx.compose.material.icons.filled.Add import androidx.compose.material.icons.filled.Add
import androidx.compose.material.icons.filled.Check import androidx.compose.material.icons.filled.Check
import androidx.compose.material.icons.filled.Clear import androidx.compose.material.icons.filled.Clear
@@ -99,12 +97,10 @@ import androidx.compose.ui.focus.focusRequester
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.input.nestedscroll.nestedScroll import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontStyle import androidx.compose.ui.text.font.FontStyle
import androidx.compose.ui.text.input.ImeAction import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.Dialog import androidx.compose.ui.window.Dialog
import androidx.compose.ui.window.DialogProperties import androidx.compose.ui.window.DialogProperties
@@ -117,6 +113,8 @@ import com.bintianqi.owndroid.MyViewModel
import com.bintianqi.owndroid.Privilege import com.bintianqi.owndroid.Privilege
import com.bintianqi.owndroid.R import com.bintianqi.owndroid.R
import com.bintianqi.owndroid.adaptiveInsets import com.bintianqi.owndroid.adaptiveInsets
import com.bintianqi.owndroid.dpm.PermissionItem
import com.bintianqi.owndroid.dpm.runtimePermissions
import com.bintianqi.owndroid.parsePackageNames import com.bintianqi.owndroid.parsePackageNames
import com.bintianqi.owndroid.showOperationResultToast import com.bintianqi.owndroid.showOperationResultToast
import com.bintianqi.owndroid.ui.FullWidthRadioButtonItem import com.bintianqi.owndroid.ui.FullWidthRadioButtonItem
@@ -126,7 +124,9 @@ import com.bintianqi.owndroid.ui.MyScaffold
import com.bintianqi.owndroid.ui.MySmallTitleScaffold import com.bintianqi.owndroid.ui.MySmallTitleScaffold
import com.bintianqi.owndroid.ui.NavIcon import com.bintianqi.owndroid.ui.NavIcon
import com.bintianqi.owndroid.ui.Notes import com.bintianqi.owndroid.ui.Notes
import com.bintianqi.owndroid.ui.PackageNameTextField
import com.bintianqi.owndroid.ui.SwitchItem import com.bintianqi.owndroid.ui.SwitchItem
import com.bintianqi.owndroid.ui.navigation.Destination
import com.google.accompanist.drawablepainter.rememberDrawablePainter import com.google.accompanist.drawablepainter.rememberDrawablePainter
import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
@@ -166,33 +166,11 @@ fun LazyItemScope.ApplicationItem(info: AppInfo, onClear: () -> Unit) {
} }
} }
@Composable
fun PackageNameTextField(
value: String, onChoosePackage: () -> Unit,
modifier: Modifier = Modifier, onValueChange: (String) -> Unit
) {
val fm = LocalFocusManager.current
OutlinedTextField(
value, onValueChange, Modifier
.fillMaxWidth()
.then(modifier),
label = { Text(stringResource(R.string.package_name)) },
trailingIcon = {
IconButton(onChoosePackage) {
Icon(Icons.AutoMirrored.Default.List, null)
}
},
isError = value.isNotEmpty() && !value.isValidPackageName,
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Ascii, imeAction = ImeAction.Done),
keyboardActions = KeyboardActions { fm.clearFocus() }
)
}
@Serializable object ApplicationsFeatures
@OptIn(ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterial3Api::class)
@Composable @Composable
fun ApplicationsFeaturesScreen(onNavigateUp: () -> Unit, onNavigate: (Any) -> Unit, onSwitchView: () -> Unit) { fun ApplicationsFeaturesScreen(
onNavigateUp: () -> Unit, onNavigate: (Destination) -> Unit, onSwitchView: () -> Unit
) {
val context = LocalContext.current val context = LocalContext.current
val sb = TopAppBarDefaults.exitUntilCollapsedScrollBehavior() val sb = TopAppBarDefaults.exitUntilCollapsedScrollBehavior()
Scaffold( Scaffold(
@@ -219,55 +197,81 @@ fun ApplicationsFeaturesScreen(onNavigateUp: () -> Unit, onNavigate: (Any) -> Un
.padding(bottom = 80.dp) .padding(bottom = 80.dp)
) { ) {
val privilege by Privilege.status.collectAsStateWithLifecycle() val privilege by Privilege.status.collectAsStateWithLifecycle()
if(VERSION.SDK_INT >= 24) FunctionItem(R.string.suspend, icon = R.drawable.block_fill0) { onNavigate(Suspend) } if(VERSION.SDK_INT >= 24) FunctionItem(R.string.suspend, icon = R.drawable.block_fill0) {
FunctionItem(R.string.hide, icon = R.drawable.visibility_off_fill0) { onNavigate(Hide) } onNavigate(Destination.Suspend)
FunctionItem(R.string.block_uninstall, icon = R.drawable.delete_forever_fill0) { onNavigate(BlockUninstall) } }
FunctionItem(R.string.hide, icon = R.drawable.visibility_off_fill0) {
onNavigate(Destination.Hide)
}
FunctionItem(R.string.block_uninstall, icon = R.drawable.delete_forever_fill0) {
onNavigate(Destination.BlockUninstall)
}
if(VERSION.SDK_INT >= 30 && (privilege.device || (VERSION.SDK_INT >= 33 && privilege.profile))) { 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) } FunctionItem(R.string.disable_user_control, icon = R.drawable.do_not_touch_fill0) {
onNavigate(Destination.DisableUserControl)
}
} }
FunctionItem(R.string.permissions, icon = R.drawable.shield_fill0) { FunctionItem(R.string.permissions, icon = R.drawable.shield_fill0) {
onNavigate(PermissionManager) onNavigate(Destination.PermissionManager)
} }
if(VERSION.SDK_INT >= 28) { if(VERSION.SDK_INT >= 28) {
FunctionItem(R.string.disable_metered_data, icon = R.drawable.money_off_fill0) { onNavigate(DisableMeteredData) } FunctionItem(R.string.disable_metered_data, icon = R.drawable.money_off_fill0) {
onNavigate(Destination.DisableMeteredData)
}
} }
if(VERSION.SDK_INT >= 28) { if(VERSION.SDK_INT >= 28) {
FunctionItem(R.string.clear_app_storage, icon = R.drawable.mop_fill0) { onNavigate(ClearAppStorage) } FunctionItem(R.string.clear_app_storage, icon = R.drawable.mop_fill0) {
onNavigate(Destination.ClearAppStorage)
}
} }
FunctionItem(R.string.install_app, icon = R.drawable.install_mobile_fill0) { FunctionItem(R.string.install_app, icon = R.drawable.install_mobile_fill0) {
context.startActivity(Intent(context, AppInstallerActivity::class.java)) context.startActivity(Intent(context, AppInstallerActivity::class.java))
} }
FunctionItem(R.string.uninstall_app, icon = R.drawable.delete_fill0) { onNavigate(UninstallApp) } FunctionItem(R.string.uninstall_app, icon = R.drawable.delete_fill0) {
onNavigate(Destination.UninstallApp)
}
if(VERSION.SDK_INT >= 28 && privilege.device) { if(VERSION.SDK_INT >= 28 && privilege.device) {
FunctionItem(R.string.keep_uninstalled_packages, icon = R.drawable.delete_fill0) { onNavigate(KeepUninstalledPackages) } FunctionItem(R.string.keep_uninstalled_packages, icon = R.drawable.delete_fill0) {
onNavigate(Destination.KeepUninstalledPackages)
}
} }
if (VERSION.SDK_INT >= 28 && (privilege.device || (privilege.profile && privilege.affiliated))) { if (VERSION.SDK_INT >= 28 && (privilege.device || (privilege.profile && privilege.affiliated))) {
FunctionItem(R.string.install_existing_app, icon = R.drawable.install_mobile_fill0) { FunctionItem(R.string.install_existing_app, icon = R.drawable.install_mobile_fill0) {
onNavigate(InstallExistingApp) onNavigate(Destination.InstallExistingApp)
} }
} }
if(VERSION.SDK_INT >= 30 && privilege.work) { if(VERSION.SDK_INT >= 30 && privilege.work) {
FunctionItem(R.string.cross_profile_apps, icon = R.drawable.work_fill0) { onNavigate(CrossProfilePackages) } FunctionItem(R.string.cross_profile_apps, icon = R.drawable.work_fill0) {
onNavigate(Destination.CrossProfilePackages)
}
} }
if(privilege.work) { if(privilege.work) {
FunctionItem(R.string.cross_profile_widget, icon = R.drawable.widgets_fill0) { onNavigate(CrossProfileWidgetProviders) } FunctionItem(R.string.cross_profile_widget, icon = R.drawable.widgets_fill0) {
onNavigate(Destination.CrossProfileWidgetProviders)
}
} }
if(VERSION.SDK_INT >= 34 && privilege.device) { if(VERSION.SDK_INT >= 34 && privilege.device) {
FunctionItem(R.string.credential_manager_policy, icon = R.drawable.license_fill0) { onNavigate(CredentialManagerPolicy) } FunctionItem(R.string.credential_manager_policy, icon = R.drawable.license_fill0) {
onNavigate(Destination.CredentialManagerPolicy)
}
} }
FunctionItem(R.string.permitted_accessibility_services, icon = R.drawable.settings_accessibility_fill0) { FunctionItem(R.string.permitted_accessibility_services, icon = R.drawable.settings_accessibility_fill0) {
onNavigate(PermittedAccessibilityServices) onNavigate(Destination.PermittedAccessibilityServices)
}
FunctionItem(R.string.permitted_ime, icon = R.drawable.keyboard_fill0) {
onNavigate(Destination.PermittedInputMethods)
}
FunctionItem(R.string.enable_system_app, icon = R.drawable.enable_fill0) {
onNavigate(Destination.EnableSystemApp)
} }
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 && (privilege.device || privilege.work)) { if(VERSION.SDK_INT >= 34 && (privilege.device || privilege.work)) {
FunctionItem(R.string.set_default_dialer, icon = R.drawable.call_fill0) { onNavigate(SetDefaultDialer) } FunctionItem(R.string.set_default_dialer, icon = R.drawable.call_fill0) {
onNavigate(Destination.SetDefaultDialer)
}
} }
} }
} }
} }
@Serializable data class ApplicationDetails(val packageName: String)
data class AppStatus( data class AppStatus(
val suspend: Boolean, val suspend: Boolean,
@@ -280,7 +284,8 @@ data class AppStatus(
@Composable @Composable
fun ApplicationDetailsScreen( fun ApplicationDetailsScreen(
param: ApplicationDetails, vm: MyViewModel, onNavigateUp: () -> Unit, onNavigate: (Any) -> Unit param: Destination.ApplicationDetails, vm: MyViewModel, onNavigateUp: () -> Unit,
onNavigate: (Destination) -> Unit
) { ) {
val packageName = param.packageName val packageName = param.packageName
val privilege by Privilege.status.collectAsStateWithLifecycle() val privilege by Privilege.status.collectAsStateWithLifecycle()
@@ -302,7 +307,9 @@ fun ApplicationDetailsScreen(
.alpha(0.7F) .alpha(0.7F)
.padding(bottom = 8.dp), style = typography.bodyMedium) .padding(bottom = 8.dp), style = typography.bodyMedium)
} }
FunctionItem(R.string.permissions, icon = R.drawable.shield_fill0) { onNavigate(AppPermissionsManager(packageName)) } FunctionItem(R.string.permissions, icon = R.drawable.shield_fill0) {
onNavigate(Destination.AppPermissionsManager(packageName))
}
if(VERSION.SDK_INT >= 24) SwitchItem( if(VERSION.SDK_INT >= 24) SwitchItem(
R.string.suspend, icon = R.drawable.block_fill0, state = status.suspend, R.string.suspend, icon = R.drawable.block_fill0, state = status.suspend,
onCheckedChange = { vm.adSetPackageSuspended(packageName, it) } onCheckedChange = { vm.adSetPackageSuspended(packageName, it) }
@@ -334,7 +341,7 @@ fun ApplicationDetailsScreen(
) )
if (appRestrictions.isNotEmpty()) { if (appRestrictions.isNotEmpty()) {
FunctionItem(R.string.managed_configuration, icon = R.drawable.description_fill0) { FunctionItem(R.string.managed_configuration, icon = R.drawable.description_fill0) {
onNavigate(ManagedConfiguration(packageName)) onNavigate(Destination.ManagedConfiguration(packageName))
} }
} }
if(VERSION.SDK_INT >= 28) FunctionItem(R.string.clear_app_storage, icon = R.drawable.mop_fill0) { dialog = 1 } if(VERSION.SDK_INT >= 28) FunctionItem(R.string.clear_app_storage, icon = R.drawable.mop_fill0) { dialog = 1 }
@@ -349,21 +356,11 @@ fun ApplicationDetailsScreen(
} }
} }
@Serializable object Suspend
@Serializable object Hide
@Serializable object BlockUninstall
@Serializable object DisableUserControl
@Serializable data class AppPermissionsManager(val packageName: String)
@Composable @Composable
fun AppPermissionsManagerScreen( fun AppPermissionsManagerScreen(
getPackagePermissions: (String) -> Map<String, Int>, getPackagePermissions: (String) -> Map<String, Int>,
setPackagePermission: (String, String, Int) -> Boolean, onNavigateUp: () -> Unit, setPackagePermission: (String, String, Int) -> Boolean, onNavigateUp: () -> Unit,
param: AppPermissionsManager param: Destination.AppPermissionsManager
) { ) {
val context = LocalContext.current val context = LocalContext.current
val privilege by Privilege.status.collectAsStateWithLifecycle() val privilege by Privilege.status.collectAsStateWithLifecycle()
@@ -453,10 +450,10 @@ fun PackagePermissionDialog(
) )
} }
@Serializable object PermissionManager
@Composable @Composable
fun PermissionManagerScreen(onNavigate: (PermissionDetail) -> Unit, onNavigateUp: () -> Unit) { fun PermissionManagerScreen(
onNavigate: (Destination.PermissionDetail) -> Unit, onNavigateUp: () -> Unit
) {
MyLazyScaffold(R.string.permissions, onNavigateUp) { MyLazyScaffold(R.string.permissions, onNavigateUp) {
items(runtimePermissions) { items(runtimePermissions) {
Row( Row(
@@ -464,7 +461,7 @@ fun PermissionManagerScreen(onNavigate: (PermissionDetail) -> Unit, onNavigateUp
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.clickable { .clickable {
onNavigate(PermissionDetail(it.id)) onNavigate(Destination.PermissionDetail(it.id))
} }
.padding(8.dp, 12.dp) .padding(8.dp, 12.dp)
) { ) {
@@ -478,12 +475,10 @@ fun PermissionManagerScreen(onNavigate: (PermissionDetail) -> Unit, onNavigateUp
} }
} }
@Serializable class PermissionDetail(val permission: String)
@OptIn(ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterial3Api::class)
@Composable @Composable
fun PermissionDetailScreen( fun PermissionDetailScreen(
param: PermissionDetail, getPermissionPackages: (String) -> List<Pair<AppInfo, Int>>, param: Destination.PermissionDetail, getPermissionPackages: (String) -> List<Pair<AppInfo, Int>>,
setPackagePermission: (String, String, Int) -> Boolean, onNavigateUp: () -> Unit setPackagePermission: (String, String, Int) -> Boolean, onNavigateUp: () -> Unit
) { ) {
val context = LocalContext.current val context = LocalContext.current
@@ -586,10 +581,6 @@ fun PermissionDetailScreen(
) { selectedPackage = null } ) { selectedPackage = null }
} }
@Serializable object DisableMeteredData
@Serializable object ClearAppStorage
@RequiresApi(28) @RequiresApi(28)
@Composable @Composable
fun ClearAppStorageScreen( fun ClearAppStorageScreen(
@@ -653,8 +644,6 @@ private fun ClearAppStorageDialog(
) )
} }
@Serializable object UninstallApp
@Composable @Composable
fun UninstallAppScreen( fun UninstallAppScreen(
chosenPackage: Channel<String>, onChoosePackage: () -> Unit, chosenPackage: Channel<String>, onChoosePackage: () -> Unit,
@@ -722,10 +711,6 @@ private fun UninstallAppDialog(
) )
} }
@Serializable object KeepUninstalledPackages
@Serializable object InstallExistingApp
@RequiresApi(28) @RequiresApi(28)
@Composable @Composable
fun InstallExistingAppScreen( fun InstallExistingAppScreen(
@@ -752,12 +737,6 @@ fun InstallExistingAppScreen(
} }
} }
@Serializable object CrossProfilePackages
@Serializable object CrossProfileWidgetProviders
@Serializable object CredentialManagerPolicy
@RequiresApi(34) @RequiresApi(34)
@Composable @Composable
fun CredentialManagerPolicyScreen( fun CredentialManagerPolicyScreen(
@@ -819,10 +798,6 @@ fun CredentialManagerPolicyScreen(
} }
} }
@Serializable object PermittedAccessibilityServices
@Serializable object PermittedInputMethods
@Composable @Composable
fun PermittedAsAndImPackages( fun PermittedAsAndImPackages(
title: Int, note: Int, chosenPackage: Channel<String>, onChoosePackage: () -> Unit, title: Int, note: Int, chosenPackage: Channel<String>, onChoosePackage: () -> Unit,
@@ -879,8 +854,6 @@ fun PermittedAsAndImPackages(
} }
} }
@Serializable object EnableSystemApp
@Composable @Composable
fun EnableSystemAppScreen( fun EnableSystemAppScreen(
chosenPackage: Channel<String>, onChoosePackage: () -> Unit, chosenPackage: Channel<String>, onChoosePackage: () -> Unit,
@@ -910,8 +883,6 @@ fun EnableSystemAppScreen(
} }
} }
@Serializable object SetDefaultDialer
@RequiresApi(34) @RequiresApi(34)
@Composable @Composable
fun SetDefaultDialerScreen( fun SetDefaultDialerScreen(
@@ -1072,8 +1043,6 @@ class AppGroup(
val id: Int, override val name: String, override val apps: List<String> val id: Int, override val name: String, override val apps: List<String>
) : BasicAppGroup(name, apps) ) : BasicAppGroup(name, apps)
@Serializable object ManageAppGroups
@OptIn(ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterial3Api::class)
@Composable @Composable
fun ManageAppGroupsScreen( fun ManageAppGroupsScreen(
@@ -1158,12 +1127,10 @@ fun ManageAppGroupsScreen(
} }
} }
@Serializable class EditAppGroup(val id: Int?, val name: String, val apps: List<String>)
@OptIn(ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterial3Api::class)
@Composable @Composable
fun EditAppGroupScreen( fun EditAppGroupScreen(
params: EditAppGroup, getAppInfo: (String) -> AppInfo, navigateUp: () -> Unit, params: Destination.EditAppGroup, getAppInfo: (String) -> AppInfo, navigateUp: () -> Unit,
setGroup: (Int?, String, List<String>) -> Unit, deleteGroup: (Int) -> Unit, setGroup: (Int?, String, List<String>) -> Unit, deleteGroup: (Int) -> Unit,
onChoosePackage: () -> Unit, chosenPackage: Channel<String> onChoosePackage: () -> Unit, chosenPackage: Channel<String>
) { ) {
@@ -1239,12 +1206,10 @@ fun EditAppGroupScreen(
} }
} }
@Serializable class ManagedConfiguration(val packageName: String)
@OptIn(ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterial3Api::class)
@Composable @Composable
fun ManagedConfigurationScreen( fun ManagedConfigurationScreen(
params: ManagedConfiguration, appRestrictions: StateFlow<List<AppRestriction>>, params: Destination.ManagedConfiguration, appRestrictions: StateFlow<List<AppRestriction>>,
setRestriction: (String, AppRestriction) -> Unit, clearRestriction: (String) -> Unit, setRestriction: (String, AppRestriction) -> Unit, clearRestriction: (String) -> Unit,
navigateUp: () -> Unit navigateUp: () -> Unit
) { ) {

View File

@@ -0,0 +1,120 @@
package com.bintianqi.owndroid.ui.screen
import android.os.Build.VERSION
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Settings
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.LargeTopAppBar
import androidx.compose.material3.MaterialTheme.typography
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.bintianqi.owndroid.BottomPadding
import com.bintianqi.owndroid.Privilege
import com.bintianqi.owndroid.R
import com.bintianqi.owndroid.SP
import com.bintianqi.owndroid.adaptiveInsets
import com.bintianqi.owndroid.ui.navigation.Destination
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun HomeScreen(onNavigate: (Destination) -> Unit) {
val privilege by Privilege.status.collectAsStateWithLifecycle()
val sb = TopAppBarDefaults.exitUntilCollapsedScrollBehavior()
Scaffold(
Modifier.nestedScroll(sb.nestedScrollConnection),
topBar = {
LargeTopAppBar(
{ Text(stringResource(R.string.app_name)) },
actions = {
IconButton({ onNavigate(Destination.WorkingModes(true)) }) {
Icon(
painterResource(R.drawable.security_fill0), null
)
}
IconButton({ onNavigate(Destination.Settings) }) {
Icon(Icons.Default.Settings, null)
}
},
scrollBehavior = sb
)
},
contentWindowInsets = adaptiveInsets()
) {
Column(
Modifier
.fillMaxSize()
.padding(it)
.verticalScroll(rememberScrollState())
) {
if (privilege.device || privilege.profile) {
HomePageItem(R.string.system, R.drawable.android_fill0) {
onNavigate(Destination.System)
}
HomePageItem(R.string.network, R.drawable.wifi_fill0) { onNavigate(Destination.Network) }
}
if (privilege.work) {
HomePageItem(R.string.work_profile, R.drawable.work_fill0) {
onNavigate(Destination.WorkProfile)
}
}
if (privilege.device || privilege.profile) {
HomePageItem(R.string.applications, R.drawable.apps_fill0) {
onNavigate(
if (SP.applicationsListView) Destination.ApplicationsList(true, true)
else Destination.ApplicationFunctions
)
}
if (VERSION.SDK_INT >= 24) {
HomePageItem(R.string.user_restriction, R.drawable.person_off) {
onNavigate(Destination.UserRestriction)
}
}
HomePageItem(R.string.users, R.drawable.manage_accounts_fill0) {
onNavigate(Destination.Users)
}
HomePageItem(
R.string.password_and_keyguard, R.drawable.password_fill0
) { onNavigate(Destination.Password) }
}
Spacer(Modifier.height(BottomPadding))
}
}
}
@Composable
fun HomePageItem(name: Int, icon: Int, onClick: () -> Unit) {
Row(
Modifier
.fillMaxWidth()
.clickable(onClick = onClick)
.padding(vertical = 12.dp),
verticalAlignment = Alignment.CenterVertically
) {
Spacer(Modifier.padding(start = 30.dp))
Icon(painterResource(icon), null)
Spacer(Modifier.padding(start = 15.dp))
Text(stringResource(name), style = typography.headlineSmall)
}
}

View File

@@ -1,4 +1,4 @@
package com.bintianqi.owndroid.dpm package com.bintianqi.owndroid.ui.screen
import android.Manifest import android.Manifest
import android.annotation.SuppressLint import android.annotation.SuppressLint
@@ -128,7 +128,9 @@ import com.bintianqi.owndroid.ui.MyScaffold
import com.bintianqi.owndroid.ui.MySmallTitleScaffold import com.bintianqi.owndroid.ui.MySmallTitleScaffold
import com.bintianqi.owndroid.ui.NavIcon import com.bintianqi.owndroid.ui.NavIcon
import com.bintianqi.owndroid.ui.Notes import com.bintianqi.owndroid.ui.Notes
import com.bintianqi.owndroid.ui.PackageNameTextField
import com.bintianqi.owndroid.ui.SwitchItem import com.bintianqi.owndroid.ui.SwitchItem
import com.bintianqi.owndroid.ui.navigation.Destination
import com.bintianqi.owndroid.writeClipBoard import com.bintianqi.owndroid.writeClipBoard
import com.bintianqi.owndroid.yesOrNo import com.bintianqi.owndroid.yesOrNo
import com.google.accompanist.permissions.ExperimentalPermissionsApi import com.google.accompanist.permissions.ExperimentalPermissionsApi
@@ -142,43 +144,57 @@ import java.text.SimpleDateFormat
import java.util.Date import java.util.Date
import java.util.Locale import java.util.Locale
@Serializable object Network
@Composable @Composable
fun NetworkScreen(onNavigateUp: () -> Unit, onNavigate: (Any) -> Unit) { fun NetworkScreen(onNavigateUp: () -> Unit, onNavigate: (Destination) -> Unit) {
val privilege by Privilege.status.collectAsStateWithLifecycle() val privilege by Privilege.status.collectAsStateWithLifecycle()
MyScaffold(R.string.network, onNavigateUp, 0.dp) { MyScaffold(R.string.network, onNavigateUp, 0.dp) {
if(!privilege.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(Destination.WiFi)
}
if(VERSION.SDK_INT >= 30) { if(VERSION.SDK_INT >= 30) {
FunctionItem(R.string.options, icon = R.drawable.tune_fill0) { onNavigate(NetworkOptions) } FunctionItem(R.string.options, icon = R.drawable.tune_fill0) {
onNavigate(Destination.NetworkOptions)
}
} }
if (!privilege.dhizuku) if (!privilege.dhizuku)
FunctionItem(R.string.network_stats, icon = R.drawable.query_stats_fill0) { onNavigate(QueryNetworkStats) } FunctionItem(R.string.network_stats, icon = R.drawable.query_stats_fill0) {
onNavigate(Destination.NetworkStats)
}
if(VERSION.SDK_INT >= 29 && privilege.device) { if(VERSION.SDK_INT >= 29 && privilege.device) {
FunctionItem(R.string.private_dns, icon = R.drawable.dns_fill0) { onNavigate(PrivateDns) } FunctionItem(R.string.private_dns, icon = R.drawable.dns_fill0) {
onNavigate(Destination.PrivateDns)
}
} }
if(VERSION.SDK_INT >= 24) { if(VERSION.SDK_INT >= 24) {
FunctionItem(R.string.always_on_vpn, icon = R.drawable.vpn_key_fill0) { onNavigate(AlwaysOnVpnPackage) } FunctionItem(R.string.always_on_vpn, icon = R.drawable.vpn_key_fill0) {
onNavigate(Destination.AlwaysOnVpnPackage)
}
} }
if(privilege.device) { if(privilege.device) {
FunctionItem(R.string.recommended_global_proxy, icon = R.drawable.vpn_key_fill0) { onNavigate(RecommendedGlobalProxy) } FunctionItem(R.string.recommended_global_proxy, icon = R.drawable.vpn_key_fill0) {
onNavigate(Destination.RecommendedGlobalProxy)
}
} }
if(VERSION.SDK_INT >= 26 && !privilege.dhizuku && (privilege.device || privilege.work)) { if(VERSION.SDK_INT >= 26 && !privilege.dhizuku && (privilege.device || privilege.work)) {
FunctionItem(R.string.network_logging, icon = R.drawable.description_fill0) { onNavigate(NetworkLogging) } FunctionItem(R.string.network_logging, icon = R.drawable.description_fill0) {
onNavigate(Destination.NetworkLogging)
}
} }
/*if(VERSION.SDK_INT >= 31) { /*if(VERSION.SDK_INT >= 31) {
FunctionItem(R.string.wifi_auth_keypair, icon = R.drawable.key_fill0) { onNavigate(WifiAuthKeypair) } FunctionItem(R.string.wifi_auth_keypair, icon = R.drawable.key_fill0) { onNavigate(Destination.WifiAuthKeypair) }
}*/ }*/
if (VERSION.SDK_INT >= 33 && (privilege.work || privilege.device)) { if (VERSION.SDK_INT >= 33 && (privilege.work || privilege.device)) {
FunctionItem(R.string.preferential_network_service, icon = R.drawable.globe_fill0) { onNavigate(PreferentialNetworkService) } FunctionItem(R.string.preferential_network_service, icon = R.drawable.globe_fill0) {
onNavigate(Destination.PreferentialNetworkService)
}
} }
if(VERSION.SDK_INT >= 28 && privilege.device) { if(VERSION.SDK_INT >= 28 && privilege.device) {
FunctionItem(R.string.override_apn, icon = R.drawable.cell_tower_fill0) { onNavigate(OverrideApn) } FunctionItem(R.string.override_apn, icon = R.drawable.cell_tower_fill0) {
onNavigate(Destination.OverrideApn)
}
} }
} }
} }
@Serializable object NetworkOptions
@Composable @Composable
fun NetworkOptionsScreen( fun NetworkOptionsScreen(
@@ -208,12 +224,10 @@ fun NetworkOptionsScreen(
) )
} }
@Serializable object WiFi
@OptIn(ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterial3Api::class)
@Composable @Composable
fun WifiScreen( fun WifiScreen(
vm: MyViewModel, onNavigateUp: () -> Unit, onNavigate: (Any) -> Unit, vm: MyViewModel, onNavigateUp: () -> Unit, onNavigate: (Destination) -> Unit,
editNetwork: (Int) -> Unit editNetwork: (Int) -> Unit
) { ) {
val coroutine = rememberCoroutineScope() val coroutine = rememberCoroutineScope()
@@ -266,7 +280,7 @@ fun WifiScreen(
@Composable @Composable
fun WifiOverviewScreen( fun WifiOverviewScreen(
setWifiEnabled: (Boolean) -> Boolean, disconnect: () -> Boolean, reconnect: () -> Boolean, setWifiEnabled: (Boolean) -> Boolean, disconnect: () -> Boolean, reconnect: () -> Boolean,
getMac: () -> String?, navigate: (Any) -> Unit getMac: () -> String?, navigate: (Destination) -> Unit
) { ) {
val context = LocalContext.current val context = LocalContext.current
val privilege by Privilege.status.collectAsStateWithLifecycle() val privilege by Privilege.status.collectAsStateWithLifecycle()
@@ -305,8 +319,12 @@ fun WifiOverviewScreen(
FunctionItem(R.string.wifi_mac_address) { macDialog = true } FunctionItem(R.string.wifi_mac_address) { macDialog = true }
} }
if(VERSION.SDK_INT >= 33 && (privilege.device || privilege.org)) { if(VERSION.SDK_INT >= 33 && (privilege.device || privilege.org)) {
FunctionItem(R.string.min_wifi_security_level) { navigate(WifiSecurityLevel) } FunctionItem(R.string.min_wifi_security_level) {
FunctionItem(R.string.wifi_ssid_policy) { navigate(WifiSsidPolicyScreen) } navigate(Destination.WifiSecurityLevel)
}
FunctionItem(R.string.wifi_ssid_policy) {
navigate(Destination.WifiSsidPolicy)
}
} }
} }
if (macDialog && VERSION.SDK_INT >= 24) { if (macDialog && VERSION.SDK_INT >= 24) {
@@ -503,9 +521,6 @@ private fun SavedNetworks(
) )
} }
@Serializable
data class UpdateNetwork(val index: Int)
@OptIn(ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterial3Api::class)
@Composable @Composable
fun UpdateNetworkScreen(info: WifiInfo, setNetwork: (WifiInfo) -> Boolean, onNavigateUp: () -> Unit) { fun UpdateNetworkScreen(info: WifiInfo, setNetwork: (WifiInfo) -> Boolean, onNavigateUp: () -> Unit) {
@@ -813,8 +828,6 @@ private fun AddNetworkScreen(
} }
} }
@Serializable object WifiSecurityLevel
@RequiresApi(33) @RequiresApi(33)
@Composable @Composable
fun WifiSecurityLevelScreen( fun WifiSecurityLevelScreen(
@@ -849,8 +862,6 @@ enum class SsidPolicyType(val id: Int, val text: Int) {
Blacklist(WifiSsidPolicy.WIFI_SSID_POLICY_TYPE_DENYLIST, R.string.blacklist) Blacklist(WifiSsidPolicy.WIFI_SSID_POLICY_TYPE_DENYLIST, R.string.blacklist)
} }
@Serializable object WifiSsidPolicyScreen
@RequiresApi(33) @RequiresApi(33)
@Composable @Composable
fun WifiSsidPolicyScreen( fun WifiSsidPolicyScreen(
@@ -948,8 +959,6 @@ data class QueryNetworkStatsParams(
val startTime: Long, val endTime: Long, val uid: Int, val tag: Int, val state: NetworkStatsState val startTime: Long, val endTime: Long, val uid: Int, val tag: Int, val state: NetworkStatsState
) )
@Serializable object QueryNetworkStats
@OptIn(ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterial3Api::class)
@Composable @Composable
fun NetworkStatsScreen( fun NetworkStatsScreen(
@@ -1266,8 +1275,6 @@ data class NetworkStatsData(
val metered: Int? val metered: Int?
) )
@Serializable object NetworkStatsViewer
@Composable @Composable
fun NetworkStatsViewerScreen( fun NetworkStatsViewerScreen(
data: List<NetworkStatsData>, clearData: () -> Unit, onNavigateUp: () -> Unit data: List<NetworkStatsData>, clearData: () -> Unit, onNavigateUp: () -> Unit
@@ -1372,8 +1379,6 @@ enum class PrivateDnsMode(val id: Int, val text: Int) {
data class PrivateDnsConfiguration(val mode: PrivateDnsMode?, val host: String) data class PrivateDnsConfiguration(val mode: PrivateDnsMode?, val host: String)
@Serializable object PrivateDns
@RequiresApi(29) @RequiresApi(29)
@Composable @Composable
fun PrivateDnsScreen( fun PrivateDnsScreen(
@@ -1413,8 +1418,6 @@ fun PrivateDnsScreen(
} }
} }
@Serializable object AlwaysOnVpnPackage
@RequiresApi(24) @RequiresApi(24)
@Composable @Composable
fun AlwaysOnVpnPackageScreen( fun AlwaysOnVpnPackageScreen(
@@ -1464,8 +1467,6 @@ data class RecommendedProxyConf(
val port: Int, val exclude: List<String> val port: Int, val exclude: List<String>
) )
@Serializable object RecommendedGlobalProxy
@Composable @Composable
fun RecommendedGlobalProxyScreen( fun RecommendedGlobalProxyScreen(
setProxy: (RecommendedProxyConf) -> Unit, onNavigateUp: () -> Unit setProxy: (RecommendedProxyConf) -> Unit, onNavigateUp: () -> Unit
@@ -1538,8 +1539,6 @@ fun RecommendedGlobalProxyScreen(
} }
} }
@Serializable object NetworkLogging
@RequiresApi(26) @RequiresApi(26)
@Composable @Composable
fun NetworkLoggingScreen( fun NetworkLoggingScreen(
@@ -1620,14 +1619,12 @@ fun NetworkLoggingScreen(
) )
} }
@Serializable object PreferentialNetworkService
@RequiresApi(33) @RequiresApi(33)
@Composable @Composable
fun PreferentialNetworkServiceScreen( fun PreferentialNetworkServiceScreen(
getEnabled: () -> Boolean, setEnabled: (Boolean) -> Unit, getEnabled: () -> Boolean, setEnabled: (Boolean) -> Unit,
pnsConfigs: StateFlow<List<PreferentialNetworkServiceInfo>>, getConfigs: () -> Unit, pnsConfigs: StateFlow<List<PreferentialNetworkServiceInfo>>, getConfigs: () -> Unit,
onNavigateUp: () -> Unit, onNavigate: (AddPreferentialNetworkServiceConfig) -> Unit onNavigateUp: () -> Unit, onNavigate: (Destination.AddPreferentialNetworkServiceConfig) -> Unit
) { ) {
var masterEnabled by rememberSaveable { mutableStateOf(getEnabled()) } var masterEnabled by rememberSaveable { mutableStateOf(getEnabled()) }
val configs by pnsConfigs.collectAsStateWithLifecycle() val configs by pnsConfigs.collectAsStateWithLifecycle()
@@ -1647,7 +1644,7 @@ fun PreferentialNetworkServiceScreen(
) { ) {
Text(config.id.toString()) Text(config.id.toString())
IconButton({ IconButton({
onNavigate(AddPreferentialNetworkServiceConfig(index)) onNavigate(Destination.AddPreferentialNetworkServiceConfig(index))
}) { }) {
Icon(Icons.Default.Edit, stringResource(R.string.edit)) Icon(Icons.Default.Edit, stringResource(R.string.edit))
} }
@@ -1656,7 +1653,7 @@ fun PreferentialNetworkServiceScreen(
Row( Row(
Modifier.fillMaxWidth() Modifier.fillMaxWidth()
.padding(top = 4.dp) .padding(top = 4.dp)
.clickable { onNavigate(AddPreferentialNetworkServiceConfig(-1)) } .clickable { onNavigate(Destination.AddPreferentialNetworkServiceConfig(-1)) }
.padding(horizontal = 8.dp, vertical = 12.dp), .padding(horizontal = 8.dp, vertical = 12.dp),
verticalAlignment = Alignment.CenterVertically verticalAlignment = Alignment.CenterVertically
) { ) {
@@ -1675,9 +1672,6 @@ data class PreferentialNetworkServiceInfo(
val includedUids: List<Int> = emptyList() val includedUids: List<Int> = emptyList()
) )
@Serializable
data class AddPreferentialNetworkServiceConfig(val index: Int)
@OptIn(ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterial3Api::class)
@RequiresApi(33) @RequiresApi(33)
@Composable @Composable
@@ -1769,8 +1763,6 @@ fun AddPreferentialNetworkServiceConfigScreen(
} }
} }
@Serializable object OverrideApn
@RequiresApi(28) @RequiresApi(28)
@Composable @Composable
fun OverrideApnScreen( fun OverrideApnScreen(
@@ -1901,8 +1893,6 @@ data class ApnConfig(
val persistent: Boolean, val alwaysOn: Boolean, val id: Int = -1 val persistent: Boolean, val alwaysOn: Boolean, val id: Int = -1
) )
@Serializable data class AddApnSetting(val index: Int)
@OptIn(ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterial3Api::class)
@RequiresApi(28) @RequiresApi(28)
@Composable @Composable

View File

@@ -1,4 +1,4 @@
package com.bintianqi.owndroid.dpm package com.bintianqi.owndroid.ui.screen
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.app.Activity import android.app.Activity
@@ -71,29 +71,37 @@ import com.bintianqi.owndroid.ui.InfoItem
import com.bintianqi.owndroid.ui.MyScaffold import com.bintianqi.owndroid.ui.MyScaffold
import com.bintianqi.owndroid.ui.Notes import com.bintianqi.owndroid.ui.Notes
import com.bintianqi.owndroid.ui.RadioButtonItem import com.bintianqi.owndroid.ui.RadioButtonItem
import com.bintianqi.owndroid.ui.navigation.Destination
import com.bintianqi.owndroid.yesOrNo import com.bintianqi.owndroid.yesOrNo
import kotlinx.serialization.Serializable
@Serializable object Password
@SuppressLint("NewApi") @SuppressLint("NewApi")
@Composable @Composable
fun PasswordScreen(vm: MyViewModel,onNavigateUp: () -> Unit, onNavigate: (Any) -> Unit) { fun PasswordScreen(vm: MyViewModel,onNavigateUp: () -> Unit, onNavigate: (Destination) -> Unit) {
val context = LocalContext.current val context = LocalContext.current
val privilege by Privilege.status.collectAsStateWithLifecycle() val privilege by Privilege.status.collectAsStateWithLifecycle()
var dialog by rememberSaveable { mutableIntStateOf(0) } var dialog by rememberSaveable { mutableIntStateOf(0) }
MyScaffold(R.string.password_and_keyguard, onNavigateUp, 0.dp) { MyScaffold(R.string.password_and_keyguard, onNavigateUp, 0.dp) {
FunctionItem(R.string.password_info, icon = R.drawable.info_fill0) { onNavigate(PasswordInfo) } FunctionItem(R.string.password_info, icon = R.drawable.info_fill0) {
onNavigate(Destination.PasswordInfo)
}
if (SP.displayDangerousFeatures) { if (SP.displayDangerousFeatures) {
if(VERSION.SDK_INT >= 26) { if(VERSION.SDK_INT >= 26) {
FunctionItem(R.string.reset_password_token, icon = R.drawable.key_vertical_fill0) { onNavigate(ResetPasswordToken) } FunctionItem(R.string.reset_password_token, icon = R.drawable.key_vertical_fill0) {
onNavigate(Destination.ResetPasswordToken)
}
}
FunctionItem(R.string.reset_password, icon = R.drawable.lock_reset_fill0) {
onNavigate(Destination.ResetPassword)
} }
FunctionItem(R.string.reset_password, icon = R.drawable.lock_reset_fill0) { onNavigate(ResetPassword) }
} }
if(VERSION.SDK_INT >= 31) { if(VERSION.SDK_INT >= 31) {
FunctionItem(R.string.required_password_complexity, icon = R.drawable.password_fill0) { onNavigate(RequiredPasswordComplexity) } FunctionItem(R.string.required_password_complexity, icon = R.drawable.password_fill0) {
onNavigate(Destination.RequiredPasswordComplexity)
}
}
FunctionItem(R.string.disable_keyguard_features, icon = R.drawable.screen_lock_portrait_fill0) {
onNavigate(Destination.KeyguardDisabledFeatures)
} }
FunctionItem(R.string.disable_keyguard_features, icon = R.drawable.screen_lock_portrait_fill0) { onNavigate(KeyguardDisabledFeatures) }
if(privilege.device) { if(privilege.device) {
FunctionItem(R.string.max_time_to_lock, icon = R.drawable.schedule_fill0) { dialog = 1 } 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.pwd_expiration_timeout, icon = R.drawable.lock_clock_fill0) { dialog = 3 }
@@ -106,7 +114,9 @@ fun PasswordScreen(vm: MyViewModel,onNavigateUp: () -> Unit, onNavigate: (Any) -
} }
FunctionItem(R.string.pwd_history, icon = R.drawable.history_fill0) { dialog = 5 } FunctionItem(R.string.pwd_history, icon = R.drawable.history_fill0) { dialog = 5 }
if(VERSION.SDK_INT < 31) { if(VERSION.SDK_INT < 31) {
FunctionItem(R.string.required_password_quality, icon = R.drawable.password_fill0) { onNavigate(RequiredPasswordQuality) } FunctionItem(R.string.required_password_quality, icon = R.drawable.password_fill0) {
onNavigate(Destination.RequiredPasswordQuality)
}
} }
} }
if(dialog != 0) { if(dialog != 0) {
@@ -205,8 +215,6 @@ enum class PasswordComplexity(val id: Int, val text: Int) {
High(DevicePolicyManager.PASSWORD_COMPLEXITY_HIGH, R.string.high) High(DevicePolicyManager.PASSWORD_COMPLEXITY_HIGH, R.string.high)
} }
@Serializable object PasswordInfo
@Composable @Composable
fun PasswordInfoScreen( fun PasswordInfoScreen(
getComplexity: () -> PasswordComplexity, isSufficient: () -> Boolean, isUnified: () -> Boolean, getComplexity: () -> PasswordComplexity, isSufficient: () -> Boolean, isUnified: () -> Boolean,
@@ -236,8 +244,6 @@ fun PasswordInfoScreen(
data class RpTokenState(val set: Boolean, val active: Boolean) data class RpTokenState(val set: Boolean, val active: Boolean)
@Serializable object ResetPasswordToken
@RequiresApi(26) @RequiresApi(26)
@Composable @Composable
fun ResetPasswordTokenScreen( fun ResetPasswordTokenScreen(
@@ -303,8 +309,6 @@ fun ResetPasswordTokenScreen(
} }
} }
@Serializable object ResetPassword
@Composable @Composable
fun ResetPasswordScreen(resetPassword: (String, String, Int) -> Boolean, onNavigateUp: () -> Unit) { fun ResetPasswordScreen(resetPassword: (String, String, Int) -> Boolean, onNavigateUp: () -> Unit) {
val context = LocalContext.current val context = LocalContext.current
@@ -358,8 +362,6 @@ fun ResetPasswordScreen(resetPassword: (String, String, Int) -> Boolean, onNavig
} }
} }
@Serializable object RequiredPasswordComplexity
@RequiresApi(31) @RequiresApi(31)
@Composable @Composable
fun RequiredPasswordComplexityScreen( fun RequiredPasswordComplexityScreen(
@@ -408,8 +410,6 @@ enum class KeyguardDisableMode(val text: Int) {
data class KeyguardDisableConfig(val mode: KeyguardDisableMode, val flags: Int) data class KeyguardDisableConfig(val mode: KeyguardDisableMode, val flags: Int)
@Serializable object KeyguardDisabledFeatures
@Composable @Composable
fun KeyguardDisabledFeaturesScreen( fun KeyguardDisabledFeaturesScreen(
getConfig: () -> KeyguardDisableConfig, setConfig: (KeyguardDisableConfig) -> Unit, getConfig: () -> KeyguardDisableConfig, setConfig: (KeyguardDisableConfig) -> Unit,
@@ -449,8 +449,6 @@ fun KeyguardDisabledFeaturesScreen(
} }
} }
@Serializable object RequiredPasswordQuality
@Composable @Composable
fun RequiredPasswordQualityScreen(onNavigateUp: () -> Unit) { fun RequiredPasswordQualityScreen(onNavigateUp: () -> Unit) {
val context = LocalContext.current val context = LocalContext.current

View File

@@ -1,4 +1,4 @@
package com.bintianqi.owndroid package com.bintianqi.owndroid.ui.screen
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
@@ -14,6 +14,7 @@ import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.Spacer
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.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.foundation.text.KeyboardOptions
@@ -54,23 +55,31 @@ import androidx.compose.ui.unit.DpOffset
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.core.net.toUri import androidx.core.net.toUri
import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.bintianqi.owndroid.BottomPadding
import com.bintianqi.owndroid.MyNotificationChannel
import com.bintianqi.owndroid.NotificationType
import com.bintianqi.owndroid.Privilege
import com.bintianqi.owndroid.R
import com.bintianqi.owndroid.ThemeSettings
import com.bintianqi.owndroid.adaptiveInsets
import com.bintianqi.owndroid.exportLogs
import com.bintianqi.owndroid.generateBase64Key
import com.bintianqi.owndroid.showOperationResultToast
import com.bintianqi.owndroid.ui.FunctionItem import com.bintianqi.owndroid.ui.FunctionItem
import com.bintianqi.owndroid.ui.MyScaffold import com.bintianqi.owndroid.ui.MyScaffold
import com.bintianqi.owndroid.ui.NavIcon import com.bintianqi.owndroid.ui.NavIcon
import com.bintianqi.owndroid.ui.Notes import com.bintianqi.owndroid.ui.Notes
import com.bintianqi.owndroid.ui.SwitchItem import com.bintianqi.owndroid.ui.SwitchItem
import com.bintianqi.owndroid.ui.navigation.Destination
import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.StateFlow
import kotlinx.serialization.Serializable
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.util.Date import java.util.Date
import java.util.Locale import java.util.Locale
import kotlin.system.exitProcess import kotlin.system.exitProcess
@Serializable object Settings
@OptIn(ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterial3Api::class)
@Composable @Composable
fun SettingsScreen(onNavigateUp: () -> Unit, onNavigate: (Any) -> Unit) { fun SettingsScreen(onNavigate: (Destination) -> Unit, onNavigateUp: () -> Unit) {
val context = LocalContext.current val context = LocalContext.current
val privilege by Privilege.status.collectAsStateWithLifecycle() val privilege by Privilege.status.collectAsStateWithLifecycle()
val exportLogsLauncher = rememberLauncherForActivityResult(ActivityResultContracts.CreateDocument("text/plain")) { val exportLogsLauncher = rememberLauncherForActivityResult(ActivityResultContracts.CreateDocument("text/plain")) {
@@ -120,22 +129,34 @@ fun SettingsScreen(onNavigateUp: () -> Unit, onNavigate: (Any) -> Unit) {
.fillMaxSize() .fillMaxSize()
.padding(paddingValues) .padding(paddingValues)
.verticalScroll(rememberScrollState()) .verticalScroll(rememberScrollState())
.padding(bottom = 80.dp)
) { ) {
FunctionItem(title = R.string.options, icon = R.drawable.tune_fill0) { onNavigate(SettingsOptions) } FunctionItem(R.string.options, icon = R.drawable.tune_fill0) {
FunctionItem(title = R.string.appearance, icon = R.drawable.format_paint_fill0) { onNavigate(Appearance) } onNavigate(Destination.SettingsOptions)
FunctionItem(R.string.app_lock, icon = R.drawable.lock_fill0) { onNavigate(AppLockSettings) } }
if (privilege.device || privilege.profile) FunctionItem(R.string.appearance, icon = R.drawable.format_paint_fill0) {
FunctionItem(title = R.string.api, icon = R.drawable.code_fill0) { onNavigate(ApiSettings) } onNavigate(Destination.AppearanceSettings)
if (privilege.device && !privilege.dhizuku) }
FunctionItem(R.string.notifications, icon = R.drawable.notifications_fill0) { onNavigate(Notifications) } FunctionItem(R.string.app_lock, icon = R.drawable.lock_fill0) {
FunctionItem(title = R.string.about, icon = R.drawable.info_fill0) { onNavigate(About) } onNavigate(Destination.AppLockSettings)
}
if (privilege.device || privilege.profile) {
FunctionItem(R.string.api, icon = R.drawable.code_fill0) {
onNavigate(Destination.ApiSettings)
}
}
if (privilege.device && !privilege.dhizuku) {
FunctionItem(R.string.notifications, icon = R.drawable.notifications_fill0) {
onNavigate(Destination.NotificationSettings)
}
}
FunctionItem(R.string.about, icon = R.drawable.info_fill0) {
onNavigate(Destination.About)
}
Spacer(Modifier.height(BottomPadding))
} }
} }
} }
@Serializable object SettingsOptions
@Composable @Composable
fun SettingsOptionsScreen( fun SettingsOptionsScreen(
getDisplayDangerousFeatures: () -> Boolean, getShortcutsEnabled: () -> Boolean, getDisplayDangerousFeatures: () -> Boolean, getShortcutsEnabled: () -> Boolean,
@@ -160,8 +181,6 @@ fun SettingsOptionsScreen(
} }
} }
@Serializable object Appearance
@Composable @Composable
fun AppearanceScreen( fun AppearanceScreen(
onNavigateUp: () -> Unit, currentTheme: StateFlow<ThemeSettings>, onNavigateUp: () -> Unit, currentTheme: StateFlow<ThemeSettings>,
@@ -225,8 +244,6 @@ data class AppLockConfig(
val password: String?, val biometrics: Boolean, val whenLeaving: Boolean val password: String?, val biometrics: Boolean, val whenLeaving: Boolean
) )
@Serializable object AppLockSettings
@Composable @Composable
fun AppLockSettingsScreen( fun AppLockSettingsScreen(
config: AppLockConfig, setConfig: (AppLockConfig) -> Unit, config: AppLockConfig, setConfig: (AppLockConfig) -> Unit,
@@ -286,8 +303,6 @@ fun AppLockSettingsScreen(
} }
} }
@Serializable object ApiSettings
@Composable @Composable
fun ApiSettings( fun ApiSettings(
getEnabled: () -> Boolean, setKey: (String) -> Unit, onNavigateUp: () -> Unit getEnabled: () -> Boolean, setKey: (String) -> Unit, onNavigateUp: () -> Unit
@@ -326,8 +341,6 @@ fun ApiSettings(
} }
} }
@Serializable object Notifications
@Composable @Composable
fun NotificationsScreen( fun NotificationsScreen(
enabledNotifications: StateFlow<List<Int>>, getState: () -> Unit, enabledNotifications: StateFlow<List<Int>>, getState: () -> Unit,
@@ -344,8 +357,6 @@ fun NotificationsScreen(
} }
} }
@Serializable object About
@Composable @Composable
fun AboutScreen(onNavigateUp: () -> Unit) { fun AboutScreen(onNavigateUp: () -> Unit) {
val context = LocalContext.current val context = LocalContext.current

View File

@@ -1,4 +1,4 @@
package com.bintianqi.owndroid.dpm package com.bintianqi.owndroid.ui.screen
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.app.admin.DevicePolicyManager import android.app.admin.DevicePolicyManager
@@ -131,7 +131,9 @@ import com.bintianqi.owndroid.ui.MyScaffold
import com.bintianqi.owndroid.ui.MySmallTitleScaffold import com.bintianqi.owndroid.ui.MySmallTitleScaffold
import com.bintianqi.owndroid.ui.NavIcon import com.bintianqi.owndroid.ui.NavIcon
import com.bintianqi.owndroid.ui.Notes import com.bintianqi.owndroid.ui.Notes
import com.bintianqi.owndroid.ui.PackageNameTextField
import com.bintianqi.owndroid.ui.SwitchItem import com.bintianqi.owndroid.ui.SwitchItem
import com.bintianqi.owndroid.ui.navigation.Destination
import com.bintianqi.owndroid.yesOrNo import com.bintianqi.owndroid.yesOrNo
import com.google.accompanist.drawablepainter.rememberDrawablePainter import com.google.accompanist.drawablepainter.rememberDrawablePainter
import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.channels.Channel
@@ -139,30 +141,33 @@ import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.serialization.Serializable
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.util.Date import java.util.Date
import java.util.Locale import java.util.Locale
import java.util.TimeZone import java.util.TimeZone
import kotlin.math.roundToLong import kotlin.math.roundToLong
@Serializable object SystemManager
@Composable @Composable
fun SystemManagerScreen( fun SystemManagerScreen(
vm: MyViewModel, onNavigateUp: () -> Unit, onNavigate: (Any) -> Unit vm: MyViewModel, onNavigateUp: () -> Unit, onNavigate: (Destination) -> Unit
) { ) {
val context = LocalContext.current val context = LocalContext.current
val privilege by Privilege.status.collectAsStateWithLifecycle() val privilege by Privilege.status.collectAsStateWithLifecycle()
/** 1: reboot, 2: bug report, 3: org name, 4: org id, 5: enrollment specific id*/ /** 1: reboot, 2: bug report, 3: org name, 4: org id, 5: enrollment specific id*/
var dialog by rememberSaveable { mutableIntStateOf(0) } var dialog by rememberSaveable { mutableIntStateOf(0) }
MyScaffold(R.string.system, onNavigateUp, 0.dp) { MyScaffold(R.string.system, onNavigateUp, 0.dp) {
FunctionItem(R.string.options, icon = R.drawable.tune_fill0) { onNavigate(SystemOptions) } FunctionItem(R.string.options, icon = R.drawable.tune_fill0) {
FunctionItem(R.string.keyguard, icon = R.drawable.screen_lock_portrait_fill0) { onNavigate(Keyguard) } onNavigate(Destination.SystemOptions)
}
FunctionItem(R.string.keyguard, icon = R.drawable.screen_lock_portrait_fill0) {
onNavigate(Destination.Keyguard)
}
if(VERSION.SDK_INT >= 24 && privilege.device && !privilege.dhizuku) if(VERSION.SDK_INT >= 24 && privilege.device && !privilege.dhizuku)
FunctionItem(R.string.hardware_monitor, icon = R.drawable.memory_fill0) { onNavigate(HardwareMonitor) } FunctionItem(R.string.hardware_monitor, icon = R.drawable.memory_fill0) {
onNavigate(Destination.HardwareMonitor)
}
FunctionItem(R.string.default_input_method, icon = R.drawable.keyboard_fill0) { FunctionItem(R.string.default_input_method, icon = R.drawable.keyboard_fill0) {
onNavigate(DefaultInputMethod) onNavigate(Destination.DefaultInputMethod)
} }
if(VERSION.SDK_INT >= 24 && privilege.device) { if(VERSION.SDK_INT >= 24 && privilege.device) {
FunctionItem(R.string.reboot, icon = R.drawable.restart_alt_fill0) { dialog = 1 } FunctionItem(R.string.reboot, icon = R.drawable.restart_alt_fill0) { dialog = 1 }
@@ -171,32 +176,56 @@ fun SystemManagerScreen(
FunctionItem(R.string.bug_report, icon = R.drawable.bug_report_fill0) { dialog = 2 } FunctionItem(R.string.bug_report, icon = R.drawable.bug_report_fill0) { dialog = 2 }
} }
if(VERSION.SDK_INT >= 28 && (privilege.device || privilege.org)) { 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_time, icon = R.drawable.schedule_fill0) {
FunctionItem(R.string.change_timezone, icon = R.drawable.globe_fill0) { onNavigate(ChangeTimeZone) } onNavigate(Destination.ChangeTime)
}
FunctionItem(R.string.change_timezone, icon = R.drawable.globe_fill0) {
onNavigate(Destination.ChangeTimezone)
}
} }
if (VERSION.SDK_INT >= 36 && (privilege.device || privilege.org)) { if (VERSION.SDK_INT >= 36 && (privilege.device || privilege.org)) {
FunctionItem(R.string.auto_time_policy, icon = R.drawable.schedule_fill0) { onNavigate(AutoTimePolicy) } FunctionItem(R.string.auto_time_policy, icon = R.drawable.schedule_fill0) {
FunctionItem(R.string.auto_timezone_policy, icon = R.drawable.globe_fill0) { onNavigate(AutoTimeZonePolicy) } onNavigate(Destination.AutoTimePolicy)
}
FunctionItem(R.string.auto_timezone_policy, icon = R.drawable.globe_fill0) {
onNavigate(Destination.AutoTimezonePolicy)
}
} }
/*if(VERSION.SDK_INT >= 28 && (deviceOwner || profileOwner)) /*if(VERSION.SDK_INT >= 28 && (deviceOwner || profileOwner))
FunctionItem(R.string.key_pairs, icon = R.drawable.key_vertical_fill0) { navCtrl.navigate("KeyPairs") }*/ FunctionItem(R.string.key_pairs, icon = R.drawable.key_vertical_fill0) { navCtrl.navigate("KeyPairs") }*/
if(VERSION.SDK_INT >= 35 && (privilege.device || (privilege.profile && privilege.affiliated))) if(VERSION.SDK_INT >= 35 && (privilege.device || (privilege.profile && privilege.affiliated)))
FunctionItem(R.string.content_protection_policy, icon = R.drawable.search_fill0) { onNavigate(ContentProtectionPolicy) } FunctionItem(R.string.content_protection_policy, icon = R.drawable.search_fill0) {
FunctionItem(R.string.permission_policy, icon = R.drawable.key_fill0) { onNavigate(PermissionPolicy) } onNavigate(Destination.ContentProtectionPolicy)
}
FunctionItem(R.string.permission_policy, icon = R.drawable.key_fill0) {
onNavigate(Destination.PermissionPolicy)
}
if(VERSION.SDK_INT >= 34 && privilege.device) { if(VERSION.SDK_INT >= 34 && privilege.device) {
FunctionItem(R.string.mte_policy, icon = R.drawable.memory_fill0) { onNavigate(MtePolicy) } FunctionItem(R.string.mte_policy, icon = R.drawable.memory_fill0) {
onNavigate(Destination.MtePolicy)
}
} }
if(VERSION.SDK_INT >= 31) { if(VERSION.SDK_INT >= 31) {
FunctionItem(R.string.nearby_streaming_policy, icon = R.drawable.share_fill0) { onNavigate(NearbyStreamingPolicy) } FunctionItem(R.string.nearby_streaming_policy, icon = R.drawable.share_fill0) {
onNavigate(Destination.NearbyStreamingPolicy)
}
} }
if (VERSION.SDK_INT >= 28 && privilege.device) { if (VERSION.SDK_INT >= 28 && privilege.device) {
FunctionItem(R.string.lock_task_mode, icon = R.drawable.lock_fill0) { onNavigate(LockTaskMode) } FunctionItem(R.string.lock_task_mode, icon = R.drawable.lock_fill0) {
onNavigate(Destination.LockTaskMode)
}
}
FunctionItem(R.string.ca_cert, icon = R.drawable.license_fill0) {
onNavigate(Destination.CaCert)
} }
FunctionItem(R.string.ca_cert, icon = R.drawable.license_fill0) { onNavigate(CaCert) }
if(VERSION.SDK_INT >= 26 && !privilege.dhizuku && (privilege.device || privilege.org)) { if(VERSION.SDK_INT >= 26 && !privilege.dhizuku && (privilege.device || privilege.org)) {
FunctionItem(R.string.security_logging, icon = R.drawable.description_fill0) { onNavigate(SecurityLogging) } FunctionItem(R.string.security_logging, icon = R.drawable.description_fill0) {
onNavigate(Destination.SecurityLogging)
}
}
FunctionItem(R.string.device_info, icon = R.drawable.perm_device_information_fill0) {
onNavigate(Destination.DeviceInfo)
} }
FunctionItem(R.string.device_info, icon = R.drawable.perm_device_information_fill0) { onNavigate(DeviceInfo) }
if(VERSION.SDK_INT >= 24 && (privilege.profile || (VERSION.SDK_INT >= 26 && privilege.device))) { 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 = 3 } FunctionItem(R.string.org_name, icon = R.drawable.corporate_fare_fill0) { dialog = 3 }
} }
@@ -207,23 +236,37 @@ fun SystemManagerScreen(
FunctionItem(R.string.enrollment_specific_id, icon = R.drawable.id_card_fill0) { dialog = 5 } FunctionItem(R.string.enrollment_specific_id, icon = R.drawable.id_card_fill0) { dialog = 5 }
} }
if(VERSION.SDK_INT >= 24 && (privilege.device || privilege.org)) { if(VERSION.SDK_INT >= 24 && (privilege.device || privilege.org)) {
FunctionItem(R.string.lock_screen_info, icon = R.drawable.screen_lock_portrait_fill0) { onNavigate(LockScreenInfo) } FunctionItem(R.string.lock_screen_info, icon = R.drawable.screen_lock_portrait_fill0) {
onNavigate(Destination.LockScreenInfo)
}
} }
if(VERSION.SDK_INT >= 24) { if(VERSION.SDK_INT >= 24) {
FunctionItem(R.string.support_messages, icon = R.drawable.chat_fill0) { onNavigate(SupportMessage) } FunctionItem(R.string.support_messages, icon = R.drawable.chat_fill0) {
onNavigate(Destination.SupportMessage)
}
}
FunctionItem(R.string.disable_account_management, icon = R.drawable.account_circle_fill0) {
onNavigate(Destination.DisableAccountManagement)
} }
FunctionItem(R.string.disable_account_management, icon = R.drawable.account_circle_fill0) { onNavigate(DisableAccountManagement) }
if (privilege.device || privilege.org) { if (privilege.device || privilege.org) {
FunctionItem(R.string.system_update_policy, icon = R.drawable.system_update_fill0) { onNavigate(SetSystemUpdatePolicy) } FunctionItem(R.string.system_update_policy, icon = R.drawable.system_update_fill0) {
onNavigate(Destination.SystemUpdatePolicy)
}
} }
if(VERSION.SDK_INT >= 29 && (privilege.device || privilege.org)) { if(VERSION.SDK_INT >= 29 && (privilege.device || privilege.org)) {
FunctionItem(R.string.install_system_update, icon = R.drawable.system_update_fill0) { onNavigate(InstallSystemUpdate) } FunctionItem(R.string.install_system_update, icon = R.drawable.system_update_fill0) {
onNavigate(Destination.InstallSystemUpdate)
}
} }
if(VERSION.SDK_INT >= 30 && (privilege.device || privilege.org)) { if(VERSION.SDK_INT >= 30 && (privilege.device || privilege.org)) {
FunctionItem(R.string.frp_policy, icon = R.drawable.device_reset_fill0) { onNavigate(FrpPolicy) } FunctionItem(R.string.frp_policy, icon = R.drawable.device_reset_fill0) {
onNavigate(Destination.FrpPolicy)
}
} }
if(SP.displayDangerousFeatures && !privilege.work) { if(SP.displayDangerousFeatures && !privilege.work) {
FunctionItem(R.string.wipe_data, icon = R.drawable.device_reset_fill0) { onNavigate(WipeData) } FunctionItem(R.string.wipe_data, icon = R.drawable.device_reset_fill0) {
onNavigate(Destination.WipeData)
}
} }
} }
if((dialog == 1 || dialog == 2) && VERSION.SDK_INT >= 24) AlertDialog( if((dialog == 1 || dialog == 2) && VERSION.SDK_INT >= 24) AlertDialog(
@@ -329,13 +372,11 @@ data class SystemOptionsStatus(
val stayOnWhilePluggedIn: Boolean = false val stayOnWhilePluggedIn: Boolean = false
) )
@Serializable object SystemOptions
class GlobalSetting(val icon: Int, val name: Int, val setting: String) // also for secure settings class GlobalSetting(val icon: Int, val name: Int, val setting: String) // also for secure settings
// STAY_ON_WHILE_PLUGGED_IN is set separately // STAY_ON_WHILE_PLUGGED_IN is set separately
val globalSettings = listOf( val globalSettings = listOf(
GlobalSetting(R.drawable.cell_tower_fill0, R.string.data_roaming, Settings.Global.DATA_ROAMING), //GlobalSetting(R.drawable.cell_tower_fill0, R.string.data_roaming, Settings.Global.DATA_ROAMING),
GlobalSetting(R.drawable.adb_fill0, R.string.enable_adb, Settings.Global.ADB_ENABLED), GlobalSetting(R.drawable.adb_fill0, R.string.enable_adb, Settings.Global.ADB_ENABLED),
GlobalSetting(R.drawable.usb_fill0, R.string.enable_usb_mass_storage, GlobalSetting(R.drawable.usb_fill0, R.string.enable_usb_mass_storage,
Settings.Global.USB_MASS_STORAGE_ENABLED), Settings.Global.USB_MASS_STORAGE_ENABLED),
@@ -457,8 +498,6 @@ fun SystemOptionsScreen(vm: MyViewModel, onNavigateUp: () -> Unit) {
) )
} }
@Serializable object Keyguard
@Composable @Composable
fun KeyguardScreen( fun KeyguardScreen(
setKeyguardDisabled: (Boolean) -> Boolean, lock: (Boolean) -> Unit, onNavigateUp: () -> Unit setKeyguardDisabled: (Boolean) -> Boolean, lock: (Boolean) -> Unit, onNavigateUp: () -> Unit
@@ -519,8 +558,6 @@ val temperatureTypes = mapOf(
HardwarePropertiesManager.DEVICE_TEMPERATURE_SKIN to R.string.skin_temp HardwarePropertiesManager.DEVICE_TEMPERATURE_SKIN to R.string.skin_temp
) )
@Serializable object HardwareMonitor
@RequiresApi(24) @RequiresApi(24)
@Composable @Composable
fun HardwareMonitorScreen( fun HardwareMonitorScreen(
@@ -586,8 +623,6 @@ fun HardwareMonitorScreen(
} }
} }
@Serializable object DefaultInputMethod
@Composable @Composable
fun DefaultInputMethodScreen( fun DefaultInputMethodScreen(
getCurrentIm: () -> String, imListState: StateFlow<List<Pair<String, AppInfo>>>, getCurrentIm: () -> String, imListState: StateFlow<List<Pair<String, AppInfo>>>,
@@ -632,8 +667,6 @@ fun DefaultInputMethodScreen(
} }
} }
@Serializable object ChangeTime
@OptIn(ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterial3Api::class)
@RequiresApi(28) @RequiresApi(28)
@Composable @Composable
@@ -768,8 +801,6 @@ fun ChangeTimeScreen(setTime: (Long, Boolean) -> Boolean, onNavigateUp: () -> Un
} }
} }
@Serializable object ChangeTimeZone
@RequiresApi(28) @RequiresApi(28)
@Composable @Composable
fun ChangeTimeZoneScreen(setTimeZone: (String) -> Boolean, onNavigateUp: () -> Unit) { fun ChangeTimeZoneScreen(setTimeZone: (String) -> Boolean, onNavigateUp: () -> Unit) {
@@ -835,8 +866,6 @@ fun ChangeTimeZoneScreen(setTimeZone: (String) -> Boolean, onNavigateUp: () -> U
) )
} }
@Serializable object AutoTimePolicy
@RequiresApi(36) @RequiresApi(36)
@Composable @Composable
fun AutoTimePolicyScreen( fun AutoTimePolicyScreen(
@@ -866,8 +895,6 @@ fun AutoTimePolicyScreen(
} }
} }
@Serializable object AutoTimeZonePolicy
@RequiresApi(36) @RequiresApi(36)
@Composable @Composable
fun AutoTimeZonePolicyScreen( fun AutoTimeZonePolicyScreen(
@@ -1074,8 +1101,6 @@ fun KeyPairs(navCtrl: NavHostController) {
} }
}*/ }*/
@Serializable object ContentProtectionPolicy
@RequiresApi(35) @RequiresApi(35)
@Composable @Composable
fun ContentProtectionPolicyScreen( fun ContentProtectionPolicyScreen(
@@ -1106,8 +1131,6 @@ fun ContentProtectionPolicyScreen(
} }
} }
@Serializable object PermissionPolicy
@Composable @Composable
fun PermissionPolicyScreen( fun PermissionPolicyScreen(
getPolicy: () -> Int, setPolicy: (Int) -> Unit, onNavigateUp: () -> Unit getPolicy: () -> Int, setPolicy: (Int) -> Unit, onNavigateUp: () -> Unit
@@ -1139,8 +1162,6 @@ fun PermissionPolicyScreen(
} }
} }
@Serializable object MtePolicy
@RequiresApi(34) @RequiresApi(34)
@Composable @Composable
fun MtePolicyScreen( fun MtePolicyScreen(
@@ -1167,8 +1188,6 @@ fun MtePolicyScreen(
} }
} }
@Serializable object NearbyStreamingPolicy
@RequiresApi(31) @RequiresApi(31)
@Composable @Composable
fun NearbyStreamingPolicyScreen( fun NearbyStreamingPolicyScreen(
@@ -1241,8 +1260,6 @@ fun NearbyStreamingPolicyScreen(
} }
} }
@Serializable object LockTaskMode
@OptIn(ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterial3Api::class)
@RequiresApi(28) @RequiresApi(28)
@Composable @Composable
@@ -1467,8 +1484,6 @@ data class CaCertInfo(
val bytes: ByteArray val bytes: ByteArray
) )
@Serializable object CaCert
@OptIn(ExperimentalMaterial3Api::class, ExperimentalStdlibApi::class) @OptIn(ExperimentalMaterial3Api::class, ExperimentalStdlibApi::class)
@Composable @Composable
fun CaCertScreen( fun CaCertScreen(
@@ -1639,8 +1654,6 @@ fun CaCertScreen(
} }
} }
@Serializable object SecurityLogging
@RequiresApi(24) @RequiresApi(24)
@Composable @Composable
fun SecurityLoggingScreen( fun SecurityLoggingScreen(
@@ -1745,8 +1758,6 @@ fun SecurityLoggingScreen(
) )
} }
@Serializable object DisableAccountManagement
@Composable @Composable
fun DisableAccountManagementScreen( fun DisableAccountManagementScreen(
mdAccounts: StateFlow<List<String>>, getMdAccounts: () -> Unit, mdAccounts: StateFlow<List<String>>, getMdAccounts: () -> Unit,
@@ -1798,8 +1809,6 @@ data class FrpPolicyInfo(
val accounts: List<String> val accounts: List<String>
) )
@Serializable object FrpPolicy
@RequiresApi(30) @RequiresApi(30)
@Composable @Composable
fun FrpPolicyScreen( fun FrpPolicyScreen(
@@ -1874,8 +1883,6 @@ fun FrpPolicyScreen(
} }
} }
@Serializable object WipeData
@Composable @Composable
fun WipeDataScreen( fun WipeDataScreen(
wipeData: (Boolean, Int, String) -> Unit, onNavigateUp: () -> Unit wipeData: (Boolean, Int, String) -> Unit, onNavigateUp: () -> Unit
@@ -1988,8 +1995,6 @@ fun WipeDataScreen(
data class SystemUpdatePolicyInfo(val type: Int, val start: Int, val end: Int) data class SystemUpdatePolicyInfo(val type: Int, val start: Int, val end: Int)
data class PendingSystemUpdateInfo(val exists: Boolean, val time: Long, val securityPatch: Boolean) data class PendingSystemUpdateInfo(val exists: Boolean, val time: Long, val securityPatch: Boolean)
@Serializable object SetSystemUpdatePolicy
@Composable @Composable
fun SystemUpdatePolicyScreen( fun SystemUpdatePolicyScreen(
getPolicy: () -> SystemUpdatePolicyInfo, setPolicy: (SystemUpdatePolicyInfo) -> Unit, getPolicy: () -> SystemUpdatePolicyInfo, setPolicy: (SystemUpdatePolicyInfo) -> Unit,
@@ -2083,8 +2088,6 @@ fun SystemUpdatePolicyScreen(
} }
} }
@Serializable object InstallSystemUpdate
@SuppressLint("NewApi") @SuppressLint("NewApi")
@Composable @Composable
fun InstallSystemUpdateScreen( fun InstallSystemUpdateScreen(

View File

@@ -1,4 +1,4 @@
package com.bintianqi.owndroid.dpm package com.bintianqi.owndroid.ui.screen
import androidx.annotation.RequiresApi import androidx.annotation.RequiresApi
import androidx.compose.foundation.background import androidx.compose.foundation.background
@@ -63,6 +63,7 @@ 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 com.bintianqi.owndroid.ui.navigation.Destination
import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.StateFlow
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
@@ -74,13 +75,11 @@ data class Restriction(
val requiresApi: Int = 0 val requiresApi: Int = 0
) )
@Serializable object UserRestriction
@OptIn(ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterial3Api::class)
@RequiresApi(24) @RequiresApi(24)
@Composable @Composable
fun UserRestrictionScreen( fun UserRestrictionScreen(
getRestrictions: () -> Unit,onNavigateUp: () -> Unit, onNavigate: (Any) -> Unit getRestrictions: () -> Unit,onNavigateUp: () -> Unit, onNavigate: (Destination) -> Unit
) { ) {
val privilege by Privilege.status.collectAsStateWithLifecycle() val privilege by Privilege.status.collectAsStateWithLifecycle()
val sb = TopAppBarDefaults.exitUntilCollapsedScrollBehavior() val sb = TopAppBarDefaults.exitUntilCollapsedScrollBehavior()
@@ -92,7 +91,7 @@ fun UserRestrictionScreen(
{ Text(stringResource(R.string.user_restriction)) }, { Text(stringResource(R.string.user_restriction)) },
navigationIcon = { NavIcon(onNavigateUp) }, navigationIcon = { NavIcon(onNavigateUp) },
actions = { actions = {
IconButton({ onNavigate(UserRestrictionEditor) }) { IconButton({ onNavigate(Destination.UserRestrictionEditor) }) {
Icon(Icons.Default.Edit, null) Icon(Icons.Default.Edit, null)
} }
}, },
@@ -119,7 +118,7 @@ fun UserRestrictionScreen(
Spacer(Modifier.padding(vertical = 2.dp)) Spacer(Modifier.padding(vertical = 2.dp))
UserRestrictionCategory.entries.forEach { UserRestrictionCategory.entries.forEach {
FunctionItem(it.title, icon = it.icon) { FunctionItem(it.title, icon = it.icon) {
onNavigate(UserRestrictionOptions(it.name)) onNavigate(Destination.UserRestrictionOptions(it.name))
} }
} }
Row( Row(
@@ -137,13 +136,10 @@ fun UserRestrictionScreen(
} }
} }
@Serializable
data class UserRestrictionOptions(val id: String)
@RequiresApi(24) @RequiresApi(24)
@Composable @Composable
fun UserRestrictionOptionsScreen( fun UserRestrictionOptionsScreen(
args: UserRestrictionOptions, userRestrictions: StateFlow<Map<String, Boolean>>, args: Destination.UserRestrictionOptions, userRestrictions: StateFlow<Map<String, Boolean>>,
setRestriction: (String, Boolean) -> Boolean, setShortcut: (String) -> Boolean, setRestriction: (String, Boolean) -> Boolean, setShortcut: (String) -> Boolean,
onNavigateUp: () -> Unit onNavigateUp: () -> Unit
) { ) {
@@ -188,8 +184,6 @@ fun UserRestrictionOptionsScreen(
} }
} }
@Serializable object UserRestrictionEditor
@OptIn(ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterial3Api::class)
@RequiresApi(24) @RequiresApi(24)
@Composable @Composable

View File

@@ -1,4 +1,4 @@
package com.bintianqi.owndroid.dpm package com.bintianqi.owndroid.ui.screen
import android.app.admin.DevicePolicyManager import android.app.admin.DevicePolicyManager
import android.graphics.Bitmap import android.graphics.Bitmap
@@ -77,15 +77,13 @@ import com.bintianqi.owndroid.ui.ListItem
import com.bintianqi.owndroid.ui.MyScaffold import com.bintianqi.owndroid.ui.MyScaffold
import com.bintianqi.owndroid.ui.Notes import com.bintianqi.owndroid.ui.Notes
import com.bintianqi.owndroid.ui.SwitchItem import com.bintianqi.owndroid.ui.SwitchItem
import com.bintianqi.owndroid.ui.navigation.Destination
import com.bintianqi.owndroid.uriToStream import com.bintianqi.owndroid.uriToStream
import com.bintianqi.owndroid.yesOrNo import com.bintianqi.owndroid.yesOrNo
import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.StateFlow
import kotlinx.serialization.Serializable
@Serializable object Users
@Composable @Composable
fun UsersScreen(vm: MyViewModel, onNavigateUp: () -> Unit, onNavigate: (Any) -> Unit) { fun UsersScreen(vm: MyViewModel, onNavigateUp: () -> Unit, onNavigate: (Destination) -> Unit) {
val context = LocalContext.current val context = LocalContext.current
val privilege by Privilege.status.collectAsStateWithLifecycle() val privilege by Privilege.status.collectAsStateWithLifecycle()
/** 1: logout */ /** 1: logout */
@@ -94,17 +92,27 @@ fun UsersScreen(vm: MyViewModel, onNavigateUp: () -> Unit, onNavigate: (Any) ->
if(VERSION.SDK_INT >= 28 && privilege.profile && privilege.affiliated) { if(VERSION.SDK_INT >= 28 && privilege.profile && privilege.affiliated) {
FunctionItem(R.string.logout, icon = R.drawable.logout_fill0) { dialog = 1 } FunctionItem(R.string.logout, icon = R.drawable.logout_fill0) { dialog = 1 }
} }
FunctionItem(R.string.user_info, icon = R.drawable.person_fill0) { onNavigate(UserInfo) } FunctionItem(R.string.user_info, icon = R.drawable.person_fill0) {
onNavigate(Destination.UserInfo)
}
if(VERSION.SDK_INT >= 28 && privilege.device) { if(VERSION.SDK_INT >= 28 && privilege.device) {
FunctionItem(R.string.options, icon = R.drawable.tune_fill0) { onNavigate(UsersOptions) } FunctionItem(R.string.options, icon = R.drawable.tune_fill0) {
onNavigate(Destination.UsersOptions)
}
} }
if(privilege.device) { if(privilege.device) {
FunctionItem(R.string.user_operation, icon = R.drawable.sync_alt_fill0) { onNavigate(UserOperation) } FunctionItem(R.string.user_operation, icon = R.drawable.sync_alt_fill0) {
onNavigate(Destination.UserOperation)
}
} }
if(VERSION.SDK_INT >= 24 && privilege.device) { if(VERSION.SDK_INT >= 24 && privilege.device) {
FunctionItem(R.string.create_user, icon = R.drawable.person_add_fill0) { onNavigate(CreateUser) } FunctionItem(R.string.create_user, icon = R.drawable.person_add_fill0) {
onNavigate(Destination.CreateUser)
}
}
FunctionItem(R.string.change_username, icon = R.drawable.edit_fill0) {
onNavigate(Destination.ChangeUsername)
} }
FunctionItem(R.string.change_username, icon = R.drawable.edit_fill0) { onNavigate(ChangeUsername) }
var changeUserIconDialog by remember { mutableStateOf(false) } var changeUserIconDialog by remember { mutableStateOf(false) }
var bitmap: Bitmap? by remember { mutableStateOf(null) } var bitmap: Bitmap? by remember { mutableStateOf(null) }
val launcher = rememberLauncherForActivityResult(ActivityResultContracts.GetContent()) { val launcher = rememberLauncherForActivityResult(ActivityResultContracts.GetContent()) {
@@ -123,10 +131,14 @@ fun UsersScreen(vm: MyViewModel, onNavigateUp: () -> Unit, onNavigate: (Any) ->
changeUserIconDialog = false changeUserIconDialog = false
}) { changeUserIconDialog = false } }) { changeUserIconDialog = false }
if(VERSION.SDK_INT >= 28 && privilege.device) { if(VERSION.SDK_INT >= 28 && privilege.device) {
FunctionItem(R.string.user_session_msg, icon = R.drawable.notifications_fill0) { onNavigate(UserSessionMessage) } FunctionItem(R.string.user_session_msg, icon = R.drawable.notifications_fill0) {
onNavigate(Destination.UserSessionMessage)
}
} }
if(VERSION.SDK_INT >= 26) { if(VERSION.SDK_INT >= 26) {
FunctionItem(R.string.affiliation_id, icon = R.drawable.id_card_fill0) { onNavigate(AffiliationId) } FunctionItem(R.string.affiliation_id, icon = R.drawable.id_card_fill0) {
onNavigate(Destination.AffiliationId)
}
} }
} }
if (VERSION.SDK_INT >= 28 && dialog == 1) AlertDialog( if (VERSION.SDK_INT >= 28 && dialog == 1) AlertDialog(
@@ -151,8 +163,6 @@ fun UsersScreen(vm: MyViewModel, onNavigateUp: () -> Unit, onNavigate: (Any) ->
) )
} }
@Serializable object UsersOptions
@Composable @Composable
fun UsersOptionsScreen( fun UsersOptionsScreen(
getLogoutEnabled: () -> Boolean, setLogoutEnabled: (Boolean) -> Unit, onNavigateUp: () -> Unit getLogoutEnabled: () -> Boolean, setLogoutEnabled: (Boolean) -> Unit, onNavigateUp: () -> Unit
@@ -176,8 +186,6 @@ data class UserInformation(
val serial: Long = 0 val serial: Long = 0
) )
@Serializable object UserInfo
@Composable @Composable
fun UserInfoScreen(getInfo: () -> UserInformation, onNavigateUp: () -> Unit) { fun UserInfoScreen(getInfo: () -> UserInformation, onNavigateUp: () -> Unit) {
var info by remember { mutableStateOf(UserInformation()) } var info by remember { mutableStateOf(UserInformation()) }
@@ -219,8 +227,6 @@ enum class UserOperationType {
Start, Switch, Stop, Delete Start, Switch, Stop, Delete
} }
@Serializable object UserOperation
@OptIn(ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterial3Api::class)
@Composable @Composable
fun UserOperationScreen( fun UserOperationScreen(
@@ -370,8 +376,6 @@ fun UserOperationScreen(
data class CreateUserResult(val message: Int, val serial: Long = -1) data class CreateUserResult(val message: Int, val serial: Long = -1)
@Serializable object CreateUser
@RequiresApi(24) @RequiresApi(24)
@Composable @Composable
fun CreateUserScreen( fun CreateUserScreen(
@@ -436,8 +440,6 @@ fun CreateUserScreen(
} }
} }
@Serializable object AffiliationId
@RequiresApi(26) @RequiresApi(26)
@Composable @Composable
fun AffiliationIdScreen( fun AffiliationIdScreen(
@@ -478,8 +480,6 @@ fun AffiliationIdScreen(
} }
} }
@Serializable object ChangeUsername
@Composable @Composable
fun ChangeUsernameScreen(setName: (String) -> Unit, onNavigateUp: () -> Unit) { fun ChangeUsernameScreen(setName: (String) -> Unit, onNavigateUp: () -> Unit) {
val context = LocalContext.current val context = LocalContext.current
@@ -507,8 +507,6 @@ fun ChangeUsernameScreen(setName: (String) -> Unit, onNavigateUp: () -> Unit) {
} }
} }
@Serializable object UserSessionMessage
@RequiresApi(28) @RequiresApi(28)
@Composable @Composable
fun UserSessionMessageScreen( fun UserSessionMessageScreen(

View File

@@ -1,4 +1,4 @@
package com.bintianqi.owndroid.dpm package com.bintianqi.owndroid.ui.screen
import android.app.admin.DevicePolicyManager import android.app.admin.DevicePolicyManager
import android.app.admin.DevicePolicyManager.WIPE_EUICC import android.app.admin.DevicePolicyManager.WIPE_EUICC
@@ -77,23 +77,30 @@ import com.bintianqi.owndroid.ui.MyScaffold
import com.bintianqi.owndroid.ui.NavIcon import com.bintianqi.owndroid.ui.NavIcon
import com.bintianqi.owndroid.ui.Notes import com.bintianqi.owndroid.ui.Notes
import com.bintianqi.owndroid.ui.SwitchItem import com.bintianqi.owndroid.ui.SwitchItem
import com.bintianqi.owndroid.ui.navigation.Destination
import com.bintianqi.owndroid.yesOrNo import com.bintianqi.owndroid.yesOrNo
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
@Serializable object WorkProfile
@Composable @Composable
fun WorkProfileScreen(onNavigateUp: () -> Unit, onNavigate: (Any) -> Unit) { fun WorkProfileScreen(onNavigateUp: () -> Unit, onNavigate: (Destination) -> Unit) {
val privilege by Privilege.status.collectAsStateWithLifecycle() val privilege by Privilege.status.collectAsStateWithLifecycle()
MyScaffold(R.string.work_profile, onNavigateUp, 0.dp) { MyScaffold(R.string.work_profile, onNavigateUp, 0.dp) {
if(VERSION.SDK_INT >= 30 && !privilege.org) { if(VERSION.SDK_INT >= 30 && !privilege.org) {
FunctionItem(R.string.org_owned_work_profile, icon = R.drawable.corporate_fare_fill0) { onNavigate(OrganizationOwnedProfile) } FunctionItem(R.string.org_owned_work_profile, icon = R.drawable.corporate_fare_fill0) {
onNavigate(Destination.OrganizationOwnedProfile)
}
} }
if(privilege.org) { if(privilege.org) {
FunctionItem(R.string.suspend_personal_app, icon = R.drawable.block_fill0) { onNavigate(SuspendPersonalApp) } FunctionItem(R.string.suspend_personal_app, icon = R.drawable.block_fill0) {
onNavigate(Destination.SuspendPersonalApp)
}
}
FunctionItem(R.string.intent_filter, icon = R.drawable.filter_alt_fill0) {
onNavigate(Destination.CrossProfileIntentFilter)
}
FunctionItem(R.string.delete_work_profile, icon = R.drawable.delete_forever_fill0) {
onNavigate(Destination.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) }
} }
} }
@@ -102,8 +109,6 @@ data class CreateWorkProfileOptions(
val accountName: String, val accountType: String, val keepAccount: Boolean val accountName: String, val accountType: String, val keepAccount: Boolean
) )
@Serializable object CreateWorkProfile
@Composable @Composable
fun CreateWorkProfileScreen( fun CreateWorkProfileScreen(
createIntent: (CreateWorkProfileOptions) -> Intent, onNavigateUp: () -> Unit createIntent: (CreateWorkProfileOptions) -> Intent, onNavigateUp: () -> Unit
@@ -165,8 +170,6 @@ fun CreateWorkProfileScreen(
} }
} }
@Serializable object OrganizationOwnedProfile
@RequiresApi(30) @RequiresApi(30)
@Composable @Composable
fun OrganizationOwnedProfileScreen( fun OrganizationOwnedProfileScreen(
@@ -205,8 +208,6 @@ fun OrganizationOwnedProfileScreen(
val activateOrgProfileCommand = "dpm mark-profile-owner-on-organization-owned-device --user " + val activateOrgProfileCommand = "dpm mark-profile-owner-on-organization-owned-device --user " +
"${Binder.getCallingUid()/100000} com.bintianqi.owndroid/com.bintianqi.owndroid.Receiver" "${Binder.getCallingUid()/100000} com.bintianqi.owndroid/com.bintianqi.owndroid.Receiver"
@Serializable object SuspendPersonalApp
@RequiresApi(30) @RequiresApi(30)
@Composable @Composable
fun SuspendPersonalAppScreen( fun SuspendPersonalAppScreen(
@@ -267,8 +268,6 @@ val crossProfileIntentFilterPresets = mapOf(
IntentFilterOptions(Intent.ACTION_SEND, Intent.CATEGORY_DEFAULT, "*/*", 3) IntentFilterOptions(Intent.ACTION_SEND, Intent.CATEGORY_DEFAULT, "*/*", 3)
) )
@Serializable object CrossProfileIntentFilter
@OptIn(ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterial3Api::class)
@Composable @Composable
fun CrossProfileIntentFilterScreen( fun CrossProfileIntentFilterScreen(
@@ -452,8 +451,6 @@ fun CrossProfileIntentFilterScreen(
} }
} }
@Serializable object DeleteWorkProfile
@Composable @Composable
fun DeleteWorkProfileScreen( fun DeleteWorkProfileScreen(
deleteProfile: (Boolean, Int, String) -> Unit, onNavigateUp: () -> Unit deleteProfile: (Boolean, Int, String) -> Unit, onNavigateUp: () -> Unit

View File

@@ -1,4 +1,4 @@
package com.bintianqi.owndroid.dpm package com.bintianqi.owndroid.ui.screen
import android.app.admin.DevicePolicyManager import android.app.admin.DevicePolicyManager
import android.content.ComponentName import android.content.ComponentName
@@ -88,8 +88,10 @@ import com.bintianqi.owndroid.HorizontalPadding
import com.bintianqi.owndroid.MyViewModel import com.bintianqi.owndroid.MyViewModel
import com.bintianqi.owndroid.Privilege import com.bintianqi.owndroid.Privilege
import com.bintianqi.owndroid.R import com.bintianqi.owndroid.R
import com.bintianqi.owndroid.Settings
import com.bintianqi.owndroid.adaptiveInsets import com.bintianqi.owndroid.adaptiveInsets
import com.bintianqi.owndroid.dpm.ACTIVATE_DEVICE_OWNER_COMMAND
import com.bintianqi.owndroid.dpm.DelegatedAdmin
import com.bintianqi.owndroid.dpm.DeviceAdmin
import com.bintianqi.owndroid.showOperationResultToast import com.bintianqi.owndroid.showOperationResultToast
import com.bintianqi.owndroid.ui.CircularProgressDialog import com.bintianqi.owndroid.ui.CircularProgressDialog
import com.bintianqi.owndroid.ui.InfoItem import com.bintianqi.owndroid.ui.InfoItem
@@ -98,21 +100,20 @@ import com.bintianqi.owndroid.ui.MyScaffold
import com.bintianqi.owndroid.ui.MySmallTitleScaffold import com.bintianqi.owndroid.ui.MySmallTitleScaffold
import com.bintianqi.owndroid.ui.NavIcon import com.bintianqi.owndroid.ui.NavIcon
import com.bintianqi.owndroid.ui.Notes import com.bintianqi.owndroid.ui.Notes
import com.bintianqi.owndroid.ui.PackageNameTextField
import com.bintianqi.owndroid.ui.SwitchItem import com.bintianqi.owndroid.ui.SwitchItem
import com.bintianqi.owndroid.ui.navigation.Destination
import com.bintianqi.owndroid.yesOrNo import com.bintianqi.owndroid.yesOrNo
import com.google.accompanist.drawablepainter.rememberDrawablePainter import com.google.accompanist.drawablepainter.rememberDrawablePainter
import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.StateFlow
import kotlinx.serialization.Serializable
@Serializable data class WorkModes(val canNavigateUp: Boolean)
@OptIn(ExperimentalMaterial3Api::class, ExperimentalLayoutApi::class) @OptIn(ExperimentalMaterial3Api::class, ExperimentalLayoutApi::class)
@Composable @Composable
fun WorkModesScreen( fun WorkModesScreen(
vm: MyViewModel, params: WorkModes, onNavigateUp: () -> Unit, onActivate: () -> Unit, vm: MyViewModel, params: Destination.WorkingModes, onNavigateUp: () -> Unit,
onDeactivate: () -> Unit, onNavigate: (Any) -> Unit onActivate: () -> Unit, onDeactivate: () -> Unit, onNavigate: (Destination) -> Unit
) { ) {
val privilege by Privilege.status.collectAsStateWithLifecycle() val privilege by Privilege.status.collectAsStateWithLifecycle()
/** 0: none, 1: device owner, 2: circular progress indicator, 3: result, 4: deactivate, 5: command */ /** 0: none, 1: device owner, 2: circular progress indicator, 3: result, 4: deactivate, 5: command */
@@ -162,7 +163,7 @@ fun WorkModesScreen(
{ Text(stringResource(R.string.delegated_admins)) }, { Text(stringResource(R.string.delegated_admins)) },
{ {
expanded = false expanded = false
onNavigate(DelegatedAdmins) onNavigate(Destination.DelegatedAdmins)
}, },
leadingIcon = { Icon(painterResource(R.drawable.admin_panel_settings_fill0), null) } leadingIcon = { Icon(painterResource(R.drawable.admin_panel_settings_fill0), null) }
) )
@@ -170,13 +171,13 @@ fun WorkModesScreen(
{ Text(stringResource(R.string.transfer_ownership)) }, { Text(stringResource(R.string.transfer_ownership)) },
{ {
expanded = false expanded = false
onNavigate(TransferOwnership) onNavigate(Destination.TransferOwnership)
}, },
leadingIcon = { Icon(painterResource(R.drawable.swap_horiz_fill0), null) } leadingIcon = { Icon(painterResource(R.drawable.swap_horiz_fill0), null) }
) )
} }
} }
if(!params.canNavigateUp) IconButton({ onNavigate(Settings) }) { if(!params.canNavigateUp) IconButton({ onNavigate(Destination.Settings) }) {
Icon(Icons.Default.Settings, null) Icon(Icons.Default.Settings, null)
} }
} }
@@ -210,14 +211,14 @@ fun WorkModesScreen(
privilege.work || (VERSION.SDK_INT < 24 || vm.isCreatingWorkProfileAllowed()) privilege.work || (VERSION.SDK_INT < 24 || vm.isCreatingWorkProfileAllowed())
) { ) {
WorkingModeItem(R.string.work_profile, privilege.work) { WorkingModeItem(R.string.work_profile, privilege.work) {
if (!privilege.work) onNavigate(CreateWorkProfile) if (!privilege.work) onNavigate(Destination.CreateWorkProfile)
} }
} }
if (privilege.activated && !privilege.dhizuku) Row( if (privilege.activated && !privilege.dhizuku) Row(
Modifier Modifier
.padding(top = 20.dp) .padding(top = 20.dp)
.fillMaxWidth() .fillMaxWidth()
.clickable { onNavigate(DhizukuServerSettings) } .clickable { onNavigate(Destination.DhizukuServerSettings) }
.padding(vertical = 4.dp), .padding(vertical = 4.dp),
verticalAlignment = Alignment.CenterVertically verticalAlignment = Alignment.CenterVertically
) { ) {
@@ -357,10 +358,6 @@ fun WorkingModeItem(text: Int, active: Boolean, onClick: () -> Unit) {
} }
} }
const val ACTIVATE_DEVICE_OWNER_COMMAND = "dpm set-device-owner com.bintianqi.owndroid/.Receiver"
@Serializable object DhizukuServerSettings
@Composable @Composable
fun DhizukuServerSettingsScreen( fun DhizukuServerSettingsScreen(
dhizukuClients: StateFlow<List<Pair<DhizukuClientInfo, AppInfo>>>, dhizukuClients: StateFlow<List<Pair<DhizukuClientInfo, AppInfo>>>,
@@ -446,8 +443,6 @@ fun DhizukuServerSettingsScreen(
} }
} }
@Serializable object LockScreenInfo
@RequiresApi(24) @RequiresApi(24)
@Composable @Composable
fun LockScreenInfoScreen( fun LockScreenInfoScreen(
@@ -509,15 +504,11 @@ val delegatedScopesList = listOf(
DelegatedScope(DevicePolicyManager.DELEGATION_SECURITY_LOGGING, R.string.security_logging, 31) DelegatedScope(DevicePolicyManager.DELEGATION_SECURITY_LOGGING, R.string.security_logging, 31)
).filter { VERSION.SDK_INT >= it.requiresApi } ).filter { VERSION.SDK_INT >= it.requiresApi }
data class DelegatedAdmin(val app: AppInfo, val scopes: List<String>)
@Serializable object DelegatedAdmins
@RequiresApi(26) @RequiresApi(26)
@Composable @Composable
fun DelegatedAdminsScreen( fun DelegatedAdminsScreen(
delegatedAdmins: StateFlow<List<DelegatedAdmin>>, getDelegatedAdmins: () -> Unit, delegatedAdmins: StateFlow<List<DelegatedAdmin>>, getDelegatedAdmins: () -> Unit,
onNavigateUp: () -> Unit, onNavigate: (AddDelegatedAdmin) -> Unit onNavigateUp: () -> Unit, onNavigate: (Destination.DelegatedAdminDetails) -> Unit
) { ) {
val admins by delegatedAdmins.collectAsStateWithLifecycle() val admins by delegatedAdmins.collectAsStateWithLifecycle()
LaunchedEffect(Unit) { getDelegatedAdmins() } LaunchedEffect(Unit) { getDelegatedAdmins() }
@@ -537,7 +528,7 @@ fun DelegatedAdminsScreen(
Text(app.name, Modifier.alpha(0.8F), style = typography.bodyMedium) Text(app.name, Modifier.alpha(0.8F), style = typography.bodyMedium)
} }
} }
IconButton({ onNavigate(AddDelegatedAdmin(app.name, scopes)) }) { IconButton({ onNavigate(Destination.DelegatedAdminDetails(app.name, scopes)) }) {
Icon(Icons.Outlined.Edit, null) Icon(Icons.Outlined.Edit, null)
} }
} }
@@ -546,7 +537,7 @@ fun DelegatedAdminsScreen(
Row( Row(
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.clickable { onNavigate(AddDelegatedAdmin()) } .clickable { onNavigate(Destination.DelegatedAdminDetails("", emptyList())) }
.padding(12.dp), .padding(12.dp),
verticalAlignment = Alignment.CenterVertically verticalAlignment = Alignment.CenterVertically
) { ) {
@@ -557,12 +548,10 @@ fun DelegatedAdminsScreen(
} }
} }
@Serializable data class AddDelegatedAdmin(val pkg: String = "", val scopes: List<String> = emptyList())
@RequiresApi(26) @RequiresApi(26)
@Composable @Composable
fun AddDelegatedAdminScreen( fun AddDelegatedAdminScreen(
chosenPackage: Channel<String>, onChoosePackage: () -> Unit, data: AddDelegatedAdmin, chosenPackage: Channel<String>, onChoosePackage: () -> Unit, data: Destination.DelegatedAdminDetails,
setDelegatedAdmin: (String, List<String>) -> Unit, onNavigateUp: () -> Unit setDelegatedAdmin: (String, List<String>) -> Unit, onNavigateUp: () -> Unit
) { ) {
val updateMode = data.pkg.isNotEmpty() val updateMode = data.pkg.isNotEmpty()
@@ -620,8 +609,6 @@ fun AddDelegatedAdminScreen(
} }
} }
@Serializable object DeviceInfo
@Composable @Composable
fun DeviceInfoScreen(vm: MyViewModel, onNavigateUp: () -> Unit) { fun DeviceInfoScreen(vm: MyViewModel, onNavigateUp: () -> Unit) {
val privilege by Privilege.status.collectAsStateWithLifecycle() val privilege by Privilege.status.collectAsStateWithLifecycle()
@@ -657,8 +644,6 @@ fun DeviceInfoScreen(vm: MyViewModel, onNavigateUp: () -> Unit) {
) )
} }
@Serializable object SupportMessage
@RequiresApi(24) @RequiresApi(24)
@Composable @Composable
fun SupportMessageScreen( fun SupportMessageScreen(
@@ -739,10 +724,6 @@ fun SupportMessageScreen(
} }
} }
data class DeviceAdmin(val app: AppInfo, val admin: ComponentName)
@Serializable object TransferOwnership
@RequiresApi(28) @RequiresApi(28)
@Composable @Composable
fun TransferOwnershipScreen( fun TransferOwnershipScreen(

View File

@@ -2,7 +2,7 @@
agp = "9.0.1" agp = "9.0.1"
kotlin = "2.3.10" kotlin = "2.3.10"
navigation-compose = "2.9.7" nav3 = "1.0.1"
composeBom = "2026.02.00" composeBom = "2026.02.00"
accompanist-drawablepainter = "0.37.3" accompanist-drawablepainter = "0.37.3"
accompanist-permissions = "0.37.3" accompanist-permissions = "0.37.3"
@@ -21,10 +21,12 @@ androidx-compose-ui-tooling-preview = { group = "androidx.compose.ui", name = "u
androidx-compose-ui-tooling = { group = "androidx.compose.ui", name = "ui-tooling" } androidx-compose-ui-tooling = { group = "androidx.compose.ui", name = "ui-tooling" }
androidx-activity-compose = { module = "androidx.activity:activity-compose" } androidx-activity-compose = { module = "androidx.activity:activity-compose" }
androidx-material3 = { module = "androidx.compose.material3:material3" } androidx-material3 = { module = "androidx.compose.material3:material3" }
androidx-navigation-compose = { module = "androidx.navigation:navigation-compose", version.ref = "navigation-compose" }
androidx-fragment = { group = "androidx.fragment", name = "fragment", version.ref = "fragment" } androidx-fragment = { group = "androidx.fragment", name = "fragment", version.ref = "fragment" }
material-icons-core = { group = "androidx.compose.material", name = "material-icons-core" } material-icons-core = { group = "androidx.compose.material", name = "material-icons-core" }
androidx-nav3-runtime = { group = "androidx.navigation3", name = "navigation3-runtime", version.ref = "nav3" }
androidx-nav3-ui = { group = "androidx.navigation3", name = "navigation3-ui", version.ref = "nav3" }
accompanist-drawablepainter = { module = "com.google.accompanist:accompanist-drawablepainter", version.ref = "accompanist-drawablepainter" } accompanist-drawablepainter = { module = "com.google.accompanist:accompanist-drawablepainter", version.ref = "accompanist-drawablepainter" }
accompanist-permissions = { group = "com.google.accompanist", name = "accompanist-permissions", version.ref = "accompanist-permissions" } accompanist-permissions = { group = "com.google.accompanist", name = "accompanist-permissions", version.ref = "accompanist-permissions" }