diff --git a/app/build.gradle.kts b/app/build.gradle.kts index cd5a8f9..00c075e 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -89,12 +89,13 @@ gradle.taskGraph.whenReady { dependencies { implementation(libs.androidx.activity.compose) implementation(platform(libs.androidx.compose.bom)) + implementation(libs.androidx.nav3.runtime) + implementation(libs.androidx.nav3.ui) implementation(libs.androidx.compose.ui.tooling.preview) debugImplementation(libs.androidx.compose.ui.tooling) implementation(libs.accompanist.drawablepainter) implementation(libs.accompanist.permissions) implementation(libs.androidx.material3) - implementation(libs.androidx.navigation.compose) implementation(libs.material.icons.core) implementation(libs.shizuku.provider) implementation(libs.shizuku.api) diff --git a/app/src/main/java/com/bintianqi/owndroid/MainActivity.kt b/app/src/main/java/com/bintianqi/owndroid/MainActivity.kt index adbe753..f0a6064 100644 --- a/app/src/main/java/com/bintianqi/owndroid/MainActivity.kt +++ b/app/src/main/java/com/bintianqi/owndroid/MainActivity.kt @@ -9,30 +9,13 @@ import androidx.activity.enableEdgeToEdge import androidx.activity.result.contract.ActivityResultContracts import androidx.activity.viewModels import androidx.compose.foundation.background -import androidx.compose.foundation.clickable -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.Box 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.ExperimentalMaterial3Api -import androidx.compose.material3.Icon -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.MaterialTheme import androidx.compose.material3.Text import androidx.compose.material3.TextButton -import androidx.compose.material3.TopAppBarDefaults import androidx.compose.runtime.Composable import androidx.compose.runtime.DisposableEffect import androidx.compose.runtime.LaunchedEffect @@ -41,207 +24,21 @@ import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.setValue -import androidx.compose.ui.Alignment 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.unit.dp import androidx.compose.ui.window.DialogProperties import androidx.fragment.app.FragmentActivity import androidx.lifecycle.Lifecycle import androidx.lifecycle.LifecycleEventObserver import androidx.lifecycle.compose.LocalLifecycleOwner import androidx.lifecycle.compose.collectAsStateWithLifecycle -import androidx.navigation.compose.NavHost -import androidx.navigation.compose.composable -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 androidx.navigation3.runtime.rememberNavBackStack +import androidx.navigation3.ui.NavDisplay import com.bintianqi.owndroid.dpm.dhizukuErrorStatus 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 kotlinx.serialization.Serializable import java.util.Locale @ExperimentalMaterial3Api @@ -267,589 +64,61 @@ class MainActivity : FragmentActivity() { var appLockDialog by rememberSaveable { mutableStateOf(false) } val theme by vm.theme.collectAsStateWithLifecycle() 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) { 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 { 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 { HomeScreen(::navigate) } - composable { - WorkModesScreen(vm, it.toRoute(), ::navigateUp, { - navController.navigate(Home) { - popUpTo { inclusive = true } - } - }, { - navController.navigate(WorkModes(false)) { - popUpTo(Home) { inclusive = true } - } - }, ::navigate) - } - composable { - DhizukuServerSettingsScreen(vm.dhizukuClients, vm::getDhizukuClients, - vm::updateDhizukuClient, vm::getDhizukuServerEnabled, vm::setDhizukuServerEnabled, - ::navigateUp) - } - - composable { - DelegatedAdminsScreen(vm.delegatedAdmins, vm::getDelegatedAdmins, ::navigateUp, ::navigate) - } - composable{ - AddDelegatedAdminScreen(vm.chosenPackage, ::chooseSinglePackage, it.toRoute(), - vm::setDelegatedAdmin, ::navigateUp) - } - composable { DeviceInfoScreen(vm, ::navigateUp) } - composable { - LockScreenInfoScreen(vm::getLockScreenInfo, vm::setLockScreenInfo, ::navigateUp) - } - composable { - SupportMessageScreen(vm::getShortSupportMessage, vm::getLongSupportMessage, - vm::setShortSupportMessage, vm::setLongSupportMessage, ::navigateUp) - } - composable { - TransferOwnershipScreen(vm.deviceAdminReceivers, vm::getDeviceAdminReceivers, - vm::transferOwnership, ::navigateUp) { - navController.navigate(WorkModes(false)) { - popUpTo(Home) { inclusive = true } - } - } - } - - composable { SystemManagerScreen(vm, ::navigateUp, ::navigate) } - composable { SystemOptionsScreen(vm, ::navigateUp) } - composable { - KeyguardScreen(vm::setKeyguardDisabled, vm::lockScreen, ::navigateUp) - } - composable { - HardwareMonitorScreen(vm.hardwareProperties, vm::getHardwareProperties, - vm::setHpRefreshInterval, ::navigateUp) - } - composable { - DefaultInputMethodScreen(vm::getCurrentInputMethod, vm.inputMethodList, - vm::getInputMethods, vm::setDefaultInputMethod, ::navigateUp) - } - composable { ChangeTimeScreen(vm::setTime, ::navigateUp) } - composable { ChangeTimeZoneScreen(vm::setTimeZone, ::navigateUp) } - composable { - AutoTimePolicyScreen(vm::getAutoTimePolicy, vm::setAutoTimePolicy, ::navigateUp) - } - composable { - AutoTimeZonePolicyScreen(vm::getAutoTimeZonePolicy, vm::setAutoTimeZonePolicy, - ::navigateUp) - } - //composable<> { KeyPairs(::navigateUp) } - composable { - ContentProtectionPolicyScreen(vm::getContentProtectionPolicy, - vm::setContentProtectionPolicy, ::navigateUp) - } - composable { - PermissionPolicyScreen(vm::getPermissionPolicy, vm::setPermissionPolicy, ::navigateUp) - } - composable { - MtePolicyScreen(vm::getMtePolicy, vm::setMtePolicy, ::navigateUp) - } - composable { - NearbyStreamingPolicyScreen(vm::getNsAppPolicy, vm::setNsAppPolicy, - vm::getNsNotificationPolicy, vm::setNsNotificationPolicy, ::navigateUp) - } - composable { - LockTaskModeScreen( - vm.chosenPackage, ::chooseSinglePackage, ::choosePackage, vm.lockTaskPackages, - vm::getLockTaskPackages, vm::setLockTaskPackage, vm::startLockTaskMode, - vm:: getLockTaskFeatures, vm::setLockTaskFeatures, ::navigateUp - ) - } - composable { - CaCertScreen(vm.installedCaCerts, vm::getCaCerts, vm.selectedCaCert, vm::selectCaCert, vm::installCaCert, vm::parseCaCert, - vm::exportCaCert, vm::uninstallCaCert, vm::uninstallAllCaCerts, ::navigateUp) - } - composable { - SecurityLoggingScreen(vm::getSecurityLoggingEnabled, vm::setSecurityLoggingEnabled, - vm::exportSecurityLogs, vm::getSecurityLogsCount, vm::deleteSecurityLogs, - vm::getPreRebootSecurityLogs, vm::exportPreRebootSecurityLogs, ::navigateUp) - } - composable { - DisableAccountManagementScreen(vm.mdAccountTypes, vm::getMdAccountTypes, - vm::setMdAccountType, ::navigateUp) - } - composable { - SystemUpdatePolicyScreen(vm::getSystemUpdatePolicy, vm::setSystemUpdatePolicy, - vm::getPendingSystemUpdate, ::navigateUp) - } - composable { - InstallSystemUpdateScreen(vm::installSystemUpdate, ::navigateUp) - } - composable { - FrpPolicyScreen(vm.getFrpPolicy(), vm::setFrpPolicy, ::navigateUp) - } - composable { WipeDataScreen(vm::wipeData, ::navigateUp) } - - composable { NetworkScreen(::navigateUp, ::navigate) } - composable { - WifiScreen(vm, ::navigateUp, ::navigate) { navController.navigate(UpdateNetwork(it)) } - } - composable { - NetworkOptionsScreen(vm::getLanEnabled, vm::setLanEnabled, ::navigateUp) - } - composable { - val info = vm.configuredNetworks.collectAsStateWithLifecycle().value[ - (it.toRoute() as UpdateNetwork).index - ] - UpdateNetworkScreen(info, vm::setWifi, ::navigateUp) - } - composable { - WifiSecurityLevelScreen(vm::getMinimumWifiSecurityLevel, - vm::setMinimumWifiSecurityLevel, ::navigateUp) - } - composable { - WifiSsidPolicyScreen(vm::getSsidPolicy, vm::setSsidPolicy, ::navigateUp) - } - composable { - NetworkStatsScreen(vm.chosenPackage, ::chooseSinglePackage, vm::getPackageUid, - vm::queryNetworkStats, ::navigateUp) { navController.navigate(NetworkStatsViewer) } - } - composable { - NetworkStatsViewerScreen(vm.networkStatsData, vm::clearNetworkStats, ::navigateUp) - } - composable { - PrivateDnsScreen(vm::getPrivateDns, vm::setPrivateDns, ::navigateUp) - } - composable { - AlwaysOnVpnPackageScreen(vm::getAlwaysOnVpnPackage, vm::getAlwaysOnVpnLockdown, - vm::setAlwaysOnVpn, vm.chosenPackage, ::chooseSinglePackage, ::navigateUp) - } - composable { - RecommendedGlobalProxyScreen(vm::setRecommendedGlobalProxy, ::navigateUp) - } - composable { - NetworkLoggingScreen(vm::getNetworkLoggingEnabled, vm::setNetworkLoggingEnabled, - vm::getNetworkLogsCount, vm::exportNetworkLogs, vm::deleteNetworkLogs, ::navigateUp) - } - //composable { WifiAuthKeypairScreen(::navigateUp) } - composable { - PreferentialNetworkServiceScreen(vm::getPnsEnabled, vm::setPnsEnabled, vm.pnsConfigs, - vm::getPnsConfigs, ::navigateUp, ::navigate) - } - composable { - val info = vm.pnsConfigs.collectAsStateWithLifecycle().value.getOrNull( - it.toRoute().index - ) ?: PreferentialNetworkServiceInfo() - AddPreferentialNetworkServiceConfigScreen(info, vm::setPnsConfig, ::navigateUp) - } - composable { - OverrideApnScreen(vm.apnConfigs, vm::getApnConfigs, vm::getApnEnabled, - vm::setApnEnabled, ::navigateUp) { navController.navigate(AddApnSetting(it)) } - } - composable { - val origin = vm.apnConfigs.collectAsStateWithLifecycle().value.getOrNull((it.toRoute() as AddApnSetting).index) - AddApnSettingScreen(vm::setApnConfig, vm::removeApnConfig, origin, ::navigateUp) - } - - composable { WorkProfileScreen(::navigateUp, ::navigate) } - composable { - OrganizationOwnedProfileScreen(vm::activateOrgProfileByShizuku, ::navigateUp) - } - composable { - CreateWorkProfileScreen(vm::createWorkProfile, ::navigateUp) - } - composable { - SuspendPersonalAppScreen( - vm::getPersonalAppsSuspendedReason, vm::setPersonalAppsSuspended, - vm::getProfileMaxTimeOff, vm::setProfileMaxTimeOff, ::navigateUp - ) - } - composable { - CrossProfileIntentFilterScreen( - vm::addCrossProfileIntentFilter, vm::clearCrossProfileIntentFilters, - vm::importCrossProfileIntentFilters, vm::exportCrossProfileIntentFilters, - ::navigateUp - ) - } - composable { DeleteWorkProfileScreen(vm::wipeData, ::navigateUp) } - - composable { - val params = it.toRoute() - AppChooserScreen( - params, vm.installedPackages, vm.refreshPackagesProgress, { name -> - if (params.canSwitchView) { - if (name == null) { - navigateUp() - } else { - navigate(ApplicationDetails(name)) + DisposableEffect(lifecycleOwner) { + val observer = LifecycleEventObserver { _, event -> + if ( + (event == Lifecycle.Event.ON_CREATE && !SP.lockPasswordHash.isNullOrEmpty()) || + (event == Lifecycle.Event.ON_RESUME && SP.lockWhenLeaving) + ) { + appLockDialog = true + } + } + lifecycleOwner.lifecycle.addObserver(observer) + onDispose { + lifecycleOwner.lifecycle.removeObserver(observer) } - } else { - if (name != null) vm.chosenPackage.trySend(name) - navigateUp() } - }, { - SP.applicationsListView = false - navController.navigate(ApplicationsFeatures) { - popUpTo(Home) + LaunchedEffect(Unit) { + val profileNotActivated = !SP.managedProfileActivated && Privilege.status.value.work + if(profileNotActivated) { + Privilege.DPM.setProfileEnabled(Privilege.DAR) + SP.managedProfileActivated = true + context.popToast(R.string.work_profile_activated) + } } - }, vm::refreshPackageList, vm::setPackageSuspended, vm::setPackageHidden) - } - composable { - ApplicationsFeaturesScreen(::navigateUp, ::navigate) { - SP.applicationsListView = true - navController.navigate(ApplicationsList(true, true)) { - popUpTo(Home) + DhizukuErrorDialog { + dhizukuErrorStatus.value = 0 + Privilege.updateStatus() + backstack += Destination.WorkingModes(false) + repeat(backstack.size - 1) { + backstack.removeFirstOrNull() + } } } } - composable { - ApplicationDetailsScreen(it.toRoute(), vm, ::navigateUp, ::navigate) - } - composable { - PackageFunctionScreen( - R.string.suspend, vm.suspendedPackages, vm::getSuspendedPackaged, - vm::setPackageSuspended, ::navigateUp, vm.chosenPackage, ::choosePackage, - ::navigateToAppGroups, vm.appGroups, R.string.info_suspend_app - ) - } - composable { - PackageFunctionScreen( - R.string.hide, vm.hiddenPackages, vm::getHiddenPackages, vm::setPackageHidden, - ::navigateUp, vm.chosenPackage, ::choosePackage, ::navigateToAppGroups, vm.appGroups - ) - } - composable { - PackageFunctionScreen( - R.string.block_uninstall, vm.ubPackages, vm::getUbPackages, vm::setPackageUb, - ::navigateUp, vm.chosenPackage, ::choosePackage, ::navigateToAppGroups, vm.appGroups - ) - } - composable { - 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 { - AppPermissionsManagerScreen( - vm::getPackagePermissions, vm::setPackagePermission, ::navigateUp, it.toRoute() - ) - } - composable { - PermissionManagerScreen(::navigate, ::navigateUp) - } - composable { - PermissionDetailScreen( - it.toRoute(), vm::getPermissionPackages, vm::setPackagePermission, ::navigateUp - ) - } - composable { - PackageFunctionScreen( - R.string.disable_metered_data, vm.mddPackages, vm::getMddPackages, - vm::setPackageMdd, ::navigateUp, vm.chosenPackage, ::choosePackage, - ::navigateToAppGroups, vm.appGroups - ) - } - composable { - ClearAppStorageScreen( - vm.chosenPackage, ::chooseSinglePackage, vm::clearAppData, ::navigateUp - ) - } - composable { - UninstallAppScreen( - vm.chosenPackage, ::chooseSinglePackage, vm::uninstallPackage, ::navigateUp - ) - } - composable { - 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 { - InstallExistingAppScreen( - vm.chosenPackage, ::chooseSinglePackage, vm::installExistingApp, ::navigateUp - ) - } - composable { - PackageFunctionScreen( - R.string.cross_profile_apps, vm.cpPackages, - vm::getCpPackages, vm::setPackageCp, ::navigateUp, vm.chosenPackage, - ::choosePackage, ::navigateToAppGroups, vm.appGroups - ) - } - composable { - PackageFunctionScreen(R.string.cross_profile_widget, vm.cpwProviders, - vm::getCpwProviders, vm::setCpwProvider, ::navigateUp, vm.chosenPackage, - ::choosePackage, ::navigateToAppGroups, vm.appGroups) - } - composable { - CredentialManagerPolicyScreen( - vm.chosenPackage, ::choosePackage, vm.cmPackages, vm::getCmPolicy, - vm::setCmPackage, vm::setCmPolicy, ::navigateUp - ) - } - composable { - 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 { - PermittedAsAndImPackages( - R.string.permitted_ime, R.string.system_ime_always_allowed, - vm.chosenPackage, ::choosePackage, vm.pimPackages, vm::getPimPackages, - vm::setPimPackage, vm::setPimPolicy, ::navigateUp - ) - } - composable { - EnableSystemAppScreen( - vm.chosenPackage, ::chooseSinglePackage, vm::enableSystemApp, ::navigateUp - ) - } - composable { - SetDefaultDialerScreen( - vm.chosenPackage, ::chooseSinglePackage, vm::setDefaultDialer, ::navigateUp - ) - } - composable { - ManagedConfigurationScreen( - it.toRoute(), vm.appRestrictions, vm::setAppRestrictions, - vm::clearAppRestrictions, ::navigateUp - ) - } - composable { - ManageAppGroupsScreen( - vm.appGroups, vm::exportAppGroups, vm::importAppGroups, - { id, name, apps -> navController.navigate(EditAppGroup(id, name, apps)) }, - ::navigateUp - ) - } - composable { - EditAppGroupScreen( - it.toRoute(), vm::getAppInfo, ::navigateUp, vm::setAppGroup, - vm::deleteAppGroup, ::choosePackage, vm.chosenPackage - ) - } - - composable { - UserRestrictionScreen(vm::getUserRestrictions, ::navigateUp, ::navigate) - } - composable { - UserRestrictionEditorScreen(vm.userRestrictions, vm::setUserRestriction, ::navigateUp) - } - composable { - UserRestrictionOptionsScreen(it.toRoute(), vm.userRestrictions, - vm::setUserRestriction, vm::createUserRestrictionShortcut, ::navigateUp) - } - - composable { UsersScreen(vm, ::navigateUp, ::navigate) } - composable { UserInfoScreen(vm::getUserInformation, ::navigateUp) } - composable { - UsersOptionsScreen(vm::getLogoutEnabled, vm::setLogoutEnabled, ::navigateUp) - } - composable { - UserOperationScreen(vm::getUserIdentifiers, vm::doUserOperation, - vm::createUserOperationShortcut, ::navigateUp) - } - composable { CreateUserScreen(vm::createUser, ::navigateUp) } - composable { ChangeUsernameScreen(vm::setProfileName, ::navigateUp) } - composable { - UserSessionMessageScreen(vm::getUserSessionMessages, vm::setStartUserSessionMessage, - vm::setEndUserSessionMessage, ::navigateUp) - } - composable { - AffiliationIdScreen(vm.affiliationIds, vm::getAffiliationIds, vm::setAffiliationId, - ::navigateUp) - } - - composable { PasswordScreen(vm, ::navigateUp, ::navigate) } - composable { - PasswordInfoScreen(vm::getPasswordComplexity, vm::isPasswordComplexitySufficient, - vm::isUsingUnifiedPassword, ::navigateUp) - } - composable { - ResetPasswordTokenScreen(vm::getRpTokenState, vm::setRpToken, - vm::createActivateRpTokenIntent, vm::clearRpToken, ::navigateUp) - } - composable { ResetPasswordScreen(vm::resetPassword, ::navigateUp) } - composable { - RequiredPasswordComplexityScreen(vm::getRequiredPasswordComplexity, - vm::setRequiredPasswordComplexity, ::navigateUp) - } - composable { - KeyguardDisabledFeaturesScreen(vm::getKeyguardDisableConfig, - vm::setKeyguardDisableConfig, ::navigateUp) - } - composable { RequiredPasswordQualityScreen(::navigateUp) } - - composable { SettingsScreen(::navigateUp, ::navigate) } - composable { - SettingsOptionsScreen(vm::getDisplayDangerousFeatures, vm::getShortcutsEnabled, - vm::setDisplayDangerousFeatures, vm::setShortcutsEnabled, ::navigateUp) - } - composable { - AppearanceScreen(::navigateUp, vm.theme, vm::changeTheme) - } - composable { - AppLockSettingsScreen(vm.getAppLockConfig(), vm::setAppLockConfig, ::navigateUp) - } - composable { - ApiSettings(vm::getApiEnabled, vm::setApiKey, ::navigateUp) - } - composable { - NotificationsScreen(vm.enabledNotifications, vm::getEnabledNotifications, - vm::setNotificationEnabled, ::navigateUp) - } - composable { AboutScreen(::navigateUp) } - } - DisposableEffect(lifecycleOwner) { - val observer = LifecycleEventObserver { _, event -> - if ( - (event == Lifecycle.Event.ON_CREATE && !SP.lockPasswordHash.isNullOrEmpty()) || - (event == Lifecycle.Event.ON_RESUME && SP.lockWhenLeaving) - ) { - onLock() - } - } - lifecycleOwner.lifecycle.addObserver(observer) - onDispose { - lifecycleOwner.lifecycle.removeObserver(observer) - } - } - LaunchedEffect(Unit) { - val profileNotActivated = !SP.managedProfileActivated && Privilege.status.value.work - if(profileNotActivated) { - Privilege.DPM.setProfileEnabled(Privilege.DAR) - SP.managedProfileActivated = true - context.popToast(R.string.work_profile_activated) - } - } - DhizukuErrorDialog { - dhizukuErrorStatus.value = 0 - Privilege.updateStatus() - navController.navigate(WorkModes(false)) { - popUpTo { inclusive = true } - launchSingleTop = true - } - } -} - -@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) - ) } } diff --git a/app/src/main/java/com/bintianqi/owndroid/MyRepository.kt b/app/src/main/java/com/bintianqi/owndroid/MyRepository.kt index 5c10ab2..3d89493 100644 --- a/app/src/main/java/com/bintianqi/owndroid/MyRepository.kt +++ b/app/src/main/java/com/bintianqi/owndroid/MyRepository.kt @@ -9,8 +9,8 @@ import androidx.annotation.RequiresApi import androidx.core.database.getIntOrNull import androidx.core.database.getLongOrNull import androidx.core.database.getStringOrNull -import com.bintianqi.owndroid.dpm.AppGroup -import com.bintianqi.owndroid.dpm.IntentFilterOptions +import com.bintianqi.owndroid.ui.screen.AppGroup +import com.bintianqi.owndroid.ui.screen.IntentFilterOptions import com.bintianqi.owndroid.dpm.NetworkLog import com.bintianqi.owndroid.dpm.SecurityEvent import com.bintianqi.owndroid.dpm.SecurityEventWithData diff --git a/app/src/main/java/com/bintianqi/owndroid/MyViewModel.kt b/app/src/main/java/com/bintianqi/owndroid/MyViewModel.kt index 78d9515..e582e52 100644 --- a/app/src/main/java/com/bintianqi/owndroid/MyViewModel.kt +++ b/app/src/main/java/com/bintianqi/owndroid/MyViewModel.kt @@ -60,57 +60,58 @@ import androidx.lifecycle.viewModelScope import com.bintianqi.owndroid.Privilege.DAR import com.bintianqi.owndroid.Privilege.DPM import com.bintianqi.owndroid.dpm.ACTIVATE_DEVICE_OWNER_COMMAND -import com.bintianqi.owndroid.dpm.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.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.getPackageInstaller -import com.bintianqi.owndroid.dpm.globalSettings import com.bintianqi.owndroid.dpm.handlePrivilegeChange import com.bintianqi.owndroid.dpm.parsePackageInstallerMessage import com.bintianqi.owndroid.dpm.runtimePermissions -import com.bintianqi.owndroid.dpm.secureSettings -import com.bintianqi.owndroid.dpm.temperatureTypes +import com.bintianqi.owndroid.ui.screen.ApnAuthType +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.DhizukuRequestPermissionListener import com.topjohnwu.superuser.Shell @@ -159,7 +160,9 @@ class MyViewModel(application: Application): AndroidViewModel(application) { } fun getAppLockConfig(): AppLockConfig { 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) { if (config.password == null) { diff --git a/app/src/main/java/com/bintianqi/owndroid/PackageChooser.kt b/app/src/main/java/com/bintianqi/owndroid/PackageChooser.kt index 618c1c2..6845524 100644 --- a/app/src/main/java/com/bintianqi/owndroid/PackageChooser.kt +++ b/app/src/main/java/com/bintianqi/owndroid/PackageChooser.kt @@ -63,9 +63,9 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.input.ImeAction import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle +import com.bintianqi.owndroid.ui.navigation.Destination import com.google.accompanist.drawablepainter.rememberDrawablePainter import kotlinx.coroutines.flow.MutableStateFlow -import kotlinx.serialization.Serializable data class AppInfo( val name: String, @@ -77,12 +77,10 @@ data class AppInfo( private fun searchInString(query: String, content: String) = query.split(' ').all { content.contains(it, true) } -@Serializable data class ApplicationsList(val canSwitchView: Boolean, val multiSelect: Boolean) - @OptIn(ExperimentalMaterial3Api::class, ExperimentalFoundationApi::class) @Composable fun AppChooserScreen( - params: ApplicationsList, packageList: MutableStateFlow>, + params: Destination.ApplicationsList, packageList: MutableStateFlow>, refreshProgress: MutableStateFlow, onChoosePackage: (String?) -> Unit, onSwitchView: () -> Unit, onRefresh: () -> Unit, setPackagesSuspend: (List, Boolean) -> Unit, diff --git a/app/src/main/java/com/bintianqi/owndroid/ShortcutUtils.kt b/app/src/main/java/com/bintianqi/owndroid/ShortcutUtils.kt index 21e4e00..c729446 100644 --- a/app/src/main/java/com/bintianqi/owndroid/ShortcutUtils.kt +++ b/app/src/main/java/com/bintianqi/owndroid/ShortcutUtils.kt @@ -5,7 +5,7 @@ import android.content.Intent import androidx.core.content.pm.ShortcutInfoCompat import androidx.core.content.pm.ShortcutManagerCompat import androidx.core.graphics.drawable.IconCompat -import com.bintianqi.owndroid.dpm.UserOperationType +import com.bintianqi.owndroid.ui.screen.UserOperationType object ShortcutUtils { fun setAllShortcuts(context: Context, enabled: Boolean) { diff --git a/app/src/main/java/com/bintianqi/owndroid/ShortcutsReceiverActivity.kt b/app/src/main/java/com/bintianqi/owndroid/ShortcutsReceiverActivity.kt index 5d0c1f4..5586e20 100644 --- a/app/src/main/java/com/bintianqi/owndroid/ShortcutsReceiverActivity.kt +++ b/app/src/main/java/com/bintianqi/owndroid/ShortcutsReceiverActivity.kt @@ -3,7 +3,7 @@ package com.bintianqi.owndroid import android.app.Activity import android.os.Bundle import android.util.Log -import com.bintianqi.owndroid.dpm.UserOperationType +import com.bintianqi.owndroid.ui.screen.UserOperationType import com.bintianqi.owndroid.dpm.doUserOperationWithContext class ShortcutsReceiverActivity : Activity() { diff --git a/app/src/main/java/com/bintianqi/owndroid/UserRestrictionsRepository.kt b/app/src/main/java/com/bintianqi/owndroid/UserRestrictionsRepository.kt index e00916b..51ce749 100644 --- a/app/src/main/java/com/bintianqi/owndroid/UserRestrictionsRepository.kt +++ b/app/src/main/java/com/bintianqi/owndroid/UserRestrictionsRepository.kt @@ -2,7 +2,7 @@ package com.bintianqi.owndroid import android.os.Build import android.os.UserManager -import com.bintianqi.owndroid.dpm.Restriction +import com.bintianqi.owndroid.ui.screen.Restriction @Suppress("InlinedApi") object UserRestrictionsRepository { diff --git a/app/src/main/java/com/bintianqi/owndroid/dpm/DPM.kt b/app/src/main/java/com/bintianqi/owndroid/dpm/DPM.kt index b0932b6..3b0eb62 100644 --- a/app/src/main/java/com/bintianqi/owndroid/dpm/DPM.kt +++ b/app/src/main/java/com/bintianqi/owndroid/dpm/DPM.kt @@ -7,6 +7,7 @@ import android.app.admin.DevicePolicyManager import android.app.admin.DnsEvent import android.app.admin.IDevicePolicyManager import android.app.admin.SecurityLog +import android.content.ComponentName import android.content.Context import android.content.Intent import android.content.pm.IPackageInstaller @@ -16,6 +17,7 @@ import android.os.UserHandle import android.os.UserManager import android.util.Log import androidx.annotation.RequiresApi +import com.bintianqi.owndroid.AppInfo import com.bintianqi.owndroid.MyApplication import com.bintianqi.owndroid.NotificationType import com.bintianqi.owndroid.NotificationUtils @@ -25,6 +27,7 @@ import com.bintianqi.owndroid.Privilege.DPM import com.bintianqi.owndroid.R import com.bintianqi.owndroid.SP import com.bintianqi.owndroid.ShortcutUtils +import com.bintianqi.owndroid.ui.screen.UserOperationType import com.rosan.dhizuku.api.Dhizuku import com.rosan.dhizuku.api.DhizukuBinderWrapper import kotlinx.coroutines.CoroutineScope @@ -589,3 +592,9 @@ fun doUserOperationWithContext( 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) + +data class DeviceAdmin(val app: AppInfo, val admin: ComponentName) diff --git a/app/src/main/java/com/bintianqi/owndroid/ui/Components.kt b/app/src/main/java/com/bintianqi/owndroid/ui/Components.kt index d0cb905..de91904 100644 --- a/app/src/main/java/com/bintianqi/owndroid/ui/Components.kt +++ b/app/src/main/java/com/bintianqi/owndroid/ui/Components.kt @@ -17,9 +17,12 @@ import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyListScope import androidx.compose.foundation.rememberScrollState 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.material.icons.Icons 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.material3.AlertDialog import androidx.compose.material3.Card @@ -31,6 +34,7 @@ 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.OutlinedTextField import androidx.compose.material3.RadioButton import androidx.compose.material3.Scaffold 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.clip import androidx.compose.ui.input.nestedscroll.nestedScroll +import androidx.compose.ui.platform.LocalFocusManager import androidx.compose.ui.res.painterResource 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.window.Dialog import com.bintianqi.owndroid.HorizontalPadding import com.bintianqi.owndroid.R import com.bintianqi.owndroid.adaptiveInsets +import com.bintianqi.owndroid.ui.screen.isValidPackageName import com.bintianqi.owndroid.zhCN @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() } + ) +} diff --git a/app/src/main/java/com/bintianqi/owndroid/ui/NavTransition.kt b/app/src/main/java/com/bintianqi/owndroid/ui/NavTransition.kt index d9dd4df..e4d6329 100644 --- a/app/src/main/java/com/bintianqi/owndroid/ui/NavTransition.kt +++ b/app/src/main/java/com/bintianqi/owndroid/ui/NavTransition.kt @@ -10,6 +10,7 @@ import androidx.compose.animation.fadeIn import androidx.compose.animation.fadeOut import androidx.compose.animation.slideInHorizontally import androidx.compose.animation.slideOutHorizontally +import androidx.compose.animation.togetherWith /** * Learned from AOSP's Activity animation @@ -42,4 +43,7 @@ object NavTransition { ) + fadeOut( tween(83, 35, LinearEasing) ) + + val transition = enterTransition togetherWith exitTransition + val popTransition = popEnterTransition togetherWith popExitTransition } diff --git a/app/src/main/java/com/bintianqi/owndroid/ui/navigation/Destination.kt b/app/src/main/java/com/bintianqi/owndroid/ui/navigation/Destination.kt new file mode 100644 index 0000000..a146d3b --- /dev/null +++ b/app/src/main/java/com/bintianqi/owndroid/ui/navigation/Destination.kt @@ -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 + ) : 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 + ) : 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() +} diff --git a/app/src/main/java/com/bintianqi/owndroid/ui/navigation/EntryProvider.kt b/app/src/main/java/com/bintianqi/owndroid/ui/navigation/EntryProvider.kt new file mode 100644 index 0000000..eace85a --- /dev/null +++ b/app/src/main/java/com/bintianqi/owndroid/ui/navigation/EntryProvider.kt @@ -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, 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 { + HomeScreen(::navigate) + } + entry { + WorkModesScreen(vm, it, ::navigateUp, { + navigateAndPopAll(Destination.Home) + }, { + navigateAndPopAll(Destination.WorkingModes(false)) + }, ::navigate) + } + entry { + DhizukuServerSettingsScreen(vm.dhizukuClients, vm::getDhizukuClients, + vm::updateDhizukuClient, vm::getDhizukuServerEnabled, vm::setDhizukuServerEnabled, + ::navigateUp) + } + + entry { + DelegatedAdminsScreen(vm.delegatedAdmins, vm::getDelegatedAdmins, ::navigateUp, ::navigate) + } + entry{ + AddDelegatedAdminScreen(vm.chosenPackage, ::chooseSinglePackage, it, + vm::setDelegatedAdmin, ::navigateUp) + } + entry { DeviceInfoScreen(vm, ::navigateUp) } + entry { + LockScreenInfoScreen(vm::getLockScreenInfo, vm::setLockScreenInfo, ::navigateUp) + } + entry { + SupportMessageScreen(vm::getShortSupportMessage, vm::getLongSupportMessage, + vm::setShortSupportMessage, vm::setLongSupportMessage, ::navigateUp) + } + entry { + TransferOwnershipScreen(vm.deviceAdminReceivers, vm::getDeviceAdminReceivers, + vm::transferOwnership, ::navigateUp + ) { + navigate(Destination.WorkingModes(false)) + } + } + + entry { SystemManagerScreen(vm, ::navigateUp, ::navigate) } + entry { SystemOptionsScreen(vm, ::navigateUp) } + entry { + KeyguardScreen(vm::setKeyguardDisabled, vm::lockScreen, ::navigateUp) + } + entry { + HardwareMonitorScreen(vm.hardwareProperties, vm::getHardwareProperties, + vm::setHpRefreshInterval, ::navigateUp) + } + entry { + DefaultInputMethodScreen(vm::getCurrentInputMethod, vm.inputMethodList, + vm::getInputMethods, vm::setDefaultInputMethod, ::navigateUp) + } + entry { ChangeTimeScreen(vm::setTime, ::navigateUp) } + entry { ChangeTimeZoneScreen(vm::setTimeZone, ::navigateUp) } + entry { + AutoTimePolicyScreen(vm::getAutoTimePolicy, vm::setAutoTimePolicy, ::navigateUp) + } + entry { + AutoTimeZonePolicyScreen(vm::getAutoTimeZonePolicy, vm::setAutoTimeZonePolicy, + ::navigateUp) + } + //entry { KeyPairs(::navigateUp) } + entry { + ContentProtectionPolicyScreen(vm::getContentProtectionPolicy, + vm::setContentProtectionPolicy, ::navigateUp) + } + entry { + PermissionPolicyScreen(vm::getPermissionPolicy, vm::setPermissionPolicy, ::navigateUp) + } + entry { + MtePolicyScreen(vm::getMtePolicy, vm::setMtePolicy, ::navigateUp) + } + entry { + NearbyStreamingPolicyScreen(vm::getNsAppPolicy, vm::setNsAppPolicy, + vm::getNsNotificationPolicy, vm::setNsNotificationPolicy, ::navigateUp) + } + entry { + LockTaskModeScreen( + vm.chosenPackage, ::chooseSinglePackage, ::choosePackage, vm.lockTaskPackages, + vm::getLockTaskPackages, vm::setLockTaskPackage, vm::startLockTaskMode, + vm:: getLockTaskFeatures, vm::setLockTaskFeatures, ::navigateUp + ) + } + entry { + CaCertScreen(vm.installedCaCerts, vm::getCaCerts, vm.selectedCaCert, vm::selectCaCert, vm::installCaCert, vm::parseCaCert, + vm::exportCaCert, vm::uninstallCaCert, vm::uninstallAllCaCerts, ::navigateUp) + } + entry { + SecurityLoggingScreen(vm::getSecurityLoggingEnabled, vm::setSecurityLoggingEnabled, + vm::exportSecurityLogs, vm::getSecurityLogsCount, vm::deleteSecurityLogs, + vm::getPreRebootSecurityLogs, vm::exportPreRebootSecurityLogs, ::navigateUp) + } + entry { + DisableAccountManagementScreen(vm.mdAccountTypes, vm::getMdAccountTypes, + vm::setMdAccountType, ::navigateUp) + } + entry { + SystemUpdatePolicyScreen(vm::getSystemUpdatePolicy, vm::setSystemUpdatePolicy, + vm::getPendingSystemUpdate, ::navigateUp) + } + entry { + InstallSystemUpdateScreen(vm::installSystemUpdate, ::navigateUp) + } + entry { + FrpPolicyScreen(vm.getFrpPolicy(), vm::setFrpPolicy, ::navigateUp) + } + entry { WipeDataScreen(vm::wipeData, ::navigateUp) } + + entry { NetworkScreen(::navigateUp, ::navigate) } + entry { + WifiScreen(vm, ::navigateUp, ::navigate) { navigate(Destination.UpdateNetwork(it)) } + } + entry { + NetworkOptionsScreen(vm::getLanEnabled, vm::setLanEnabled, ::navigateUp) + } + entry { + val info = vm.configuredNetworks.collectAsStateWithLifecycle().value[ + it.index + ] + UpdateNetworkScreen(info, vm::setWifi, ::navigateUp) + } + entry { + WifiSecurityLevelScreen(vm::getMinimumWifiSecurityLevel, + vm::setMinimumWifiSecurityLevel, ::navigateUp) + } + entry { + WifiSsidPolicyScreen(vm::getSsidPolicy, vm::setSsidPolicy, ::navigateUp) + } + entry { + NetworkStatsScreen(vm.chosenPackage, ::chooseSinglePackage, vm::getPackageUid, + vm::queryNetworkStats, ::navigateUp) { navigate(Destination.NetworkStatsViewer) } + } + entry { + NetworkStatsViewerScreen(vm.networkStatsData, vm::clearNetworkStats, ::navigateUp) + } + entry { + PrivateDnsScreen(vm::getPrivateDns, vm::setPrivateDns, ::navigateUp) + } + entry { + AlwaysOnVpnPackageScreen(vm::getAlwaysOnVpnPackage, vm::getAlwaysOnVpnLockdown, + vm::setAlwaysOnVpn, vm.chosenPackage, ::chooseSinglePackage, ::navigateUp) + } + entry { + RecommendedGlobalProxyScreen(vm::setRecommendedGlobalProxy, ::navigateUp) + } + entry { + NetworkLoggingScreen(vm::getNetworkLoggingEnabled, vm::setNetworkLoggingEnabled, + vm::getNetworkLogsCount, vm::exportNetworkLogs, vm::deleteNetworkLogs, ::navigateUp) + } + //entry { WifiAuthKeypairScreen(::navigateUp) } + entry { + PreferentialNetworkServiceScreen(vm::getPnsEnabled, vm::setPnsEnabled, vm.pnsConfigs, + vm::getPnsConfigs, ::navigateUp, ::navigate) + } + entry { + val info = vm.pnsConfigs.collectAsStateWithLifecycle().value.getOrNull( + it.index + ) ?: PreferentialNetworkServiceInfo() + AddPreferentialNetworkServiceConfigScreen(info, vm::setPnsConfig, ::navigateUp) + } + entry { + OverrideApnScreen(vm.apnConfigs, vm::getApnConfigs, vm::getApnEnabled, + vm::setApnEnabled, ::navigateUp) { navigate(Destination.AddApnSetting(it)) } + } + entry { + val origin = vm.apnConfigs.collectAsStateWithLifecycle().value.getOrNull(it.index) + AddApnSettingScreen(vm::setApnConfig, vm::removeApnConfig, origin, ::navigateUp) + } + + entry { WorkProfileScreen(::navigateUp, ::navigate) } + entry { + OrganizationOwnedProfileScreen(vm::activateOrgProfileByShizuku, ::navigateUp) + } + entry { + CreateWorkProfileScreen(vm::createWorkProfile, ::navigateUp) + } + entry { + SuspendPersonalAppScreen( + vm::getPersonalAppsSuspendedReason, vm::setPersonalAppsSuspended, + vm::getProfileMaxTimeOff, vm::setProfileMaxTimeOff, ::navigateUp + ) + } + entry { + CrossProfileIntentFilterScreen( + vm::addCrossProfileIntentFilter, vm::clearCrossProfileIntentFilters, + vm::importCrossProfileIntentFilters, vm::exportCrossProfileIntentFilters, + ::navigateUp + ) + } + entry { DeleteWorkProfileScreen(vm::wipeData, ::navigateUp) } + + entry { 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 { + ApplicationsFeaturesScreen(::navigateUp, ::navigate) { + SP.applicationsListView = true + navigate(Destination.ApplicationsList(true, true)) + backstack.removeAt(backstack.size - 2) + } + } + entry { + ApplicationDetailsScreen(it, vm, ::navigateUp, ::navigate) + } + entry { + PackageFunctionScreen( + R.string.suspend, vm.suspendedPackages, vm::getSuspendedPackaged, + vm::setPackageSuspended, ::navigateUp, vm.chosenPackage, ::choosePackage, + ::navigateToAppGroups, vm.appGroups, R.string.info_suspend_app + ) + } + entry { + PackageFunctionScreen( + R.string.hide, vm.hiddenPackages, vm::getHiddenPackages, vm::setPackageHidden, + ::navigateUp, vm.chosenPackage, ::choosePackage, ::navigateToAppGroups, vm.appGroups + ) + } + entry { + PackageFunctionScreen( + R.string.block_uninstall, vm.ubPackages, vm::getUbPackages, vm::setPackageUb, + ::navigateUp, vm.chosenPackage, ::choosePackage, ::navigateToAppGroups, vm.appGroups + ) + } + entry { + 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 { + AppPermissionsManagerScreen( + vm::getPackagePermissions, vm::setPackagePermission, ::navigateUp, it + ) + } + entry { + PermissionManagerScreen(::navigate, ::navigateUp) + } + entry { + PermissionDetailScreen( + it, vm::getPermissionPackages, vm::setPackagePermission, ::navigateUp + ) + } + entry { + PackageFunctionScreen( + R.string.disable_metered_data, vm.mddPackages, vm::getMddPackages, + vm::setPackageMdd, ::navigateUp, vm.chosenPackage, ::choosePackage, + ::navigateToAppGroups, vm.appGroups + ) + } + entry { + ClearAppStorageScreen( + vm.chosenPackage, ::chooseSinglePackage, vm::clearAppData, ::navigateUp + ) + } + entry { + UninstallAppScreen( + vm.chosenPackage, ::chooseSinglePackage, vm::uninstallPackage, ::navigateUp + ) + } + entry { + 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 { + InstallExistingAppScreen( + vm.chosenPackage, ::chooseSinglePackage, vm::installExistingApp, ::navigateUp + ) + } + entry { + PackageFunctionScreen( + R.string.cross_profile_apps, vm.cpPackages, + vm::getCpPackages, vm::setPackageCp, ::navigateUp, vm.chosenPackage, + ::choosePackage, ::navigateToAppGroups, vm.appGroups + ) + } + entry { + PackageFunctionScreen(R.string.cross_profile_widget, vm.cpwProviders, + vm::getCpwProviders, vm::setCpwProvider, ::navigateUp, vm.chosenPackage, + ::choosePackage, ::navigateToAppGroups, vm.appGroups) + } + entry { + CredentialManagerPolicyScreen( + vm.chosenPackage, ::choosePackage, vm.cmPackages, vm::getCmPolicy, + vm::setCmPackage, vm::setCmPolicy, ::navigateUp + ) + } + entry { + 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 { + PermittedAsAndImPackages( + R.string.permitted_ime, R.string.system_ime_always_allowed, + vm.chosenPackage, ::choosePackage, vm.pimPackages, vm::getPimPackages, + vm::setPimPackage, vm::setPimPolicy, ::navigateUp + ) + } + entry { + EnableSystemAppScreen( + vm.chosenPackage, ::chooseSinglePackage, vm::enableSystemApp, ::navigateUp + ) + } + entry { + SetDefaultDialerScreen( + vm.chosenPackage, ::chooseSinglePackage, vm::setDefaultDialer, ::navigateUp + ) + } + entry { + ManagedConfigurationScreen( + it, vm.appRestrictions, vm::setAppRestrictions, + vm::clearAppRestrictions, ::navigateUp + ) + } + entry { + ManageAppGroupsScreen( + vm.appGroups, vm::exportAppGroups, vm::importAppGroups, + { id, name, apps -> navigate(Destination.EditAppGroup(id, name, apps)) }, + ::navigateUp + ) + } + entry { + EditAppGroupScreen( + it, vm::getAppInfo, ::navigateUp, vm::setAppGroup, + vm::deleteAppGroup, ::choosePackage, vm.chosenPackage + ) + } + + entry { + UserRestrictionScreen(vm::getUserRestrictions, ::navigateUp, ::navigate) + } + entry { + UserRestrictionEditorScreen(vm.userRestrictions, vm::setUserRestriction, ::navigateUp) + } + entry { + UserRestrictionOptionsScreen(it, vm.userRestrictions, + vm::setUserRestriction, vm::createUserRestrictionShortcut, ::navigateUp) + } + + entry { UsersScreen(vm, ::navigateUp, ::navigate) } + entry { UserInfoScreen(vm::getUserInformation, ::navigateUp) } + entry { + UsersOptionsScreen(vm::getLogoutEnabled, vm::setLogoutEnabled, ::navigateUp) + } + entry { + UserOperationScreen(vm::getUserIdentifiers, vm::doUserOperation, + vm::createUserOperationShortcut, ::navigateUp) + } + entry { CreateUserScreen(vm::createUser, ::navigateUp) } + entry { ChangeUsernameScreen(vm::setProfileName, ::navigateUp) } + entry { + UserSessionMessageScreen(vm::getUserSessionMessages, vm::setStartUserSessionMessage, + vm::setEndUserSessionMessage, ::navigateUp) + } + entry { + AffiliationIdScreen(vm.affiliationIds, vm::getAffiliationIds, vm::setAffiliationId, + ::navigateUp) + } + + entry { PasswordScreen(vm, ::navigateUp, ::navigate) } + entry { + PasswordInfoScreen(vm::getPasswordComplexity, vm::isPasswordComplexitySufficient, + vm::isUsingUnifiedPassword, ::navigateUp) + } + entry { + ResetPasswordTokenScreen(vm::getRpTokenState, vm::setRpToken, + vm::createActivateRpTokenIntent, vm::clearRpToken, ::navigateUp) + } + entry { ResetPasswordScreen(vm::resetPassword, ::navigateUp) } + entry { + RequiredPasswordComplexityScreen(vm::getRequiredPasswordComplexity, + vm::setRequiredPasswordComplexity, ::navigateUp) + } + entry { + KeyguardDisabledFeaturesScreen(vm::getKeyguardDisableConfig, + vm::setKeyguardDisableConfig, ::navigateUp) + } + entry { RequiredPasswordQualityScreen(::navigateUp) } + + entry { SettingsScreen(::navigate, ::navigateUp) } + entry { + SettingsOptionsScreen( + vm::getDisplayDangerousFeatures, vm::getShortcutsEnabled, + vm::setDisplayDangerousFeatures, vm::setShortcutsEnabled, ::navigateUp + ) + } + entry { + AppearanceScreen(::navigateUp, vm.theme, vm::changeTheme) + } + entry { + AppLockSettingsScreen(vm.getAppLockConfig(), vm::setAppLockConfig, ::navigateUp) + } + entry { + ApiSettings(vm::getApiEnabled, vm::setApiKey, ::navigateUp) + } + entry { + NotificationsScreen( + vm.enabledNotifications, vm::getEnabledNotifications, + vm::setNotificationEnabled, ::navigateUp + ) + } + entry { AboutScreen(::navigateUp) } +}(destination) as NavEntry diff --git a/app/src/main/java/com/bintianqi/owndroid/dpm/Applications.kt b/app/src/main/java/com/bintianqi/owndroid/ui/screen/Applications.kt similarity index 94% rename from app/src/main/java/com/bintianqi/owndroid/dpm/Applications.kt rename to app/src/main/java/com/bintianqi/owndroid/ui/screen/Applications.kt index 096e2a9..5fa0f5a 100644 --- a/app/src/main/java/com/bintianqi/owndroid/dpm/Applications.kt +++ b/app/src/main/java/com/bintianqi/owndroid/ui/screen/Applications.kt @@ -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_DENIED @@ -33,12 +33,10 @@ import androidx.compose.foundation.lazy.itemsIndexed import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.foundation.text.KeyboardActions import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.foundation.text.selection.SelectionContainer import androidx.compose.foundation.verticalScroll 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.Check 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.input.nestedscroll.nestedScroll 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.text.font.FontStyle import androidx.compose.ui.text.input.ImeAction -import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.unit.dp import androidx.compose.ui.window.Dialog import androidx.compose.ui.window.DialogProperties @@ -117,6 +113,8 @@ import com.bintianqi.owndroid.MyViewModel import com.bintianqi.owndroid.Privilege import com.bintianqi.owndroid.R 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.showOperationResultToast 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.NavIcon import com.bintianqi.owndroid.ui.Notes +import com.bintianqi.owndroid.ui.PackageNameTextField import com.bintianqi.owndroid.ui.SwitchItem +import com.bintianqi.owndroid.ui.navigation.Destination import com.google.accompanist.drawablepainter.rememberDrawablePainter import kotlinx.coroutines.channels.Channel 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) @Composable -fun ApplicationsFeaturesScreen(onNavigateUp: () -> Unit, onNavigate: (Any) -> Unit, onSwitchView: () -> Unit) { +fun ApplicationsFeaturesScreen( + onNavigateUp: () -> Unit, onNavigate: (Destination) -> Unit, onSwitchView: () -> Unit +) { val context = LocalContext.current val sb = TopAppBarDefaults.exitUntilCollapsedScrollBehavior() Scaffold( @@ -219,56 +197,82 @@ fun ApplicationsFeaturesScreen(onNavigateUp: () -> Unit, onNavigate: (Any) -> Un .padding(bottom = 80.dp) ) { val privilege by Privilege.status.collectAsStateWithLifecycle() - if(VERSION.SDK_INT >= 24) FunctionItem(R.string.suspend, icon = R.drawable.block_fill0) { onNavigate(Suspend) } - FunctionItem(R.string.hide, icon = R.drawable.visibility_off_fill0) { onNavigate(Hide) } - FunctionItem(R.string.block_uninstall, icon = R.drawable.delete_forever_fill0) { onNavigate(BlockUninstall) } + if(VERSION.SDK_INT >= 24) FunctionItem(R.string.suspend, icon = R.drawable.block_fill0) { + onNavigate(Destination.Suspend) + } + 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))) { - 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) { - onNavigate(PermissionManager) + onNavigate(Destination.PermissionManager) } 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) { - 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) { 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) { - 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))) { FunctionItem(R.string.install_existing_app, icon = R.drawable.install_mobile_fill0) { - onNavigate(InstallExistingApp) + onNavigate(Destination.InstallExistingApp) } } 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) { - 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) { - 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) { - 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)) { - 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( val suspend: Boolean, val hide: Boolean, @@ -280,7 +284,8 @@ data class AppStatus( @Composable 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 privilege by Privilege.status.collectAsStateWithLifecycle() @@ -302,7 +307,9 @@ fun ApplicationDetailsScreen( .alpha(0.7F) .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( R.string.suspend, icon = R.drawable.block_fill0, state = status.suspend, onCheckedChange = { vm.adSetPackageSuspended(packageName, it) } @@ -334,7 +341,7 @@ fun ApplicationDetailsScreen( ) if (appRestrictions.isNotEmpty()) { 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 } @@ -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 fun AppPermissionsManagerScreen( getPackagePermissions: (String) -> Map, setPackagePermission: (String, String, Int) -> Boolean, onNavigateUp: () -> Unit, - param: AppPermissionsManager + param: Destination.AppPermissionsManager ) { val context = LocalContext.current val privilege by Privilege.status.collectAsStateWithLifecycle() @@ -453,10 +450,10 @@ fun PackagePermissionDialog( ) } -@Serializable object PermissionManager - @Composable -fun PermissionManagerScreen(onNavigate: (PermissionDetail) -> Unit, onNavigateUp: () -> Unit) { +fun PermissionManagerScreen( + onNavigate: (Destination.PermissionDetail) -> Unit, onNavigateUp: () -> Unit +) { MyLazyScaffold(R.string.permissions, onNavigateUp) { items(runtimePermissions) { Row( @@ -464,7 +461,7 @@ fun PermissionManagerScreen(onNavigate: (PermissionDetail) -> Unit, onNavigateUp modifier = Modifier .fillMaxWidth() .clickable { - onNavigate(PermissionDetail(it.id)) + onNavigate(Destination.PermissionDetail(it.id)) } .padding(8.dp, 12.dp) ) { @@ -478,12 +475,10 @@ fun PermissionManagerScreen(onNavigate: (PermissionDetail) -> Unit, onNavigateUp } } -@Serializable class PermissionDetail(val permission: String) - @OptIn(ExperimentalMaterial3Api::class) @Composable fun PermissionDetailScreen( - param: PermissionDetail, getPermissionPackages: (String) -> List>, + param: Destination.PermissionDetail, getPermissionPackages: (String) -> List>, setPackagePermission: (String, String, Int) -> Boolean, onNavigateUp: () -> Unit ) { val context = LocalContext.current @@ -586,10 +581,6 @@ fun PermissionDetailScreen( ) { selectedPackage = null } } -@Serializable object DisableMeteredData - -@Serializable object ClearAppStorage - @RequiresApi(28) @Composable fun ClearAppStorageScreen( @@ -653,8 +644,6 @@ private fun ClearAppStorageDialog( ) } -@Serializable object UninstallApp - @Composable fun UninstallAppScreen( chosenPackage: Channel, onChoosePackage: () -> Unit, @@ -722,10 +711,6 @@ private fun UninstallAppDialog( ) } -@Serializable object KeepUninstalledPackages - -@Serializable object InstallExistingApp - @RequiresApi(28) @Composable fun InstallExistingAppScreen( @@ -752,12 +737,6 @@ fun InstallExistingAppScreen( } } -@Serializable object CrossProfilePackages - -@Serializable object CrossProfileWidgetProviders - -@Serializable object CredentialManagerPolicy - @RequiresApi(34) @Composable fun CredentialManagerPolicyScreen( @@ -819,10 +798,6 @@ fun CredentialManagerPolicyScreen( } } -@Serializable object PermittedAccessibilityServices - -@Serializable object PermittedInputMethods - @Composable fun PermittedAsAndImPackages( title: Int, note: Int, chosenPackage: Channel, onChoosePackage: () -> Unit, @@ -879,8 +854,6 @@ fun PermittedAsAndImPackages( } } -@Serializable object EnableSystemApp - @Composable fun EnableSystemAppScreen( chosenPackage: Channel, onChoosePackage: () -> Unit, @@ -910,8 +883,6 @@ fun EnableSystemAppScreen( } } -@Serializable object SetDefaultDialer - @RequiresApi(34) @Composable fun SetDefaultDialerScreen( @@ -1072,8 +1043,6 @@ class AppGroup( val id: Int, override val name: String, override val apps: List ) : BasicAppGroup(name, apps) -@Serializable object ManageAppGroups - @OptIn(ExperimentalMaterial3Api::class) @Composable fun ManageAppGroupsScreen( @@ -1158,12 +1127,10 @@ fun ManageAppGroupsScreen( } } -@Serializable class EditAppGroup(val id: Int?, val name: String, val apps: List) - @OptIn(ExperimentalMaterial3Api::class) @Composable fun EditAppGroupScreen( - params: EditAppGroup, getAppInfo: (String) -> AppInfo, navigateUp: () -> Unit, + params: Destination.EditAppGroup, getAppInfo: (String) -> AppInfo, navigateUp: () -> Unit, setGroup: (Int?, String, List) -> Unit, deleteGroup: (Int) -> Unit, onChoosePackage: () -> Unit, chosenPackage: Channel ) { @@ -1239,12 +1206,10 @@ fun EditAppGroupScreen( } } -@Serializable class ManagedConfiguration(val packageName: String) - @OptIn(ExperimentalMaterial3Api::class) @Composable fun ManagedConfigurationScreen( - params: ManagedConfiguration, appRestrictions: StateFlow>, + params: Destination.ManagedConfiguration, appRestrictions: StateFlow>, setRestriction: (String, AppRestriction) -> Unit, clearRestriction: (String) -> Unit, navigateUp: () -> Unit ) { diff --git a/app/src/main/java/com/bintianqi/owndroid/ui/screen/Home.kt b/app/src/main/java/com/bintianqi/owndroid/ui/screen/Home.kt new file mode 100644 index 0000000..2fcc9a5 --- /dev/null +++ b/app/src/main/java/com/bintianqi/owndroid/ui/screen/Home.kt @@ -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) + } +} diff --git a/app/src/main/java/com/bintianqi/owndroid/dpm/Network.kt b/app/src/main/java/com/bintianqi/owndroid/ui/screen/Network.kt similarity index 98% rename from app/src/main/java/com/bintianqi/owndroid/dpm/Network.kt rename to app/src/main/java/com/bintianqi/owndroid/ui/screen/Network.kt index 8723f40..1da9a25 100644 --- a/app/src/main/java/com/bintianqi/owndroid/dpm/Network.kt +++ b/app/src/main/java/com/bintianqi/owndroid/ui/screen/Network.kt @@ -1,4 +1,4 @@ -package com.bintianqi.owndroid.dpm +package com.bintianqi.owndroid.ui.screen import android.Manifest 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.NavIcon import com.bintianqi.owndroid.ui.Notes +import com.bintianqi.owndroid.ui.PackageNameTextField import com.bintianqi.owndroid.ui.SwitchItem +import com.bintianqi.owndroid.ui.navigation.Destination import com.bintianqi.owndroid.writeClipBoard import com.bintianqi.owndroid.yesOrNo import com.google.accompanist.permissions.ExperimentalPermissionsApi @@ -142,44 +144,58 @@ import java.text.SimpleDateFormat import java.util.Date import java.util.Locale -@Serializable object Network - @Composable -fun NetworkScreen(onNavigateUp: () -> Unit, onNavigate: (Any) -> Unit) { +fun NetworkScreen(onNavigateUp: () -> Unit, onNavigate: (Destination) -> Unit) { val privilege by Privilege.status.collectAsStateWithLifecycle() 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) { - 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) - 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) { - 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) { - 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) { - 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)) { - 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) { - 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)) { - 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) { - 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 fun NetworkOptionsScreen( getLanEnabled: () -> Boolean, setLanEnabled: (Boolean) -> Unit, onNavigateUp: () -> Unit @@ -208,12 +224,10 @@ fun NetworkOptionsScreen( ) } -@Serializable object WiFi - @OptIn(ExperimentalMaterial3Api::class) @Composable fun WifiScreen( - vm: MyViewModel, onNavigateUp: () -> Unit, onNavigate: (Any) -> Unit, + vm: MyViewModel, onNavigateUp: () -> Unit, onNavigate: (Destination) -> Unit, editNetwork: (Int) -> Unit ) { val coroutine = rememberCoroutineScope() @@ -266,7 +280,7 @@ fun WifiScreen( @Composable fun WifiOverviewScreen( setWifiEnabled: (Boolean) -> Boolean, disconnect: () -> Boolean, reconnect: () -> Boolean, - getMac: () -> String?, navigate: (Any) -> Unit + getMac: () -> String?, navigate: (Destination) -> Unit ) { val context = LocalContext.current val privilege by Privilege.status.collectAsStateWithLifecycle() @@ -305,8 +319,12 @@ fun WifiOverviewScreen( FunctionItem(R.string.wifi_mac_address) { macDialog = true } } if(VERSION.SDK_INT >= 33 && (privilege.device || privilege.org)) { - FunctionItem(R.string.min_wifi_security_level) { navigate(WifiSecurityLevel) } - FunctionItem(R.string.wifi_ssid_policy) { navigate(WifiSsidPolicyScreen) } + FunctionItem(R.string.min_wifi_security_level) { + navigate(Destination.WifiSecurityLevel) + } + FunctionItem(R.string.wifi_ssid_policy) { + navigate(Destination.WifiSsidPolicy) + } } } if (macDialog && VERSION.SDK_INT >= 24) { @@ -503,9 +521,6 @@ private fun SavedNetworks( ) } -@Serializable -data class UpdateNetwork(val index: Int) - @OptIn(ExperimentalMaterial3Api::class) @Composable fun UpdateNetworkScreen(info: WifiInfo, setNetwork: (WifiInfo) -> Boolean, onNavigateUp: () -> Unit) { @@ -813,8 +828,6 @@ private fun AddNetworkScreen( } } -@Serializable object WifiSecurityLevel - @RequiresApi(33) @Composable 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) } -@Serializable object WifiSsidPolicyScreen - @RequiresApi(33) @Composable fun WifiSsidPolicyScreen( @@ -948,8 +959,6 @@ data class QueryNetworkStatsParams( val startTime: Long, val endTime: Long, val uid: Int, val tag: Int, val state: NetworkStatsState ) -@Serializable object QueryNetworkStats - @OptIn(ExperimentalMaterial3Api::class) @Composable fun NetworkStatsScreen( @@ -1266,8 +1275,6 @@ data class NetworkStatsData( val metered: Int? ) -@Serializable object NetworkStatsViewer - @Composable fun NetworkStatsViewerScreen( data: List, 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) -@Serializable object PrivateDns - @RequiresApi(29) @Composable fun PrivateDnsScreen( @@ -1413,8 +1418,6 @@ fun PrivateDnsScreen( } } -@Serializable object AlwaysOnVpnPackage - @RequiresApi(24) @Composable fun AlwaysOnVpnPackageScreen( @@ -1464,8 +1467,6 @@ data class RecommendedProxyConf( val port: Int, val exclude: List ) -@Serializable object RecommendedGlobalProxy - @Composable fun RecommendedGlobalProxyScreen( setProxy: (RecommendedProxyConf) -> Unit, onNavigateUp: () -> Unit @@ -1538,8 +1539,6 @@ fun RecommendedGlobalProxyScreen( } } -@Serializable object NetworkLogging - @RequiresApi(26) @Composable fun NetworkLoggingScreen( @@ -1620,14 +1619,12 @@ fun NetworkLoggingScreen( ) } -@Serializable object PreferentialNetworkService - @RequiresApi(33) @Composable fun PreferentialNetworkServiceScreen( getEnabled: () -> Boolean, setEnabled: (Boolean) -> Unit, pnsConfigs: StateFlow>, getConfigs: () -> Unit, - onNavigateUp: () -> Unit, onNavigate: (AddPreferentialNetworkServiceConfig) -> Unit + onNavigateUp: () -> Unit, onNavigate: (Destination.AddPreferentialNetworkServiceConfig) -> Unit ) { var masterEnabled by rememberSaveable { mutableStateOf(getEnabled()) } val configs by pnsConfigs.collectAsStateWithLifecycle() @@ -1647,7 +1644,7 @@ fun PreferentialNetworkServiceScreen( ) { Text(config.id.toString()) IconButton({ - onNavigate(AddPreferentialNetworkServiceConfig(index)) + onNavigate(Destination.AddPreferentialNetworkServiceConfig(index)) }) { Icon(Icons.Default.Edit, stringResource(R.string.edit)) } @@ -1656,7 +1653,7 @@ fun PreferentialNetworkServiceScreen( Row( Modifier.fillMaxWidth() .padding(top = 4.dp) - .clickable { onNavigate(AddPreferentialNetworkServiceConfig(-1)) } + .clickable { onNavigate(Destination.AddPreferentialNetworkServiceConfig(-1)) } .padding(horizontal = 8.dp, vertical = 12.dp), verticalAlignment = Alignment.CenterVertically ) { @@ -1675,9 +1672,6 @@ data class PreferentialNetworkServiceInfo( val includedUids: List = emptyList() ) -@Serializable -data class AddPreferentialNetworkServiceConfig(val index: Int) - @OptIn(ExperimentalMaterial3Api::class) @RequiresApi(33) @Composable @@ -1769,8 +1763,6 @@ fun AddPreferentialNetworkServiceConfigScreen( } } -@Serializable object OverrideApn - @RequiresApi(28) @Composable fun OverrideApnScreen( @@ -1901,8 +1893,6 @@ data class ApnConfig( val persistent: Boolean, val alwaysOn: Boolean, val id: Int = -1 ) -@Serializable data class AddApnSetting(val index: Int) - @OptIn(ExperimentalMaterial3Api::class) @RequiresApi(28) @Composable diff --git a/app/src/main/java/com/bintianqi/owndroid/dpm/Password.kt b/app/src/main/java/com/bintianqi/owndroid/ui/screen/Password.kt similarity index 96% rename from app/src/main/java/com/bintianqi/owndroid/dpm/Password.kt rename to app/src/main/java/com/bintianqi/owndroid/ui/screen/Password.kt index db843e3..5b1fb61 100644 --- a/app/src/main/java/com/bintianqi/owndroid/dpm/Password.kt +++ b/app/src/main/java/com/bintianqi/owndroid/ui/screen/Password.kt @@ -1,4 +1,4 @@ -package com.bintianqi.owndroid.dpm +package com.bintianqi.owndroid.ui.screen import android.annotation.SuppressLint 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.Notes import com.bintianqi.owndroid.ui.RadioButtonItem +import com.bintianqi.owndroid.ui.navigation.Destination import com.bintianqi.owndroid.yesOrNo -import kotlinx.serialization.Serializable - -@Serializable object Password @SuppressLint("NewApi") @Composable -fun PasswordScreen(vm: MyViewModel,onNavigateUp: () -> Unit, onNavigate: (Any) -> Unit) { +fun PasswordScreen(vm: MyViewModel,onNavigateUp: () -> Unit, onNavigate: (Destination) -> Unit) { val context = LocalContext.current val privilege by Privilege.status.collectAsStateWithLifecycle() var dialog by rememberSaveable { mutableIntStateOf(0) } 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(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) { - 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) { 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 } @@ -106,7 +114,9 @@ fun PasswordScreen(vm: MyViewModel,onNavigateUp: () -> Unit, onNavigate: (Any) - } FunctionItem(R.string.pwd_history, icon = R.drawable.history_fill0) { dialog = 5 } if(VERSION.SDK_INT < 31) { - FunctionItem(R.string.required_password_quality, icon = R.drawable.password_fill0) { onNavigate(RequiredPasswordQuality) } + FunctionItem(R.string.required_password_quality, icon = R.drawable.password_fill0) { + onNavigate(Destination.RequiredPasswordQuality) + } } } if(dialog != 0) { @@ -205,8 +215,6 @@ enum class PasswordComplexity(val id: Int, val text: Int) { High(DevicePolicyManager.PASSWORD_COMPLEXITY_HIGH, R.string.high) } -@Serializable object PasswordInfo - @Composable fun PasswordInfoScreen( getComplexity: () -> PasswordComplexity, isSufficient: () -> Boolean, isUnified: () -> Boolean, @@ -236,8 +244,6 @@ fun PasswordInfoScreen( data class RpTokenState(val set: Boolean, val active: Boolean) -@Serializable object ResetPasswordToken - @RequiresApi(26) @Composable fun ResetPasswordTokenScreen( @@ -303,8 +309,6 @@ fun ResetPasswordTokenScreen( } } -@Serializable object ResetPassword - @Composable fun ResetPasswordScreen(resetPassword: (String, String, Int) -> Boolean, onNavigateUp: () -> Unit) { val context = LocalContext.current @@ -358,8 +362,6 @@ fun ResetPasswordScreen(resetPassword: (String, String, Int) -> Boolean, onNavig } } -@Serializable object RequiredPasswordComplexity - @RequiresApi(31) @Composable fun RequiredPasswordComplexityScreen( @@ -408,8 +410,6 @@ enum class KeyguardDisableMode(val text: Int) { data class KeyguardDisableConfig(val mode: KeyguardDisableMode, val flags: Int) -@Serializable object KeyguardDisabledFeatures - @Composable fun KeyguardDisabledFeaturesScreen( getConfig: () -> KeyguardDisableConfig, setConfig: (KeyguardDisableConfig) -> Unit, @@ -449,8 +449,6 @@ fun KeyguardDisabledFeaturesScreen( } } -@Serializable object RequiredPasswordQuality - @Composable fun RequiredPasswordQualityScreen(onNavigateUp: () -> Unit) { val context = LocalContext.current diff --git a/app/src/main/java/com/bintianqi/owndroid/Settings.kt b/app/src/main/java/com/bintianqi/owndroid/ui/screen/Settings.kt similarity index 89% rename from app/src/main/java/com/bintianqi/owndroid/Settings.kt rename to app/src/main/java/com/bintianqi/owndroid/ui/screen/Settings.kt index a005535..8ee2602 100644 --- a/app/src/main/java/com/bintianqi/owndroid/Settings.kt +++ b/app/src/main/java/com/bintianqi/owndroid/ui/screen/Settings.kt @@ -1,4 +1,4 @@ -package com.bintianqi.owndroid +package com.bintianqi.owndroid.ui.screen import android.content.Context 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.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.text.KeyboardOptions @@ -54,23 +55,31 @@ import androidx.compose.ui.unit.DpOffset import androidx.compose.ui.unit.dp import androidx.core.net.toUri 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.MyScaffold import com.bintianqi.owndroid.ui.NavIcon import com.bintianqi.owndroid.ui.Notes import com.bintianqi.owndroid.ui.SwitchItem +import com.bintianqi.owndroid.ui.navigation.Destination import kotlinx.coroutines.flow.StateFlow -import kotlinx.serialization.Serializable import java.text.SimpleDateFormat import java.util.Date import java.util.Locale import kotlin.system.exitProcess -@Serializable object Settings - @OptIn(ExperimentalMaterial3Api::class) @Composable -fun SettingsScreen(onNavigateUp: () -> Unit, onNavigate: (Any) -> Unit) { +fun SettingsScreen(onNavigate: (Destination) -> Unit, onNavigateUp: () -> Unit) { val context = LocalContext.current val privilege by Privilege.status.collectAsStateWithLifecycle() val exportLogsLauncher = rememberLauncherForActivityResult(ActivityResultContracts.CreateDocument("text/plain")) { @@ -120,22 +129,34 @@ fun SettingsScreen(onNavigateUp: () -> Unit, onNavigate: (Any) -> Unit) { .fillMaxSize() .padding(paddingValues) .verticalScroll(rememberScrollState()) - .padding(bottom = 80.dp) ) { - FunctionItem(title = R.string.options, icon = R.drawable.tune_fill0) { onNavigate(SettingsOptions) } - FunctionItem(title = R.string.appearance, icon = R.drawable.format_paint_fill0) { onNavigate(Appearance) } - FunctionItem(R.string.app_lock, icon = R.drawable.lock_fill0) { onNavigate(AppLockSettings) } - if (privilege.device || privilege.profile) - FunctionItem(title = R.string.api, icon = R.drawable.code_fill0) { onNavigate(ApiSettings) } - if (privilege.device && !privilege.dhizuku) - FunctionItem(R.string.notifications, icon = R.drawable.notifications_fill0) { onNavigate(Notifications) } - FunctionItem(title = R.string.about, icon = R.drawable.info_fill0) { onNavigate(About) } + FunctionItem(R.string.options, icon = R.drawable.tune_fill0) { + onNavigate(Destination.SettingsOptions) + } + FunctionItem(R.string.appearance, icon = R.drawable.format_paint_fill0) { + onNavigate(Destination.AppearanceSettings) + } + FunctionItem(R.string.app_lock, icon = R.drawable.lock_fill0) { + 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 fun SettingsOptionsScreen( getDisplayDangerousFeatures: () -> Boolean, getShortcutsEnabled: () -> Boolean, @@ -160,8 +181,6 @@ fun SettingsOptionsScreen( } } -@Serializable object Appearance - @Composable fun AppearanceScreen( onNavigateUp: () -> Unit, currentTheme: StateFlow, @@ -225,8 +244,6 @@ data class AppLockConfig( val password: String?, val biometrics: Boolean, val whenLeaving: Boolean ) -@Serializable object AppLockSettings - @Composable fun AppLockSettingsScreen( config: AppLockConfig, setConfig: (AppLockConfig) -> Unit, @@ -286,8 +303,6 @@ fun AppLockSettingsScreen( } } -@Serializable object ApiSettings - @Composable fun ApiSettings( getEnabled: () -> Boolean, setKey: (String) -> Unit, onNavigateUp: () -> Unit @@ -326,8 +341,6 @@ fun ApiSettings( } } -@Serializable object Notifications - @Composable fun NotificationsScreen( enabledNotifications: StateFlow>, getState: () -> Unit, @@ -344,8 +357,6 @@ fun NotificationsScreen( } } -@Serializable object About - @Composable fun AboutScreen(onNavigateUp: () -> Unit) { val context = LocalContext.current diff --git a/app/src/main/java/com/bintianqi/owndroid/dpm/System.kt b/app/src/main/java/com/bintianqi/owndroid/ui/screen/System.kt similarity index 97% rename from app/src/main/java/com/bintianqi/owndroid/dpm/System.kt rename to app/src/main/java/com/bintianqi/owndroid/ui/screen/System.kt index 3f4a433..58bf94c 100644 --- a/app/src/main/java/com/bintianqi/owndroid/dpm/System.kt +++ b/app/src/main/java/com/bintianqi/owndroid/ui/screen/System.kt @@ -1,4 +1,4 @@ -package com.bintianqi.owndroid.dpm +package com.bintianqi.owndroid.ui.screen import android.annotation.SuppressLint 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.NavIcon import com.bintianqi.owndroid.ui.Notes +import com.bintianqi.owndroid.ui.PackageNameTextField import com.bintianqi.owndroid.ui.SwitchItem +import com.bintianqi.owndroid.ui.navigation.Destination import com.bintianqi.owndroid.yesOrNo import com.google.accompanist.drawablepainter.rememberDrawablePainter import kotlinx.coroutines.channels.Channel @@ -139,30 +141,33 @@ import kotlinx.coroutines.delay import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.launch -import kotlinx.serialization.Serializable import java.text.SimpleDateFormat import java.util.Date import java.util.Locale import java.util.TimeZone import kotlin.math.roundToLong -@Serializable object SystemManager - @Composable fun SystemManagerScreen( - vm: MyViewModel, onNavigateUp: () -> Unit, onNavigate: (Any) -> Unit + vm: MyViewModel, onNavigateUp: () -> Unit, onNavigate: (Destination) -> Unit ) { val context = LocalContext.current val privilege by Privilege.status.collectAsStateWithLifecycle() /** 1: reboot, 2: bug report, 3: org name, 4: org id, 5: enrollment specific id*/ var dialog by rememberSaveable { mutableIntStateOf(0) } MyScaffold(R.string.system, onNavigateUp, 0.dp) { - FunctionItem(R.string.options, icon = R.drawable.tune_fill0) { onNavigate(SystemOptions) } - FunctionItem(R.string.keyguard, icon = R.drawable.screen_lock_portrait_fill0) { onNavigate(Keyguard) } + FunctionItem(R.string.options, icon = R.drawable.tune_fill0) { + 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) - 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) { - onNavigate(DefaultInputMethod) + onNavigate(Destination.DefaultInputMethod) } if(VERSION.SDK_INT >= 24 && privilege.device) { 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 } } if(VERSION.SDK_INT >= 28 && (privilege.device || privilege.org)) { - FunctionItem(R.string.change_time, icon = R.drawable.schedule_fill0) { onNavigate(ChangeTime) } - FunctionItem(R.string.change_timezone, icon = R.drawable.globe_fill0) { onNavigate(ChangeTimeZone) } + FunctionItem(R.string.change_time, icon = R.drawable.schedule_fill0) { + 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)) { - FunctionItem(R.string.auto_time_policy, icon = R.drawable.schedule_fill0) { onNavigate(AutoTimePolicy) } - FunctionItem(R.string.auto_timezone_policy, icon = R.drawable.globe_fill0) { onNavigate(AutoTimeZonePolicy) } + FunctionItem(R.string.auto_time_policy, icon = R.drawable.schedule_fill0) { + onNavigate(Destination.AutoTimePolicy) + } + FunctionItem(R.string.auto_timezone_policy, icon = R.drawable.globe_fill0) { + onNavigate(Destination.AutoTimezonePolicy) + } } /*if(VERSION.SDK_INT >= 28 && (deviceOwner || profileOwner)) FunctionItem(R.string.key_pairs, icon = R.drawable.key_vertical_fill0) { navCtrl.navigate("KeyPairs") }*/ if(VERSION.SDK_INT >= 35 && (privilege.device || (privilege.profile && privilege.affiliated))) - FunctionItem(R.string.content_protection_policy, icon = R.drawable.search_fill0) { onNavigate(ContentProtectionPolicy) } - FunctionItem(R.string.permission_policy, icon = R.drawable.key_fill0) { onNavigate(PermissionPolicy) } + FunctionItem(R.string.content_protection_policy, icon = R.drawable.search_fill0) { + onNavigate(Destination.ContentProtectionPolicy) + } + FunctionItem(R.string.permission_policy, icon = R.drawable.key_fill0) { + onNavigate(Destination.PermissionPolicy) + } 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) { - 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) { - 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)) { - 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))) { 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 } } 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) { - 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) { - 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)) { - 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)) { - 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) { - 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( @@ -329,13 +372,11 @@ data class SystemOptionsStatus( val stayOnWhilePluggedIn: Boolean = false ) -@Serializable object SystemOptions - class GlobalSetting(val icon: Int, val name: Int, val setting: String) // also for secure settings // STAY_ON_WHILE_PLUGGED_IN is set separately 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.usb_fill0, R.string.enable_usb_mass_storage, Settings.Global.USB_MASS_STORAGE_ENABLED), @@ -457,8 +498,6 @@ fun SystemOptionsScreen(vm: MyViewModel, onNavigateUp: () -> Unit) { ) } -@Serializable object Keyguard - @Composable fun KeyguardScreen( setKeyguardDisabled: (Boolean) -> Boolean, lock: (Boolean) -> Unit, onNavigateUp: () -> Unit @@ -519,8 +558,6 @@ val temperatureTypes = mapOf( HardwarePropertiesManager.DEVICE_TEMPERATURE_SKIN to R.string.skin_temp ) -@Serializable object HardwareMonitor - @RequiresApi(24) @Composable fun HardwareMonitorScreen( @@ -586,8 +623,6 @@ fun HardwareMonitorScreen( } } -@Serializable object DefaultInputMethod - @Composable fun DefaultInputMethodScreen( getCurrentIm: () -> String, imListState: StateFlow>>, @@ -632,8 +667,6 @@ fun DefaultInputMethodScreen( } } -@Serializable object ChangeTime - @OptIn(ExperimentalMaterial3Api::class) @RequiresApi(28) @Composable @@ -768,8 +801,6 @@ fun ChangeTimeScreen(setTime: (Long, Boolean) -> Boolean, onNavigateUp: () -> Un } } -@Serializable object ChangeTimeZone - @RequiresApi(28) @Composable fun ChangeTimeZoneScreen(setTimeZone: (String) -> Boolean, onNavigateUp: () -> Unit) { @@ -835,8 +866,6 @@ fun ChangeTimeZoneScreen(setTimeZone: (String) -> Boolean, onNavigateUp: () -> U ) } -@Serializable object AutoTimePolicy - @RequiresApi(36) @Composable fun AutoTimePolicyScreen( @@ -866,8 +895,6 @@ fun AutoTimePolicyScreen( } } -@Serializable object AutoTimeZonePolicy - @RequiresApi(36) @Composable fun AutoTimeZonePolicyScreen( @@ -1074,8 +1101,6 @@ fun KeyPairs(navCtrl: NavHostController) { } }*/ -@Serializable object ContentProtectionPolicy - @RequiresApi(35) @Composable fun ContentProtectionPolicyScreen( @@ -1106,8 +1131,6 @@ fun ContentProtectionPolicyScreen( } } -@Serializable object PermissionPolicy - @Composable fun PermissionPolicyScreen( getPolicy: () -> Int, setPolicy: (Int) -> Unit, onNavigateUp: () -> Unit @@ -1139,8 +1162,6 @@ fun PermissionPolicyScreen( } } -@Serializable object MtePolicy - @RequiresApi(34) @Composable fun MtePolicyScreen( @@ -1167,8 +1188,6 @@ fun MtePolicyScreen( } } -@Serializable object NearbyStreamingPolicy - @RequiresApi(31) @Composable fun NearbyStreamingPolicyScreen( @@ -1241,8 +1260,6 @@ fun NearbyStreamingPolicyScreen( } } -@Serializable object LockTaskMode - @OptIn(ExperimentalMaterial3Api::class) @RequiresApi(28) @Composable @@ -1467,8 +1484,6 @@ data class CaCertInfo( val bytes: ByteArray ) -@Serializable object CaCert - @OptIn(ExperimentalMaterial3Api::class, ExperimentalStdlibApi::class) @Composable fun CaCertScreen( @@ -1639,8 +1654,6 @@ fun CaCertScreen( } } -@Serializable object SecurityLogging - @RequiresApi(24) @Composable fun SecurityLoggingScreen( @@ -1745,8 +1758,6 @@ fun SecurityLoggingScreen( ) } -@Serializable object DisableAccountManagement - @Composable fun DisableAccountManagementScreen( mdAccounts: StateFlow>, getMdAccounts: () -> Unit, @@ -1798,8 +1809,6 @@ data class FrpPolicyInfo( val accounts: List ) -@Serializable object FrpPolicy - @RequiresApi(30) @Composable fun FrpPolicyScreen( @@ -1874,8 +1883,6 @@ fun FrpPolicyScreen( } } -@Serializable object WipeData - @Composable fun WipeDataScreen( 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 PendingSystemUpdateInfo(val exists: Boolean, val time: Long, val securityPatch: Boolean) -@Serializable object SetSystemUpdatePolicy - @Composable fun SystemUpdatePolicyScreen( getPolicy: () -> SystemUpdatePolicyInfo, setPolicy: (SystemUpdatePolicyInfo) -> Unit, @@ -2083,8 +2088,6 @@ fun SystemUpdatePolicyScreen( } } -@Serializable object InstallSystemUpdate - @SuppressLint("NewApi") @Composable fun InstallSystemUpdateScreen( diff --git a/app/src/main/java/com/bintianqi/owndroid/dpm/UserRestriction.kt b/app/src/main/java/com/bintianqi/owndroid/ui/screen/UserRestriction.kt similarity index 95% rename from app/src/main/java/com/bintianqi/owndroid/dpm/UserRestriction.kt rename to app/src/main/java/com/bintianqi/owndroid/ui/screen/UserRestriction.kt index 8fe03b4..f324210 100644 --- a/app/src/main/java/com/bintianqi/owndroid/dpm/UserRestriction.kt +++ b/app/src/main/java/com/bintianqi/owndroid/ui/screen/UserRestriction.kt @@ -1,4 +1,4 @@ -package com.bintianqi.owndroid.dpm +package com.bintianqi.owndroid.ui.screen import androidx.annotation.RequiresApi 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.MyLazyScaffold import com.bintianqi.owndroid.ui.NavIcon +import com.bintianqi.owndroid.ui.navigation.Destination import kotlinx.coroutines.flow.StateFlow import kotlinx.serialization.Serializable @@ -74,13 +75,11 @@ data class Restriction( val requiresApi: Int = 0 ) -@Serializable object UserRestriction - @OptIn(ExperimentalMaterial3Api::class) @RequiresApi(24) @Composable fun UserRestrictionScreen( - getRestrictions: () -> Unit,onNavigateUp: () -> Unit, onNavigate: (Any) -> Unit + getRestrictions: () -> Unit,onNavigateUp: () -> Unit, onNavigate: (Destination) -> Unit ) { val privilege by Privilege.status.collectAsStateWithLifecycle() val sb = TopAppBarDefaults.exitUntilCollapsedScrollBehavior() @@ -92,7 +91,7 @@ fun UserRestrictionScreen( { Text(stringResource(R.string.user_restriction)) }, navigationIcon = { NavIcon(onNavigateUp) }, actions = { - IconButton({ onNavigate(UserRestrictionEditor) }) { + IconButton({ onNavigate(Destination.UserRestrictionEditor) }) { Icon(Icons.Default.Edit, null) } }, @@ -119,7 +118,7 @@ fun UserRestrictionScreen( Spacer(Modifier.padding(vertical = 2.dp)) UserRestrictionCategory.entries.forEach { FunctionItem(it.title, icon = it.icon) { - onNavigate(UserRestrictionOptions(it.name)) + onNavigate(Destination.UserRestrictionOptions(it.name)) } } Row( @@ -137,13 +136,10 @@ fun UserRestrictionScreen( } } -@Serializable -data class UserRestrictionOptions(val id: String) - @RequiresApi(24) @Composable fun UserRestrictionOptionsScreen( - args: UserRestrictionOptions, userRestrictions: StateFlow>, + args: Destination.UserRestrictionOptions, userRestrictions: StateFlow>, setRestriction: (String, Boolean) -> Boolean, setShortcut: (String) -> Boolean, onNavigateUp: () -> Unit ) { @@ -188,8 +184,6 @@ fun UserRestrictionOptionsScreen( } } -@Serializable object UserRestrictionEditor - @OptIn(ExperimentalMaterial3Api::class) @RequiresApi(24) @Composable diff --git a/app/src/main/java/com/bintianqi/owndroid/dpm/Users.kt b/app/src/main/java/com/bintianqi/owndroid/ui/screen/Users.kt similarity index 97% rename from app/src/main/java/com/bintianqi/owndroid/dpm/Users.kt rename to app/src/main/java/com/bintianqi/owndroid/ui/screen/Users.kt index 18776a3..3168369 100644 --- a/app/src/main/java/com/bintianqi/owndroid/dpm/Users.kt +++ b/app/src/main/java/com/bintianqi/owndroid/ui/screen/Users.kt @@ -1,4 +1,4 @@ -package com.bintianqi.owndroid.dpm +package com.bintianqi.owndroid.ui.screen import android.app.admin.DevicePolicyManager 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.Notes import com.bintianqi.owndroid.ui.SwitchItem +import com.bintianqi.owndroid.ui.navigation.Destination import com.bintianqi.owndroid.uriToStream import com.bintianqi.owndroid.yesOrNo import kotlinx.coroutines.flow.StateFlow -import kotlinx.serialization.Serializable - -@Serializable object Users @Composable -fun UsersScreen(vm: MyViewModel, onNavigateUp: () -> Unit, onNavigate: (Any) -> Unit) { +fun UsersScreen(vm: MyViewModel, onNavigateUp: () -> Unit, onNavigate: (Destination) -> Unit) { val context = LocalContext.current val privilege by Privilege.status.collectAsStateWithLifecycle() /** 1: logout */ @@ -94,17 +92,27 @@ fun UsersScreen(vm: MyViewModel, onNavigateUp: () -> Unit, onNavigate: (Any) -> if(VERSION.SDK_INT >= 28 && privilege.profile && privilege.affiliated) { 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) { - 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) { - 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) { - 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 bitmap: Bitmap? by remember { mutableStateOf(null) } val launcher = rememberLauncherForActivityResult(ActivityResultContracts.GetContent()) { @@ -123,10 +131,14 @@ fun UsersScreen(vm: MyViewModel, onNavigateUp: () -> Unit, onNavigate: (Any) -> changeUserIconDialog = false }) { changeUserIconDialog = false } 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) { - 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( @@ -151,8 +163,6 @@ fun UsersScreen(vm: MyViewModel, onNavigateUp: () -> Unit, onNavigate: (Any) -> ) } -@Serializable object UsersOptions - @Composable fun UsersOptionsScreen( getLogoutEnabled: () -> Boolean, setLogoutEnabled: (Boolean) -> Unit, onNavigateUp: () -> Unit @@ -176,8 +186,6 @@ data class UserInformation( val serial: Long = 0 ) -@Serializable object UserInfo - @Composable fun UserInfoScreen(getInfo: () -> UserInformation, onNavigateUp: () -> Unit) { var info by remember { mutableStateOf(UserInformation()) } @@ -219,8 +227,6 @@ enum class UserOperationType { Start, Switch, Stop, Delete } -@Serializable object UserOperation - @OptIn(ExperimentalMaterial3Api::class) @Composable fun UserOperationScreen( @@ -370,8 +376,6 @@ fun UserOperationScreen( data class CreateUserResult(val message: Int, val serial: Long = -1) -@Serializable object CreateUser - @RequiresApi(24) @Composable fun CreateUserScreen( @@ -436,8 +440,6 @@ fun CreateUserScreen( } } -@Serializable object AffiliationId - @RequiresApi(26) @Composable fun AffiliationIdScreen( @@ -478,8 +480,6 @@ fun AffiliationIdScreen( } } -@Serializable object ChangeUsername - @Composable fun ChangeUsernameScreen(setName: (String) -> Unit, onNavigateUp: () -> Unit) { val context = LocalContext.current @@ -507,8 +507,6 @@ fun ChangeUsernameScreen(setName: (String) -> Unit, onNavigateUp: () -> Unit) { } } -@Serializable object UserSessionMessage - @RequiresApi(28) @Composable fun UserSessionMessageScreen( diff --git a/app/src/main/java/com/bintianqi/owndroid/dpm/WorkProfile.kt b/app/src/main/java/com/bintianqi/owndroid/ui/screen/WorkProfile.kt similarity index 97% rename from app/src/main/java/com/bintianqi/owndroid/dpm/WorkProfile.kt rename to app/src/main/java/com/bintianqi/owndroid/ui/screen/WorkProfile.kt index 7b1ca53..50eb325 100644 --- a/app/src/main/java/com/bintianqi/owndroid/dpm/WorkProfile.kt +++ b/app/src/main/java/com/bintianqi/owndroid/ui/screen/WorkProfile.kt @@ -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.WIPE_EUICC @@ -77,23 +77,30 @@ import com.bintianqi.owndroid.ui.MyScaffold import com.bintianqi.owndroid.ui.NavIcon import com.bintianqi.owndroid.ui.Notes import com.bintianqi.owndroid.ui.SwitchItem +import com.bintianqi.owndroid.ui.navigation.Destination import com.bintianqi.owndroid.yesOrNo import kotlinx.serialization.Serializable -@Serializable object WorkProfile - @Composable -fun WorkProfileScreen(onNavigateUp: () -> Unit, onNavigate: (Any) -> Unit) { +fun WorkProfileScreen(onNavigateUp: () -> Unit, onNavigate: (Destination) -> Unit) { val privilege by Privilege.status.collectAsStateWithLifecycle() MyScaffold(R.string.work_profile, onNavigateUp, 0.dp) { 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) { - 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 ) -@Serializable object CreateWorkProfile - @Composable fun CreateWorkProfileScreen( createIntent: (CreateWorkProfileOptions) -> Intent, onNavigateUp: () -> Unit @@ -165,8 +170,6 @@ fun CreateWorkProfileScreen( } } -@Serializable object OrganizationOwnedProfile - @RequiresApi(30) @Composable fun OrganizationOwnedProfileScreen( @@ -205,8 +208,6 @@ fun OrganizationOwnedProfileScreen( val activateOrgProfileCommand = "dpm mark-profile-owner-on-organization-owned-device --user " + "${Binder.getCallingUid()/100000} com.bintianqi.owndroid/com.bintianqi.owndroid.Receiver" -@Serializable object SuspendPersonalApp - @RequiresApi(30) @Composable fun SuspendPersonalAppScreen( @@ -267,8 +268,6 @@ val crossProfileIntentFilterPresets = mapOf( IntentFilterOptions(Intent.ACTION_SEND, Intent.CATEGORY_DEFAULT, "*/*", 3) ) -@Serializable object CrossProfileIntentFilter - @OptIn(ExperimentalMaterial3Api::class) @Composable fun CrossProfileIntentFilterScreen( @@ -452,8 +451,6 @@ fun CrossProfileIntentFilterScreen( } } -@Serializable object DeleteWorkProfile - @Composable fun DeleteWorkProfileScreen( deleteProfile: (Boolean, Int, String) -> Unit, onNavigateUp: () -> Unit diff --git a/app/src/main/java/com/bintianqi/owndroid/dpm/Permissions.kt b/app/src/main/java/com/bintianqi/owndroid/ui/screen/WorkingModes.kt similarity index 95% rename from app/src/main/java/com/bintianqi/owndroid/dpm/Permissions.kt rename to app/src/main/java/com/bintianqi/owndroid/ui/screen/WorkingModes.kt index 059071d..e29cc38 100644 --- a/app/src/main/java/com/bintianqi/owndroid/dpm/Permissions.kt +++ b/app/src/main/java/com/bintianqi/owndroid/ui/screen/WorkingModes.kt @@ -1,4 +1,4 @@ -package com.bintianqi.owndroid.dpm +package com.bintianqi.owndroid.ui.screen import android.app.admin.DevicePolicyManager import android.content.ComponentName @@ -88,8 +88,10 @@ import com.bintianqi.owndroid.HorizontalPadding import com.bintianqi.owndroid.MyViewModel import com.bintianqi.owndroid.Privilege import com.bintianqi.owndroid.R -import com.bintianqi.owndroid.Settings 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.ui.CircularProgressDialog 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.NavIcon import com.bintianqi.owndroid.ui.Notes +import com.bintianqi.owndroid.ui.PackageNameTextField import com.bintianqi.owndroid.ui.SwitchItem +import com.bintianqi.owndroid.ui.navigation.Destination import com.bintianqi.owndroid.yesOrNo import com.google.accompanist.drawablepainter.rememberDrawablePainter import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.delay import kotlinx.coroutines.flow.StateFlow -import kotlinx.serialization.Serializable - -@Serializable data class WorkModes(val canNavigateUp: Boolean) @OptIn(ExperimentalMaterial3Api::class, ExperimentalLayoutApi::class) @Composable fun WorkModesScreen( - vm: MyViewModel, params: WorkModes, onNavigateUp: () -> Unit, onActivate: () -> Unit, - onDeactivate: () -> Unit, onNavigate: (Any) -> Unit + vm: MyViewModel, params: Destination.WorkingModes, onNavigateUp: () -> Unit, + onActivate: () -> Unit, onDeactivate: () -> Unit, onNavigate: (Destination) -> Unit ) { val privilege by Privilege.status.collectAsStateWithLifecycle() /** 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)) }, { expanded = false - onNavigate(DelegatedAdmins) + onNavigate(Destination.DelegatedAdmins) }, leadingIcon = { Icon(painterResource(R.drawable.admin_panel_settings_fill0), null) } ) @@ -170,13 +171,13 @@ fun WorkModesScreen( { Text(stringResource(R.string.transfer_ownership)) }, { expanded = false - onNavigate(TransferOwnership) + onNavigate(Destination.TransferOwnership) }, 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) } } @@ -210,14 +211,14 @@ fun WorkModesScreen( privilege.work || (VERSION.SDK_INT < 24 || vm.isCreatingWorkProfileAllowed()) ) { WorkingModeItem(R.string.work_profile, privilege.work) { - if (!privilege.work) onNavigate(CreateWorkProfile) + if (!privilege.work) onNavigate(Destination.CreateWorkProfile) } } if (privilege.activated && !privilege.dhizuku) Row( Modifier .padding(top = 20.dp) .fillMaxWidth() - .clickable { onNavigate(DhizukuServerSettings) } + .clickable { onNavigate(Destination.DhizukuServerSettings) } .padding(vertical = 4.dp), 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 fun DhizukuServerSettingsScreen( dhizukuClients: StateFlow>>, @@ -446,8 +443,6 @@ fun DhizukuServerSettingsScreen( } } -@Serializable object LockScreenInfo - @RequiresApi(24) @Composable fun LockScreenInfoScreen( @@ -509,15 +504,11 @@ val delegatedScopesList = listOf( DelegatedScope(DevicePolicyManager.DELEGATION_SECURITY_LOGGING, R.string.security_logging, 31) ).filter { VERSION.SDK_INT >= it.requiresApi } -data class DelegatedAdmin(val app: AppInfo, val scopes: List) - -@Serializable object DelegatedAdmins - @RequiresApi(26) @Composable fun DelegatedAdminsScreen( delegatedAdmins: StateFlow>, getDelegatedAdmins: () -> Unit, - onNavigateUp: () -> Unit, onNavigate: (AddDelegatedAdmin) -> Unit + onNavigateUp: () -> Unit, onNavigate: (Destination.DelegatedAdminDetails) -> Unit ) { val admins by delegatedAdmins.collectAsStateWithLifecycle() LaunchedEffect(Unit) { getDelegatedAdmins() } @@ -537,7 +528,7 @@ fun DelegatedAdminsScreen( 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) } } @@ -546,7 +537,7 @@ fun DelegatedAdminsScreen( Row( modifier = Modifier .fillMaxWidth() - .clickable { onNavigate(AddDelegatedAdmin()) } + .clickable { onNavigate(Destination.DelegatedAdminDetails("", emptyList())) } .padding(12.dp), verticalAlignment = Alignment.CenterVertically ) { @@ -557,12 +548,10 @@ fun DelegatedAdminsScreen( } } -@Serializable data class AddDelegatedAdmin(val pkg: String = "", val scopes: List = emptyList()) - @RequiresApi(26) @Composable fun AddDelegatedAdminScreen( - chosenPackage: Channel, onChoosePackage: () -> Unit, data: AddDelegatedAdmin, + chosenPackage: Channel, onChoosePackage: () -> Unit, data: Destination.DelegatedAdminDetails, setDelegatedAdmin: (String, List) -> Unit, onNavigateUp: () -> Unit ) { val updateMode = data.pkg.isNotEmpty() @@ -620,8 +609,6 @@ fun AddDelegatedAdminScreen( } } -@Serializable object DeviceInfo - @Composable fun DeviceInfoScreen(vm: MyViewModel, onNavigateUp: () -> Unit) { val privilege by Privilege.status.collectAsStateWithLifecycle() @@ -657,8 +644,6 @@ fun DeviceInfoScreen(vm: MyViewModel, onNavigateUp: () -> Unit) { ) } -@Serializable object SupportMessage - @RequiresApi(24) @Composable fun SupportMessageScreen( @@ -739,10 +724,6 @@ fun SupportMessageScreen( } } -data class DeviceAdmin(val app: AppInfo, val admin: ComponentName) - -@Serializable object TransferOwnership - @RequiresApi(28) @Composable fun TransferOwnershipScreen( diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 41bc244..aa9d1b0 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -2,7 +2,7 @@ agp = "9.0.1" kotlin = "2.3.10" -navigation-compose = "2.9.7" +nav3 = "1.0.1" composeBom = "2026.02.00" accompanist-drawablepainter = "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-activity-compose = { module = "androidx.activity:activity-compose" } 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" } 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-permissions = { group = "com.google.accompanist", name = "accompanist-permissions", version.ref = "accompanist-permissions" }