Use main NavHost to navigate across all pages

Upgrade dependencies
Upload dependencies to GitHub in workflow
This commit is contained in:
BinTianqi
2024-12-07 12:31:13 +08:00
parent 0c670e9265
commit 380675cf8f
19 changed files with 656 additions and 1109 deletions

View File

@@ -58,6 +58,9 @@ jobs:
name: OwnDroid-CI-${{ env.SHORT_SHA }}-release-signed name: OwnDroid-CI-${{ env.SHORT_SHA }}-release-signed
path: app/build/outputs/apk/release/app-release.apk path: app/build/outputs/apk/release/app-release.apk
- name: Generate and submit dependency graph
uses: gradle/actions/dependency-submission@v4
upload-telegram: upload-telegram:
name: Upload Builds name: Upload Builds
if: ${{ success() }} if: ${{ success() }}

View File

@@ -18,7 +18,6 @@ import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.imePadding import androidx.compose.foundation.layout.imePadding
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.statusBarsPadding
import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.verticalScroll import androidx.compose.foundation.verticalScroll
@@ -27,6 +26,7 @@ import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme.colorScheme import androidx.compose.material3.MaterialTheme.colorScheme
import androidx.compose.material3.MaterialTheme.typography import androidx.compose.material3.MaterialTheme.typography
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.material3.TextButton import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
@@ -53,15 +53,70 @@ import androidx.navigation.NavHostController
import androidx.navigation.compose.NavHost import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable import androidx.navigation.compose.composable
import androidx.navigation.compose.rememberNavController import androidx.navigation.compose.rememberNavController
import com.bintianqi.owndroid.dpm.AffiliationID
import com.bintianqi.owndroid.dpm.AlwaysOnVPNPackage
import com.bintianqi.owndroid.dpm.ApplicationManage import com.bintianqi.owndroid.dpm.ApplicationManage
import com.bintianqi.owndroid.dpm.DpmPermissions import com.bintianqi.owndroid.dpm.CACert
import com.bintianqi.owndroid.dpm.ManagedProfile import com.bintianqi.owndroid.dpm.ChangeTime
import com.bintianqi.owndroid.dpm.ChangeTimeZone
import com.bintianqi.owndroid.dpm.ChangeUserIcon
import com.bintianqi.owndroid.dpm.ChangeUsername
import com.bintianqi.owndroid.dpm.CreateUser
import com.bintianqi.owndroid.dpm.CreateWorkProfile
import com.bintianqi.owndroid.dpm.CurrentUserInfo
import com.bintianqi.owndroid.dpm.DeleteWorkProfile
import com.bintianqi.owndroid.dpm.DeviceAdmin
import com.bintianqi.owndroid.dpm.DeviceInfo
import com.bintianqi.owndroid.dpm.DeviceOwner
import com.bintianqi.owndroid.dpm.DisableAccountManagement
import com.bintianqi.owndroid.dpm.DisableKeyguardFeatures
import com.bintianqi.owndroid.dpm.FRPPolicy
import com.bintianqi.owndroid.dpm.InstallSystemUpdate
import com.bintianqi.owndroid.dpm.IntentFilter
import com.bintianqi.owndroid.dpm.Keyguard
import com.bintianqi.owndroid.dpm.LockScreenInfo
import com.bintianqi.owndroid.dpm.LockTaskMode
import com.bintianqi.owndroid.dpm.MTEPolicy
import com.bintianqi.owndroid.dpm.WorkProfile
import com.bintianqi.owndroid.dpm.NearbyStreamingPolicy
import com.bintianqi.owndroid.dpm.Network import com.bintianqi.owndroid.dpm.Network
import com.bintianqi.owndroid.dpm.NetworkLogging
import com.bintianqi.owndroid.dpm.NetworkOptions
import com.bintianqi.owndroid.dpm.OrgOwnedProfile
import com.bintianqi.owndroid.dpm.OverrideAPN
import com.bintianqi.owndroid.dpm.Password import com.bintianqi.owndroid.dpm.Password
import com.bintianqi.owndroid.dpm.PasswordComplexity
import com.bintianqi.owndroid.dpm.PasswordInfo
import com.bintianqi.owndroid.dpm.PasswordQuality
import com.bintianqi.owndroid.dpm.PermissionPolicy
import com.bintianqi.owndroid.dpm.Permissions
import com.bintianqi.owndroid.dpm.PreferentialNetworkService
import com.bintianqi.owndroid.dpm.PrivateDNS
import com.bintianqi.owndroid.dpm.ProfileOwner
import com.bintianqi.owndroid.dpm.RecommendedGlobalProxy
import com.bintianqi.owndroid.dpm.ResetPassword
import com.bintianqi.owndroid.dpm.ResetPasswordToken
import com.bintianqi.owndroid.dpm.RestrictionData
import com.bintianqi.owndroid.dpm.SecurityLogging
import com.bintianqi.owndroid.dpm.Shizuku
import com.bintianqi.owndroid.dpm.SupportMessages
import com.bintianqi.owndroid.dpm.SuspendPersonalApp
import com.bintianqi.owndroid.dpm.SystemManage import com.bintianqi.owndroid.dpm.SystemManage
import com.bintianqi.owndroid.dpm.UserManage import com.bintianqi.owndroid.dpm.SystemOptions
import com.bintianqi.owndroid.dpm.SystemUpdatePolicy
import com.bintianqi.owndroid.dpm.TransferOwnership
import com.bintianqi.owndroid.dpm.UserOperation
import com.bintianqi.owndroid.dpm.UserOptions
import com.bintianqi.owndroid.dpm.UserRestriction import com.bintianqi.owndroid.dpm.UserRestriction
import com.bintianqi.owndroid.dpm.UserRestrictionItem
import com.bintianqi.owndroid.dpm.UserSessionMessage
import com.bintianqi.owndroid.dpm.Users
import com.bintianqi.owndroid.dpm.WifiAuthKeypair
import com.bintianqi.owndroid.dpm.WifiSecurityLevel
import com.bintianqi.owndroid.dpm.WifiSsidPolicy
import com.bintianqi.owndroid.dpm.WipeData
import com.bintianqi.owndroid.dpm.dhizukuErrorStatus import com.bintianqi.owndroid.dpm.dhizukuErrorStatus
import com.bintianqi.owndroid.dpm.dhizukuPermissionGranted
import com.bintianqi.owndroid.dpm.getDPM import com.bintianqi.owndroid.dpm.getDPM
import com.bintianqi.owndroid.dpm.getReceiver import com.bintianqi.owndroid.dpm.getReceiver
import com.bintianqi.owndroid.dpm.isDeviceAdmin import com.bintianqi.owndroid.dpm.isDeviceAdmin
@@ -70,6 +125,7 @@ import com.bintianqi.owndroid.dpm.isProfileOwner
import com.bintianqi.owndroid.dpm.setDefaultAffiliationID import com.bintianqi.owndroid.dpm.setDefaultAffiliationID
import com.bintianqi.owndroid.dpm.toggleInstallAppActivity import com.bintianqi.owndroid.dpm.toggleInstallAppActivity
import com.bintianqi.owndroid.ui.Animations import com.bintianqi.owndroid.ui.Animations
import com.bintianqi.owndroid.ui.MyScaffold
import com.bintianqi.owndroid.ui.theme.OwnDroidTheme import com.bintianqi.owndroid.ui.theme.OwnDroidTheme
import com.rosan.dhizuku.api.Dhizuku import com.rosan.dhizuku.api.Dhizuku
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
@@ -119,7 +175,7 @@ class MainActivity : FragmentActivity() {
} }
if (sharedPref.getBoolean("dhizuku", false)) { if (sharedPref.getBoolean("dhizuku", false)) {
if (Dhizuku.init(applicationContext)) { if (Dhizuku.init(applicationContext)) {
if (!Dhizuku.isPermissionGranted()) { dhizukuErrorStatus.value = 2 } if (!dhizukuPermissionGranted()) { dhizukuErrorStatus.value = 2 }
} else { } else {
sharedPref.edit().putBoolean("dhizuku", false).apply() sharedPref.edit().putBoolean("dhizuku", false).apply()
dhizukuErrorStatus.value = 1 dhizukuErrorStatus.value = 1
@@ -157,20 +213,105 @@ fun Home(vm: MyViewModel) {
popExitTransition = Animations.navHostPopExitTransition popExitTransition = Animations.navHostPopExitTransition
) { ) {
composable(route = "HomePage") { HomePage(navCtrl) } composable(route = "HomePage") { HomePage(navCtrl) }
composable(route = "Permissions") { Permissions(navCtrl) }
composable(route = "Shizuku") { Shizuku(navCtrl) }
composable(route = "DeviceAdmin") { DeviceAdmin(navCtrl) }
composable(route = "ProfileOwner") { ProfileOwner(navCtrl) }
composable(route = "DeviceOwner") { DeviceOwner(navCtrl) }
composable(route = "DeviceInfo") { DeviceInfo(navCtrl) }
composable(route = "LockScreenInfo") { LockScreenInfo(navCtrl) }
composable(route = "SupportMessages") { SupportMessages(navCtrl) }
composable(route = "TransferOwnership") { TransferOwnership(navCtrl) }
composable(route = "System") { SystemManage(navCtrl) } composable(route = "System") { SystemManage(navCtrl) }
composable(route = "ManagedProfile") { ManagedProfile(navCtrl) } composable(route = "SystemOptions") { SystemOptions(navCtrl) }
composable(route = "Permissions") { DpmPermissions(navCtrl) } composable(route = "Keyguard") { Keyguard(navCtrl) }
composable(route = "Applications") { ApplicationManage(navCtrl, dialogStatus) } composable(route = "ChangeTime") { ChangeTime(navCtrl) }
composable(route = "UserRestriction") { UserRestriction(navCtrl) } composable(route = "ChangeTimeZone") { ChangeTimeZone(navCtrl) }
composable(route = "Users") { UserManage(navCtrl) } composable(route = "PermissionPolicy") { PermissionPolicy(navCtrl) }
composable(route = "Password") { Password(navCtrl) } composable(route = "MTEPolicy") { MTEPolicy(navCtrl) }
composable(route = "Settings") { AppSetting(navCtrl, vm) } composable(route = "NearbyStreamingPolicy") { NearbyStreamingPolicy(navCtrl) }
composable(route = "LockTaskMode") { LockTaskMode(navCtrl) }
composable(route = "CACert") { CACert(navCtrl) }
composable(route = "SecurityLogs") { SecurityLogging(navCtrl) }
composable(route = "DisableAccountManagement") { DisableAccountManagement(navCtrl) }
composable(route = "SystemUpdatePolicy") { SystemUpdatePolicy(navCtrl) }
composable(route = "InstallSystemUpdate") { InstallSystemUpdate(navCtrl) }
composable(route = "FRPPolicy") { FRPPolicy(navCtrl) }
composable(route = "WipeData") { WipeData(navCtrl) }
composable(route = "Network") { Network(navCtrl) } composable(route = "Network") { Network(navCtrl) }
composable(route = "NetworkOptions") { NetworkOptions(navCtrl) }
composable(route = "MinWifiSecurityLevel") { WifiSecurityLevel(navCtrl) }
composable(route = "WifiSsidPolicy") { WifiSsidPolicy(navCtrl) }
composable(route = "PrivateDNS") { PrivateDNS(navCtrl) }
composable(route = "AlwaysOnVpn") { AlwaysOnVPNPackage(navCtrl) }
composable(route = "RecommendedGlobalProxy") { RecommendedGlobalProxy(navCtrl) }
composable(route = "NetworkLog") { NetworkLogging(navCtrl) }
composable(route = "WifiAuthKeypair") { WifiAuthKeypair(navCtrl) }
composable(route = "PreferentialNetworkService") { PreferentialNetworkService(navCtrl) }
composable(route = "OverrideAPN") { OverrideAPN(navCtrl) }
composable(route = "WorkProfile") { WorkProfile(navCtrl) }
composable(route = "OrgOwnedWorkProfile") { OrgOwnedProfile(navCtrl) }
composable(route = "CreateWorkProfile") { CreateWorkProfile(navCtrl) }
composable(route = "SuspendPersonalApp") { SuspendPersonalApp(navCtrl) }
composable(route = "IntentFilter") { IntentFilter(navCtrl) }
composable(route = "DeleteWorkProfile") { DeleteWorkProfile(navCtrl) }
composable(route = "Applications") { ApplicationManage(navCtrl, dialogStatus) }
composable(route = "UserRestriction") { UserRestriction(navCtrl) }
composable(route = "UR-Internet") {
MyScaffold(R.string.network_and_internet, 0.dp, navCtrl) { RestrictionData.internet.forEach { UserRestrictionItem(it) } }
}
composable(route = "UR-Connectivity") {
MyScaffold(R.string.connectivity, 0.dp, navCtrl) { RestrictionData.connectivity.forEach { UserRestrictionItem(it) } }
}
composable(route = "UR-Applications") {
MyScaffold(R.string.applications, 0.dp, navCtrl) { RestrictionData.applications.forEach { UserRestrictionItem(it) } }
}
composable(route = "UR-Users") {
MyScaffold(R.string.users, 0.dp, navCtrl) { RestrictionData.users.forEach { UserRestrictionItem(it) } }
}
composable(route = "UR-Media") {
MyScaffold(R.string.media, 0.dp, navCtrl) { RestrictionData.media.forEach { UserRestrictionItem(it) } }
}
composable(route = "UR-Other") {
MyScaffold(R.string.other, 0.dp, navCtrl) { RestrictionData.other.forEach { UserRestrictionItem(it) } }
}
composable(route = "Users") { Users(navCtrl) }
composable(route = "UserInfo") { CurrentUserInfo(navCtrl) }
composable(route = "UserOptions") { UserOptions(navCtrl) }
composable(route = "UserOperation") { UserOperation(navCtrl) }
composable(route = "CreateUser") { CreateUser(navCtrl) }
composable(route = "ChangeUsername") { ChangeUsername(navCtrl) }
composable(route = "ChangeUserIcon") { ChangeUserIcon(navCtrl) }
composable(route = "UserSessionMessage") { UserSessionMessage(navCtrl) }
composable(route = "AffiliationID") { AffiliationID(navCtrl) }
composable(route = "Password") { Password(navCtrl) }
composable(route = "PasswordInfo") { PasswordInfo(navCtrl) }
composable(route = "ResetPasswordToken") { ResetPasswordToken(navCtrl) }
composable(route = "ResetPassword") { ResetPassword(navCtrl) }
composable(route = "RequirePasswordComplexity") { PasswordComplexity(navCtrl) }
composable(route = "DisableKeyguardFeatures") { DisableKeyguardFeatures(navCtrl) }
composable(route = "RequirePasswordQuality") { PasswordQuality(navCtrl) }
composable(route = "Settings") { Settings(navCtrl) }
composable(route = "Options") { SettingsOptions(navCtrl) }
composable(route = "Appearance") { Appearance(navCtrl, vm) }
composable(route = "AuthSettings") { AuthSettings(navCtrl) }
composable(route = "Automation") { Automation(navCtrl) }
composable(route = "About") { About(navCtrl) }
composable(route = "PackageSelector") { PackageSelector(navCtrl) } composable(route = "PackageSelector") { PackageSelector(navCtrl) }
} }
LaunchedEffect(Unit) { LaunchedEffect(Unit) {
val profileInited = sharedPref.getBoolean("ManagedProfileActivated", false) val profileInitialized = sharedPref.getBoolean("ManagedProfileActivated", false)
val profileNotActivated = !profileInited && context.isProfileOwner && (VERSION.SDK_INT < 24 || (VERSION.SDK_INT >= 24 && dpm.isManagedProfile(receiver))) val profileNotActivated = !profileInitialized && context.isProfileOwner && (VERSION.SDK_INT < 24 || dpm.isManagedProfile(receiver))
if(profileNotActivated) { if(profileNotActivated) {
dpm.setProfileEnabled(receiver) dpm.setProfileEnabled(receiver)
sharedPref.edit().putBoolean("ManagedProfileActivated", true).apply() sharedPref.edit().putBoolean("ManagedProfileActivated", true).apply()
@@ -203,58 +344,60 @@ private fun HomePage(navCtrl:NavHostController) {
else if(deviceAdmin) R.string.device_admin else R.string.click_to_activate else if(deviceAdmin) R.string.device_admin else R.string.click_to_activate
) )
} }
Column(modifier = Modifier.background(colorScheme.background).statusBarsPadding().verticalScroll(rememberScrollState())) { Scaffold {
Spacer(Modifier.padding(vertical = 25.dp)) Column(modifier = Modifier.padding(it).verticalScroll(rememberScrollState())) {
Text( Spacer(Modifier.padding(vertical = 25.dp))
text = stringResource(R.string.app_name), style = typography.headlineLarge, Text(
modifier = Modifier.padding(start = 10.dp), color = colorScheme.onBackground text = stringResource(R.string.app_name), style = typography.headlineLarge,
) modifier = Modifier.padding(start = 10.dp)
Spacer(Modifier.padding(vertical = 8.dp))
Row(
modifier = Modifier
.fillMaxWidth()
.padding(vertical = 8.dp, horizontal = 8.dp)
.clip(RoundedCornerShape(15))
.background(color = colorScheme.primary)
.clickable(onClick = { navCtrl.navigate("Permissions") })
.padding(vertical = 16.dp),
verticalAlignment = Alignment.CenterVertically
) {
Spacer(modifier = Modifier.padding(start = 22.dp))
Icon(
painter = painterResource(if(activated) R.drawable.check_circle_fill1 else R.drawable.block_fill0),
contentDescription = null,
tint = colorScheme.onPrimary
) )
Spacer(modifier = Modifier.padding(start = 10.dp)) Spacer(Modifier.padding(vertical = 8.dp))
Column { Row(
Text( modifier = Modifier
text = stringResource(if(activated) R.string.activated else R.string.deactivated), .fillMaxWidth()
style = typography.headlineSmall, .padding(vertical = 8.dp, horizontal = 8.dp)
color = colorScheme.onPrimary, .clip(RoundedCornerShape(15))
modifier = Modifier.padding(bottom = 2.dp) .background(color = colorScheme.primary)
.clickable(onClick = { navCtrl.navigate("Permissions") })
.padding(vertical = 16.dp),
verticalAlignment = Alignment.CenterVertically
) {
Spacer(modifier = Modifier.padding(start = 22.dp))
Icon(
painter = painterResource(if(activated) R.drawable.check_circle_fill1 else R.drawable.block_fill0),
contentDescription = null,
tint = colorScheme.onPrimary
) )
if(activateType != "") { Text(text = activateType, color = colorScheme.onPrimary) } Spacer(modifier = Modifier.padding(start = 10.dp))
Column {
Text(
text = stringResource(if(activated) R.string.activated else R.string.deactivated),
style = typography.headlineSmall,
color = colorScheme.onPrimary,
modifier = Modifier.padding(bottom = 2.dp)
)
if(activateType != "") { Text(text = activateType, color = colorScheme.onPrimary) }
}
} }
HomePageItem(R.string.system, R.drawable.android_fill0, "System", navCtrl)
if(deviceOwner || profileOwner) { HomePageItem(R.string.network, R.drawable.wifi_fill0, "Network", navCtrl) }
if(
(VERSION.SDK_INT < 24 && !deviceOwner) || (
VERSION.SDK_INT >= 24 && (dpm.isProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE) ||
(profileOwner && dpm.isManagedProfile(receiver)))
)
) {
HomePageItem(R.string.work_profile, R.drawable.work_fill0, "ManagedProfile", navCtrl)
}
if(deviceOwner || profileOwner) HomePageItem(R.string.applications, R.drawable.apps_fill0, "Applications", navCtrl)
if(VERSION.SDK_INT >= 24 && (profileOwner || deviceOwner)) {
HomePageItem(R.string.user_restriction, R.drawable.person_off, "UserRestriction", navCtrl)
}
HomePageItem(R.string.users,R.drawable.manage_accounts_fill0,"Users", navCtrl)
HomePageItem(R.string.password_and_keyguard, R.drawable.password_fill0, "Password", navCtrl)
HomePageItem(R.string.settings, R.drawable.settings_fill0, "Settings", navCtrl)
Spacer(Modifier.padding(vertical = 20.dp))
} }
HomePageItem(R.string.system, R.drawable.android_fill0, "System", navCtrl)
if(deviceOwner || profileOwner) { HomePageItem(R.string.network, R.drawable.wifi_fill0, "Network", navCtrl) }
if(
(VERSION.SDK_INT < 24 && !deviceOwner) || (
VERSION.SDK_INT >= 24 && (dpm.isProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE) ||
(profileOwner && dpm.isManagedProfile(receiver)))
)
) {
HomePageItem(R.string.work_profile, R.drawable.work_fill0, "ManagedProfile", navCtrl)
}
if(deviceOwner || profileOwner) HomePageItem(R.string.applications, R.drawable.apps_fill0, "Applications", navCtrl)
if(VERSION.SDK_INT >= 24 && (profileOwner || deviceOwner)) {
HomePageItem(R.string.user_restrict, R.drawable.person_off, "UserRestriction", navCtrl)
}
HomePageItem(R.string.users,R.drawable.manage_accounts_fill0,"Users", navCtrl)
HomePageItem(R.string.password_and_keyguard, R.drawable.password_fill0, "Password", navCtrl)
HomePageItem(R.string.settings, R.drawable.settings_fill0, "Settings", navCtrl)
Spacer(Modifier.padding(vertical = 20.dp))
} }
} }
@@ -263,22 +406,19 @@ fun HomePageItem(name: Int, imgVector: Int, navTo: String, navCtrl: NavHostContr
Row( Row(
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.clip(RoundedCornerShape(25))
.clickable(onClick = { navCtrl.navigate(navTo) }) .clickable(onClick = { navCtrl.navigate(navTo) })
.padding(vertical = 13.dp), .padding(vertical = 12.dp),
verticalAlignment = Alignment.CenterVertically verticalAlignment = Alignment.CenterVertically
) { ) {
Spacer(Modifier.padding(start = 30.dp)) Spacer(Modifier.padding(start = 30.dp))
Icon( Icon(
painter = painterResource(imgVector), painter = painterResource(imgVector),
contentDescription = null, contentDescription = null
tint = colorScheme.onBackground
) )
Spacer(Modifier.padding(start = 15.dp)) Spacer(Modifier.padding(start = 15.dp))
Text( Text(
text = stringResource(name), text = stringResource(name),
style = typography.headlineSmall, style = typography.headlineSmall,
color = colorScheme.onBackground,
modifier = Modifier.padding(bottom = if(zhCN) { 2 } else { 0 }.dp) modifier = Modifier.padding(bottom = if(zhCN) { 2 } else { 0 }.dp)
) )
} }

View File

@@ -8,21 +8,15 @@ import android.widget.Toast
import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.AnimatedVisibility
import androidx.compose.foundation.isSystemInDarkTheme import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.Button import androidx.compose.material3.Button
import androidx.compose.material3.DropdownMenu import androidx.compose.material3.DropdownMenu
import androidx.compose.material3.DropdownMenuItem import androidx.compose.material3.DropdownMenuItem
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme.typography
import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
@@ -37,68 +31,36 @@ import androidx.compose.ui.unit.DpOffset
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.navigation.NavHostController import androidx.navigation.NavHostController
import androidx.navigation.compose.NavHost import com.bintianqi.owndroid.ui.FunctionItem
import androidx.navigation.compose.composable import com.bintianqi.owndroid.ui.MyScaffold
import androidx.navigation.compose.currentBackStackEntryAsState
import androidx.navigation.compose.rememberNavController
import com.bintianqi.owndroid.ui.Animations
import com.bintianqi.owndroid.ui.SubPageItem
import com.bintianqi.owndroid.ui.SwitchItem import com.bintianqi.owndroid.ui.SwitchItem
import com.bintianqi.owndroid.ui.TopBar
import java.security.SecureRandom import java.security.SecureRandom
@Composable @Composable
fun AppSetting(navCtrl:NavHostController, vm: MyViewModel) { fun Settings(navCtrl: NavHostController) {
val localNavCtrl = rememberNavController() MyScaffold(R.string.settings, 0.dp, navCtrl) {
val backStackEntry by localNavCtrl.currentBackStackEntryAsState() FunctionItem(R.string.options, "", R.drawable.tune_fill0) { navCtrl.navigate("Options") }
Scaffold( FunctionItem(R.string.appearance, "", R.drawable.format_paint_fill0) { navCtrl.navigate("Appearance") }
topBar = { FunctionItem(R.string.security, "", R.drawable.lock_fill0) { navCtrl.navigate("AuthSettings") }
TopBar(backStackEntry, navCtrl, localNavCtrl) FunctionItem(R.string.automation_api, "", R.drawable.apps_fill0) { navCtrl.navigate("Automation") }
} FunctionItem(R.string.about, "", R.drawable.info_fill0) { navCtrl.navigate("About") }
) {
NavHost(
navController = localNavCtrl, startDestination = "Home",
enterTransition = Animations.navHostEnterTransition,
exitTransition = Animations.navHostExitTransition,
popEnterTransition = Animations.navHostPopEnterTransition,
popExitTransition = Animations.navHostPopExitTransition,
modifier = Modifier.padding(top = it.calculateTopPadding())
) {
composable(route = "Home") { Home(localNavCtrl) }
composable(route = "Options") { Options() }
composable(route = "Theme") { ThemeSettings(vm) }
composable(route = "Auth") { AuthSettings() }
composable(route = "Automation") { Automation() }
composable(route = "About") { About() }
}
} }
} }
@Composable @Composable
private fun Home(navCtrl: NavHostController) { fun SettingsOptions(navCtrl: NavHostController) {
Column(modifier = Modifier.fillMaxSize()) {
SubPageItem(R.string.options, "", R.drawable.tune_fill0) { navCtrl.navigate("Options") }
SubPageItem(R.string.appearance, "", R.drawable.format_paint_fill0) { navCtrl.navigate("Theme") }
SubPageItem(R.string.security, "", R.drawable.lock_fill0) { navCtrl.navigate("Auth") }
SubPageItem(R.string.automation_api, "", R.drawable.apps_fill0) { navCtrl.navigate("Automation") }
SubPageItem(R.string.about, "", R.drawable.info_fill0) { navCtrl.navigate("About") }
}
}
@Composable
private fun Options() {
val sharedPref = LocalContext.current.getSharedPreferences("data", Context.MODE_PRIVATE) val sharedPref = LocalContext.current.getSharedPreferences("data", Context.MODE_PRIVATE)
Column(modifier = Modifier.fillMaxSize().verticalScroll(rememberScrollState()).padding(start = 20.dp, end = 16.dp)) { MyScaffold(R.string.options, 0.dp, navCtrl) {
SwitchItem( SwitchItem(
R.string.show_dangerous_features, "", R.drawable.warning_fill0, R.string.show_dangerous_features, "", R.drawable.warning_fill0,
{ sharedPref.getBoolean("dangerous_features", false) }, { sharedPref.getBoolean("dangerous_features", false) },
{ sharedPref.edit().putBoolean("dangerous_features", it).apply() }, padding = false { sharedPref.edit().putBoolean("dangerous_features", it).apply() }
) )
} }
} }
@Composable @Composable
private fun ThemeSettings(vm: MyViewModel) { fun Appearance(navCtrl: NavHostController, vm: MyViewModel) {
val theme by vm.theme.collectAsStateWithLifecycle() val theme by vm.theme.collectAsStateWithLifecycle()
var darkThemeMenu by remember { mutableStateOf(false) } var darkThemeMenu by remember { mutableStateOf(false) }
val darkThemeTextID = when(theme.darkTheme) { val darkThemeTextID = when(theme.darkTheme) {
@@ -106,7 +68,7 @@ private fun ThemeSettings(vm: MyViewModel) {
false -> R.string.off false -> R.string.off
null -> R.string.follow_system null -> R.string.follow_system
} }
Column(modifier = Modifier.fillMaxSize().verticalScroll(rememberScrollState())) { MyScaffold(R.string.appearance, 0.dp, navCtrl) {
if(VERSION.SDK_INT >= 31) { if(VERSION.SDK_INT >= 31) {
SwitchItem( SwitchItem(
R.string.material_you_color, "", null, R.string.material_you_color, "", null,
@@ -115,7 +77,7 @@ private fun ThemeSettings(vm: MyViewModel) {
) )
} }
Box { Box {
SubPageItem(R.string.dark_theme, stringResource(darkThemeTextID)) { darkThemeMenu = true } FunctionItem(R.string.dark_theme, stringResource(darkThemeTextID)) { darkThemeMenu = true }
DropdownMenu( DropdownMenu(
expanded = darkThemeMenu, onDismissRequest = { darkThemeMenu = false }, expanded = darkThemeMenu, onDismissRequest = { darkThemeMenu = false },
offset = DpOffset(x = 25.dp, y = 0.dp) offset = DpOffset(x = 25.dp, y = 0.dp)
@@ -154,44 +116,42 @@ private fun ThemeSettings(vm: MyViewModel) {
} }
@Composable @Composable
private fun AuthSettings() { fun AuthSettings(navCtrl: NavHostController) {
val sharedPref = LocalContext.current.getSharedPreferences("data", Context.MODE_PRIVATE) val sharedPref = LocalContext.current.getSharedPreferences("data", Context.MODE_PRIVATE)
var auth by remember{ mutableStateOf(sharedPref.getBoolean("auth",false)) } var auth by remember{ mutableStateOf(sharedPref.getBoolean("auth",false)) }
Column(modifier = Modifier.fillMaxSize().verticalScroll(rememberScrollState()).padding(start = 20.dp, end = 16.dp)) { MyScaffold(R.string.security, 0.dp, navCtrl) {
SwitchItem( SwitchItem(
R.string.lock_owndroid, "", null, auth, R.string.lock_owndroid, "", null, auth,
{ {
sharedPref.edit().putBoolean("auth", it).apply() sharedPref.edit().putBoolean("auth", it).apply()
auth = sharedPref.getBoolean("auth", false) auth = sharedPref.getBoolean("auth", false)
}, padding = false }
) )
if(auth) { if(auth) {
SwitchItem( SwitchItem(
R.string.enable_bio_auth, "", null, R.string.enable_bio_auth, "", null,
{ sharedPref.getBoolean("bio_auth", false) }, { sharedPref.getBoolean("bio_auth", false) },
{ sharedPref.edit().putBoolean("bio_auth", it).apply() }, padding = false { sharedPref.edit().putBoolean("bio_auth", it).apply() }
) )
SwitchItem( SwitchItem(
R.string.lock_in_background, stringResource(R.string.developing), null, R.string.lock_in_background, stringResource(R.string.developing), null,
{ sharedPref.getBoolean("lock_in_background", false) }, { sharedPref.getBoolean("lock_in_background", false) },
{ sharedPref.edit().putBoolean("lock_in_background", it).apply() }, padding = false { sharedPref.edit().putBoolean("lock_in_background", it).apply() }
) )
} }
SwitchItem( SwitchItem(
R.string.protect_storage, "", null, R.string.protect_storage, "", null,
{ sharedPref.getBoolean("protect_storage", false) }, { sharedPref.getBoolean("protect_storage", false) },
{ sharedPref.edit().putBoolean("protect_storage", it).apply() }, padding = false { sharedPref.edit().putBoolean("protect_storage", it).apply() }
) )
} }
} }
@Composable @Composable
private fun Automation() { fun Automation(navCtrl: NavHostController) {
val context = LocalContext.current val context = LocalContext.current
val sharedPref = context.getSharedPreferences("data", Context.MODE_PRIVATE) val sharedPref = context.getSharedPreferences("data", Context.MODE_PRIVATE)
Column(modifier = Modifier.fillMaxSize().padding(horizontal = 8.dp).verticalScroll(rememberScrollState())) { MyScaffold(R.string.automation_api, 8.dp, navCtrl) {
Spacer(Modifier.padding(vertical = 10.dp))
Text(text = stringResource(R.string.automation_api), style = typography.headlineLarge)
Spacer(Modifier.padding(vertical = 5.dp)) Spacer(Modifier.padding(vertical = 5.dp))
var key by remember { mutableStateOf("") } var key by remember { mutableStateOf("") }
OutlinedTextField( OutlinedTextField(
@@ -229,18 +189,15 @@ private fun Automation() {
} }
@Composable @Composable
private fun About() { fun About(navCtrl: NavHostController) {
val context = LocalContext.current val context = LocalContext.current
val pkgInfo = context.packageManager.getPackageInfo(context.packageName,0) val pkgInfo = context.packageManager.getPackageInfo(context.packageName,0)
val verCode = pkgInfo.versionCode val verCode = pkgInfo.versionCode
val verName = pkgInfo.versionName val verName = pkgInfo.versionName
Column(modifier = Modifier.fillMaxSize().verticalScroll(rememberScrollState())) { MyScaffold(R.string.about, 0.dp, navCtrl) {
Spacer(Modifier.padding(vertical = 10.dp)) Text(text = stringResource(R.string.app_name)+" v$verName ($verCode)", modifier = Modifier.padding(start = 16.dp))
Text(text = stringResource(R.string.about), style = typography.headlineLarge, modifier = Modifier.padding(start = 26.dp))
Spacer(Modifier.padding(vertical = 5.dp)) Spacer(Modifier.padding(vertical = 5.dp))
Text(text = stringResource(R.string.app_name)+" v$verName ($verCode)", modifier = Modifier.padding(start = 26.dp)) FunctionItem(R.string.project_homepage, "GitHub", R.drawable.open_in_new) { shareLink(context, "https://github.com/BinTianqi/OwnDroid") }
Spacer(Modifier.padding(vertical = 5.dp))
SubPageItem(R.string.project_homepage, "GitHub", R.drawable.open_in_new) { shareLink(context, "https://github.com/BinTianqi/OwnDroid") }
} }
} }

View File

@@ -90,7 +90,7 @@ import com.bintianqi.owndroid.ui.Information
import com.bintianqi.owndroid.ui.ListItem import com.bintianqi.owndroid.ui.ListItem
import com.bintianqi.owndroid.ui.NavIcon import com.bintianqi.owndroid.ui.NavIcon
import com.bintianqi.owndroid.ui.RadioButtonItem import com.bintianqi.owndroid.ui.RadioButtonItem
import com.bintianqi.owndroid.ui.SubPageItem import com.bintianqi.owndroid.ui.FunctionItem
import com.bintianqi.owndroid.ui.SwitchItem import com.bintianqi.owndroid.ui.SwitchItem
import java.util.concurrent.Executors import java.util.concurrent.Executors
@@ -119,7 +119,7 @@ fun ApplicationManage(navCtrl:NavHostController, dialogStatus: MutableIntState)
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Ascii, imeAction = ImeAction.Done), keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Ascii, imeAction = ImeAction.Done),
keyboardActions = KeyboardActions(onDone = { focusMgr.clearFocus() }), keyboardActions = KeyboardActions(onDone = { focusMgr.clearFocus() }),
trailingIcon = { trailingIcon = {
Icon(painter = painterResource(R.drawable.checklist_fill0), contentDescription = null, Icon(painter = painterResource(R.drawable.list_fill0), contentDescription = null,
modifier = Modifier modifier = Modifier
.clip(RoundedCornerShape(50)) .clip(RoundedCornerShape(50))
.clickable(onClick = { .clickable(onClick = {
@@ -216,7 +216,7 @@ private fun Home(
if(VERSION.SDK_INT >= 24 && profileOwner && dpm.isManagedProfile(receiver)) { if(VERSION.SDK_INT >= 24 && profileOwner && dpm.isManagedProfile(receiver)) {
Text(text = stringResource(R.string.scope_is_work_profile), textAlign = TextAlign.Center,modifier = Modifier.fillMaxWidth()) Text(text = stringResource(R.string.scope_is_work_profile), textAlign = TextAlign.Center,modifier = Modifier.fillMaxWidth())
} }
SubPageItem(R.string.app_info,"", R.drawable.open_in_new) { FunctionItem(R.string.app_info,"", R.drawable.open_in_new) {
val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS) val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
intent.setData(Uri.parse("package:$pkgName")) intent.setData(Uri.parse("package:$pkgName"))
startActivity(context, intent, null) startActivity(context, intent, null)
@@ -242,37 +242,37 @@ private fun Home(
onClickBlank = { appControlAction = 3; appControlDialog = true } onClickBlank = { appControlAction = 3; appControlDialog = true }
) )
if((VERSION.SDK_INT >= 33 && profileOwner) || (VERSION.SDK_INT >= 30 && deviceOwner)) { if((VERSION.SDK_INT >= 33 && profileOwner) || (VERSION.SDK_INT >= 30 && deviceOwner)) {
SubPageItem(R.string.ucd, "", R.drawable.do_not_touch_fill0) { navCtrl.navigate("UserControlDisabled") } FunctionItem(R.string.ucd, "", R.drawable.do_not_touch_fill0) { navCtrl.navigate("UserControlDisabled") }
} }
if(VERSION.SDK_INT>=23) { if(VERSION.SDK_INT>=23) {
SubPageItem(R.string.permission_manage, "", R.drawable.key_fill0) { navCtrl.navigate("PermissionManage") } FunctionItem(R.string.permission_manage, "", R.drawable.key_fill0) { navCtrl.navigate("PermissionManage") }
} }
if(VERSION.SDK_INT >= 30 && profileOwner && dpm.isManagedProfile(receiver)) { if(VERSION.SDK_INT >= 30 && profileOwner && dpm.isManagedProfile(receiver)) {
SubPageItem(R.string.cross_profile_package, "", R.drawable.work_fill0) { navCtrl.navigate("CrossProfilePackage") } FunctionItem(R.string.cross_profile_package, "", R.drawable.work_fill0) { navCtrl.navigate("CrossProfilePackage") }
} }
if(profileOwner) { if(profileOwner) {
SubPageItem(R.string.cross_profile_widget, "", R.drawable.widgets_fill0) { navCtrl.navigate("CrossProfileWidget") } FunctionItem(R.string.cross_profile_widget, "", R.drawable.widgets_fill0) { navCtrl.navigate("CrossProfileWidget") }
} }
if(VERSION.SDK_INT >= 34 && deviceOwner) { if(VERSION.SDK_INT >= 34 && deviceOwner) {
SubPageItem(R.string.credential_manage_policy, "", R.drawable.license_fill0) { navCtrl.navigate("CredentialManagePolicy") } FunctionItem(R.string.credential_manage_policy, "", R.drawable.license_fill0) { navCtrl.navigate("CredentialManagePolicy") }
} }
SubPageItem(R.string.permitted_accessibility_services, "", R.drawable.settings_accessibility_fill0) { navCtrl.navigate("Accessibility") } FunctionItem(R.string.permitted_accessibility_services, "", R.drawable.settings_accessibility_fill0) { navCtrl.navigate("Accessibility") }
SubPageItem(R.string.permitted_ime, "", R.drawable.keyboard_fill0) { navCtrl.navigate("IME") } FunctionItem(R.string.permitted_ime, "", R.drawable.keyboard_fill0) { navCtrl.navigate("IME") }
SubPageItem(R.string.enable_system_app, "", R.drawable.enable_fill0) { FunctionItem(R.string.enable_system_app, "", R.drawable.enable_fill0) {
if(pkgName != "") dialogStatus.intValue = 1 if(pkgName != "") dialogStatus.intValue = 1
} }
if(VERSION.SDK_INT >= 28 && deviceOwner) { if(VERSION.SDK_INT >= 28 && deviceOwner) {
SubPageItem(R.string.keep_uninstalled_packages, "", R.drawable.delete_fill0) { navCtrl.navigate("KeepUninstalled") } FunctionItem(R.string.keep_uninstalled_packages, "", R.drawable.delete_fill0) { navCtrl.navigate("KeepUninstalled") }
} }
if(VERSION.SDK_INT >= 28) { if(VERSION.SDK_INT >= 28) {
SubPageItem(R.string.clear_app_storage, "", R.drawable.mop_fill0) { FunctionItem(R.string.clear_app_storage, "", R.drawable.mop_fill0) {
if(pkgName != "") dialogStatus.intValue = 2 if(pkgName != "") dialogStatus.intValue = 2
} }
} }
SubPageItem(R.string.install_app, "", R.drawable.install_mobile_fill0) { navCtrl.navigate("InstallApp") } FunctionItem(R.string.install_app, "", R.drawable.install_mobile_fill0) { navCtrl.navigate("InstallApp") }
SubPageItem(R.string.uninstall_app, "", R.drawable.delete_fill0) { navCtrl.navigate("UninstallApp") } FunctionItem(R.string.uninstall_app, "", R.drawable.delete_fill0) { navCtrl.navigate("UninstallApp") }
if(VERSION.SDK_INT >= 34 && (deviceOwner || dpm.isOrgProfile(receiver))) { if(VERSION.SDK_INT >= 34 && (deviceOwner || dpm.isOrgProfile(receiver))) {
SubPageItem(R.string.set_default_dialer, "", R.drawable.call_fill0) { FunctionItem(R.string.set_default_dialer, "", R.drawable.call_fill0) {
if(pkgName != "") dialogStatus.intValue = 3 if(pkgName != "") dialogStatus.intValue = 3
} }
} }

View File

@@ -153,7 +153,7 @@ private fun binderWrapperPackageInstaller(appContext: Context): PackageInstaller
fun Context.getPI(): PackageInstaller { fun Context.getPI(): PackageInstaller {
val sharedPref = this.getSharedPreferences("data", Context.MODE_PRIVATE) val sharedPref = this.getSharedPreferences("data", Context.MODE_PRIVATE)
if(sharedPref.getBoolean("dhizuku", false)) { if(sharedPref.getBoolean("dhizuku", false)) {
if (!Dhizuku.isPermissionGranted()) { if (!dhizukuPermissionGranted()) {
dhizukuErrorStatus.value = 2 dhizukuErrorStatus.value = 2
backToHomeStateFlow.value = true backToHomeStateFlow.value = true
return this.packageManager.packageInstaller return this.packageManager.packageInstaller
@@ -167,7 +167,7 @@ fun Context.getPI(): PackageInstaller {
fun Context.getDPM(): DevicePolicyManager { fun Context.getDPM(): DevicePolicyManager {
val sharedPref = this.getSharedPreferences("data", Context.MODE_PRIVATE) val sharedPref = this.getSharedPreferences("data", Context.MODE_PRIVATE)
if(sharedPref.getBoolean("dhizuku", false)) { if(sharedPref.getBoolean("dhizuku", false)) {
if (!Dhizuku.isPermissionGranted()) { if (!dhizukuPermissionGranted()) {
dhizukuErrorStatus.value = 2 dhizukuErrorStatus.value = 2
backToHomeStateFlow.value = true backToHomeStateFlow.value = true
return this.getSystemService(Context.DEVICE_POLICY_SERVICE) as DevicePolicyManager return this.getSystemService(Context.DEVICE_POLICY_SERVICE) as DevicePolicyManager
@@ -193,7 +193,7 @@ fun Context.resetDevicePolicy() {
val dpm = getDPM() val dpm = getDPM()
val receiver = getReceiver() val receiver = getReceiver()
RestrictionData.getAllRestrictions().forEach { RestrictionData.getAllRestrictions().forEach {
dpm.clearUserRestriction(receiver, it) dpm.clearUserRestriction(receiver, it.id)
} }
dpm.accountTypesWithManagementDisabled?.forEach { dpm.accountTypesWithManagementDisabled?.forEach {
dpm.setAccountManagementDisabled(receiver, it, false) dpm.setAccountManagementDisabled(receiver, it, false)
@@ -428,7 +428,7 @@ fun parseSecurityEventData(event: SecurityLog.SecurityEvent): JsonElement? {
val payload = event.data as Array<*> val payload = event.data as Array<*>
buildJsonObject { buildJsonObject {
put("mac", payload[0] as String) put("mac", payload[0] as String)
(payload[2] as String).let { if(it != "") put("reason", it) } (payload[1] as String).let { if(it != "") put("reason", it) }
} }
} }
SecurityLog.TAG_CAMERA_POLICY_SET -> { SecurityLog.TAG_CAMERA_POLICY_SET -> {
@@ -619,3 +619,11 @@ fun setDefaultAffiliationID(context: Context) {
} }
} }
} }
fun dhizukuPermissionGranted() =
try {
Dhizuku.isPermissionGranted()
} catch(_: Exception) {
false
}

View File

@@ -22,21 +22,17 @@ import android.widget.Toast
import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.AnimatedVisibility
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.text.KeyboardActions import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.foundation.text.selection.SelectionContainer import androidx.compose.foundation.text.selection.SelectionContainer
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.AlertDialog import androidx.compose.material3.AlertDialog
import androidx.compose.material3.Button import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.MaterialTheme.colorScheme import androidx.compose.material3.MaterialTheme.colorScheme
import androidx.compose.material3.MaterialTheme.typography import androidx.compose.material3.MaterialTheme.typography
import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.material3.TextButton import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
@@ -55,88 +51,47 @@ import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.navigation.NavHostController import androidx.navigation.NavHostController
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import androidx.navigation.compose.currentBackStackEntryAsState
import androidx.navigation.compose.rememberNavController
import com.bintianqi.owndroid.R import com.bintianqi.owndroid.R
import com.bintianqi.owndroid.ui.Animations import com.bintianqi.owndroid.ui.CardItem
import com.bintianqi.owndroid.ui.CheckBoxItem import com.bintianqi.owndroid.ui.CheckBoxItem
import com.bintianqi.owndroid.ui.CopyTextButton import com.bintianqi.owndroid.ui.CopyTextButton
import com.bintianqi.owndroid.ui.InfoCard import com.bintianqi.owndroid.ui.InfoCard
import com.bintianqi.owndroid.ui.SubPageItem import com.bintianqi.owndroid.ui.FunctionItem
import com.bintianqi.owndroid.ui.MyScaffold
import com.bintianqi.owndroid.ui.SwitchItem import com.bintianqi.owndroid.ui.SwitchItem
import com.bintianqi.owndroid.ui.TopBar import com.bintianqi.owndroid.yesOrNo
@Composable @Composable
fun ManagedProfile(navCtrl: NavHostController) { fun WorkProfile(navCtrl: NavHostController) {
val localNavCtrl = rememberNavController()
val backStackEntry by localNavCtrl.currentBackStackEntryAsState()
Scaffold(
topBar = {
TopBar(backStackEntry, navCtrl, localNavCtrl)
}
) {
NavHost(
navController = localNavCtrl, startDestination = "Home",
enterTransition = Animations.navHostEnterTransition,
exitTransition = Animations.navHostExitTransition,
popEnterTransition = Animations.navHostPopEnterTransition,
popExitTransition = Animations.navHostPopExitTransition,
modifier = Modifier.padding(top = it.calculateTopPadding())
) {
composable(route = "Home") { Home(localNavCtrl) }
composable(route = "OrgOwnedWorkProfile") { OrgOwnedProfile() }
composable(route = "CreateWorkProfile") { CreateWorkProfile() }
composable(route = "SuspendPersonalApp") { SuspendPersonalApp() }
composable(route = "IntentFilter") { IntentFilter() }
composable(route = "DeleteWorkProfile") { DeleteWorkProfile() }
}
}
}
@Composable
private fun Home(navCtrl: NavHostController) {
val context = LocalContext.current val context = LocalContext.current
val dpm = context.getDPM() val dpm = context.getDPM()
val receiver = context.getReceiver() val receiver = context.getReceiver()
val profileOwner = context.isProfileOwner val profileOwner = context.isProfileOwner
Column( MyScaffold(R.string.work_profile, 0.dp, navCtrl) {
modifier = Modifier.fillMaxSize().verticalScroll(rememberScrollState())
) {
Text(
text = stringResource(R.string.work_profile),
style = typography.headlineLarge,
modifier = Modifier.padding(top = 8.dp, bottom = 5.dp, start = 16.dp)
)
if(VERSION.SDK_INT >= 30 && profileOwner && dpm.isManagedProfile(receiver)) { if(VERSION.SDK_INT >= 30 && profileOwner && dpm.isManagedProfile(receiver)) {
SubPageItem(R.string.org_owned_work_profile, "", R.drawable.corporate_fare_fill0) { navCtrl.navigate("OrgOwnedWorkProfile") } FunctionItem(R.string.org_owned_work_profile, "", R.drawable.corporate_fare_fill0) { navCtrl.navigate("OrgOwnedWorkProfile") }
} }
if(VERSION.SDK_INT<24 || (VERSION.SDK_INT>=24 && dpm.isProvisioningAllowed(ACTION_PROVISION_MANAGED_PROFILE))) { if(VERSION.SDK_INT<24 || (VERSION.SDK_INT>=24 && dpm.isProvisioningAllowed(ACTION_PROVISION_MANAGED_PROFILE))) {
SubPageItem(R.string.create_work_profile, "", R.drawable.work_fill0) { navCtrl.navigate("CreateWorkProfile") } FunctionItem(R.string.create_work_profile, "", R.drawable.work_fill0) { navCtrl.navigate("CreateWorkProfile") }
} }
if(dpm.isOrgProfile(receiver)) { if(dpm.isOrgProfile(receiver)) {
SubPageItem(R.string.suspend_personal_app, "", R.drawable.block_fill0) { navCtrl.navigate("SuspendPersonalApp") } FunctionItem(R.string.suspend_personal_app, "", R.drawable.block_fill0) { navCtrl.navigate("SuspendPersonalApp") }
} }
if(profileOwner && (VERSION.SDK_INT < 24 || (VERSION.SDK_INT >= 24 && dpm.isManagedProfile(receiver)))) { if(profileOwner && (VERSION.SDK_INT < 24 || (VERSION.SDK_INT >= 24 && dpm.isManagedProfile(receiver)))) {
SubPageItem(R.string.intent_filter, "", R.drawable.filter_alt_fill0) { navCtrl.navigate("IntentFilter") } FunctionItem(R.string.intent_filter, "", R.drawable.filter_alt_fill0) { navCtrl.navigate("IntentFilter") }
} }
if(profileOwner && (VERSION.SDK_INT < 24 || (VERSION.SDK_INT >= 24 && dpm.isManagedProfile(receiver)))) { if(profileOwner && (VERSION.SDK_INT < 24 || (VERSION.SDK_INT >= 24 && dpm.isManagedProfile(receiver)))) {
SubPageItem(R.string.delete_work_profile, "", R.drawable.delete_forever_fill0) { navCtrl.navigate("DeleteWorkProfile") } FunctionItem(R.string.delete_work_profile, "", R.drawable.delete_forever_fill0) { navCtrl.navigate("DeleteWorkProfile") }
} }
Spacer(Modifier.padding(vertical = 30.dp))
} }
} }
@Composable @Composable
private fun CreateWorkProfile() { fun CreateWorkProfile(navCtrl: NavHostController) {
val context = LocalContext.current val context = LocalContext.current
val receiver = context.getReceiver() val receiver = context.getReceiver()
val focusMgr = LocalFocusManager.current val focusMgr = LocalFocusManager.current
Column(modifier = Modifier.fillMaxSize().padding(horizontal = 8.dp).verticalScroll(rememberScrollState())) { MyScaffold(R.string.create_work_profile, 8.dp, navCtrl) {
Spacer(Modifier.padding(vertical = 10.dp))
Text(text = stringResource(R.string.create_work_profile), style = typography.headlineLarge)
Spacer(Modifier.padding(vertical = 5.dp))
var skipEncrypt by remember { mutableStateOf(false) } var skipEncrypt by remember { mutableStateOf(false) }
var offlineProvisioning by remember { mutableStateOf(true) } var offlineProvisioning by remember { mutableStateOf(true) }
var migrateAccount by remember { mutableStateOf(false) } var migrateAccount by remember { mutableStateOf(false) }
@@ -206,14 +161,11 @@ private fun CreateWorkProfile() {
@SuppressLint("NewApi") @SuppressLint("NewApi")
@Composable @Composable
private fun OrgOwnedProfile() { fun OrgOwnedProfile(navCtrl: NavHostController) {
val context = LocalContext.current val context = LocalContext.current
val dpm = context.getDPM() val dpm = context.getDPM()
Column(modifier = Modifier.fillMaxSize().padding(horizontal = 8.dp).verticalScroll(rememberScrollState())) { MyScaffold(R.string.org_owned_work_profile, 8.dp, navCtrl, false) {
Spacer(Modifier.padding(vertical = 10.dp)) CardItem(R.string.org_owned_work_profile, dpm.isOrganizationOwnedDeviceWithManagedProfile.yesOrNo)
Text(text = stringResource(R.string.org_owned_work_profile), style = typography.headlineLarge)
Spacer(Modifier.padding(vertical = 5.dp))
Text(text = stringResource(R.string.is_org_owned_profile,dpm.isOrganizationOwnedDeviceWithManagedProfile))
Spacer(Modifier.padding(vertical = 5.dp)) Spacer(Modifier.padding(vertical = 5.dp))
if(!dpm.isOrganizationOwnedDeviceWithManagedProfile) { if(!dpm.isOrganizationOwnedDeviceWithManagedProfile) {
SelectionContainer { SelectionContainer {
@@ -229,14 +181,13 @@ private fun OrgOwnedProfile() {
@SuppressLint("NewApi") @SuppressLint("NewApi")
@Composable @Composable
private fun SuspendPersonalApp() { fun SuspendPersonalApp(navCtrl: NavHostController) {
val context = LocalContext.current val context = LocalContext.current
val dpm = context.getDPM() val dpm = context.getDPM()
val receiver = context.getReceiver() val receiver = context.getReceiver()
val focusMgr = LocalFocusManager.current val focusMgr = LocalFocusManager.current
var suspend by remember { mutableStateOf(dpm.getPersonalAppsSuspendedReasons(receiver) != PERSONAL_APPS_NOT_SUSPENDED) } var suspend by remember { mutableStateOf(dpm.getPersonalAppsSuspendedReasons(receiver) != PERSONAL_APPS_NOT_SUSPENDED) }
Column(modifier = Modifier.fillMaxSize().padding(horizontal = 8.dp).verticalScroll(rememberScrollState())) { MyScaffold(R.string.suspend_personal_app, 8.dp, navCtrl) {
Spacer(Modifier.padding(vertical = 10.dp))
SwitchItem( SwitchItem(
R.string.suspend_personal_app, "", null, R.string.suspend_personal_app, "", null,
suspend, suspend,
@@ -277,16 +228,13 @@ private fun SuspendPersonalApp() {
} }
@Composable @Composable
private fun IntentFilter() { fun IntentFilter(navCtrl: NavHostController) {
val context = LocalContext.current val context = LocalContext.current
val dpm = context.getDPM() val dpm = context.getDPM()
val receiver = context.getReceiver() val receiver = context.getReceiver()
val focusMgr = LocalFocusManager.current val focusMgr = LocalFocusManager.current
Column(modifier = Modifier.fillMaxSize().padding(horizontal = 8.dp).verticalScroll(rememberScrollState())) { MyScaffold(R.string.intent_filter, 8.dp, navCtrl) {
var action by remember { mutableStateOf("") } var action by remember { mutableStateOf("") }
Spacer(Modifier.padding(vertical = 10.dp))
Text(text = stringResource(R.string.intent_filter), style = typography.headlineLarge)
Spacer(Modifier.padding(vertical = 5.dp))
OutlinedTextField( OutlinedTextField(
value = action, onValueChange = { action = it }, value = action, onValueChange = { action = it },
label = { Text("Action") }, label = { Text("Action") },
@@ -328,7 +276,7 @@ private fun IntentFilter() {
} }
@Composable @Composable
private fun DeleteWorkProfile() { fun DeleteWorkProfile(navCtrl: NavHostController) {
val context = LocalContext.current val context = LocalContext.current
val dpm = context.getDPM() val dpm = context.getDPM()
val focusMgr = LocalFocusManager.current val focusMgr = LocalFocusManager.current
@@ -337,14 +285,7 @@ private fun DeleteWorkProfile() {
var euicc by remember { mutableStateOf(false) } var euicc by remember { mutableStateOf(false) }
var silent by remember { mutableStateOf(false) } var silent by remember { mutableStateOf(false) }
var reason by remember { mutableStateOf("") } var reason by remember { mutableStateOf("") }
Column(modifier = Modifier.fillMaxSize().padding(horizontal = 8.dp).verticalScroll(rememberScrollState())) { MyScaffold(R.string.delete_work_profile, 8.dp, navCtrl) {
Spacer(Modifier.padding(vertical = 10.dp))
Text(
text = stringResource(R.string.delete_work_profile),
style = typography.headlineLarge,
modifier = Modifier.padding(6.dp),color = colorScheme.error
)
Spacer(Modifier.padding(vertical = 5.dp))
CheckBoxItem(R.string.wipe_external_storage, externalStorage, { externalStorage = it }) CheckBoxItem(R.string.wipe_external_storage, externalStorage, { externalStorage = it })
if(VERSION.SDK_INT >= 28) { CheckBoxItem(R.string.wipe_euicc, euicc, { euicc = it }) } if(VERSION.SDK_INT >= 28) { CheckBoxItem(R.string.wipe_euicc, euicc, { euicc = it }) }
CheckBoxItem(R.string.wipe_silently, silent, { silent = it }) CheckBoxItem(R.string.wipe_silently, silent, { silent = it })
@@ -367,7 +308,6 @@ private fun DeleteWorkProfile() {
) { ) {
Text(stringResource(R.string.delete)) Text(stringResource(R.string.delete))
} }
Spacer(Modifier.padding(vertical = 30.dp))
} }
if(warning) { if(warning) {
LaunchedEffect(Unit) { silent = reason == "" } LaunchedEffect(Unit) { silent = reason == "" }

View File

@@ -43,21 +43,17 @@ import android.telephony.data.ApnSetting.PROTOCOL_UNSTRUCTURED
import android.widget.Toast import android.widget.Toast
import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.animateContentSize import androidx.compose.animation.animateContentSize
import androidx.compose.foundation.ScrollState
import androidx.compose.foundation.clickable import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.text.KeyboardActions import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.KeyboardArrowLeft import androidx.compose.material.icons.automirrored.filled.KeyboardArrowLeft
import androidx.compose.material.icons.automirrored.filled.KeyboardArrowRight import androidx.compose.material.icons.automirrored.filled.KeyboardArrowRight
@@ -69,14 +65,12 @@ import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme.typography import androidx.compose.material3.MaterialTheme.typography
import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Switch import androidx.compose.material3.Switch
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.material3.TextButton import androidx.compose.material3.TextButton
import androidx.compose.material3.TextField import androidx.compose.material3.TextField
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.MutableState
import androidx.compose.runtime.collectAsState import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableIntStateOf import androidx.compose.runtime.mutableIntStateOf
@@ -88,7 +82,6 @@ import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.alpha
import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.clip
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalFocusManager import androidx.compose.ui.platform.LocalFocusManager
@@ -99,72 +92,73 @@ import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.core.net.toUri import androidx.core.net.toUri
import androidx.navigation.NavHostController import androidx.navigation.NavHostController
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import androidx.navigation.compose.currentBackStackEntryAsState
import androidx.navigation.compose.rememberNavController
import com.bintianqi.owndroid.R import com.bintianqi.owndroid.R
import com.bintianqi.owndroid.exportFile import com.bintianqi.owndroid.exportFile
import com.bintianqi.owndroid.exportFilePath import com.bintianqi.owndroid.exportFilePath
import com.bintianqi.owndroid.formatFileSize import com.bintianqi.owndroid.formatFileSize
import com.bintianqi.owndroid.selectedPackage import com.bintianqi.owndroid.selectedPackage
import com.bintianqi.owndroid.ui.Animations
import com.bintianqi.owndroid.ui.CheckBoxItem import com.bintianqi.owndroid.ui.CheckBoxItem
import com.bintianqi.owndroid.ui.FunctionItem
import com.bintianqi.owndroid.ui.InfoCard import com.bintianqi.owndroid.ui.InfoCard
import com.bintianqi.owndroid.ui.ListItem import com.bintianqi.owndroid.ui.ListItem
import com.bintianqi.owndroid.ui.MyScaffold
import com.bintianqi.owndroid.ui.RadioButtonItem import com.bintianqi.owndroid.ui.RadioButtonItem
import com.bintianqi.owndroid.ui.SubPageItem
import com.bintianqi.owndroid.ui.SwitchItem import com.bintianqi.owndroid.ui.SwitchItem
import com.bintianqi.owndroid.ui.TopBar
import com.bintianqi.owndroid.writeClipBoard import com.bintianqi.owndroid.writeClipBoard
import kotlin.math.max import kotlin.math.max
@Composable @Composable
fun Network(navCtrl: NavHostController) { fun Network(navCtrl:NavHostController) {
val localNavCtrl = rememberNavController() val context = LocalContext.current
val backStackEntry by localNavCtrl.currentBackStackEntryAsState() val dpm = context.getDPM()
val scrollState = rememberScrollState() val receiver = context.getReceiver()
val wifiMacDialog = remember { mutableStateOf(false) } val deviceOwner = context.isDeviceOwner
Scaffold( val profileOwner = context.isProfileOwner
topBar = { val sharedPref = context.getSharedPreferences("data", Context.MODE_PRIVATE)
TopBar(backStackEntry,navCtrl,localNavCtrl) { val dhizuku = sharedPref.getBoolean("dhizuku", false)
if(backStackEntry?.destination?.route == "Home" && scrollState.maxValue > 80) { var wifiMacDialog by remember { mutableStateOf(false) }
Text( MyScaffold(R.string.network, 0.dp, navCtrl) {
text = stringResource(R.string.network), if(VERSION.SDK_INT >= 24 && (deviceOwner || dpm.isOrgProfile(receiver))) {
modifier = Modifier.alpha((maxOf(scrollState.value-30,0)).toFloat()/80) FunctionItem(R.string.wifi_mac_address, "", R.drawable.wifi_fill0) { wifiMacDialog = true }
)
}
}
} }
) { if(VERSION.SDK_INT >= 30) {
NavHost( FunctionItem(R.string.options, "", R.drawable.tune_fill0) { navCtrl.navigate("NetworkOptions") }
navController = localNavCtrl, startDestination = "Home", }
enterTransition = Animations.navHostEnterTransition, if(VERSION.SDK_INT >= 33 && (deviceOwner || dpm.isOrgProfile(receiver))) {
exitTransition = Animations.navHostExitTransition, FunctionItem(R.string.min_wifi_security_level, "", R.drawable.wifi_password_fill0) { navCtrl.navigate("MinWifiSecurityLevel") }
popEnterTransition = Animations.navHostPopEnterTransition, }
popExitTransition = Animations.navHostPopExitTransition, if(VERSION.SDK_INT >= 33 && (deviceOwner || dpm.isOrgProfile(receiver))) {
modifier = Modifier.padding(top = it.calculateTopPadding()) FunctionItem(R.string.wifi_ssid_policy, "", R.drawable.wifi_fill0) { navCtrl.navigate("WifiSsidPolicy") }
) { }
composable(route = "Home") { Home(localNavCtrl, scrollState, wifiMacDialog) } if(VERSION.SDK_INT >= 29 && deviceOwner) {
composable(route = "Switches") { Switches() } FunctionItem(R.string.private_dns, "", R.drawable.dns_fill0) { navCtrl.navigate("PrivateDNS") }
composable(route = "MinWifiSecurityLevel") { WifiSecLevel() } }
composable(route = "WifiSsidPolicy") { WifiSsidPolicy() } if(VERSION.SDK_INT >= 24 && (deviceOwner || profileOwner)) {
composable(route = "PrivateDNS") { PrivateDNS() } FunctionItem(R.string.always_on_vpn, "", R.drawable.vpn_key_fill0) { navCtrl.navigate("AlwaysOnVpn") }
composable(route = "AlwaysOnVpn") { AlwaysOnVPNPackage(navCtrl) } }
composable(route = "RecommendedGlobalProxy") { RecommendedGlobalProxy() } if(deviceOwner) {
composable(route = "NetworkLog") { NetworkLog() } FunctionItem(R.string.recommended_global_proxy, "", R.drawable.vpn_key_fill0) { navCtrl.navigate("RecommendedGlobalProxy") }
composable(route = "WifiAuthKeypair") { WifiAuthKeypair() } }
composable(route = "PreferentialNetworkService") { PreferentialNetworkService() } if(VERSION.SDK_INT >= 26 && !dhizuku && (deviceOwner || (profileOwner && dpm.isManagedProfile(receiver)))) {
composable(route = "APN") { APN() } FunctionItem(R.string.network_logging, "", R.drawable.description_fill0) { navCtrl.navigate("NetworkLog") }
}
if(VERSION.SDK_INT >= 31 && (deviceOwner || profileOwner)) {
FunctionItem(R.string.wifi_auth_keypair, "", R.drawable.key_fill0) { navCtrl.navigate("WifiAuthKeypair") }
}
if(VERSION.SDK_INT >= 33 && (deviceOwner || profileOwner)) {
FunctionItem(R.string.preferential_network_service, "", R.drawable.globe_fill0) { navCtrl.navigate("PreferentialNetworkService") }
}
if(VERSION.SDK_INT >= 28 && deviceOwner) {
FunctionItem(R.string.override_apn_settings, "", R.drawable.cell_tower_fill0) { navCtrl.navigate("OverrideAPN") }
} }
} }
if(wifiMacDialog.value && VERSION.SDK_INT >= 24) { if(wifiMacDialog && VERSION.SDK_INT >= 24) {
val context = LocalContext.current val context = LocalContext.current
val dpm = context.getDPM() val dpm = context.getDPM()
val receiver = context.getReceiver() val receiver = context.getReceiver()
AlertDialog( AlertDialog(
onDismissRequest = { wifiMacDialog.value = false }, onDismissRequest = { wifiMacDialog = false },
confirmButton = { TextButton(onClick = { wifiMacDialog.value = false }) { Text(stringResource(R.string.confirm)) } }, confirmButton = { TextButton(onClick = { wifiMacDialog = false }) { Text(stringResource(R.string.confirm)) } },
title = { Text(stringResource(R.string.wifi_mac_address)) }, title = { Text(stringResource(R.string.wifi_mac_address)) },
text = { text = {
val mac = dpm.getWifiMacAddress(receiver) val mac = dpm.getWifiMacAddress(receiver)
@@ -184,66 +178,13 @@ fun Network(navCtrl: NavHostController) {
} }
@Composable @Composable
private fun Home(navCtrl:NavHostController, scrollState: ScrollState, wifiMacDialog: MutableState<Boolean>) { fun NetworkOptions(navCtrl: NavHostController) {
val context = LocalContext.current
val dpm = context.getDPM()
val receiver = context.getReceiver()
val deviceOwner = context.isDeviceOwner
val profileOwner = context.isProfileOwner
val sharedPref = context.getSharedPreferences("data", Context.MODE_PRIVATE)
val dhizuku = sharedPref.getBoolean("dhizuku", false)
Column(modifier = Modifier.fillMaxSize().verticalScroll(scrollState)) {
Text(
text = stringResource(R.string.network),
style = typography.headlineLarge,
modifier = Modifier.padding(top = 8.dp, bottom = 5.dp, start = 16.dp)
)
if(VERSION.SDK_INT >= 24 && (deviceOwner || dpm.isOrgProfile(receiver))) {
SubPageItem(R.string.wifi_mac_address, "", R.drawable.wifi_fill0) { wifiMacDialog.value = true }
}
if(VERSION.SDK_INT >= 30) {
SubPageItem(R.string.options, "", R.drawable.tune_fill0) { navCtrl.navigate("Switches") }
}
if(VERSION.SDK_INT >= 33 && (deviceOwner || dpm.isOrgProfile(receiver))) {
SubPageItem(R.string.min_wifi_security_level, "", R.drawable.wifi_password_fill0) { navCtrl.navigate("MinWifiSecurityLevel") }
}
if(VERSION.SDK_INT >= 33 && (deviceOwner || dpm.isOrgProfile(receiver))) {
SubPageItem(R.string.wifi_ssid_policy, "", R.drawable.wifi_fill0) { navCtrl.navigate("WifiSsidPolicy") }
}
if(VERSION.SDK_INT >= 29 && deviceOwner) {
SubPageItem(R.string.private_dns, "", R.drawable.dns_fill0) { navCtrl.navigate("PrivateDNS") }
}
if(VERSION.SDK_INT >= 24 && (deviceOwner || profileOwner)) {
SubPageItem(R.string.always_on_vpn, "", R.drawable.vpn_key_fill0) { navCtrl.navigate("AlwaysOnVpn") }
}
if(deviceOwner) {
SubPageItem(R.string.recommended_global_proxy, "", R.drawable.vpn_key_fill0) { navCtrl.navigate("RecommendedGlobalProxy") }
}
if(VERSION.SDK_INT >= 26 && !dhizuku && (deviceOwner || (profileOwner && dpm.isManagedProfile(receiver)))) {
SubPageItem(R.string.retrieve_net_logs, "", R.drawable.description_fill0) { navCtrl.navigate("NetworkLog") }
}
if(VERSION.SDK_INT >= 31 && (deviceOwner || profileOwner)) {
SubPageItem(R.string.wifi_auth_keypair, "", R.drawable.key_fill0) { navCtrl.navigate("WifiAuthKeypair") }
}
if(VERSION.SDK_INT >= 33 && (deviceOwner || profileOwner)) {
SubPageItem(R.string.preferential_network_service, "", R.drawable.globe_fill0) { navCtrl.navigate("PreferentialNetworkService") }
}
if(VERSION.SDK_INT >= 28 && deviceOwner) {
SubPageItem(R.string.override_apn_settings, "", R.drawable.cell_tower_fill0) { navCtrl.navigate("APN") }
}
Spacer(Modifier.padding(vertical = 30.dp))
}
}
@Composable
private fun Switches() {
val context = LocalContext.current val context = LocalContext.current
val dpm = context.getDPM() val dpm = context.getDPM()
val receiver = context.getReceiver() val receiver = context.getReceiver()
val deviceOwner = context.isDeviceOwner val deviceOwner = context.isDeviceOwner
var dialog by remember { mutableIntStateOf(0) } var dialog by remember { mutableIntStateOf(0) }
Column(modifier = Modifier.fillMaxSize()) { MyScaffold(R.string.options, 0.dp, navCtrl) {
Spacer(Modifier.padding(vertical = 5.dp))
if(VERSION.SDK_INT>=30 && (deviceOwner || dpm.isOrgProfile(receiver))) { if(VERSION.SDK_INT>=30 && (deviceOwner || dpm.isOrgProfile(receiver))) {
SwitchItem(R.string.lockdown_admin_configured_network, "", R.drawable.wifi_password_fill0, SwitchItem(R.string.lockdown_admin_configured_network, "", R.drawable.wifi_password_fill0,
{ dpm.hasLockdownAdminConfiguredNetworks(receiver) }, { dpm.setConfiguredNetworksLockdownState(receiver,it) }, { dpm.hasLockdownAdminConfiguredNetworks(receiver) }, { dpm.setConfiguredNetworksLockdownState(receiver,it) },
@@ -262,15 +203,12 @@ private fun Switches() {
@SuppressLint("NewApi") @SuppressLint("NewApi")
@Composable @Composable
private fun WifiSecLevel() { fun WifiSecurityLevel(navCtrl: NavHostController) {
val context = LocalContext.current val context = LocalContext.current
val dpm = context.getDPM() val dpm = context.getDPM()
var selectedWifiSecLevel by remember { mutableIntStateOf(0) } var selectedWifiSecLevel by remember { mutableIntStateOf(0) }
LaunchedEffect(Unit) { selectedWifiSecLevel = dpm.minimumRequiredWifiSecurityLevel } LaunchedEffect(Unit) { selectedWifiSecLevel = dpm.minimumRequiredWifiSecurityLevel }
Column(modifier = Modifier.fillMaxSize().padding(horizontal = 8.dp).verticalScroll(rememberScrollState())) { MyScaffold(R.string.min_wifi_security_level, 8.dp, navCtrl) {
Spacer(Modifier.padding(vertical = 10.dp))
Text(text = stringResource(R.string.min_wifi_security_level), style = typography.headlineLarge)
Spacer(Modifier.padding(vertical = 5.dp))
RadioButtonItem( RadioButtonItem(
R.string.wifi_security_open, R.string.wifi_security_open,
selectedWifiSecLevel == WIFI_SECURITY_OPEN, selectedWifiSecLevel == WIFI_SECURITY_OPEN,
@@ -307,11 +245,11 @@ private fun WifiSecLevel() {
@SuppressLint("NewApi") @SuppressLint("NewApi")
@Composable @Composable
private fun WifiSsidPolicy() { fun WifiSsidPolicy(navCtrl: NavHostController) {
val context = LocalContext.current val context = LocalContext.current
val dpm = context.getDPM() val dpm = context.getDPM()
val focusMgr = LocalFocusManager.current val focusMgr = LocalFocusManager.current
Column(modifier = Modifier.fillMaxSize().padding(horizontal = 8.dp).verticalScroll(rememberScrollState())) { MyScaffold(R.string.wifi_ssid_policy, 8.dp, navCtrl) {
var selectedPolicyType by remember { mutableIntStateOf(-1) } var selectedPolicyType by remember { mutableIntStateOf(-1) }
val ssidList = remember { mutableStateListOf<WifiSsid>() } val ssidList = remember { mutableStateListOf<WifiSsid>() }
val refreshPolicy = { val refreshPolicy = {
@@ -321,9 +259,6 @@ private fun WifiSsidPolicy() {
ssidList.addAll(policy?.ssids ?: mutableSetOf()) ssidList.addAll(policy?.ssids ?: mutableSetOf())
} }
LaunchedEffect(Unit) { refreshPolicy() } LaunchedEffect(Unit) { refreshPolicy() }
Spacer(Modifier.padding(vertical = 10.dp))
Text(text = stringResource(R.string.wifi_ssid_policy), style = typography.headlineLarge)
Spacer(Modifier.padding(vertical = 5.dp))
RadioButtonItem( RadioButtonItem(
R.string.none, R.string.none,
selectedPolicyType == -1, selectedPolicyType == -1,
@@ -387,20 +322,17 @@ private fun WifiSsidPolicy() {
) { ) {
Text(stringResource(R.string.apply)) Text(stringResource(R.string.apply))
} }
Spacer(Modifier.padding(vertical = 30.dp))
} }
} }
@SuppressLint("NewApi") @SuppressLint("NewApi")
@Composable @Composable
private fun PrivateDNS() { fun PrivateDNS(navCtrl: NavHostController) {
val context = LocalContext.current val context = LocalContext.current
val dpm = context.getDPM() val dpm = context.getDPM()
val receiver = context.getReceiver() val receiver = context.getReceiver()
val focusMgr = LocalFocusManager.current val focusMgr = LocalFocusManager.current
Column(modifier = Modifier.fillMaxSize().padding(horizontal = 8.dp).verticalScroll(rememberScrollState())) { MyScaffold(R.string.private_dns, 8.dp, navCtrl) {
Spacer(Modifier.padding(vertical = 10.dp))
Text(text = stringResource(R.string.private_dns), style = typography.headlineLarge)
val dnsStatus = mapOf( val dnsStatus = mapOf(
PRIVATE_DNS_MODE_UNKNOWN to stringResource(R.string.unknown), PRIVATE_DNS_MODE_UNKNOWN to stringResource(R.string.unknown),
PRIVATE_DNS_MODE_OFF to stringResource(R.string.disabled), PRIVATE_DNS_MODE_OFF to stringResource(R.string.disabled),
@@ -462,7 +394,6 @@ private fun PrivateDNS() {
Text(stringResource(R.string.set_dns_host)) Text(stringResource(R.string.set_dns_host))
} }
InfoCard(R.string.info_set_private_dns_host) InfoCard(R.string.info_set_private_dns_host)
Spacer(Modifier.padding(vertical = 30.dp))
} }
} }
@@ -499,9 +430,7 @@ fun AlwaysOnVPNPackage(navCtrl: NavHostController) {
false false
} }
} }
Column(modifier = Modifier.fillMaxSize().verticalScroll(rememberScrollState()).padding(horizontal = 8.dp)) { MyScaffold(R.string.always_on_vpn, 8.dp, navCtrl) {
Spacer(Modifier.padding(vertical = 10.dp))
Text(text = stringResource(R.string.always_on_vpn), style = typography.headlineLarge, modifier = Modifier.padding(vertical = 8.dp))
OutlinedTextField( OutlinedTextField(
value = pkgName, value = pkgName,
onValueChange = { pkgName = it }, onValueChange = { pkgName = it },
@@ -509,7 +438,7 @@ fun AlwaysOnVPNPackage(navCtrl: NavHostController) {
keyboardOptions = KeyboardOptions(imeAction = ImeAction.Done), keyboardOptions = KeyboardOptions(imeAction = ImeAction.Done),
keyboardActions = KeyboardActions(onDone = { focusMgr.clearFocus() }), keyboardActions = KeyboardActions(onDone = { focusMgr.clearFocus() }),
trailingIcon = { trailingIcon = {
Icon(painter = painterResource(R.drawable.checklist_fill0), contentDescription = null, Icon(painter = painterResource(R.drawable.list_fill0), contentDescription = null,
modifier = Modifier modifier = Modifier
.clip(RoundedCornerShape(50)) .clip(RoundedCornerShape(50))
.clickable(onClick = { .clickable(onClick = {
@@ -536,12 +465,11 @@ fun AlwaysOnVPNPackage(navCtrl: NavHostController) {
Text(stringResource(R.string.clear_current_config)) Text(stringResource(R.string.clear_current_config))
} }
InfoCard(R.string.info_always_on_vpn) InfoCard(R.string.info_always_on_vpn)
Spacer(Modifier.padding(vertical = 30.dp))
} }
} }
@Composable @Composable
private fun RecommendedGlobalProxy() { fun RecommendedGlobalProxy(navCtrl: NavHostController) {
val context = LocalContext.current val context = LocalContext.current
val dpm = context.getDPM() val dpm = context.getDPM()
val receiver = context.getReceiver() val receiver = context.getReceiver()
@@ -551,10 +479,7 @@ private fun RecommendedGlobalProxy() {
var specifyPort by remember { mutableStateOf(false) } var specifyPort by remember { mutableStateOf(false) }
var proxyPort by remember { mutableStateOf("") } var proxyPort by remember { mutableStateOf("") }
var exclList by remember { mutableStateOf("") } var exclList by remember { mutableStateOf("") }
Column(modifier = Modifier.fillMaxSize().padding(horizontal = 8.dp).verticalScroll(rememberScrollState())) { MyScaffold(R.string.recommended_global_proxy, 8.dp, navCtrl) {
Spacer(Modifier.padding(vertical = 10.dp))
Text(text = stringResource(R.string.recommended_global_proxy), style = typography.headlineLarge)
Spacer(Modifier.padding(vertical = 5.dp))
RadioButtonItem(R.string.proxy_type_off, proxyType == 0, { proxyType = 0 }) RadioButtonItem(R.string.proxy_type_off, proxyType == 0, { proxyType = 0 })
RadioButtonItem(R.string.proxy_type_pac, proxyType == 1, { proxyType = 1 }) RadioButtonItem(R.string.proxy_type_pac, proxyType == 1, { proxyType = 1 })
RadioButtonItem(R.string.proxy_type_direct, proxyType == 2, { proxyType = 2 }) RadioButtonItem(R.string.proxy_type_direct, proxyType == 2, { proxyType = 2 })
@@ -641,7 +566,7 @@ private fun RecommendedGlobalProxy() {
@SuppressLint("NewApi") @SuppressLint("NewApi")
@Composable @Composable
private fun NetworkLog() { fun NetworkLogging(navCtrl: NavHostController) {
val context = LocalContext.current val context = LocalContext.current
val dpm = context.getDPM() val dpm = context.getDPM()
val receiver = context.getReceiver() val receiver = context.getReceiver()
@@ -650,10 +575,7 @@ private fun NetworkLog() {
LaunchedEffect(Unit) { LaunchedEffect(Unit) {
fileSize = logFile.length() fileSize = logFile.length()
} }
Column(modifier = Modifier.fillMaxSize().padding(horizontal = 8.dp).verticalScroll(rememberScrollState())) { MyScaffold(R.string.network_logging, 8.dp, navCtrl) {
Spacer(Modifier.padding(vertical = 10.dp))
Text(text = stringResource(R.string.retrieve_net_logs), style = typography.headlineLarge)
Spacer(Modifier.padding(vertical = 5.dp))
SwitchItem(R.string.enable, "", null, { dpm.isNetworkLoggingEnabled(receiver) }, { dpm.setNetworkLoggingEnabled(receiver,it) }, padding = false) SwitchItem(R.string.enable, "", null, { dpm.isNetworkLoggingEnabled(receiver) }, { dpm.setNetworkLoggingEnabled(receiver,it) }, padding = false)
Text(stringResource(R.string.log_file_size_is, formatFileSize(fileSize))) Text(stringResource(R.string.log_file_size_is, formatFileSize(fileSize)))
Row(horizontalArrangement = Arrangement.SpaceBetween, modifier = Modifier.fillMaxWidth()) { Row(horizontalArrangement = Arrangement.SpaceBetween, modifier = Modifier.fillMaxWidth()) {
@@ -688,15 +610,12 @@ private fun NetworkLog() {
@SuppressLint("NewApi") @SuppressLint("NewApi")
@Composable @Composable
private fun WifiAuthKeypair() { fun WifiAuthKeypair(navCtrl: NavHostController) {
val context = LocalContext.current val context = LocalContext.current
val dpm = context.getDPM() val dpm = context.getDPM()
val focusMgr = LocalFocusManager.current val focusMgr = LocalFocusManager.current
Column(modifier = Modifier.fillMaxSize().padding(horizontal = 8.dp).verticalScroll(rememberScrollState())) { var keyPair by remember { mutableStateOf("") }
var keyPair by remember { mutableStateOf("") } MyScaffold(R.string.wifi_auth_keypair, 8.dp, navCtrl) {
Spacer(Modifier.padding(vertical = 10.dp))
Text(text = stringResource(R.string.wifi_auth_keypair), style = typography.headlineLarge)
Spacer(Modifier.padding(vertical = 5.dp))
OutlinedTextField( OutlinedTextField(
value = keyPair, value = keyPair,
label = { Text(stringResource(R.string.alias)) }, label = { Text(stringResource(R.string.alias)) },
@@ -739,7 +658,7 @@ private fun WifiAuthKeypair() {
@SuppressLint("NewApi") @SuppressLint("NewApi")
@Composable @Composable
fun PreferentialNetworkService() { fun PreferentialNetworkService(navCtrl: NavHostController) {
val focusMgr = LocalFocusManager.current val focusMgr = LocalFocusManager.current
val context = LocalContext.current val context = LocalContext.current
val dpm = context.getDPM() val dpm = context.getDPM()
@@ -778,10 +697,7 @@ fun PreferentialNetworkService() {
refresh() refresh()
} }
LaunchedEffect(Unit) { initialize() } LaunchedEffect(Unit) { initialize() }
Column(modifier = Modifier.fillMaxSize().padding(horizontal = 8.dp).verticalScroll(rememberScrollState())) { MyScaffold(R.string.preferential_network_service, 8.dp, navCtrl) {
Spacer(Modifier.padding(vertical = 10.dp))
Text(text = stringResource(R.string.preferential_network_service), style = typography.headlineLarge)
Spacer(Modifier.padding(vertical = 5.dp))
SwitchItem( SwitchItem(
title = R.string.enabled, desc = "", icon = null, title = R.string.enabled, desc = "", icon = null,
state = masterEnabled, onCheckedChange = { masterEnabled = it }, padding = false state = masterEnabled, onCheckedChange = { masterEnabled = it }, padding = false
@@ -895,25 +811,21 @@ fun PreferentialNetworkService() {
) { ) {
Text(stringResource(R.string.apply)) Text(stringResource(R.string.apply))
} }
Spacer(Modifier.padding(vertical = 30.dp))
} }
} }
@SuppressLint("NewApi") @SuppressLint("NewApi")
@Composable @Composable
private fun APN() { fun OverrideAPN(navCtrl: NavHostController) {
val context = LocalContext.current val context = LocalContext.current
val dpm = context.getDPM() val dpm = context.getDPM()
val receiver = context.getReceiver() val receiver = context.getReceiver()
val focusMgr = LocalFocusManager.current val focusMgr = LocalFocusManager.current
Column(modifier = Modifier.fillMaxSize().padding(horizontal = 8.dp).verticalScroll(rememberScrollState())) { val setting = dpm.getOverrideApns(receiver)
val setting = dpm.getOverrideApns(receiver) var inputNum by remember { mutableStateOf("0") }
var inputNum by remember { mutableStateOf("0") } var nextStep by remember { mutableStateOf(false) }
var nextStep by remember { mutableStateOf(false) } val builder = Builder()
val builder = Builder() MyScaffold(R.string.override_apn_settings, 8.dp, navCtrl) {
Spacer(Modifier.padding(vertical = 10.dp))
Text(text = stringResource(R.string.override_apn_settings), style = typography.headlineLarge)
Spacer(Modifier.padding(vertical = 5.dp))
Text(text = stringResource(id = R.string.developing)) Text(text = stringResource(id = R.string.developing))
Spacer(Modifier.padding(vertical = 5.dp)) Spacer(Modifier.padding(vertical = 5.dp))
SwitchItem(R.string.enable, "", null, { dpm.isOverrideApnEnabled(receiver) }, { dpm.setOverrideApnsEnabled(receiver,it) }, padding = false) SwitchItem(R.string.enable, "", null, { dpm.isOverrideApnEnabled(receiver) }, { dpm.setOverrideApnsEnabled(receiver,it) }, padding = false)
@@ -1275,6 +1187,5 @@ private fun APN() {
} }
} }
} }
Spacer(Modifier.padding(vertical = 30.dp))
} }
} }

View File

@@ -35,25 +35,20 @@ import android.os.Build.VERSION
import android.os.UserManager import android.os.UserManager
import android.widget.Toast import android.widget.Toast
import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.AnimatedVisibility
import androidx.compose.foundation.ScrollState
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.text.KeyboardActions import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.AlertDialog import androidx.compose.material3.AlertDialog
import androidx.compose.material3.Button import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.MaterialTheme.colorScheme import androidx.compose.material3.MaterialTheme.colorScheme
import androidx.compose.material3.MaterialTheme.typography import androidx.compose.material3.MaterialTheme.typography
import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.material3.TextButton import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
@@ -65,7 +60,6 @@ import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.alpha
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalFocusManager import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
@@ -75,103 +69,56 @@ import androidx.compose.ui.text.input.PasswordVisualTransformation
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.core.content.ContextCompat.startActivity import androidx.core.content.ContextCompat.startActivity
import androidx.navigation.NavHostController import androidx.navigation.NavHostController
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import androidx.navigation.compose.currentBackStackEntryAsState
import androidx.navigation.compose.rememberNavController
import com.bintianqi.owndroid.R import com.bintianqi.owndroid.R
import com.bintianqi.owndroid.toggle import com.bintianqi.owndroid.toggle
import com.bintianqi.owndroid.ui.Animations
import com.bintianqi.owndroid.ui.CardItem import com.bintianqi.owndroid.ui.CardItem
import com.bintianqi.owndroid.ui.CheckBoxItem import com.bintianqi.owndroid.ui.CheckBoxItem
import com.bintianqi.owndroid.ui.FunctionItem
import com.bintianqi.owndroid.ui.InfoCard import com.bintianqi.owndroid.ui.InfoCard
import com.bintianqi.owndroid.ui.Information import com.bintianqi.owndroid.ui.Information
import com.bintianqi.owndroid.ui.MyScaffold
import com.bintianqi.owndroid.ui.RadioButtonItem import com.bintianqi.owndroid.ui.RadioButtonItem
import com.bintianqi.owndroid.ui.SubPageItem
import com.bintianqi.owndroid.ui.TopBar
import com.bintianqi.owndroid.yesOrNo import com.bintianqi.owndroid.yesOrNo
@Composable
fun Password(navCtrl: NavHostController) {
val localNavCtrl = rememberNavController()
val backStackEntry by localNavCtrl.currentBackStackEntryAsState()
val scrollState = rememberScrollState()
Scaffold(
topBar = {
TopBar(backStackEntry,navCtrl,localNavCtrl) {
if(backStackEntry?.destination?.route == "Home" && scrollState.maxValue > 100) {
Text(
text = stringResource(R.string.password_and_keyguard),
modifier = Modifier.alpha((maxOf(scrollState.value-30,0)).toFloat()/80)
)
}
}
}
) {
NavHost(
navController = localNavCtrl, startDestination = "Home",
enterTransition = Animations.navHostEnterTransition,
exitTransition = Animations.navHostExitTransition,
popEnterTransition = Animations.navHostPopEnterTransition,
popExitTransition = Animations.navHostPopExitTransition,
modifier = Modifier.padding(top = it.calculateTopPadding())
) {
composable(route = "Home") { Home(localNavCtrl,scrollState) }
composable(route = "PasswordInfo") { PasswordInfo() }
composable(route = "ResetPasswordToken") { ResetPasswordToken() }
composable(route = "ResetPassword") { ResetPassword() }
composable(route = "RequirePasswordComplexity") { PasswordComplexity() }
composable(route = "DisableKeyguardFeatures") { DisableKeyguardFeatures() }
composable(route = "RequirePasswordQuality") { PasswordQuality() }
}
}
}
@SuppressLint("NewApi") @SuppressLint("NewApi")
@Composable @Composable
private fun Home(navCtrl:NavHostController, scrollState: ScrollState) { fun Password(navCtrl: NavHostController) {
val context = LocalContext.current val context = LocalContext.current
val sharedPrefs = context.getSharedPreferences("data", Context.MODE_PRIVATE) val sharedPrefs = context.getSharedPreferences("data", Context.MODE_PRIVATE)
val deviceAdmin = context.isDeviceAdmin val deviceAdmin = context.isDeviceAdmin
val deviceOwner = context.isDeviceOwner val deviceOwner = context.isDeviceOwner
val profileOwner = context.isProfileOwner val profileOwner = context.isProfileOwner
var dialog by remember { mutableIntStateOf(0) } var dialog by remember { mutableIntStateOf(0) }
Column(modifier = Modifier.fillMaxSize().verticalScroll(scrollState)) { MyScaffold(R.string.password_and_keyguard, 0.dp, navCtrl) {
Text( FunctionItem(R.string.password_info, "", R.drawable.info_fill0) { navCtrl.navigate("PasswordInfo") }
text = stringResource(R.string.password_and_keyguard),
style = typography.headlineLarge,
modifier = Modifier.padding(top = 8.dp, bottom = 5.dp, start = 16.dp)
)
SubPageItem(R.string.password_info, "", R.drawable.info_fill0) { navCtrl.navigate("PasswordInfo") }
if(sharedPrefs.getBoolean("dangerous_features", false)) { if(sharedPrefs.getBoolean("dangerous_features", false)) {
if(VERSION.SDK_INT >= 26 && (deviceOwner || profileOwner)) { if(VERSION.SDK_INT >= 26 && (deviceOwner || profileOwner)) {
SubPageItem(R.string.reset_password_token, "", R.drawable.key_vertical_fill0) { navCtrl.navigate("ResetPasswordToken") } FunctionItem(R.string.reset_password_token, "", R.drawable.key_vertical_fill0) { navCtrl.navigate("ResetPasswordToken") }
} }
if(deviceAdmin || deviceOwner || profileOwner) { if(deviceAdmin || deviceOwner || profileOwner) {
SubPageItem(R.string.reset_password, "", R.drawable.lock_reset_fill0) { navCtrl.navigate("ResetPassword") } FunctionItem(R.string.reset_password, "", R.drawable.lock_reset_fill0) { navCtrl.navigate("ResetPassword") }
} }
} }
if(VERSION.SDK_INT >= 31 && (deviceOwner || profileOwner)) { if(VERSION.SDK_INT >= 31 && (deviceOwner || profileOwner)) {
SubPageItem(R.string.required_password_complexity, "", R.drawable.password_fill0) { navCtrl.navigate("RequirePasswordComplexity") } FunctionItem(R.string.required_password_complexity, "", R.drawable.password_fill0) { navCtrl.navigate("RequirePasswordComplexity") }
} }
if(deviceAdmin) { if(deviceAdmin) {
SubPageItem(R.string.disable_keyguard_features, "", R.drawable.screen_lock_portrait_fill0) { navCtrl.navigate("DisableKeyguardFeatures") } FunctionItem(R.string.disable_keyguard_features, "", R.drawable.screen_lock_portrait_fill0) { navCtrl.navigate("DisableKeyguardFeatures") }
} }
if(deviceOwner) { if(deviceOwner) {
SubPageItem(R.string.max_time_to_lock, "", R.drawable.schedule_fill0) { dialog = 1 } FunctionItem(R.string.max_time_to_lock, "", R.drawable.schedule_fill0) { dialog = 1 }
SubPageItem(R.string.pwd_expiration_timeout, "", R.drawable.lock_clock_fill0) { dialog = 3 } FunctionItem(R.string.pwd_expiration_timeout, "", R.drawable.lock_clock_fill0) { dialog = 3 }
SubPageItem(R.string.max_pwd_fail, "", R.drawable.no_encryption_fill0) { dialog = 4 } FunctionItem(R.string.max_pwd_fail, "", R.drawable.no_encryption_fill0) { dialog = 4 }
} }
if(VERSION.SDK_INT >= 26 && (deviceOwner || profileOwner)) { if(VERSION.SDK_INT >= 26 && (deviceOwner || profileOwner)) {
SubPageItem(R.string.required_strong_auth_timeout, "", R.drawable.fingerprint_off_fill0) { dialog = 2 } FunctionItem(R.string.required_strong_auth_timeout, "", R.drawable.fingerprint_off_fill0) { dialog = 2 }
} }
if(deviceAdmin){ if(deviceAdmin){
SubPageItem(R.string.pwd_history, "", R.drawable.history_fill0) { dialog = 5 } FunctionItem(R.string.pwd_history, "", R.drawable.history_fill0) { dialog = 5 }
} }
if(VERSION.SDK_INT < 31 && (deviceOwner || profileOwner)) { if(VERSION.SDK_INT < 31 && (deviceOwner || profileOwner)) {
SubPageItem(R.string.required_password_quality, "", R.drawable.password_fill0) { navCtrl.navigate("RequirePasswordQuality") } FunctionItem(R.string.required_password_quality, "", R.drawable.password_fill0) { navCtrl.navigate("RequirePasswordQuality") }
} }
Spacer(Modifier.padding(vertical = 30.dp))
} }
if(dialog != 0) { if(dialog != 0) {
val dpm = context.getDPM() val dpm = context.getDPM()
@@ -263,16 +210,13 @@ private fun Home(navCtrl:NavHostController, scrollState: ScrollState) {
} }
@Composable @Composable
private fun PasswordInfo() { fun PasswordInfo(navCtrl: NavHostController) {
val context = LocalContext.current val context = LocalContext.current
val dpm = context.getDPM() val dpm = context.getDPM()
val receiver = context.getReceiver() val receiver = context.getReceiver()
val deviceOwner = context.isDeviceOwner val deviceOwner = context.isDeviceOwner
val profileOwner = context.isProfileOwner val profileOwner = context.isProfileOwner
Column(modifier = Modifier.fillMaxSize().padding(horizontal = 8.dp).verticalScroll(rememberScrollState())) { MyScaffold(R.string.password_info, 8.dp, navCtrl) {
Spacer(Modifier.padding(vertical = 10.dp))
Text(text = stringResource(R.string.password_info), style = typography.headlineLarge)
Spacer(Modifier.padding(vertical = 5.dp))
if(VERSION.SDK_INT >= 29) { if(VERSION.SDK_INT >= 29) {
val passwordComplexity = mapOf( val passwordComplexity = mapOf(
PASSWORD_COMPLEXITY_NONE to R.string.password_complexity_none, PASSWORD_COMPLEXITY_NONE to R.string.password_complexity_none,
@@ -293,17 +237,14 @@ private fun PasswordInfo() {
@SuppressLint("NewApi") @SuppressLint("NewApi")
@Composable @Composable
private fun ResetPasswordToken() { fun ResetPasswordToken(navCtrl: NavHostController) {
val context = LocalContext.current val context = LocalContext.current
val dpm = context.getDPM() val dpm = context.getDPM()
val receiver = context.getReceiver() val receiver = context.getReceiver()
var token by remember { mutableStateOf("") } var token by remember { mutableStateOf("") }
val tokenByteArray = token.toByteArray() val tokenByteArray = token.toByteArray()
val focusMgr = LocalFocusManager.current val focusMgr = LocalFocusManager.current
Column(modifier = Modifier.fillMaxSize().padding(horizontal = 8.dp).verticalScroll(rememberScrollState())) { MyScaffold(R.string.reset_password_token, 8.dp, navCtrl) {
Spacer(Modifier.padding(vertical = 10.dp))
Text(text = stringResource(R.string.reset_password_token), style = typography.headlineLarge)
Spacer(Modifier.padding(vertical = 5.dp))
OutlinedTextField( OutlinedTextField(
value = token, onValueChange = { token = it }, value = token, onValueChange = { token = it },
label = { Text(stringResource(R.string.token)) }, label = { Text(stringResource(R.string.token)) },
@@ -367,7 +308,7 @@ private fun ResetPasswordToken() {
} }
@Composable @Composable
private fun ResetPassword() { fun ResetPassword(navCtrl: NavHostController) {
val context = LocalContext.current val context = LocalContext.current
val dpm = context.getDPM() val dpm = context.getDPM()
val receiver = context.getReceiver() val receiver = context.getReceiver()
@@ -378,10 +319,7 @@ private fun ResetPassword() {
val tokenByteArray = token.toByteArray() val tokenByteArray = token.toByteArray()
val flags = remember { mutableStateListOf<Int>() } val flags = remember { mutableStateListOf<Int>() }
var confirmDialog by remember { mutableStateOf(false) } var confirmDialog by remember { mutableStateOf(false) }
Column(modifier = Modifier.fillMaxSize().padding(horizontal = 8.dp).verticalScroll(rememberScrollState())) { MyScaffold(R.string.reset_password, 8.dp, navCtrl) {
Spacer(Modifier.padding(vertical = 10.dp))
Text(text = stringResource(R.string.reset_password),style = typography.headlineLarge)
Spacer(Modifier.padding(vertical = 5.dp))
if(VERSION.SDK_INT >= 26) { if(VERSION.SDK_INT >= 26) {
OutlinedTextField( OutlinedTextField(
value = token, onValueChange = { token = it }, value = token, onValueChange = { token = it },
@@ -444,7 +382,6 @@ private fun ResetPassword() {
} }
} }
InfoCard(R.string.info_reset_password) InfoCard(R.string.info_reset_password)
Spacer(Modifier.padding(vertical = 30.dp))
} }
if(confirmDialog) { if(confirmDialog) {
var confirmPassword by remember { mutableStateOf("") } var confirmPassword by remember { mutableStateOf("") }
@@ -494,7 +431,7 @@ private fun ResetPassword() {
@SuppressLint("NewApi") @SuppressLint("NewApi")
@Composable @Composable
private fun PasswordComplexity() { fun PasswordComplexity(navCtrl: NavHostController) {
val context = LocalContext.current val context = LocalContext.current
val dpm = context.getDPM() val dpm = context.getDPM()
val passwordComplexity = mapOf( val passwordComplexity = mapOf(
@@ -502,19 +439,12 @@ private fun PasswordComplexity() {
PASSWORD_COMPLEXITY_LOW to R.string.password_complexity_low, PASSWORD_COMPLEXITY_LOW to R.string.password_complexity_low,
PASSWORD_COMPLEXITY_MEDIUM to R.string.password_complexity_medium, PASSWORD_COMPLEXITY_MEDIUM to R.string.password_complexity_medium,
PASSWORD_COMPLEXITY_HIGH to R.string.password_complexity_high PASSWORD_COMPLEXITY_HIGH to R.string.password_complexity_high
).toList() )
var selectedItem by remember { mutableIntStateOf(passwordComplexity[0].first) } var selectedItem by remember { mutableIntStateOf(PASSWORD_COMPLEXITY_NONE) }
LaunchedEffect(Unit) { selectedItem = dpm.requiredPasswordComplexity } LaunchedEffect(Unit) { selectedItem = dpm.requiredPasswordComplexity }
Column(modifier = Modifier.fillMaxSize().padding(horizontal = 8.dp).verticalScroll(rememberScrollState())) { MyScaffold(R.string.required_password_complexity, 8.dp, navCtrl) {
Spacer(Modifier.padding(vertical = 10.dp)) passwordComplexity.forEach {
Text(text = stringResource(R.string.required_password_complexity), style = typography.headlineLarge) RadioButtonItem(it.value, selectedItem == it.key, { selectedItem = it.key })
Spacer(Modifier.padding(vertical = 5.dp))
for(index in 0..3) {
RadioButtonItem(
passwordComplexity[index].second,
selectedItem == passwordComplexity[index].first,
{ selectedItem = passwordComplexity[index].first }
)
} }
Spacer(Modifier.padding(vertical = 5.dp)) Spacer(Modifier.padding(vertical = 5.dp))
Button( Button(
@@ -533,12 +463,11 @@ private fun PasswordComplexity() {
) { ) {
Text(stringResource(R.string.require_set_new_password)) Text(stringResource(R.string.require_set_new_password))
} }
Spacer(Modifier.padding(vertical = 30.dp))
} }
} }
@Composable @Composable
private fun DisableKeyguardFeatures() { fun DisableKeyguardFeatures(navCtrl: NavHostController) {
val context = LocalContext.current val context = LocalContext.current
val dpm = context.getDPM() val dpm = context.getDPM()
val receiver = context.getReceiver() val receiver = context.getReceiver()
@@ -579,10 +508,7 @@ private fun DisableKeyguardFeatures() {
} }
calculateCustomFeature() calculateCustomFeature()
} }
Column(modifier = Modifier.fillMaxSize().padding(horizontal = 8.dp).verticalScroll(rememberScrollState())) { MyScaffold(R.string.disable_keyguard_features, 8.dp, navCtrl) {
Spacer(Modifier.padding(vertical = 10.dp))
Text(text = stringResource(R.string.disable_keyguard_features), style = typography.headlineLarge)
Spacer(Modifier.padding(vertical = 5.dp))
RadioButtonItem(R.string.enable_all, state == 0, { state = 0 }) RadioButtonItem(R.string.enable_all, state == 0, { state = 0 })
RadioButtonItem(R.string.disable_all, state == 1, { state = 1 }) RadioButtonItem(R.string.disable_all, state == 1, { state = 1 })
RadioButtonItem(R.string.custom, state == 2 , { state = 2 }) RadioButtonItem(R.string.custom, state == 2 , { state = 2 })
@@ -630,12 +556,11 @@ private fun DisableKeyguardFeatures() {
) { ) {
Text(text = stringResource(R.string.apply)) Text(text = stringResource(R.string.apply))
} }
Spacer(Modifier.padding(vertical = 30.dp))
} }
} }
@Composable @Composable
private fun PasswordQuality() { fun PasswordQuality(navCtrl: NavHostController) {
val context = LocalContext.current val context = LocalContext.current
val dpm = context.getDPM() val dpm = context.getDPM()
val receiver = context.getReceiver() val receiver = context.getReceiver()
@@ -647,15 +572,12 @@ private fun PasswordQuality() {
PASSWORD_QUALITY_ALPHANUMERIC to R.string.password_quality_alphanumeric, PASSWORD_QUALITY_ALPHANUMERIC to R.string.password_quality_alphanumeric,
PASSWORD_QUALITY_BIOMETRIC_WEAK to R.string.password_quality_biometrics_weak, PASSWORD_QUALITY_BIOMETRIC_WEAK to R.string.password_quality_biometrics_weak,
PASSWORD_QUALITY_NUMERIC_COMPLEX to R.string.password_quality_numeric_complex PASSWORD_QUALITY_NUMERIC_COMPLEX to R.string.password_quality_numeric_complex
).toList() )
var selectedItem by remember { mutableIntStateOf(passwordQuality[0].first) } var selectedItem by remember { mutableIntStateOf(PASSWORD_QUALITY_UNSPECIFIED) }
LaunchedEffect(Unit) { selectedItem=dpm.getPasswordQuality(receiver) } LaunchedEffect(Unit) { selectedItem=dpm.getPasswordQuality(receiver) }
Column(modifier = Modifier.fillMaxSize().padding(horizontal = 8.dp).verticalScroll(rememberScrollState())) { MyScaffold(R.string.required_password_quality, 8.dp, navCtrl) {
Spacer(Modifier.padding(vertical = 10.dp)) passwordQuality.forEach {
Text(text = stringResource(R.string.required_password_quality), style = typography.headlineLarge) RadioButtonItem(it.value, selectedItem == it.key, { selectedItem = it.key })
Spacer(Modifier.padding(vertical = 5.dp))
for(index in 1..6) {
RadioButtonItem(passwordQuality[index].second, selectedItem == passwordQuality[index].first, { selectedItem = passwordQuality[index].first })
} }
Spacer(Modifier.padding(vertical = 5.dp)) Spacer(Modifier.padding(vertical = 5.dp))
Button( Button(
@@ -667,7 +589,6 @@ private fun PasswordQuality() {
) { ) {
Text(stringResource(R.string.apply)) Text(stringResource(R.string.apply))
} }
Spacer(Modifier.padding(vertical = 30.dp))
} }
} }

View File

@@ -13,7 +13,6 @@ import android.os.RemoteException
import android.os.UserManager import android.os.UserManager
import android.widget.Toast import android.widget.Toast
import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.AnimatedVisibility
import androidx.compose.foundation.*
import androidx.compose.foundation.layout.* import androidx.compose.foundation.layout.*
import androidx.compose.foundation.text.KeyboardActions import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.foundation.text.KeyboardOptions
@@ -23,7 +22,6 @@ import androidx.compose.material3.MaterialTheme.colorScheme
import androidx.compose.material3.MaterialTheme.typography import androidx.compose.material3.MaterialTheme.typography
import androidx.compose.runtime.* import androidx.compose.runtime.*
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.alpha
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalFocusManager import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.painterResource
@@ -31,10 +29,6 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.input.ImeAction import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.navigation.NavHostController import androidx.navigation.NavHostController
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import androidx.navigation.compose.currentBackStackEntryAsState
import androidx.navigation.compose.rememberNavController
import com.bintianqi.owndroid.R import com.bintianqi.owndroid.R
import com.bintianqi.owndroid.backToHomeStateFlow import com.bintianqi.owndroid.backToHomeStateFlow
import com.bintianqi.owndroid.ui.* import com.bintianqi.owndroid.ui.*
@@ -44,47 +38,9 @@ import com.rosan.dhizuku.api.Dhizuku
import com.rosan.dhizuku.api.DhizukuRequestPermissionListener import com.rosan.dhizuku.api.DhizukuRequestPermissionListener
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
@Composable
fun DpmPermissions(navCtrl:NavHostController) {
val localNavCtrl = rememberNavController()
val backStackEntry by localNavCtrl.currentBackStackEntryAsState()
val scrollState = rememberScrollState()
Scaffold(
topBar = {
TopBar(backStackEntry,navCtrl,localNavCtrl) {
if(backStackEntry?.destination?.route=="Home"&&scrollState.maxValue > 100) {
Text(
text = stringResource(R.string.permission),
modifier = Modifier.alpha((maxOf(scrollState.value-30,0)).toFloat()/80)
)
}
}
}
) {
NavHost(
navController = localNavCtrl, startDestination = "Home",
enterTransition = Animations.navHostEnterTransition,
exitTransition = Animations.navHostExitTransition,
popEnterTransition = Animations.navHostPopEnterTransition,
popExitTransition = Animations.navHostPopExitTransition,
modifier = Modifier.padding(top = it.calculateTopPadding())
) {
composable(route = "Home") { Home(localNavCtrl,scrollState) }
composable(route = "Shizuku") { ShizukuActivate() }
composable(route = "DeviceAdmin") { DeviceAdmin() }
composable(route = "ProfileOwner") { ProfileOwner() }
composable(route = "DeviceOwner") { DeviceOwner() }
composable(route = "DeviceInfo") { DeviceInfo() }
composable(route = "LockScreenInfo") { LockScreenInfo() }
composable(route = "SupportMsg") { SupportMsg() }
composable(route = "TransformOwnership") { TransferOwnership() }
}
}
}
@SuppressLint("NewApi") @SuppressLint("NewApi")
@Composable @Composable
private fun Home(localNavCtrl:NavHostController,listScrollState:ScrollState) { fun Permissions(navCtrl: NavHostController) {
val context = LocalContext.current val context = LocalContext.current
val dpm = context.getDPM() val dpm = context.getDPM()
val receiver = context.getReceiver() val receiver = context.getReceiver()
@@ -95,12 +51,7 @@ private fun Home(localNavCtrl:NavHostController,listScrollState:ScrollState) {
val userManager = context.getSystemService(Context.USER_SERVICE) as UserManager val userManager = context.getSystemService(Context.USER_SERVICE) as UserManager
var dialog by remember { mutableIntStateOf(0) } var dialog by remember { mutableIntStateOf(0) }
val enrollmentSpecificId = if(VERSION.SDK_INT >= 31 && (deviceOwner || profileOwner)) dpm.enrollmentSpecificId else "" val enrollmentSpecificId = if(VERSION.SDK_INT >= 31 && (deviceOwner || profileOwner)) dpm.enrollmentSpecificId else ""
Column(modifier = Modifier.fillMaxSize().verticalScroll(listScrollState)) { MyScaffold(R.string.permissions, 0.dp, navCtrl) {
Text(
text = stringResource(R.string.permission),
style = typography.headlineLarge,
modifier = Modifier.padding(top = 8.dp, bottom = 5.dp, start = 16.dp)
)
if(!dpm.isDeviceOwnerApp(context.packageName)) { if(!dpm.isDeviceOwnerApp(context.packageName)) {
SwitchItem( SwitchItem(
R.string.dhizuku, "", null, R.string.dhizuku, "", null,
@@ -109,43 +60,42 @@ private fun Home(localNavCtrl:NavHostController,listScrollState:ScrollState) {
onClickBlank = { dialog = 4 } onClickBlank = { dialog = 4 }
) )
} }
SubPageItem( FunctionItem(
R.string.device_admin, stringResource(if(deviceAdmin) R.string.activated else R.string.deactivated), R.string.device_admin, stringResource(if(deviceAdmin) R.string.activated else R.string.deactivated),
operation = { localNavCtrl.navigate("DeviceAdmin") } operation = { navCtrl.navigate("DeviceAdmin") }
) )
if(profileOwner || !userManager.isSystemUser) { if(profileOwner || !userManager.isSystemUser) {
SubPageItem( FunctionItem(
R.string.profile_owner, stringResource(if(profileOwner) R.string.activated else R.string.deactivated), R.string.profile_owner, stringResource(if(profileOwner) R.string.activated else R.string.deactivated),
operation = { localNavCtrl.navigate("ProfileOwner") } operation = { navCtrl.navigate("ProfileOwner") }
) )
} }
if(!profileOwner && userManager.isSystemUser) { if(!profileOwner && userManager.isSystemUser) {
SubPageItem( FunctionItem(
R.string.device_owner, stringResource(if(deviceOwner) R.string.activated else R.string.deactivated), R.string.device_owner, stringResource(if(deviceOwner) R.string.activated else R.string.deactivated),
operation = { localNavCtrl.navigate("DeviceOwner") } operation = { navCtrl.navigate("DeviceOwner") }
) )
} }
SubPageItem(R.string.shizuku,"") { localNavCtrl.navigate("Shizuku") } FunctionItem(R.string.shizuku,"") { navCtrl.navigate("Shizuku") }
SubPageItem(R.string.device_info, "", R.drawable.perm_device_information_fill0) { localNavCtrl.navigate("DeviceInfo") } FunctionItem(R.string.device_info, "", R.drawable.perm_device_information_fill0) { navCtrl.navigate("DeviceInfo") }
if((VERSION.SDK_INT >= 26 && deviceOwner) || (VERSION.SDK_INT>=24 && profileOwner)) { if((VERSION.SDK_INT >= 26 && deviceOwner) || (VERSION.SDK_INT>=24 && profileOwner)) {
SubPageItem(R.string.org_name, "", R.drawable.corporate_fare_fill0) { dialog = 2 } FunctionItem(R.string.org_name, "", R.drawable.corporate_fare_fill0) { dialog = 2 }
} }
if(VERSION.SDK_INT >= 31 && (profileOwner || deviceOwner)) { if(VERSION.SDK_INT >= 31 && (profileOwner || deviceOwner)) {
SubPageItem(R.string.org_id, "", R.drawable.corporate_fare_fill0) { dialog = 3 } FunctionItem(R.string.org_id, "", R.drawable.corporate_fare_fill0) { dialog = 3 }
} }
if(enrollmentSpecificId != "") { if(enrollmentSpecificId != "") {
SubPageItem(R.string.enrollment_specific_id, "", R.drawable.id_card_fill0) { dialog = 1 } FunctionItem(R.string.enrollment_specific_id, "", R.drawable.id_card_fill0) { dialog = 1 }
} }
if(VERSION.SDK_INT >= 24 && (deviceOwner || dpm.isOrgProfile(receiver))) { if(VERSION.SDK_INT >= 24 && (deviceOwner || dpm.isOrgProfile(receiver))) {
SubPageItem(R.string.device_owner_lock_screen_info, "", R.drawable.screen_lock_portrait_fill0) { localNavCtrl.navigate("LockScreenInfo") } FunctionItem(R.string.lock_screen_info, "", R.drawable.screen_lock_portrait_fill0) { navCtrl.navigate("LockScreenInfo") }
} }
if(VERSION.SDK_INT >= 24 && deviceAdmin) { if(VERSION.SDK_INT >= 24 && deviceAdmin) {
SubPageItem(R.string.support_msg, "", R.drawable.chat_fill0) { localNavCtrl.navigate("SupportMsg") } FunctionItem(R.string.support_messages, "", R.drawable.chat_fill0) { navCtrl.navigate("SupportMessages") }
} }
if(VERSION.SDK_INT >= 28 && (deviceOwner || profileOwner)) { if(VERSION.SDK_INT >= 28 && (deviceOwner || profileOwner)) {
SubPageItem(R.string.transfer_ownership, "", R.drawable.admin_panel_settings_fill0) { localNavCtrl.navigate("TransformOwnership") } FunctionItem(R.string.transfer_ownership, "", R.drawable.admin_panel_settings_fill0) { navCtrl.navigate("TransferOwnership") }
} }
Spacer(Modifier.padding(vertical = 30.dp))
} }
if(dialog != 0) { if(dialog != 0) {
var input by remember { mutableStateOf("") } var input by remember { mutableStateOf("") }
@@ -157,7 +107,7 @@ private fun Home(localNavCtrl:NavHostController,listScrollState:ScrollState) {
2 -> R.string.org_name 2 -> R.string.org_name
3 -> R.string.org_id 3 -> R.string.org_id
4 -> R.string.dhizuku 4 -> R.string.dhizuku
else -> R.string.permission else -> R.string.permissions
} }
)) ))
}, },
@@ -176,7 +126,7 @@ private fun Home(localNavCtrl:NavHostController,listScrollState:ScrollState) {
1 -> R.string.enrollment_specific_id 1 -> R.string.enrollment_specific_id
2 -> R.string.org_name 2 -> R.string.org_name
3 -> R.string.org_id 3 -> R.string.org_id
else -> R.string.permission else -> R.string.permissions
} }
)) ))
}, },
@@ -237,7 +187,7 @@ private fun toggleDhizukuMode(status: Boolean, context: Context) {
dhizukuErrorStatus.value = 1 dhizukuErrorStatus.value = 1
return return
} }
if(Dhizuku.isPermissionGranted()) { if(dhizukuPermissionGranted()) {
sharedPref.edit().putBoolean("dhizuku", true).apply() sharedPref.edit().putBoolean("dhizuku", true).apply()
Dhizuku.init(context) Dhizuku.init(context)
backToHomeStateFlow.value = true backToHomeStateFlow.value = true
@@ -260,17 +210,16 @@ private fun toggleDhizukuMode(status: Boolean, context: Context) {
@SuppressLint("NewApi") @SuppressLint("NewApi")
@Composable @Composable
private fun LockScreenInfo() { fun LockScreenInfo(navCtrl: NavHostController) {
val context = LocalContext.current val context = LocalContext.current
val dpm = context.getDPM() val dpm = context.getDPM()
val receiver = context.getReceiver() val receiver = context.getReceiver()
val focusMgr = LocalFocusManager.current val focusMgr = LocalFocusManager.current
var infoText by remember { mutableStateOf(dpm.deviceOwnerLockScreenInfo?.toString() ?: "") } var infoText by remember { mutableStateOf(dpm.deviceOwnerLockScreenInfo?.toString() ?: "") }
Column(modifier = Modifier.fillMaxSize().verticalScroll(rememberScrollState()).padding(horizontal = 8.dp)) { MyScaffold(R.string.lock_screen_info, 8.dp, navCtrl) {
Text(text = stringResource(R.string.device_owner_lock_screen_info), style = typography.headlineLarge)
OutlinedTextField( OutlinedTextField(
value = infoText, value = infoText,
label = { Text(stringResource(R.string.device_owner_lock_screen_info)) }, label = { Text(stringResource(R.string.lock_screen_info)) },
onValueChange = { infoText = it }, onValueChange = { infoText = it },
keyboardOptions = KeyboardOptions(imeAction = ImeAction.Done), keyboardOptions = KeyboardOptions(imeAction = ImeAction.Done),
keyboardActions = KeyboardActions { focusMgr.clearFocus() }, keyboardActions = KeyboardActions { focusMgr.clearFocus() },
@@ -302,15 +251,13 @@ private fun LockScreenInfo() {
} }
@Composable @Composable
private fun DeviceAdmin() { fun DeviceAdmin(navCtrl: NavHostController) {
val context = LocalContext.current val context = LocalContext.current
val dpm = context.getDPM() val dpm = context.getDPM()
val receiver = context.getReceiver() val receiver = context.getReceiver()
var deactivateDialog by remember { mutableStateOf(false) } var deactivateDialog by remember { mutableStateOf(false) }
val deviceAdmin = context.isDeviceAdmin val deviceAdmin = context.isDeviceAdmin
Column(modifier = Modifier.fillMaxSize().verticalScroll(rememberScrollState()).padding(horizontal = 8.dp)) { MyScaffold(R.string.device_admin, 8.dp, navCtrl) {
Spacer(Modifier.padding(vertical = 10.dp))
Text(text = stringResource(R.string.device_admin), style = typography.headlineLarge)
Text(text = stringResource(if(context.isDeviceAdmin) R.string.activated else R.string.deactivated), style = typography.titleLarge) Text(text = stringResource(if(context.isDeviceAdmin) R.string.activated else R.string.deactivated), style = typography.titleLarge)
Spacer(Modifier.padding(vertical = 5.dp)) Spacer(Modifier.padding(vertical = 5.dp))
AnimatedVisibility(deviceAdmin) { AnimatedVisibility(deviceAdmin) {
@@ -361,15 +308,13 @@ private fun DeviceAdmin() {
} }
@Composable @Composable
private fun ProfileOwner() { fun ProfileOwner(navCtrl: NavHostController) {
val context = LocalContext.current val context = LocalContext.current
val dpm = context.getDPM() val dpm = context.getDPM()
val receiver = context.getReceiver() val receiver = context.getReceiver()
var deactivateDialog by remember { mutableStateOf(false) } var deactivateDialog by remember { mutableStateOf(false) }
val profileOwner = context.isProfileOwner val profileOwner = context.isProfileOwner
Column(modifier = Modifier.fillMaxSize().verticalScroll(rememberScrollState()).padding(horizontal = 8.dp)) { MyScaffold(R.string.profile_owner, 8.dp, navCtrl) {
Spacer(Modifier.padding(vertical = 10.dp))
Text(text = stringResource(R.string.profile_owner), style = typography.headlineLarge)
Text(stringResource(if(profileOwner) R.string.activated else R.string.deactivated), style = typography.titleLarge) Text(stringResource(if(profileOwner) R.string.activated else R.string.deactivated), style = typography.titleLarge)
Spacer(Modifier.padding(vertical = 5.dp)) Spacer(Modifier.padding(vertical = 5.dp))
if(VERSION.SDK_INT >= 24 && profileOwner) { if(VERSION.SDK_INT >= 24 && profileOwner) {
@@ -416,14 +361,12 @@ private fun ProfileOwner() {
} }
@Composable @Composable
private fun DeviceOwner() { fun DeviceOwner(navCtrl: NavHostController) {
val context = LocalContext.current val context = LocalContext.current
val dpm = context.getDPM() val dpm = context.getDPM()
var deactivateDialog by remember { mutableStateOf(false) } var deactivateDialog by remember { mutableStateOf(false) }
val deviceOwner = context.isDeviceOwner val deviceOwner = context.isDeviceOwner
Column(modifier = Modifier.fillMaxSize().verticalScroll(rememberScrollState()).padding(horizontal = 8.dp)) { MyScaffold(R.string.device_owner, 8.dp, navCtrl) {
Spacer(Modifier.padding(vertical = 10.dp))
Text(text = stringResource(R.string.device_owner), style = typography.headlineLarge)
Text(text = stringResource(if(deviceOwner) R.string.activated else R.string.deactivated), style = typography.titleLarge) Text(text = stringResource(if(deviceOwner) R.string.activated else R.string.deactivated), style = typography.titleLarge)
Spacer(Modifier.padding(vertical = 5.dp)) Spacer(Modifier.padding(vertical = 5.dp))
AnimatedVisibility(deviceOwner) { AnimatedVisibility(deviceOwner) {
@@ -488,15 +431,12 @@ private fun DeviceOwner() {
} }
@Composable @Composable
fun DeviceInfo() { fun DeviceInfo(navCtrl: NavHostController) {
val context = LocalContext.current val context = LocalContext.current
val dpm = context.getDPM() val dpm = context.getDPM()
val receiver = context.getReceiver() val receiver = context.getReceiver()
var dialog by remember { mutableIntStateOf(0) } var dialog by remember { mutableIntStateOf(0) }
Column(modifier = Modifier.fillMaxSize().verticalScroll(rememberScrollState()).padding(horizontal = 8.dp)) { MyScaffold(R.string.device_info, 8.dp, navCtrl) {
Spacer(Modifier.padding(vertical = 10.dp))
Text(text = stringResource(R.string.device_info), style = typography.headlineLarge)
Spacer(Modifier.padding(vertical = 5.dp))
if(VERSION.SDK_INT>=34 && (context.isDeviceOwner || dpm.isOrgProfile(receiver))) { if(VERSION.SDK_INT>=34 && (context.isDeviceOwner || dpm.isOrgProfile(receiver))) {
CardItem(R.string.financed_device, dpm.isDeviceFinanced.yesOrNo) CardItem(R.string.financed_device, dpm.isDeviceFinanced.yesOrNo)
} }
@@ -532,7 +472,7 @@ fun DeviceInfo() {
@SuppressLint("NewApi") @SuppressLint("NewApi")
@Composable @Composable
private fun SupportMsg() { fun SupportMessages(navCtrl: NavHostController) {
val context = LocalContext.current val context = LocalContext.current
val dpm = context.getDPM() val dpm = context.getDPM()
val receiver = context.getReceiver() val receiver = context.getReceiver()
@@ -543,10 +483,7 @@ private fun SupportMsg() {
longMsg = dpm.getLongSupportMessage(receiver)?.toString() ?: "" longMsg = dpm.getLongSupportMessage(receiver)?.toString() ?: ""
} }
LaunchedEffect(Unit) { refreshMsg() } LaunchedEffect(Unit) { refreshMsg() }
Column(modifier = Modifier.fillMaxSize().verticalScroll(rememberScrollState()).padding(horizontal = 8.dp)) { MyScaffold(R.string.support_messages, 8.dp, navCtrl) {
Spacer(Modifier.padding(vertical = 10.dp))
Text(text = stringResource(R.string.support_msg), style = typography.headlineLarge)
Spacer(Modifier.padding(vertical = 5.dp))
OutlinedTextField( OutlinedTextField(
value = shortMsg, value = shortMsg,
label = { Text(stringResource(R.string.short_support_msg)) }, label = { Text(stringResource(R.string.short_support_msg)) },
@@ -608,22 +545,18 @@ private fun SupportMsg() {
} }
} }
InfoCard(R.string.info_long_support_message) InfoCard(R.string.info_long_support_message)
Spacer(Modifier.padding(vertical = 30.dp))
} }
} }
@SuppressLint("NewApi") @SuppressLint("NewApi")
@Composable @Composable
private fun TransferOwnership() { fun TransferOwnership(navCtrl: NavHostController) {
val context = LocalContext.current val context = LocalContext.current
val focusMgr = LocalFocusManager.current val focusMgr = LocalFocusManager.current
var input by remember { mutableStateOf("") } var input by remember { mutableStateOf("") }
val componentName = ComponentName.unflattenFromString(input) val componentName = ComponentName.unflattenFromString(input)
var dialog by remember { mutableStateOf(false) } var dialog by remember { mutableStateOf(false) }
Column(modifier = Modifier.fillMaxSize().verticalScroll(rememberScrollState()).padding(horizontal = 8.dp)) { MyScaffold(R.string.transfer_ownership, 8.dp, navCtrl) {
Spacer(Modifier.padding(vertical = 10.dp))
Text(text = stringResource(R.string.transfer_ownership), style = typography.headlineLarge)
Spacer(Modifier.padding(vertical = 5.dp))
OutlinedTextField( OutlinedTextField(
value = input, onValueChange = { input = it }, label = { Text(stringResource(R.string.target_component_name)) }, value = input, onValueChange = { input = it }, label = { Text(stringResource(R.string.target_component_name)) },
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),

View File

@@ -10,14 +10,12 @@ import android.os.IBinder
import android.widget.Toast import android.widget.Toast
import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.AnimatedVisibility
import androidx.compose.foundation.horizontalScroll import androidx.compose.foundation.horizontalScroll
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.wrapContentWidth
import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.text.selection.SelectionContainer import androidx.compose.foundation.text.selection.SelectionContainer
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.Button import androidx.compose.material3.Button
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
@@ -34,8 +32,10 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.navigation.NavHostController
import com.bintianqi.owndroid.IUserService import com.bintianqi.owndroid.IUserService
import com.bintianqi.owndroid.R import com.bintianqi.owndroid.R
import com.bintianqi.owndroid.ui.MyScaffold
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import rikka.shizuku.Shizuku import rikka.shizuku.Shizuku
@@ -43,7 +43,7 @@ import rikka.shizuku.Shizuku
private var waitGrantPermission = false private var waitGrantPermission = false
@Composable @Composable
fun ShizukuActivate() { fun Shizuku(navCtrl: NavHostController) {
val context = LocalContext.current val context = LocalContext.current
val dpm = context.getDPM() val dpm = context.getDPM()
val receiver = context.getReceiver() val receiver = context.getReceiver()
@@ -69,19 +69,14 @@ fun ShizukuActivate() {
shizukuService.value = null shizukuService.value = null
userServiceControl(context, true) userServiceControl(context, true)
} }
Column( MyScaffold(R.string.shizuku, 0.dp, navCtrl, false) {
modifier = Modifier AnimatedVisibility(visible = bindShizuku, modifier = Modifier.fillMaxWidth()) {
.fillMaxSize()
.padding(horizontal = 8.dp)
.verticalScroll(rememberScrollState()),
horizontalAlignment = Alignment.CenterHorizontally
) {
AnimatedVisibility(bindShizuku) {
Button( Button(
onClick = { onClick = {
userServiceControl(context, true) userServiceControl(context, true)
outputText = "" outputText = ""
} },
modifier = Modifier.wrapContentWidth(Alignment.CenterHorizontally)
) { ) {
Text(stringResource(R.string.bind_shizuku)) Text(stringResource(R.string.bind_shizuku))
} }
@@ -100,7 +95,8 @@ fun ShizukuActivate() {
coScope.launch { coScope.launch {
outputTextScrollState.animateScrollTo(0) outputTextScrollState.animateScrollTo(0)
} }
} },
modifier = Modifier.align(Alignment.CenterHorizontally)
) { ) {
Text(text = stringResource(R.string.check_shizuku)) Text(text = stringResource(R.string.check_shizuku))
} }
@@ -112,7 +108,8 @@ fun ShizukuActivate() {
outputTextScrollState.animateScrollTo(0) outputTextScrollState.animateScrollTo(0)
} }
}, },
enabled = enabled enabled = enabled,
modifier = Modifier.align(Alignment.CenterHorizontally)
) { ) {
Text(text = stringResource(R.string.list_owners)) Text(text = stringResource(R.string.list_owners))
} }
@@ -123,7 +120,8 @@ fun ShizukuActivate() {
outputTextScrollState.animateScrollTo(0) outputTextScrollState.animateScrollTo(0)
} }
}, },
enabled = enabled enabled = enabled,
modifier = Modifier.align(Alignment.CenterHorizontally)
) { ) {
Text(text = stringResource(R.string.list_users)) Text(text = stringResource(R.string.list_users))
} }
@@ -134,7 +132,8 @@ fun ShizukuActivate() {
outputTextScrollState.animateScrollTo(0) outputTextScrollState.animateScrollTo(0)
} }
}, },
enabled = enabled enabled = enabled,
modifier = Modifier.align(Alignment.CenterHorizontally)
) { ) {
Text(text = stringResource(R.string.list_accounts)) Text(text = stringResource(R.string.list_accounts))
} }
@@ -150,7 +149,8 @@ fun ShizukuActivate() {
showDeviceAdminButton = !context.isDeviceAdmin showDeviceAdminButton = !context.isDeviceAdmin
} }
}, },
enabled = enabled enabled = enabled,
modifier = Modifier.align(Alignment.CenterHorizontally)
) { ) {
Text(text = stringResource(R.string.activate_device_admin)) Text(text = stringResource(R.string.activate_device_admin))
} }
@@ -166,7 +166,8 @@ fun ShizukuActivate() {
showDeviceOwnerButton = !context.isDeviceOwner showDeviceOwnerButton = !context.isDeviceOwner
} }
}, },
enabled = enabled enabled = enabled,
modifier = Modifier.align(Alignment.CenterHorizontally)
) { ) {
Text(text = stringResource(R.string.activate_device_owner)) Text(text = stringResource(R.string.activate_device_owner))
} }
@@ -186,7 +187,8 @@ fun ShizukuActivate() {
showOrgProfileOwnerButton = !dpm.isOrganizationOwnedDeviceWithManagedProfile showOrgProfileOwnerButton = !dpm.isOrganizationOwnedDeviceWithManagedProfile
} }
}, },
enabled = enabled enabled = enabled,
modifier = Modifier.align(Alignment.CenterHorizontally)
) { ) {
Text(text = stringResource(R.string.activate_org_profile)) Text(text = stringResource(R.string.activate_org_profile))
} }
@@ -194,10 +196,8 @@ fun ShizukuActivate() {
} }
SelectionContainer(modifier = Modifier.fillMaxWidth().horizontalScroll(outputTextScrollState)) { SelectionContainer(modifier = Modifier.fillMaxWidth().horizontalScroll(outputTextScrollState)) {
Text(text = outputText, softWrap = false, modifier = Modifier.padding(4.dp)) Text(text = outputText, softWrap = false, modifier = Modifier.padding(vertical = 9.dp, horizontal = 12.dp))
} }
Spacer(Modifier.padding(vertical = 30.dp))
} }
} }

View File

@@ -44,23 +44,19 @@ import android.os.UserManager
import android.widget.Toast import android.widget.Toast
import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.animateContentSize import androidx.compose.animation.animateContentSize
import androidx.compose.foundation.ScrollState
import androidx.compose.foundation.clickable import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width import androidx.compose.foundation.layout.width
import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.text.KeyboardActions import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.List import androidx.compose.material.icons.automirrored.filled.List
import androidx.compose.material.icons.filled.Add import androidx.compose.material.icons.filled.Add
@@ -72,7 +68,6 @@ import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme.colorScheme import androidx.compose.material3.MaterialTheme.colorScheme
import androidx.compose.material3.MaterialTheme.typography import androidx.compose.material3.MaterialTheme.typography
import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Switch import androidx.compose.material3.Switch
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.material3.TextButton import androidx.compose.material3.TextButton
@@ -90,7 +85,6 @@ import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.alpha
import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.clip
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalFocusManager import androidx.compose.ui.platform.LocalFocusManager
@@ -101,10 +95,6 @@ import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.core.app.NotificationCompat import androidx.core.app.NotificationCompat
import androidx.navigation.NavHostController import androidx.navigation.NavHostController
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import androidx.navigation.compose.currentBackStackEntryAsState
import androidx.navigation.compose.rememberNavController
import com.bintianqi.owndroid.R import com.bintianqi.owndroid.R
import com.bintianqi.owndroid.StopLockTaskModeReceiver import com.bintianqi.owndroid.StopLockTaskModeReceiver
import com.bintianqi.owndroid.exportFile import com.bintianqi.owndroid.exportFile
@@ -115,15 +105,14 @@ import com.bintianqi.owndroid.getFile
import com.bintianqi.owndroid.prepareForNotification import com.bintianqi.owndroid.prepareForNotification
import com.bintianqi.owndroid.selectedPackage import com.bintianqi.owndroid.selectedPackage
import com.bintianqi.owndroid.toggle import com.bintianqi.owndroid.toggle
import com.bintianqi.owndroid.ui.Animations
import com.bintianqi.owndroid.ui.CheckBoxItem import com.bintianqi.owndroid.ui.CheckBoxItem
import com.bintianqi.owndroid.ui.FunctionItem
import com.bintianqi.owndroid.ui.InfoCard import com.bintianqi.owndroid.ui.InfoCard
import com.bintianqi.owndroid.ui.Information import com.bintianqi.owndroid.ui.Information
import com.bintianqi.owndroid.ui.ListItem import com.bintianqi.owndroid.ui.ListItem
import com.bintianqi.owndroid.ui.MyScaffold
import com.bintianqi.owndroid.ui.RadioButtonItem import com.bintianqi.owndroid.ui.RadioButtonItem
import com.bintianqi.owndroid.ui.SubPageItem
import com.bintianqi.owndroid.ui.SwitchItem import com.bintianqi.owndroid.ui.SwitchItem
import com.bintianqi.owndroid.ui.TopBar
import com.bintianqi.owndroid.uriToStream import com.bintianqi.owndroid.uriToStream
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
@@ -137,54 +126,9 @@ import java.util.TimeZone
import java.util.concurrent.Executors import java.util.concurrent.Executors
import kotlin.math.pow import kotlin.math.pow
@Composable
fun SystemManage(navCtrl: NavHostController) {
val localNavCtrl = rememberNavController()
val backStackEntry by localNavCtrl.currentBackStackEntryAsState()
val scrollState = rememberScrollState()
Scaffold(
topBar = {
TopBar(backStackEntry,navCtrl,localNavCtrl) {
if(backStackEntry?.destination?.route=="Home"&&scrollState.maxValue > 100) {
Text(
text = stringResource(R.string.system),
modifier = Modifier.alpha((maxOf(scrollState.value-30,0)).toFloat()/80)
)
}
}
}
) {
NavHost(
navController = localNavCtrl, startDestination = "Home",
enterTransition = Animations.navHostEnterTransition,
exitTransition = Animations.navHostExitTransition,
popEnterTransition = Animations.navHostPopEnterTransition,
popExitTransition = Animations.navHostPopExitTransition,
modifier = Modifier.padding(top = it.calculateTopPadding())
) {
composable(route = "Home") { Home(localNavCtrl, scrollState) }
composable(route = "Switches") { Switches() }
composable(route = "Keyguard") { Keyguard() }
composable(route = "EditTime") { EditTime() }
composable(route = "EditTimeZone") { EditTimeZone() }
composable(route = "PermissionPolicy") { PermissionPolicy() }
composable(route = "MTEPolicy") { MTEPolicy() }
composable(route = "NearbyStreamingPolicy") { NearbyStreamingPolicy() }
composable(route = "LockTaskMode") { LockTaskMode(navCtrl) }
composable(route = "CaCert") { CaCert() }
composable(route = "SecurityLogs") { SecurityLogs() }
composable(route = "DisableAccountManagement") { DisableAccountManagement() }
composable(route = "SystemUpdatePolicy") { SysUpdatePolicy() }
composable(route = "InstallSystemUpdate") { InstallSystemUpdate() }
composable(route = "WipeData") { WipeData() }
composable(route = "FRP") { FactoryResetProtection() }
}
}
}
@SuppressLint("NewApi") @SuppressLint("NewApi")
@Composable @Composable
private fun Home(navCtrl: NavHostController, scrollState: ScrollState) { fun SystemManage(navCtrl: NavHostController) {
val context = LocalContext.current val context = LocalContext.current
val dpm = context.getDPM() val dpm = context.getDPM()
val receiver = context.getReceiver() val receiver = context.getReceiver()
@@ -194,60 +138,54 @@ private fun Home(navCtrl: NavHostController, scrollState: ScrollState) {
val deviceOwner = context.isDeviceOwner val deviceOwner = context.isDeviceOwner
val profileOwner = context.isProfileOwner val profileOwner = context.isProfileOwner
var dialog by remember { mutableIntStateOf(0) } var dialog by remember { mutableIntStateOf(0) }
Column(modifier = Modifier.fillMaxSize().verticalScroll(scrollState)) { MyScaffold(R.string.system, 0.dp, navCtrl) {
Text(
text = stringResource(R.string.system),
style = typography.headlineLarge,
modifier = Modifier.padding(top = 8.dp, bottom = 5.dp, start = 16.dp)
)
if(deviceOwner || profileOwner) { if(deviceOwner || profileOwner) {
SubPageItem(R.string.options, "", R.drawable.tune_fill0) { navCtrl.navigate("Switches") } FunctionItem(R.string.options, "", R.drawable.tune_fill0) { navCtrl.navigate("SystemOptions") }
} }
SubPageItem(R.string.keyguard, "", R.drawable.screen_lock_portrait_fill0) { navCtrl.navigate("Keyguard") } FunctionItem(R.string.keyguard, "", R.drawable.screen_lock_portrait_fill0) { navCtrl.navigate("Keyguard") }
if(VERSION.SDK_INT >= 24 && deviceOwner) { if(VERSION.SDK_INT >= 24 && deviceOwner) {
SubPageItem(R.string.reboot, "", R.drawable.restart_alt_fill0) { dialog = 1 } FunctionItem(R.string.reboot, "", R.drawable.restart_alt_fill0) { dialog = 1 }
} }
if(deviceOwner && ((VERSION.SDK_INT >= 28 && dpm.isAffiliatedUser) || VERSION.SDK_INT >= 24)) { if(deviceOwner && ((VERSION.SDK_INT >= 28 && dpm.isAffiliatedUser) || VERSION.SDK_INT >= 24)) {
SubPageItem(R.string.bug_report, "", R.drawable.bug_report_fill0) { dialog = 2 } FunctionItem(R.string.bug_report, "", R.drawable.bug_report_fill0) { dialog = 2 }
} }
if(VERSION.SDK_INT >= 28 && (deviceOwner || dpm.isOrgProfile(receiver))) { if(VERSION.SDK_INT >= 28 && (deviceOwner || dpm.isOrgProfile(receiver))) {
SubPageItem(R.string.change_time, "", R.drawable.schedule_fill0) { navCtrl.navigate("EditTime") } FunctionItem(R.string.change_time, "", R.drawable.schedule_fill0) { navCtrl.navigate("ChangeTime") }
SubPageItem(R.string.change_timezone, "", R.drawable.schedule_fill0) { navCtrl.navigate("EditTimeZone") } FunctionItem(R.string.change_timezone, "", R.drawable.schedule_fill0) { navCtrl.navigate("ChangeTimeZone") }
} }
if(VERSION.SDK_INT >= 23 && (deviceOwner || profileOwner)) { if(VERSION.SDK_INT >= 23 && (deviceOwner || profileOwner)) {
SubPageItem(R.string.permission_policy, "", R.drawable.key_fill0) { navCtrl.navigate("PermissionPolicy") } FunctionItem(R.string.permission_policy, "", R.drawable.key_fill0) { navCtrl.navigate("PermissionPolicy") }
} }
if(VERSION.SDK_INT >= 34 && deviceOwner) { if(VERSION.SDK_INT >= 34 && deviceOwner) {
SubPageItem(R.string.mte_policy, "", R.drawable.memory_fill0) { navCtrl.navigate("MTEPolicy") } FunctionItem(R.string.mte_policy, "", R.drawable.memory_fill0) { navCtrl.navigate("MTEPolicy") }
} }
if(VERSION.SDK_INT >= 31 && (deviceOwner || profileOwner)) { if(VERSION.SDK_INT >= 31 && (deviceOwner || profileOwner)) {
SubPageItem(R.string.nearby_streaming_policy, "", R.drawable.share_fill0) { navCtrl.navigate("NearbyStreamingPolicy") } FunctionItem(R.string.nearby_streaming_policy, "", R.drawable.share_fill0) { navCtrl.navigate("NearbyStreamingPolicy") }
} }
if(VERSION.SDK_INT >= 28 && deviceOwner) { if(VERSION.SDK_INT >= 28 && deviceOwner) {
SubPageItem(R.string.lock_task_mode, "", R.drawable.lock_fill0) { navCtrl.navigate("LockTaskMode") } FunctionItem(R.string.lock_task_mode, "", R.drawable.lock_fill0) { navCtrl.navigate("LockTaskMode") }
} }
if(deviceOwner || profileOwner) { if(deviceOwner || profileOwner) {
SubPageItem(R.string.ca_cert, "", R.drawable.license_fill0) { navCtrl.navigate("CaCert") } FunctionItem(R.string.ca_cert, "", R.drawable.license_fill0) { navCtrl.navigate("CACert") }
} }
if(VERSION.SDK_INT >= 26 && !dhizuku && (deviceOwner || dpm.isOrgProfile(receiver))) { if(VERSION.SDK_INT >= 26 && !dhizuku && (deviceOwner || dpm.isOrgProfile(receiver))) {
SubPageItem(R.string.security_logs, "", R.drawable.description_fill0) { navCtrl.navigate("SecurityLogs") } FunctionItem(R.string.security_logging, "", R.drawable.description_fill0) { navCtrl.navigate("SecurityLogging") }
} }
if(deviceOwner || profileOwner) { if(deviceOwner || profileOwner) {
SubPageItem(R.string.disable_account_management, "", R.drawable.account_circle_fill0) { navCtrl.navigate("DisableAccountManagement") } FunctionItem(R.string.disable_account_management, "", R.drawable.account_circle_fill0) { navCtrl.navigate("DisableAccountManagement") }
} }
if(VERSION.SDK_INT >= 23 && (deviceOwner || dpm.isOrgProfile(receiver))) { if(VERSION.SDK_INT >= 23 && (deviceOwner || dpm.isOrgProfile(receiver))) {
SubPageItem(R.string.system_update_policy, "", R.drawable.system_update_fill0) { navCtrl.navigate("SystemUpdatePolicy") } FunctionItem(R.string.system_update_policy, "", R.drawable.system_update_fill0) { navCtrl.navigate("SystemUpdatePolicy") }
} }
if(VERSION.SDK_INT >= 29 && (deviceOwner || dpm.isOrgProfile(receiver))) { if(VERSION.SDK_INT >= 29 && (deviceOwner || dpm.isOrgProfile(receiver))) {
SubPageItem(R.string.install_system_update, "", R.drawable.system_update_fill0) { navCtrl.navigate("InstallSystemUpdate") } FunctionItem(R.string.install_system_update, "", R.drawable.system_update_fill0) { navCtrl.navigate("InstallSystemUpdate") }
} }
if(VERSION.SDK_INT >= 30 && (deviceOwner || dpm.isOrgProfile(receiver))) { if(VERSION.SDK_INT >= 30 && (deviceOwner || dpm.isOrgProfile(receiver))) {
SubPageItem(R.string.frp_policy, "", R.drawable.device_reset_fill0) { navCtrl.navigate("FRP") } FunctionItem(R.string.frp_policy, "", R.drawable.device_reset_fill0) { navCtrl.navigate("FRPPolicy") }
} }
if(dangerousFeatures && context.isDeviceAdmin && !(VERSION.SDK_INT >= 24 && profileOwner && dpm.isManagedProfile(receiver))) { if(dangerousFeatures && context.isDeviceAdmin && !(VERSION.SDK_INT >= 24 && profileOwner && dpm.isManagedProfile(receiver))) {
SubPageItem(R.string.wipe_data, "", R.drawable.device_reset_fill0) { navCtrl.navigate("WipeData") } FunctionItem(R.string.wipe_data, "", R.drawable.device_reset_fill0) { navCtrl.navigate("WipeData") }
} }
Spacer(Modifier.padding(vertical = 30.dp))
LaunchedEffect(Unit) { fileUriFlow.value = Uri.parse("") } LaunchedEffect(Unit) { fileUriFlow.value = Uri.parse("") }
} }
if(dialog != 0) AlertDialog( if(dialog != 0) AlertDialog(
@@ -279,7 +217,7 @@ private fun Home(navCtrl: NavHostController, scrollState: ScrollState) {
} }
@Composable @Composable
private fun Switches() { fun SystemOptions(navCtrl: NavHostController) {
val context = LocalContext.current val context = LocalContext.current
val dpm = context.getDPM() val dpm = context.getDPM()
val receiver = context.getReceiver() val receiver = context.getReceiver()
@@ -287,8 +225,7 @@ private fun Switches() {
val profileOwner = context.isProfileOwner val profileOwner = context.isProfileOwner
val um = context.getSystemService(Context.USER_SERVICE) as UserManager val um = context.getSystemService(Context.USER_SERVICE) as UserManager
var dialog by remember { mutableIntStateOf(0) } var dialog by remember { mutableIntStateOf(0) }
Column(modifier = Modifier.fillMaxSize().verticalScroll(rememberScrollState())) { MyScaffold(R.string.options, 0.dp, navCtrl) {
Spacer(Modifier.padding(vertical = 5.dp))
if(deviceOwner || profileOwner) { if(deviceOwner || profileOwner) {
SwitchItem(R.string.disable_cam,"", R.drawable.photo_camera_fill0, SwitchItem(R.string.disable_cam,"", R.drawable.photo_camera_fill0,
{ dpm.getCameraDisabled(null) }, { dpm.setCameraDisabled(receiver,it) } { dpm.getCameraDisabled(null) }, { dpm.setCameraDisabled(receiver,it) }
@@ -344,7 +281,6 @@ private fun Switches() {
{ dpm.isUsbDataSignalingEnabled = !it }, { dpm.isUsbDataSignalingEnabled = !it },
) )
} }
Spacer(Modifier.padding(vertical = 30.dp))
} }
if(dialog != 0) AlertDialog( if(dialog != 0) AlertDialog(
text = { text = {
@@ -364,17 +300,14 @@ private fun Switches() {
} }
@Composable @Composable
private fun Keyguard() { fun Keyguard(navCtrl: NavHostController) {
val context = LocalContext.current val context = LocalContext.current
val dpm = context.getDPM() val dpm = context.getDPM()
val receiver = context.getReceiver() val receiver = context.getReceiver()
val deviceOwner = context.isDeviceOwner val deviceOwner = context.isDeviceOwner
val profileOwner = context.isProfileOwner val profileOwner = context.isProfileOwner
Column(modifier = Modifier.fillMaxSize().padding(horizontal = 8.dp).verticalScroll(rememberScrollState())) { MyScaffold(R.string.keyguard, 8.dp, navCtrl) {
Spacer(Modifier.padding(vertical = 10.dp))
if(VERSION.SDK_INT >= 23) { if(VERSION.SDK_INT >= 23) {
Text(text = stringResource(R.string.keyguard), style = typography.headlineLarge)
Spacer(Modifier.padding(vertical = 5.dp))
Row( Row(
horizontalArrangement = Arrangement.SpaceBetween, horizontalArrangement = Arrangement.SpaceBetween,
modifier = Modifier.fillMaxWidth() modifier = Modifier.fillMaxWidth()
@@ -401,7 +334,7 @@ private fun Keyguard() {
InfoCard(R.string.info_disable_keyguard) InfoCard(R.string.info_disable_keyguard)
Spacer(Modifier.padding(vertical = 12.dp)) Spacer(Modifier.padding(vertical = 12.dp))
} }
Text(text = stringResource(R.string.lock_now), style = typography.headlineLarge) if(VERSION.SDK_INT >= 23) Text(text = stringResource(R.string.lock_now), style = typography.headlineLarge)
Spacer(Modifier.padding(vertical = 2.dp)) Spacer(Modifier.padding(vertical = 2.dp))
var flag by remember { mutableIntStateOf(0) } var flag by remember { mutableIntStateOf(0) }
if(VERSION.SDK_INT >= 26 && profileOwner && dpm.isManagedProfile(receiver)) { if(VERSION.SDK_INT >= 26 && profileOwner && dpm.isManagedProfile(receiver)) {
@@ -424,22 +357,18 @@ private fun Keyguard() {
if(VERSION.SDK_INT >= 26 && profileOwner && dpm.isManagedProfile(receiver)) { if(VERSION.SDK_INT >= 26 && profileOwner && dpm.isManagedProfile(receiver)) {
InfoCard(R.string.info_evict_credential_encryption_key) InfoCard(R.string.info_evict_credential_encryption_key)
} }
Spacer(Modifier.padding(vertical = 30.dp))
} }
} }
@SuppressLint("NewApi") @SuppressLint("NewApi")
@Composable @Composable
private fun EditTime() { fun ChangeTime(navCtrl: NavHostController) {
val context = LocalContext.current val context = LocalContext.current
val dpm = context.getDPM() val dpm = context.getDPM()
val receiver = context.getReceiver() val receiver = context.getReceiver()
val focusMgr = LocalFocusManager.current val focusMgr = LocalFocusManager.current
var inputTime by remember { mutableStateOf("") } var inputTime by remember { mutableStateOf("") }
Column(modifier = Modifier.fillMaxSize().padding(horizontal = 8.dp).verticalScroll(rememberScrollState())) { MyScaffold(R.string.change_time, 8.dp, navCtrl) {
Spacer(Modifier.padding(vertical = 10.dp))
Text(text = stringResource(R.string.change_time), style = typography.headlineLarge)
Spacer(Modifier.padding(vertical = 5.dp))
OutlinedTextField( OutlinedTextField(
value = inputTime, value = inputTime,
label = { Text(stringResource(R.string.time_unit_ms)) }, label = { Text(stringResource(R.string.time_unit_ms)) },
@@ -459,22 +388,17 @@ private fun EditTime() {
} }
} }
} }
@SuppressLint("NewApi") @SuppressLint("NewApi")
@Composable @Composable
private fun EditTimeZone() { fun ChangeTimeZone(navCtrl: NavHostController) {
val context = LocalContext.current val context = LocalContext.current
val dpm = context.getDPM() val dpm = context.getDPM()
val focusMgr = LocalFocusManager.current val focusMgr = LocalFocusManager.current
val receiver = context.getReceiver() val receiver = context.getReceiver()
var inputTimezone by remember { mutableStateOf("") } var inputTimezone by remember { mutableStateOf("") }
var dialog by remember { mutableStateOf(false) } var dialog by remember { mutableStateOf(false) }
Column( MyScaffold(R.string.change_timezone, 8.dp, navCtrl) {
modifier = Modifier.fillMaxSize().padding(horizontal = 8.dp).verticalScroll(rememberScrollState()),
horizontalAlignment = Alignment.CenterHorizontally
) {
Spacer(Modifier.padding(vertical = 10.dp))
Text(text = stringResource(R.string.change_timezone), style = typography.headlineLarge, modifier = Modifier.align(Alignment.Start))
Spacer(Modifier.padding(vertical = 5.dp))
OutlinedTextField( OutlinedTextField(
value = inputTimezone, value = inputTimezone,
label = { Text(stringResource(R.string.timezone_id)) }, label = { Text(stringResource(R.string.timezone_id)) },
@@ -533,15 +457,12 @@ private fun EditTimeZone() {
@SuppressLint("NewApi") @SuppressLint("NewApi")
@Composable @Composable
private fun PermissionPolicy() { fun PermissionPolicy(navCtrl: NavHostController) {
val context = LocalContext.current val context = LocalContext.current
val dpm = context.getDPM() val dpm = context.getDPM()
val receiver = context.getReceiver() val receiver = context.getReceiver()
Column(modifier = Modifier.fillMaxSize().padding(horizontal = 8.dp).verticalScroll(rememberScrollState())) { var selectedPolicy by remember { mutableIntStateOf(dpm.getPermissionPolicy(receiver)) }
var selectedPolicy by remember { mutableIntStateOf(dpm.getPermissionPolicy(receiver)) } MyScaffold(R.string.permission_policy, 8.dp, navCtrl) {
Spacer(Modifier.padding(vertical = 10.dp))
Text(text = stringResource(R.string.permission_policy), style = typography.headlineLarge)
Spacer(Modifier.padding(vertical = 5.dp))
RadioButtonItem(R.string.default_stringres, selectedPolicy == PERMISSION_POLICY_PROMPT, { selectedPolicy = PERMISSION_POLICY_PROMPT }) RadioButtonItem(R.string.default_stringres, selectedPolicy == PERMISSION_POLICY_PROMPT, { selectedPolicy = PERMISSION_POLICY_PROMPT })
RadioButtonItem(R.string.auto_grant, selectedPolicy == PERMISSION_POLICY_AUTO_GRANT, { selectedPolicy = PERMISSION_POLICY_AUTO_GRANT }) RadioButtonItem(R.string.auto_grant, selectedPolicy == PERMISSION_POLICY_AUTO_GRANT, { selectedPolicy = PERMISSION_POLICY_AUTO_GRANT })
RadioButtonItem(R.string.auto_deny, selectedPolicy == PERMISSION_POLICY_AUTO_DENY, { selectedPolicy = PERMISSION_POLICY_AUTO_DENY }) RadioButtonItem(R.string.auto_deny, selectedPolicy == PERMISSION_POLICY_AUTO_DENY, { selectedPolicy = PERMISSION_POLICY_AUTO_DENY })
@@ -561,14 +482,11 @@ private fun PermissionPolicy() {
@SuppressLint("NewApi") @SuppressLint("NewApi")
@Composable @Composable
private fun MTEPolicy() { fun MTEPolicy(navCtrl: NavHostController) {
val context = LocalContext.current val context = LocalContext.current
val dpm = context.getDPM() val dpm = context.getDPM()
Column(modifier = Modifier.fillMaxSize().padding(horizontal = 8.dp).verticalScroll(rememberScrollState())) { var selectedMtePolicy by remember { mutableIntStateOf(dpm.mtePolicy) }
Spacer(Modifier.padding(vertical = 10.dp)) MyScaffold(R.string.mte_policy, 8.dp, navCtrl) {
Text(text = stringResource(R.string.mte_policy), style = typography.headlineLarge)
Spacer(Modifier.padding(vertical = 5.dp))
var selectedMtePolicy by remember { mutableIntStateOf(dpm.mtePolicy) }
RadioButtonItem( RadioButtonItem(
R.string.decide_by_user, R.string.decide_by_user,
selectedMtePolicy == MTE_NOT_CONTROLLED_BY_POLICY, selectedMtePolicy == MTE_NOT_CONTROLLED_BY_POLICY,
@@ -599,17 +517,16 @@ private fun MTEPolicy() {
Text(stringResource(R.string.apply)) Text(stringResource(R.string.apply))
} }
InfoCard(R.string.info_mte_policy) InfoCard(R.string.info_mte_policy)
Spacer(Modifier.padding(vertical = 30.dp))
} }
} }
@SuppressLint("NewApi") @SuppressLint("NewApi")
@Composable @Composable
private fun NearbyStreamingPolicy() { fun NearbyStreamingPolicy(navCtrl: NavHostController) {
val context = LocalContext.current val context = LocalContext.current
val dpm = context.getDPM() val dpm = context.getDPM()
Column(modifier = Modifier.fillMaxSize().padding(horizontal = 8.dp).verticalScroll(rememberScrollState())) { var appPolicy by remember { mutableIntStateOf(dpm.nearbyAppStreamingPolicy) }
var appPolicy by remember { mutableIntStateOf(dpm.nearbyAppStreamingPolicy) } MyScaffold(R.string.nearby_streaming_policy, 8.dp, navCtrl) {
Spacer(Modifier.padding(vertical = 10.dp)) Spacer(Modifier.padding(vertical = 10.dp))
Text(text = stringResource(R.string.nearby_app_streaming), style = typography.titleLarge) Text(text = stringResource(R.string.nearby_app_streaming), style = typography.titleLarge)
Spacer(Modifier.padding(vertical = 3.dp)) Spacer(Modifier.padding(vertical = 3.dp))
@@ -679,20 +596,19 @@ private fun NearbyStreamingPolicy() {
Text(stringResource(R.string.apply)) Text(stringResource(R.string.apply))
} }
InfoCard(R.string.info_nearby_notification_streaming_policy) InfoCard(R.string.info_nearby_notification_streaming_policy)
Spacer(Modifier.padding(vertical = 30.dp))
} }
} }
@SuppressLint("NewApi") @SuppressLint("NewApi")
@Composable @Composable
private fun LockTaskMode(navCtrl: NavHostController) { fun LockTaskMode(navCtrl: NavHostController) {
val context = LocalContext.current val context = LocalContext.current
val dpm = context.getDPM() val dpm = context.getDPM()
val receiver = context.getReceiver() val receiver = context.getReceiver()
val focusMgr = LocalFocusManager.current val focusMgr = LocalFocusManager.current
val coroutine = rememberCoroutineScope() val coroutine = rememberCoroutineScope()
var appSelectorRequest by rememberSaveable { mutableIntStateOf(0) } var appSelectorRequest by rememberSaveable { mutableIntStateOf(0) }
Column(modifier = Modifier.fillMaxSize().padding(horizontal = 8.dp).verticalScroll(rememberScrollState())) { MyScaffold(R.string.lock_task_mode, 8.dp, navCtrl, false) {
val lockTaskFeatures = remember { mutableStateListOf<Int>() } val lockTaskFeatures = remember { mutableStateListOf<Int>() }
var custom by rememberSaveable { mutableStateOf(false) } var custom by rememberSaveable { mutableStateOf(false) }
val refreshFeature = { val refreshFeature = {
@@ -710,7 +626,7 @@ private fun LockTaskMode(navCtrl: NavHostController) {
} }
if(calculate - 1 >= 0) { lockTaskFeatures += 1 } if(calculate - 1 >= 0) { lockTaskFeatures += 1 }
custom = true custom = true
}else{ } else {
custom = false custom = false
} }
} }
@@ -803,7 +719,7 @@ private fun LockTaskMode(navCtrl: NavHostController) {
keyboardOptions = KeyboardOptions(imeAction = ImeAction.Done), keyboardOptions = KeyboardOptions(imeAction = ImeAction.Done),
keyboardActions = KeyboardActions(onDone = { focusMgr.clearFocus() }), keyboardActions = KeyboardActions(onDone = { focusMgr.clearFocus() }),
trailingIcon = { trailingIcon = {
Icon(painter = painterResource(R.drawable.checklist_fill0), contentDescription = null, Icon(painter = painterResource(R.drawable.list_fill0), contentDescription = null,
modifier = Modifier modifier = Modifier
.clip(RoundedCornerShape(50)) .clip(RoundedCornerShape(50))
.clickable(onClick = { .clickable(onClick = {
@@ -865,7 +781,7 @@ private fun LockTaskMode(navCtrl: NavHostController) {
keyboardOptions = KeyboardOptions(imeAction = ImeAction.Done), keyboardOptions = KeyboardOptions(imeAction = ImeAction.Done),
keyboardActions = KeyboardActions(onDone = { focusMgr.clearFocus() }), keyboardActions = KeyboardActions(onDone = { focusMgr.clearFocus() }),
trailingIcon = { trailingIcon = {
Icon(painter = painterResource(R.drawable.checklist_fill0), contentDescription = null, Icon(painter = painterResource(R.drawable.list_fill0), contentDescription = null,
modifier = Modifier modifier = Modifier
.clip(RoundedCornerShape(50)) .clip(RoundedCornerShape(50))
.clickable(onClick = { .clickable(onClick = {
@@ -915,12 +831,11 @@ private fun LockTaskMode(navCtrl: NavHostController) {
Text(stringResource(R.string.start)) Text(stringResource(R.string.start))
} }
InfoCard(R.string.info_start_lock_task_mode) InfoCard(R.string.info_start_lock_task_mode)
Spacer(Modifier.padding(vertical = 30.dp))
} }
} }
@Composable @Composable
private fun CaCert() { fun CACert(navCtrl: NavHostController) {
val context = LocalContext.current val context = LocalContext.current
val dpm = context.getDPM() val dpm = context.getDPM()
val receiver = context.getReceiver() val receiver = context.getReceiver()
@@ -941,10 +856,7 @@ private fun CaCert() {
exist = dpm.hasCaCertInstalled(receiver, caCertByteArray) exist = dpm.hasCaCertInstalled(receiver, caCertByteArray)
} }
} }
Column(modifier = Modifier.fillMaxSize().padding(horizontal = 8.dp).verticalScroll(rememberScrollState())) { MyScaffold(R.string.ca_cert, 8.dp, navCtrl) {
Spacer(Modifier.padding(vertical = 10.dp))
Text(text = stringResource(R.string.ca_cert), style = typography.headlineLarge)
Spacer(Modifier.padding(vertical = 5.dp))
AnimatedVisibility(uriPath != "") { AnimatedVisibility(uriPath != "") {
Text(text = uriPath) Text(text = uriPath)
} }
@@ -1004,7 +916,7 @@ private fun CaCert() {
@SuppressLint("NewApi") @SuppressLint("NewApi")
@Composable @Composable
private fun SecurityLogs() { fun SecurityLogging(navCtrl: NavHostController) {
val context = LocalContext.current val context = LocalContext.current
val dpm = context.getDPM() val dpm = context.getDPM()
val receiver = context.getReceiver() val receiver = context.getReceiver()
@@ -1013,10 +925,7 @@ private fun SecurityLogs() {
LaunchedEffect(Unit) { LaunchedEffect(Unit) {
fileSize = logFile.length() fileSize = logFile.length()
} }
Column(modifier = Modifier.fillMaxSize().padding(horizontal = 8.dp).verticalScroll(rememberScrollState())) { MyScaffold(R.string.security_logging, 8.dp, navCtrl) {
Spacer(Modifier.padding(vertical = 10.dp))
Text(text = stringResource(R.string.security_logs), style = typography.headlineLarge)
Spacer(Modifier.padding(vertical = 5.dp))
SwitchItem(R.string.enable, "", null, { dpm.isSecurityLoggingEnabled(receiver) }, { dpm.setSecurityLoggingEnabled(receiver, it) }, padding = false) SwitchItem(R.string.enable, "", null, { dpm.isSecurityLoggingEnabled(receiver) }, { dpm.setSecurityLoggingEnabled(receiver, it) }, padding = false)
Text(stringResource(R.string.log_file_size_is, formatFileSize(fileSize))) Text(stringResource(R.string.log_file_size_is, formatFileSize(fileSize)))
Row(horizontalArrangement = Arrangement.SpaceBetween, modifier = Modifier.fillMaxWidth()) { Row(horizontalArrangement = Arrangement.SpaceBetween, modifier = Modifier.fillMaxWidth()) {
@@ -1087,21 +996,18 @@ private fun SecurityLogs() {
} }
@Composable @Composable
private fun DisableAccountManagement() { fun DisableAccountManagement(navCtrl: NavHostController) {
val context = LocalContext.current val context = LocalContext.current
val dpm = context.getDPM() val dpm = context.getDPM()
val receiver = context.getReceiver() val receiver = context.getReceiver()
val focusMgr = LocalFocusManager.current val focusMgr = LocalFocusManager.current
Column(modifier = Modifier.fillMaxSize().verticalScroll(rememberScrollState()).padding(horizontal = 8.dp)) { MyScaffold(R.string.disable_account_management, 8.dp, navCtrl) {
Spacer(Modifier.padding(vertical = 10.dp))
Text(text = stringResource(R.string.disable_account_management), style = typography.headlineLarge)
val list = remember { mutableStateListOf<String>() } val list = remember { mutableStateListOf<String>() }
fun refreshList() { fun refreshList() {
list.clear() list.clear()
dpm.accountTypesWithManagementDisabled?.forEach { list += it } dpm.accountTypesWithManagementDisabled?.forEach { list += it }
} }
LaunchedEffect(Unit) { refreshList() } LaunchedEffect(Unit) { refreshList() }
Spacer(Modifier.padding(vertical = 5.dp))
Column(modifier = Modifier.animateContentSize()) { Column(modifier = Modifier.animateContentSize()) {
if(list.isEmpty()) Text(stringResource(R.string.none)) if(list.isEmpty()) Text(stringResource(R.string.none))
for(i in list) { for(i in list) {
@@ -1139,7 +1045,7 @@ private fun DisableAccountManagement() {
@SuppressLint("NewApi") @SuppressLint("NewApi")
@Composable @Composable
fun FactoryResetProtection() { fun FRPPolicy(navCtrl: NavHostController) {
val context = LocalContext.current val context = LocalContext.current
val dpm = context.getDPM() val dpm = context.getDPM()
val focusMgr = LocalFocusManager.current val focusMgr = LocalFocusManager.current
@@ -1165,12 +1071,7 @@ fun FactoryResetProtection() {
} }
} }
} }
Column(modifier = Modifier.fillMaxSize().padding(horizontal = 8.dp).verticalScroll(rememberScrollState())) { MyScaffold(R.string.frp_policy, 8.dp, navCtrl) {
Spacer(Modifier.padding(vertical = 10.dp))
Text(text = stringResource(R.string.frp_policy), style = typography.headlineLarge)
Spacer(Modifier.padding(vertical = 3.dp))
Text(stringResource(R.string.factory_reset_protection_policy))
Spacer(Modifier.padding(vertical = 5.dp))
Row( Row(
horizontalArrangement = Arrangement.SpaceBetween, verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.SpaceBetween, verticalAlignment = Alignment.CenterVertically,
modifier = Modifier.fillMaxWidth().padding(horizontal = 6.dp, vertical = 8.dp) modifier = Modifier.fillMaxWidth().padding(horizontal = 6.dp, vertical = 8.dp)
@@ -1231,13 +1132,12 @@ fun FactoryResetProtection() {
if(unsupported) Text(stringResource(R.string.frp_policy_not_supported)) if(unsupported) Text(stringResource(R.string.frp_policy_not_supported))
Spacer(Modifier.padding(vertical = 6.dp)) Spacer(Modifier.padding(vertical = 6.dp))
InfoCard(R.string.info_frp_policy) InfoCard(R.string.info_frp_policy)
Spacer(Modifier.padding(vertical = 30.dp))
} }
} }
@SuppressLint("NewApi") @SuppressLint("NewApi")
@Composable @Composable
private fun WipeData() { fun WipeData(navCtrl: NavHostController) {
val context = LocalContext.current val context = LocalContext.current
val userManager = context.getSystemService(Context.USER_SERVICE) as UserManager val userManager = context.getSystemService(Context.USER_SERVICE) as UserManager
val dpm = context.getDPM() val dpm = context.getDPM()
@@ -1249,14 +1149,7 @@ private fun WipeData() {
var euicc by remember { mutableStateOf(false) } var euicc by remember { mutableStateOf(false) }
var silent by remember { mutableStateOf(false) } var silent by remember { mutableStateOf(false) }
var reason by remember { mutableStateOf("") } var reason by remember { mutableStateOf("") }
Column(modifier = Modifier.fillMaxSize().padding(horizontal = 8.dp).verticalScroll(rememberScrollState())) { MyScaffold(R.string.wipe_data, 8.dp, navCtrl) {
Spacer(Modifier.padding(vertical = 10.dp))
Text(
text = stringResource(R.string.wipe_data),
style = typography.headlineLarge,
modifier = Modifier.padding(6.dp),color = colorScheme.error
)
Spacer(Modifier.padding(vertical = 5.dp))
CheckBoxItem( CheckBoxItem(
R.string.wipe_external_storage, R.string.wipe_external_storage,
externalStorage, { externalStorage = it } externalStorage, { externalStorage = it }
@@ -1302,7 +1195,6 @@ private fun WipeData() {
Text("WipeDevice") Text("WipeDevice")
} }
} }
Spacer(Modifier.padding(vertical = 30.dp))
} }
if(warning) { if(warning) {
LaunchedEffect(Unit) { silent = reason == "" } LaunchedEffect(Unit) { silent = reason == "" }
@@ -1360,18 +1252,15 @@ private fun WipeData() {
} }
@Composable @Composable
private fun SysUpdatePolicy() { fun SystemUpdatePolicy(navCtrl: NavHostController) {
val context = LocalContext.current val context = LocalContext.current
val dpm = context.getDPM() val dpm = context.getDPM()
val receiver = context.getReceiver() val receiver = context.getReceiver()
val focusMgr = LocalFocusManager.current val focusMgr = LocalFocusManager.current
Column(modifier = Modifier.fillMaxSize().padding(horizontal = 8.dp).verticalScroll(rememberScrollState())) { MyScaffold(R.string.system_update_policy, 8.dp, navCtrl) {
Spacer(Modifier.padding(vertical = 10.dp))
if(VERSION.SDK_INT >= 23) { if(VERSION.SDK_INT >= 23) {
Column { Column {
var selectedPolicy by remember { mutableStateOf(dpm.systemUpdatePolicy?.policyType) } var selectedPolicy by remember { mutableStateOf(dpm.systemUpdatePolicy?.policyType) }
Text(text = stringResource(R.string.system_update_policy), style = typography.headlineLarge)
Spacer(Modifier.padding(vertical = 5.dp))
RadioButtonItem( RadioButtonItem(
R.string.system_update_policy_automatic, R.string.system_update_policy_automatic,
selectedPolicy == TYPE_INSTALL_AUTOMATIC, { selectedPolicy = TYPE_INSTALL_AUTOMATIC } selectedPolicy == TYPE_INSTALL_AUTOMATIC, { selectedPolicy = TYPE_INSTALL_AUTOMATIC }
@@ -1447,13 +1336,12 @@ private fun SysUpdatePolicy() {
} }
} }
} }
Spacer(Modifier.padding(vertical = 30.dp))
} }
} }
@SuppressLint("NewApi") @SuppressLint("NewApi")
@Composable @Composable
fun InstallSystemUpdate() { fun InstallSystemUpdate(navCtrl: NavHostController) {
val context = LocalContext.current val context = LocalContext.current
val dpm = context.getDPM() val dpm = context.getDPM()
val receiver = context.getReceiver() val receiver = context.getReceiver()
@@ -1472,10 +1360,7 @@ fun InstallSystemUpdate() {
} }
} }
val uri by fileUriFlow.collectAsState() val uri by fileUriFlow.collectAsState()
Column(modifier = Modifier.fillMaxSize().padding(horizontal = 8.dp).verticalScroll(rememberScrollState())) { MyScaffold(R.string.install_system_update, 8.dp, navCtrl) {
Spacer(Modifier.padding(vertical = 10.dp))
Text(text = stringResource(R.string.install_system_update), style = typography.headlineLarge)
Spacer(Modifier.padding(vertical = 5.dp))
Button( Button(
onClick = { onClick = {
val intent = Intent(Intent.ACTION_GET_CONTENT) val intent = Intent(Intent.ACTION_GET_CONTENT)
@@ -1508,10 +1393,7 @@ fun InstallSystemUpdate() {
} }
} }
Spacer(Modifier.padding(vertical = 10.dp)) Spacer(Modifier.padding(vertical = 10.dp))
Information { InfoCard(R.string.auto_reboot_after_install_succeed)
Text(stringResource(R.string.auto_reboot_after_install_succeed))
}
Spacer(Modifier.padding(vertical = 30.dp))
} }
} }

View File

@@ -6,34 +6,20 @@ import android.os.UserManager
import android.widget.Toast import android.widget.Toast
import androidx.annotation.DrawableRes import androidx.annotation.DrawableRes
import androidx.annotation.StringRes import androidx.annotation.StringRes
import androidx.compose.foundation.ScrollState
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.MaterialTheme.typography
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.alpha
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.navigation.NavHostController import androidx.navigation.NavHostController
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import androidx.navigation.compose.currentBackStackEntryAsState
import androidx.navigation.compose.rememberNavController
import com.bintianqi.owndroid.R import com.bintianqi.owndroid.R
import com.bintianqi.owndroid.ui.Animations import com.bintianqi.owndroid.ui.FunctionItem
import com.bintianqi.owndroid.ui.SubPageItem import com.bintianqi.owndroid.ui.MyScaffold
import com.bintianqi.owndroid.ui.SwitchItem import com.bintianqi.owndroid.ui.SwitchItem
import com.bintianqi.owndroid.ui.TopBar
data class Restriction( data class Restriction(
val id: String, val id: String,
@@ -42,92 +28,29 @@ data class Restriction(
) )
@Composable @Composable
fun UserRestriction(navCtrl: NavHostController) { fun UserRestriction(navCtrl:NavHostController) {
val localNavCtrl = rememberNavController()
val backStackEntry by localNavCtrl.currentBackStackEntryAsState()
val scrollState = rememberScrollState()
/*val titleMap = mapOf(
"Internet" to R.string.network_internet,
"Connectivity" to R.string.more_connectivity,
"Users" to R.string.users,
"Media" to R.string.media,
"Applications" to R.string.applications,
"Other" to R.string.other
)*/
Scaffold(
topBar = {
/*TopAppBar(
title = {Text(text = stringResource(titleMap[backStackEntry?.destination?.route]?:R.string.user_restrict))},
navigationIcon = {NavIcon{if(backStackEntry?.destination?.route=="Home"){navCtrl.navigateUp()}else{localNavCtrl.navigateUp()}}},
colors = TopAppBarDefaults.topAppBarColors(containerColor = colorScheme.surfaceVariant)
)*/
TopBar(backStackEntry,navCtrl,localNavCtrl){
if(backStackEntry?.destination?.route=="Home"&&scrollState.maxValue>80){
Text(
text = stringResource(R.string.user_restrict),
modifier = Modifier.alpha((maxOf(scrollState.value-30, 0)).toFloat() / 80)
)
}
}
}
) {
NavHost(
navController = localNavCtrl, startDestination = "Home",
enterTransition = Animations.navHostEnterTransition,
exitTransition = Animations.navHostExitTransition,
popEnterTransition = Animations.navHostPopEnterTransition,
popExitTransition = Animations.navHostPopExitTransition,
modifier = Modifier.padding(top = it.calculateTopPadding())
) {
composable(route = "Home") { Home(localNavCtrl, scrollState) }
composable(route = "Internet") { UserRestrictionPage(RestrictionData.internet()) }
composable(route = "Connectivity") { UserRestrictionPage(RestrictionData.connectivity())}
composable(route = "Applications") { UserRestrictionPage(RestrictionData.connectivity()) }
composable(route = "Users") { UserRestrictionPage(RestrictionData.user()) }
composable(route = "Media") { UserRestrictionPage(RestrictionData.media()) }
composable(route = "Other") { UserRestrictionPage(RestrictionData.other()) }
}
}
}
@Composable
private fun Home(navCtrl:NavHostController, scrollState: ScrollState) {
val context = LocalContext.current val context = LocalContext.current
val dpm = context.getDPM() val dpm = context.getDPM()
val receiver = context.getReceiver() val receiver = context.getReceiver()
Column(modifier = Modifier.fillMaxSize().verticalScroll(scrollState)) { MyScaffold(R.string.user_restriction, 0.dp, navCtrl) {
Text(
text = stringResource(R.string.user_restrict),
style = typography.headlineLarge,
modifier = Modifier.padding(top = 8.dp, bottom = 7.dp, start = 16.dp)
)
Text(text = stringResource(R.string.switch_to_disable_feature), modifier = Modifier.padding(start = 16.dp)) Text(text = stringResource(R.string.switch_to_disable_feature), modifier = Modifier.padding(start = 16.dp))
if(context.isProfileOwner) { Text(text = stringResource(R.string.profile_owner_is_restricted), modifier = Modifier.padding(start = 16.dp)) } if(context.isProfileOwner) { Text(text = stringResource(R.string.profile_owner_is_restricted), modifier = Modifier.padding(start = 16.dp)) }
if(context.isProfileOwner && (VERSION.SDK_INT < 24 || (VERSION.SDK_INT >= 24 && dpm.isManagedProfile(receiver)))) { if(context.isProfileOwner && (VERSION.SDK_INT < 24 || (VERSION.SDK_INT >= 24 && dpm.isManagedProfile(receiver)))) {
Text(text = stringResource(R.string.some_features_invalid_in_work_profile), modifier = Modifier.padding(start = 16.dp)) Text(text = stringResource(R.string.some_features_invalid_in_work_profile), modifier = Modifier.padding(start = 16.dp))
} }
Spacer(Modifier.padding(vertical = 2.dp)) Spacer(Modifier.padding(vertical = 2.dp))
SubPageItem(R.string.network_internet, "", R.drawable.wifi_fill0) { navCtrl.navigate("Internet") } FunctionItem(R.string.network_and_internet, "", R.drawable.wifi_fill0) { navCtrl.navigate("UR-Internet") }
SubPageItem(R.string.more_connectivity, "", R.drawable.devices_other_fill0) { navCtrl.navigate("Connectivity") } FunctionItem(R.string.connectivity, "", R.drawable.devices_other_fill0) { navCtrl.navigate("UR-Connectivity") }
SubPageItem(R.string.applications, "", R.drawable.apps_fill0) { navCtrl.navigate("Applications") } FunctionItem(R.string.applications, "", R.drawable.apps_fill0) { navCtrl.navigate("UR-Applications") }
SubPageItem(R.string.users, "", R.drawable.account_circle_fill0) { navCtrl.navigate("Users") } FunctionItem(R.string.users, "", R.drawable.account_circle_fill0) { navCtrl.navigate("UR-Users") }
SubPageItem(R.string.media, "", R.drawable.volume_up_fill0) { navCtrl.navigate("Media") } FunctionItem(R.string.media, "", R.drawable.volume_up_fill0) { navCtrl.navigate("UR-Media") }
SubPageItem(R.string.other, "", R.drawable.more_horiz_fill0) { navCtrl.navigate("Other") } FunctionItem(R.string.other, "", R.drawable.more_horiz_fill0) { navCtrl.navigate("UR-Other") }
Spacer(Modifier.padding(vertical = 30.dp))
}
}
@Composable
private fun UserRestrictionPage(restrictions: List<Restriction>) {
Column(modifier = Modifier.fillMaxSize().verticalScroll(rememberScrollState())) {
restrictions.forEach { UserRestrictionItem(it) }
Spacer(Modifier.padding(vertical = 30.dp))
} }
} }
@SuppressLint("NewApi") @SuppressLint("NewApi")
@Composable @Composable
private fun UserRestrictionItem(restriction: Restriction) { fun UserRestrictionItem(restriction: Restriction) {
val context = LocalContext.current val context = LocalContext.current
val dpm = context.getDPM() val dpm = context.getDPM()
val receiver = context.getReceiver() val receiver = context.getReceiver()
@@ -153,7 +76,7 @@ private fun UserRestrictionItem(restriction: Restriction) {
} }
object RestrictionData { object RestrictionData {
fun internet(): List<Restriction> { val internet: List<Restriction> get() {
val list = mutableListOf<Restriction>() val list = mutableListOf<Restriction>()
list += Restriction(UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS, R.string.config_mobile_network, R.drawable.signal_cellular_alt_fill0) list += Restriction(UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS, R.string.config_mobile_network, R.drawable.signal_cellular_alt_fill0)
list += Restriction(UserManager.DISALLOW_CONFIG_WIFI, R.string.config_wifi, R.drawable.wifi_fill0) list += Restriction(UserManager.DISALLOW_CONFIG_WIFI, R.string.config_wifi, R.drawable.wifi_fill0)
@@ -179,7 +102,7 @@ object RestrictionData {
list += Restriction(UserManager.DISALLOW_OUTGOING_CALLS, R.string.outgoing_calls, R.drawable.phone_forwarded_fill0) list += Restriction(UserManager.DISALLOW_OUTGOING_CALLS, R.string.outgoing_calls, R.drawable.phone_forwarded_fill0)
return list return list
} }
fun connectivity(): List<Restriction> { val connectivity: List<Restriction> get() {
val list = mutableListOf<Restriction>() val list = mutableListOf<Restriction>()
if(VERSION.SDK_INT>=26) { if(VERSION.SDK_INT>=26) {
list += Restriction(UserManager.DISALLOW_BLUETOOTH, R.string.bluetooth, R.drawable.bluetooth_fill0) list += Restriction(UserManager.DISALLOW_BLUETOOTH, R.string.bluetooth, R.drawable.bluetooth_fill0)
@@ -193,7 +116,7 @@ object RestrictionData {
if(VERSION.SDK_INT>=28) list += Restriction(UserManager.DISALLOW_PRINTING, R.string.printing, R.drawable.print_fill0) if(VERSION.SDK_INT>=28) list += Restriction(UserManager.DISALLOW_PRINTING, R.string.printing, R.drawable.print_fill0)
return list return list
} }
fun application(): List<Restriction> { val applications: List<Restriction> get() {
val list = mutableListOf<Restriction>() val list = mutableListOf<Restriction>()
list += Restriction(UserManager.DISALLOW_INSTALL_APPS, R.string.install_app, R.drawable.android_fill0) list += Restriction(UserManager.DISALLOW_INSTALL_APPS, R.string.install_app, R.drawable.android_fill0)
if(VERSION.SDK_INT>=29) list += Restriction(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES_GLOBALLY, R.string.install_unknown_src_globally, R.drawable.android_fill0) if(VERSION.SDK_INT>=29) list += Restriction(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES_GLOBALLY, R.string.install_unknown_src_globally, R.drawable.android_fill0)
@@ -203,7 +126,7 @@ object RestrictionData {
if(VERSION.SDK_INT>=34) list += Restriction(UserManager.DISALLOW_CONFIG_DEFAULT_APPS, R.string.config_default_apps, R.drawable.apps_fill0) if(VERSION.SDK_INT>=34) list += Restriction(UserManager.DISALLOW_CONFIG_DEFAULT_APPS, R.string.config_default_apps, R.drawable.apps_fill0)
return list return list
} }
fun media(): List<Restriction> { val media: List<Restriction> get() {
val list = mutableListOf<Restriction>() val list = mutableListOf<Restriction>()
if(VERSION.SDK_INT>=28) { if(VERSION.SDK_INT>=28) {
list += Restriction(UserManager.DISALLOW_CONFIG_BRIGHTNESS, R.string.config_brightness, R.drawable.brightness_5_fill0) list += Restriction(UserManager.DISALLOW_CONFIG_BRIGHTNESS, R.string.config_brightness, R.drawable.brightness_5_fill0)
@@ -218,7 +141,7 @@ object RestrictionData {
} }
return list return list
} }
fun user(): List<Restriction> { val users: List<Restriction> get() {
val list = mutableListOf<Restriction>() val list = mutableListOf<Restriction>()
list += Restriction(UserManager.DISALLOW_ADD_USER, R.string.add_user, R.drawable.account_circle_fill0) list += Restriction(UserManager.DISALLOW_ADD_USER, R.string.add_user, R.drawable.account_circle_fill0)
list += Restriction(UserManager.DISALLOW_REMOVE_USER, R.string.remove_user, R.drawable.account_circle_fill0) list += Restriction(UserManager.DISALLOW_REMOVE_USER, R.string.remove_user, R.drawable.account_circle_fill0)
@@ -231,7 +154,7 @@ object RestrictionData {
} }
return list return list
} }
fun other(): List<Restriction> { val other: List<Restriction> get() {
val list = mutableListOf<Restriction>() val list = mutableListOf<Restriction>()
if(VERSION.SDK_INT>=26) list += Restriction(UserManager.DISALLOW_AUTOFILL, R.string.autofill, R.drawable.password_fill0) if(VERSION.SDK_INT>=26) list += Restriction(UserManager.DISALLOW_AUTOFILL, R.string.autofill, R.drawable.password_fill0)
list += Restriction(UserManager.DISALLOW_CONFIG_CREDENTIALS, R.string.config_credentials, R.drawable.android_fill0) list += Restriction(UserManager.DISALLOW_CONFIG_CREDENTIALS, R.string.config_credentials, R.drawable.android_fill0)
@@ -254,14 +177,7 @@ object RestrictionData {
list += Restriction(UserManager.DISALLOW_DEBUGGING_FEATURES, R.string.debug_features, R.drawable.adb_fill0) list += Restriction(UserManager.DISALLOW_DEBUGGING_FEATURES, R.string.debug_features, R.drawable.adb_fill0)
return list return list
} }
fun getAllRestrictions(): List<String> { fun getAllRestrictions(): List<Restriction> =
val result = mutableListOf<String>() internet + connectivity + media + applications + users + other
internet().forEach { result.add(it.id) }
connectivity().forEach { result.add(it.id) }
media().forEach { result.add(it.id) }
application().forEach { result.add(it.id) }
user().forEach { result.add(it.id) }
other().forEach { result.add(it.id) }
return result
}
} }

View File

@@ -18,20 +18,16 @@ import androidx.annotation.StringRes
import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.animateContentSize import androidx.compose.animation.animateContentSize
import androidx.compose.foundation.Image import androidx.compose.foundation.Image
import androidx.compose.foundation.ScrollState
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.size
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.text.KeyboardActions import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Add import androidx.compose.material.icons.filled.Add
import androidx.compose.material3.AlertDialog import androidx.compose.material3.AlertDialog
@@ -39,9 +35,7 @@ import androidx.compose.material3.Button
import androidx.compose.material3.Card import androidx.compose.material3.Card
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme.typography
import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.material3.TextButton import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
@@ -55,7 +49,6 @@ import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.alpha
import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.asImageBitmap import androidx.compose.ui.graphics.asImageBitmap
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
@@ -65,106 +58,56 @@ import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.navigation.NavHostController import androidx.navigation.NavHostController
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import androidx.navigation.compose.currentBackStackEntryAsState
import androidx.navigation.compose.rememberNavController
import com.bintianqi.owndroid.R import com.bintianqi.owndroid.R
import com.bintianqi.owndroid.fileUriFlow import com.bintianqi.owndroid.fileUriFlow
import com.bintianqi.owndroid.getFile import com.bintianqi.owndroid.getFile
import com.bintianqi.owndroid.parseTimestamp import com.bintianqi.owndroid.parseTimestamp
import com.bintianqi.owndroid.toggle import com.bintianqi.owndroid.toggle
import com.bintianqi.owndroid.ui.Animations
import com.bintianqi.owndroid.ui.CardItem import com.bintianqi.owndroid.ui.CardItem
import com.bintianqi.owndroid.ui.CheckBoxItem import com.bintianqi.owndroid.ui.CheckBoxItem
import com.bintianqi.owndroid.ui.FunctionItem
import com.bintianqi.owndroid.ui.InfoCard import com.bintianqi.owndroid.ui.InfoCard
import com.bintianqi.owndroid.ui.ListItem import com.bintianqi.owndroid.ui.ListItem
import com.bintianqi.owndroid.ui.SubPageItem import com.bintianqi.owndroid.ui.MyScaffold
import com.bintianqi.owndroid.ui.SwitchItem import com.bintianqi.owndroid.ui.SwitchItem
import com.bintianqi.owndroid.ui.TopBar
import com.bintianqi.owndroid.uriToStream import com.bintianqi.owndroid.uriToStream
import com.bintianqi.owndroid.yesOrNo import com.bintianqi.owndroid.yesOrNo
@Composable @Composable
fun UserManage(navCtrl: NavHostController) { fun Users(navCtrl: NavHostController) {
val localNavCtrl = rememberNavController()
val backStackEntry by localNavCtrl.currentBackStackEntryAsState()
val scrollState = rememberScrollState()
Scaffold(
topBar = {
TopBar(backStackEntry, navCtrl, localNavCtrl) {
if(backStackEntry?.destination?.route == "Home" && scrollState.maxValue > 100) {
Text(
text = stringResource(R.string.users),
modifier = Modifier.alpha((maxOf(scrollState.value-30, 0)).toFloat() / 80)
)
}
}
}
) {
NavHost(
navController = localNavCtrl, startDestination = "Home",
enterTransition = Animations.navHostEnterTransition,
exitTransition = Animations.navHostExitTransition,
popEnterTransition = Animations.navHostPopEnterTransition,
popExitTransition = Animations.navHostPopExitTransition,
modifier = Modifier.padding(top = it.calculateTopPadding())
) {
composable(route = "Home") { Home(localNavCtrl, scrollState) }
composable(route = "UserInfo") { CurrentUserInfo() }
composable(route = "Options") { Options() }
composable(route = "UserOperation") { UserOperation() }
composable(route = "CreateUser") { CreateUser() }
composable(route = "EditUsername") { Username() }
composable(route = "ChangeUserIcon") { UserIcon() }
composable(route = "UserSessionMessage") { UserSessionMessage() }
composable(route = "AffiliationID") { AffiliationID() }
}
}
}
@Composable
private fun Home(navCtrl: NavHostController,scrollState: ScrollState) {
val context = LocalContext.current val context = LocalContext.current
val dpm = context.getDPM() val dpm = context.getDPM()
val receiver = context.getReceiver() val receiver = context.getReceiver()
val deviceOwner = context.isDeviceOwner val deviceOwner = context.isDeviceOwner
val profileOwner = context.isProfileOwner val profileOwner = context.isProfileOwner
//var logoutDialog by remember { mutableStateOf(false) }
var dialog by remember { mutableIntStateOf(0) } var dialog by remember { mutableIntStateOf(0) }
Column(modifier = Modifier.fillMaxSize().verticalScroll(scrollState)) { MyScaffold(R.string.users, 0.dp, navCtrl) {
Text( FunctionItem(R.string.user_info, "", R.drawable.person_fill0) { navCtrl.navigate("UserInfo") }
text = stringResource(R.string.users),
style = typography.headlineLarge,
modifier = Modifier.padding(top = 8.dp, bottom = 5.dp, start = 16.dp)
)
SubPageItem(R.string.user_info, "", R.drawable.person_fill0) { navCtrl.navigate("UserInfo") }
if(deviceOwner && VERSION.SDK_INT >= 28) { if(deviceOwner && VERSION.SDK_INT >= 28) {
SubPageItem(R.string.secondary_users, "", R.drawable.list_fill0) { dialog = 1 } FunctionItem(R.string.secondary_users, "", R.drawable.list_fill0) { dialog = 1 }
SubPageItem(R.string.options, "", R.drawable.tune_fill0) { navCtrl.navigate("Options") } FunctionItem(R.string.options, "", R.drawable.tune_fill0) { navCtrl.navigate("UserOptions") }
} }
if(deviceOwner) { if(deviceOwner) {
SubPageItem(R.string.user_operation, "", R.drawable.sync_alt_fill0) { navCtrl.navigate("UserOperation") } FunctionItem(R.string.user_operation, "", R.drawable.sync_alt_fill0) { navCtrl.navigate("UserOperation") }
} }
if(VERSION.SDK_INT >= 24 && deviceOwner) { if(VERSION.SDK_INT >= 24 && deviceOwner) {
SubPageItem(R.string.create_user, "", R.drawable.person_add_fill0) { navCtrl.navigate("CreateUser") } FunctionItem(R.string.create_user, "", R.drawable.person_add_fill0) { navCtrl.navigate("CreateUser") }
} }
if(VERSION.SDK_INT >= 28 && profileOwner && dpm.isAffiliatedUser) { if(VERSION.SDK_INT >= 28 && profileOwner && dpm.isAffiliatedUser) {
SubPageItem(R.string.logout_current_user, "", R.drawable.logout_fill0) { dialog = 2 } FunctionItem(R.string.logout_current_user, "", R.drawable.logout_fill0) { dialog = 2 }
} }
if(deviceOwner || profileOwner) { if(deviceOwner || profileOwner) {
SubPageItem(R.string.change_username, "", R.drawable.edit_fill0) { navCtrl.navigate("EditUsername") } FunctionItem(R.string.change_username, "", R.drawable.edit_fill0) { navCtrl.navigate("ChangeUsername") }
} }
if(VERSION.SDK_INT >= 23 && (deviceOwner || profileOwner)) { if(VERSION.SDK_INT >= 23 && (deviceOwner || profileOwner)) {
SubPageItem(R.string.change_user_icon, "", R.drawable.account_circle_fill0) { navCtrl.navigate("ChangeUserIcon") } FunctionItem(R.string.change_user_icon, "", R.drawable.account_circle_fill0) { navCtrl.navigate("ChangeUserIcon") }
} }
if(VERSION.SDK_INT >= 28 && deviceOwner) { if(VERSION.SDK_INT >= 28 && deviceOwner) {
SubPageItem(R.string.user_session_msg, "", R.drawable.notifications_fill0) { navCtrl.navigate("UserSessionMessage") } FunctionItem(R.string.user_session_msg, "", R.drawable.notifications_fill0) { navCtrl.navigate("UserSessionMessage") }
} }
if(VERSION.SDK_INT >= 26 && (deviceOwner || profileOwner)) { if(VERSION.SDK_INT >= 26 && (deviceOwner || profileOwner)) {
SubPageItem(R.string.affiliation_id, "", R.drawable.id_card_fill0) { navCtrl.navigate("AffiliationID") } FunctionItem(R.string.affiliation_id, "", R.drawable.id_card_fill0) { navCtrl.navigate("AffiliationID") }
} }
Spacer(Modifier.padding(vertical = 30.dp))
LaunchedEffect(Unit) { fileUriFlow.value = Uri.parse("") } LaunchedEffect(Unit) { fileUriFlow.value = Uri.parse("") }
} }
if(dialog != 0 && VERSION.SDK_INT >= 28) AlertDialog( if(dialog != 0 && VERSION.SDK_INT >= 28) AlertDialog(
@@ -208,11 +151,11 @@ private fun Home(navCtrl: NavHostController,scrollState: ScrollState) {
} }
@Composable @Composable
private fun Options() { fun UserOptions(navCtrl: NavHostController) {
val context = LocalContext.current val context = LocalContext.current
val dpm = context.getDPM() val dpm = context.getDPM()
val receiver = context.getReceiver() val receiver = context.getReceiver()
Column(modifier = Modifier.fillMaxSize().verticalScroll(rememberScrollState())) { MyScaffold(R.string.options, 0.dp, navCtrl) {
if(VERSION.SDK_INT >= 28) { if(VERSION.SDK_INT >= 28) {
SwitchItem(R.string.enable_logout, "", null, { dpm.isLogoutEnabled }, { dpm.setLogoutEnabled(receiver, it) }) SwitchItem(R.string.enable_logout, "", null, { dpm.isLogoutEnabled }, { dpm.setLogoutEnabled(receiver, it) })
} }
@@ -220,17 +163,14 @@ private fun Options() {
} }
@Composable @Composable
private fun CurrentUserInfo() { fun CurrentUserInfo(navCtrl: NavHostController) {
val context = LocalContext.current val context = LocalContext.current
val dpm = context.getDPM() val dpm = context.getDPM()
val receiver = context.getReceiver() val receiver = context.getReceiver()
val userManager = context.getSystemService(Context.USER_SERVICE) as UserManager val userManager = context.getSystemService(Context.USER_SERVICE) as UserManager
val user = Process.myUserHandle() val user = Process.myUserHandle()
var infoDialog by remember { mutableIntStateOf(0) } var infoDialog by remember { mutableIntStateOf(0) }
Column(modifier = Modifier.fillMaxSize().padding(horizontal = 8.dp).verticalScroll(rememberScrollState())) { MyScaffold(R.string.user_info, 8.dp, navCtrl) {
Spacer(Modifier.padding(vertical = 10.dp))
Text(text = stringResource(R.string.user_info), style = typography.headlineLarge)
Spacer(Modifier.padding(vertical = 5.dp))
if(VERSION.SDK_INT >= 24) CardItem(R.string.support_multiuser, UserManager.supportsMultipleUsers().yesOrNo) if(VERSION.SDK_INT >= 24) CardItem(R.string.support_multiuser, UserManager.supportsMultipleUsers().yesOrNo)
if(VERSION.SDK_INT >= 31) CardItem(R.string.headless_system_user_mode, UserManager.isHeadlessSystemUserMode().yesOrNo) { infoDialog = 1 } if(VERSION.SDK_INT >= 31) CardItem(R.string.headless_system_user_mode, UserManager.isHeadlessSystemUserMode().yesOrNo) { infoDialog = 1 }
Spacer(Modifier.padding(vertical = 8.dp)) Spacer(Modifier.padding(vertical = 8.dp))
@@ -247,7 +187,6 @@ private fun CurrentUserInfo() {
} }
CardItem(R.string.user_id, (Binder.getCallingUid() / 100000).toString()) CardItem(R.string.user_id, (Binder.getCallingUid() / 100000).toString())
CardItem(R.string.user_serial_number, userManager.getSerialNumberForUser(Process.myUserHandle()).toString()) CardItem(R.string.user_serial_number, userManager.getSerialNumberForUser(Process.myUserHandle()).toString())
Spacer(Modifier.padding(vertical = 30.dp))
} }
if(infoDialog != 0) AlertDialog( if(infoDialog != 0) AlertDialog(
text = { Text(stringResource(R.string.info_headless_system_user_mode)) }, text = { Text(stringResource(R.string.info_headless_system_user_mode)) },
@@ -261,7 +200,7 @@ private fun CurrentUserInfo() {
} }
@Composable @Composable
private fun UserOperation() { fun UserOperation(navCtrl: NavHostController) {
val context = LocalContext.current val context = LocalContext.current
val userManager = context.getSystemService(Context.USER_SERVICE) as UserManager val userManager = context.getSystemService(Context.USER_SERVICE) as UserManager
val dpm = context.getDPM() val dpm = context.getDPM()
@@ -287,10 +226,7 @@ private fun UserOperation() {
} catch(_: Exception) { } catch(_: Exception) {
false false
} }
Column(modifier = Modifier.fillMaxSize().padding(horizontal = 8.dp).verticalScroll(rememberScrollState())) { MyScaffold(R.string.user_operation, 8.dp, navCtrl) {
Spacer(Modifier.padding(vertical = 10.dp))
Text(text = stringResource(R.string.user_operation), style = typography.headlineLarge)
Spacer(Modifier.padding(vertical = 5.dp))
OutlinedTextField( OutlinedTextField(
value = idInput, value = idInput,
onValueChange = { onValueChange = {
@@ -365,13 +301,12 @@ private fun UserOperation() {
Text(stringResource(R.string.delete)) Text(stringResource(R.string.delete))
} }
InfoCard(R.string.info_user_operation) InfoCard(R.string.info_user_operation)
Spacer(Modifier.padding(vertical = 30.dp))
} }
} }
@SuppressLint("NewApi") @SuppressLint("NewApi")
@Composable @Composable
private fun CreateUser() { fun CreateUser(navCtrl: NavHostController) {
val context = LocalContext.current val context = LocalContext.current
val userManager = context.getSystemService(Context.USER_SERVICE) as UserManager val userManager = context.getSystemService(Context.USER_SERVICE) as UserManager
val dpm = context.getDPM() val dpm = context.getDPM()
@@ -379,10 +314,7 @@ private fun CreateUser() {
val focusMgr = LocalFocusManager.current val focusMgr = LocalFocusManager.current
var userName by remember { mutableStateOf("") } var userName by remember { mutableStateOf("") }
val flags = remember { mutableStateListOf<Int>() } val flags = remember { mutableStateListOf<Int>() }
Column(modifier = Modifier.fillMaxSize().padding(horizontal = 8.dp).verticalScroll(rememberScrollState())) { MyScaffold(R.string.create_user, 8.dp, navCtrl) {
Spacer(Modifier.padding(vertical = 10.dp))
Text(text = stringResource(R.string.create_user), style = typography.headlineLarge)
Spacer(Modifier.padding(vertical = 5.dp))
OutlinedTextField( OutlinedTextField(
value = userName, value = userName,
onValueChange = { userName= it }, onValueChange = { userName= it },
@@ -423,13 +355,12 @@ private fun CreateUser() {
} }
Spacer(Modifier.padding(vertical = 5.dp)) Spacer(Modifier.padding(vertical = 5.dp))
if(newUserHandle != null) { Text(text = stringResource(R.string.serial_number_of_new_user_is, userManager.getSerialNumberForUser(newUserHandle))) } if(newUserHandle != null) { Text(text = stringResource(R.string.serial_number_of_new_user_is, userManager.getSerialNumberForUser(newUserHandle))) }
Spacer(Modifier.padding(vertical = 30.dp))
} }
} }
@SuppressLint("NewApi") @SuppressLint("NewApi")
@Composable @Composable
private fun AffiliationID() { fun AffiliationID(navCtrl: NavHostController) {
val context = LocalContext.current val context = LocalContext.current
val dpm = context.getDPM() val dpm = context.getDPM()
val receiver = context.getReceiver() val receiver = context.getReceiver()
@@ -441,10 +372,7 @@ private fun AffiliationID() {
list.addAll(dpm.getAffiliationIds(receiver)) list.addAll(dpm.getAffiliationIds(receiver))
} }
LaunchedEffect(Unit) { refreshIds() } LaunchedEffect(Unit) { refreshIds() }
Column(modifier = Modifier.fillMaxSize().padding(horizontal = 8.dp).verticalScroll(rememberScrollState())) { MyScaffold(R.string.affiliation_id, 8.dp, navCtrl) {
Spacer(Modifier.padding(vertical = 10.dp))
Text(text = stringResource(R.string.affiliation_id), style = typography.headlineLarge)
Spacer(Modifier.padding(vertical = 5.dp))
Column(modifier = Modifier.animateContentSize()) { Column(modifier = Modifier.animateContentSize()) {
if(list.isEmpty()) Text(stringResource(R.string.none)) if(list.isEmpty()) Text(stringResource(R.string.none))
for(i in list) { for(i in list) {
@@ -483,21 +411,17 @@ private fun AffiliationID() {
Text(stringResource(R.string.apply)) Text(stringResource(R.string.apply))
} }
InfoCard(R.string.info_affiliated_id) InfoCard(R.string.info_affiliated_id)
Spacer(Modifier.padding(vertical = 30.dp))
} }
} }
@Composable @Composable
private fun Username() { fun ChangeUsername(navCtrl: NavHostController) {
val context = LocalContext.current val context = LocalContext.current
val dpm = context.getDPM() val dpm = context.getDPM()
val receiver = context.getReceiver() val receiver = context.getReceiver()
val focusMgr = LocalFocusManager.current val focusMgr = LocalFocusManager.current
var inputUsername by remember { mutableStateOf("") } var inputUsername by remember { mutableStateOf("") }
Column(modifier = Modifier.fillMaxSize().padding(horizontal = 8.dp).verticalScroll(rememberScrollState())) { MyScaffold(R.string.change_username, 8.dp, navCtrl) {
Spacer(Modifier.padding(vertical = 10.dp))
Text(text = stringResource(R.string.change_username), style = typography.headlineLarge)
Spacer(Modifier.padding(vertical = 5.dp))
OutlinedTextField( OutlinedTextField(
value = inputUsername, value = inputUsername,
onValueChange = { inputUsername= it }, onValueChange = { inputUsername= it },
@@ -527,7 +451,7 @@ private fun Username() {
@SuppressLint("NewApi") @SuppressLint("NewApi")
@Composable @Composable
private fun UserSessionMessage() { fun UserSessionMessage(navCtrl: NavHostController) {
val context = LocalContext.current val context = LocalContext.current
val dpm = context.getDPM() val dpm = context.getDPM()
val receiver = context.getReceiver() val receiver = context.getReceiver()
@@ -539,10 +463,7 @@ private fun UserSessionMessage() {
end = dpm.getEndUserSessionMessage(receiver)?.toString() ?: "" end = dpm.getEndUserSessionMessage(receiver)?.toString() ?: ""
} }
LaunchedEffect(Unit) { refreshMsg() } LaunchedEffect(Unit) { refreshMsg() }
Column(modifier = Modifier.fillMaxSize().padding(horizontal = 8.dp).verticalScroll(rememberScrollState())) { MyScaffold(R.string.user_session_msg, 8.dp, navCtrl) {
Spacer(Modifier.padding(vertical = 10.dp))
Text(text = stringResource(R.string.user_session_msg), style = typography.headlineLarge)
Spacer(Modifier.padding(vertical = 5.dp))
OutlinedTextField( OutlinedTextField(
value = start, value = start,
onValueChange = { start= it }, onValueChange = { start= it },
@@ -604,13 +525,12 @@ private fun UserSessionMessage() {
Text(stringResource(R.string.reset)) Text(stringResource(R.string.reset))
} }
} }
Spacer(Modifier.padding(vertical = 30.dp))
} }
} }
@SuppressLint("NewApi") @SuppressLint("NewApi")
@Composable @Composable
private fun UserIcon() { fun ChangeUserIcon(navCtrl: NavHostController) {
val context = LocalContext.current val context = LocalContext.current
val dpm = context.getDPM() val dpm = context.getDPM()
val receiver = context.getReceiver() val receiver = context.getReceiver()
@@ -623,10 +543,7 @@ private fun UserIcon() {
bitmap = BitmapFactory.decodeStream(stream) bitmap = BitmapFactory.decodeStream(stream)
} }
} }
Column(modifier = Modifier.fillMaxSize().padding(horizontal = 8.dp).verticalScroll(rememberScrollState())) { MyScaffold(R.string.change_user_icon, 8.dp, navCtrl) {
Spacer(Modifier.padding(vertical = 10.dp))
Text(text = stringResource(R.string.change_user_icon), style = typography.headlineLarge)
Spacer(Modifier.padding(vertical = 5.dp))
CheckBoxItem(R.string.file_picker_instead_gallery, getContent, { getContent = it }) CheckBoxItem(R.string.file_picker_instead_gallery, getContent, { getContent = it })
Spacer(Modifier.padding(vertical = 5.dp)) Spacer(Modifier.padding(vertical = 5.dp))
Button( Button(

View File

@@ -8,8 +8,10 @@ import androidx.compose.foundation.background
import androidx.compose.foundation.clickable import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.* import androidx.compose.foundation.layout.*
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.text.selection.SelectionContainer import androidx.compose.foundation.text.selection.SelectionContainer
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.Info import androidx.compose.material.icons.outlined.Info
import androidx.compose.material3.* import androidx.compose.material3.*
@@ -18,11 +20,13 @@ import androidx.compose.material3.MaterialTheme.typography
import androidx.compose.runtime.* import androidx.compose.runtime.*
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.alpha
import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.navigation.NavBackStackEntry import androidx.navigation.NavBackStackEntry
import androidx.navigation.NavHostController import androidx.navigation.NavHostController
@@ -33,9 +37,9 @@ import kotlinx.coroutines.delay
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
@Composable @Composable
fun SubPageItem( fun FunctionItem(
@StringRes title: Int, @StringRes title: Int,
desc:String, desc: String,
@DrawableRes icon: Int? = null, @DrawableRes icon: Int? = null,
operation: () -> Unit operation: () -> Unit
) { ) {
@@ -48,8 +52,7 @@ fun SubPageItem(
verticalAlignment = Alignment.CenterVertically verticalAlignment = Alignment.CenterVertically
) { ) {
if(icon != null) Icon( if(icon != null) Icon(
painter = painterResource(icon), painter = painterResource(icon), contentDescription = null,
contentDescription = null,
modifier = Modifier.padding(top = 1.dp, end = 20.dp).offset(x = (-2).dp) modifier = Modifier.padding(top = 1.dp, end = 20.dp).offset(x = (-2).dp)
) )
Column { Column {
@@ -194,25 +197,6 @@ fun SwitchItem(
} }
} }
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun TopBar(
backStackEntry: NavBackStackEntry?,
navCtrl: NavHostController,
localNavCtrl: NavHostController,
title: @Composable ()->Unit = {}
) {
TopAppBar(
title = title,
navigationIcon = {
NavIcon{
if(backStackEntry?.destination?.route == "Home") { navCtrl.navigateUp() } else { localNavCtrl.navigateUp() }
}
},
colors = TopAppBarDefaults.topAppBarColors(containerColor = colorScheme.background)
)
}
@Composable @Composable
fun CopyTextButton(@StringRes label: Int, content: String) { fun CopyTextButton(@StringRes label: Int, content: String) {
val context = LocalContext.current val context = LocalContext.current
@@ -287,6 +271,7 @@ fun ListItem(text: String, onDelete: () -> Unit) {
fun InfoCard(@StringRes strID: Int) { fun InfoCard(@StringRes strID: Int) {
Column( Column(
modifier = Modifier modifier = Modifier
.fillMaxWidth()
.padding(vertical = 8.dp) .padding(vertical = 8.dp)
.clip(RoundedCornerShape(10)) .clip(RoundedCornerShape(10))
.background(color = colorScheme.tertiaryContainer) .background(color = colorScheme.tertiaryContainer)
@@ -296,3 +281,53 @@ fun InfoCard(@StringRes strID: Int) {
Text(stringResource(strID)) Text(stringResource(strID))
} }
} }
@Composable
fun MyScaffold(
@StringRes title: Int,
horizonPadding: Dp,
navCtrl: NavHostController,
displayTitle: Boolean = true,
content: @Composable ColumnScope.() -> Unit
) = MyScaffold(title, horizonPadding, { navCtrl.navigateUp() }, displayTitle, content)
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun MyScaffold(
@StringRes title: Int,
horizonPadding: Dp,
onNavIconClicked: () -> Unit,
displayTitle: Boolean,
content: @Composable ColumnScope.() -> Unit
) {
val scrollState = rememberScrollState()
Scaffold(
topBar = {
TopAppBar(
title = {
Text(
text = stringResource(title),
modifier = if(displayTitle) Modifier.alpha((maxOf(scrollState.value-90,0)).toFloat()/50) else Modifier
)
},
navigationIcon = { NavIcon (onNavIconClicked) }
)
}
) { paddingValues ->
Column(
modifier = Modifier
.fillMaxSize()
.padding(paddingValues)
.padding(horizontal = horizonPadding)
.verticalScroll(scrollState)
.padding(bottom = 80.dp)
) {
if(displayTitle) Text(
text = stringResource(title),
style = typography.headlineLarge,
modifier = Modifier.padding(start = if(horizonPadding == 0.dp) 16.dp else 0.dp,top = 10.dp, bottom = 5.dp)
)
content()
}
}
}

View File

@@ -91,8 +91,8 @@
<string name="account_type">Тип аккаунта</string> <string name="account_type">Тип аккаунта</string>
<string name="transfer_ownership">Передача прав владения</string> <string name="transfer_ownership">Передача прав владения</string>
<string name="target_component_name">Имя целевого компонента</string> <string name="target_component_name">Имя целевого компонента</string>
<string name="device_owner_lock_screen_info">Информация на экране блокировки</string> <string name="lock_screen_info">Информация на экране блокировки</string>
<string name="support_msg">Сообщение поддержки</string> <string name="support_messages">Сообщение поддержки</string>
<string name="short_support_msg">Краткое сообщение</string> <string name="short_support_msg">Краткое сообщение</string>
<string name="long_support_msg">Подробное сообщение</string> <string name="long_support_msg">Подробное сообщение</string>
<string name="transfer">Передать</string> <string name="transfer">Передать</string>
@@ -175,7 +175,7 @@
<string name="cert_installed">Сертификат установлен: %1$s</string> <string name="cert_installed">Сертификат установлен: %1$s</string>
<string name="select_ca_cert" tools:ignore="TypographyEllipsis">Выберите сертификат...</string> <string name="select_ca_cert" tools:ignore="TypographyEllipsis">Выберите сертификат...</string>
<string name="uninstall_all_user_ca_cert">Удалить все пользовательские CA-сертификаты</string> <string name="uninstall_all_user_ca_cert">Удалить все пользовательские CA-сертификаты</string>
<string name="security_logs">Журналы безопасности</string> <string name="security_logging">Security logging</string> <!--TODO-->
<string name="pre_reboot_security_logs">Журналы безопасности перед перезагрузкой</string> <string name="pre_reboot_security_logs">Журналы безопасности перед перезагрузкой</string>
<string name="wipe_data">Стереть данные</string> <string name="wipe_data">Стереть данные</string>
<string name="wipe_external_storage">Стереть внешнее хранилище</string> <string name="wipe_external_storage">Стереть внешнее хранилище</string>
@@ -186,7 +186,6 @@
<string name="wipe_work_profile_warning">Ваш рабочий профиль будет УДАЛЕН</string> <string name="wipe_work_profile_warning">Ваш рабочий профиль будет УДАЛЕН</string>
<string name="encryption_status">Статус шифрования</string> <string name="encryption_status">Статус шифрования</string>
<string name="frp_policy">Политика FRP</string> <string name="frp_policy">Политика FRP</string>
<string name="factory_reset_protection_policy">Политика защиты от сброса к заводским настройкам</string>
<string name="frp_policy_not_supported">Политика FRP не поддерживается на этом устройстве</string> <string name="frp_policy_not_supported">Политика FRP не поддерживается на этом устройстве</string>
<string name="enable_frp">Включить FRP</string> <string name="enable_frp">Включить FRP</string>
<string name="account_list_is">Список аккаунтов: </string> <string name="account_list_is">Список аккаунтов: </string>
@@ -236,12 +235,11 @@
<string name="specify_port">Указать порт</string> <string name="specify_port">Указать порт</string>
<string name="invalid_config">Неверная конфигурация</string> <string name="invalid_config">Неверная конфигурация</string>
<string name="exclude_hosts">Исключить хосты</string> <string name="exclude_hosts">Исключить хосты</string>
<string name="retrieve_net_logs">Журналы сети</string> <string name="network_logging">Network logging</string> <!--TODO-->
<string name="log_file_size_is">Размер файла журнала: %1$s</string> <string name="log_file_size_is">Размер файла журнала: %1$s</string>
<string name="delete_logs">Удалить журналы</string> <string name="delete_logs">Удалить журналы</string>
<string name="export_logs">Экспортировать журналы</string> <string name="export_logs">Экспортировать журналы</string>
<string name="wifi_auth_keypair">Пара ключей Wi-Fi</string> <string name="wifi_auth_keypair">Пара ключей Wi-Fi</string>
<string name="keypair">Пара ключей</string>
<string name="preferential_network_service">Предпочтительная сетевая служба</string> <string name="preferential_network_service">Предпочтительная сетевая служба</string>
<string name="network_id">Идентификатор сети</string> <string name="network_id">Идентификатор сети</string>
<string name="allow_fallback_to_default_connection">Разрешить переход на соединение по умолчанию</string> <string name="allow_fallback_to_default_connection">Разрешить переход на соединение по умолчанию</string>
@@ -286,7 +284,6 @@
<string name="migrate_account">Перенести аккаунт</string> <string name="migrate_account">Перенести аккаунт</string>
<string name="account_name">Имя аккаунта</string> <string name="account_name">Имя аккаунта</string>
<string name="keep_account">Сохранить аккаунт</string> <string name="keep_account">Сохранить аккаунт</string>
<string name="is_org_owned_profile">Рабочий профиль принадлежит организации: %1$s</string>
<string name="org_owned_work_profile">Рабочий профиль организации</string> <string name="org_owned_work_profile">Рабочий профиль организации</string>
<string name="skip_encryption">Пропустить шифрование</string> <string name="skip_encryption">Пропустить шифрование</string>
<string name="create">Создать</string> <string name="create">Создать</string>
@@ -316,7 +313,7 @@
<string name="always_on_vpn">Постоянный VPN</string> <string name="always_on_vpn">Постоянный VPN</string>
<string name="enable_lockdown">Включить блокировку</string> <string name="enable_lockdown">Включить блокировку</string>
<string name="clear_current_config">Очистить текущую конфигурацию</string> <string name="clear_current_config">Очистить текущую конфигурацию</string>
<string name="permission">Разрешение</string> <string name="permissions">Разрешение</string>
<string name="scope_is_work_profile">Область действия: рабочий профиль</string> <string name="scope_is_work_profile">Область действия: рабочий профиль</string>
<string name="app_info">Информация о приложении</string> <string name="app_info">Информация о приложении</string>
<string name="not_installed">Не установлено</string> <string name="not_installed">Не установлено</string>
@@ -366,12 +363,12 @@
<!--Ограничения пользователя--> <!--Ограничения пользователя-->
<string name="user_restrict">Ограничения пользователя</string> <string name="user_restriction">Ограничения пользователя</string>
<string name="profile_owner_is_restricted">Владелец профиля может использовать ограниченные функции</string> <string name="profile_owner_is_restricted">Владелец профиля может использовать ограниченные функции</string>
<string name="switch_to_disable_feature">Включите переключатель, чтобы отключить эту функцию.</string> <string name="switch_to_disable_feature">Включите переключатель, чтобы отключить эту функцию.</string>
<string name="some_features_invalid_in_work_profile">Функции в рабочем профиле ограничены.</string> <string name="some_features_invalid_in_work_profile">Функции в рабочем профиле ограничены.</string>
<string name="network_internet">Сеть</string> <string name="network_and_internet">Сеть</string>
<string name="more_connectivity">Другие подключения</string> <string name="connectivity">Другие подключения</string>
<string name="media">Медиа</string> <string name="media">Медиа</string>
<string name="other">Другое</string> <string name="other">Другое</string>
<string name="require_device_owner">Требуется владелец устройства</string> <string name="require_device_owner">Требуется владелец устройства</string>
@@ -478,7 +475,6 @@
<string name="change_user_icon">Изменить значок пользователя</string> <string name="change_user_icon">Изменить значок пользователя</string>
<string name="file_picker_instead_gallery">Использовать выборщик файлов вместо галереи</string> <string name="file_picker_instead_gallery">Использовать выборщик файлов вместо галереи</string>
<string name="select_picture" tools:ignore="TypographyEllipsis">Выберите изображение...</string> <string name="select_picture" tools:ignore="TypographyEllipsis">Выберите изображение...</string>
<string name="unknown_result">Неизвестный результат (возможно, ошибка)</string>
<string name="fail_managed_profile">Ошибка: управляемый профиль</string> <string name="fail_managed_profile">Ошибка: управляемый профиль</string>
<string name="fail_current_user">Ошибка: текущий пользователь</string> <string name="fail_current_user">Ошибка: текущий пользователь</string>
<string name="user_session_msg">Сообщение о сеансе пользователя</string> <string name="user_session_msg">Сообщение о сеансе пользователя</string>

View File

@@ -92,8 +92,8 @@
<string name="account_type">Hesap Türleri</string> <string name="account_type">Hesap Türleri</string>
<string name="transfer_ownership">Sahipliği Devret</string> <string name="transfer_ownership">Sahipliği Devret</string>
<string name="target_component_name">Target component name</string> <!--TODO--> <string name="target_component_name">Target component name</string> <!--TODO-->
<string name="device_owner_lock_screen_info">Ekran Kilidi Bilgisi</string> <string name="lock_screen_info">Ekran Kilidi Bilgisi</string>
<string name="support_msg">Destek Mesajı</string> <string name="support_messages">Destek Mesajı</string>
<string name="short_support_msg">Kısa Mesaj</string> <string name="short_support_msg">Kısa Mesaj</string>
<string name="long_support_msg">Uzun Mesaj</string> <string name="long_support_msg">Uzun Mesaj</string>
<string name="transfer">Transfer</string> <string name="transfer">Transfer</string>
@@ -177,7 +177,7 @@
<string name="cert_installed">Yüklenen sertifika: %1$s</string> <!--TODO--> <string name="cert_installed">Yüklenen sertifika: %1$s</string> <!--TODO-->
<string name="select_ca_cert" tools:ignore="TypographyEllipsis">Sertifika seç...</string> <!--TODO--> <string name="select_ca_cert" tools:ignore="TypographyEllipsis">Sertifika seç...</string> <!--TODO-->
<string name="uninstall_all_user_ca_cert">Tüm kullanıcı sertifikalarını kaldır</string> <!--TODO--> <string name="uninstall_all_user_ca_cert">Tüm kullanıcı sertifikalarını kaldır</string> <!--TODO-->
<string name="security_logs">Güvenlik kayıtları</string> <string name="security_logging">Security logging</string> <!--TODO-->
<string name="pre_reboot_security_logs">Yeniden başlatmadan önce güvenlik kayıtları</string> <string name="pre_reboot_security_logs">Yeniden başlatmadan önce güvenlik kayıtları</string>
<string name="wipe_data">Verileri sil</string> <string name="wipe_data">Verileri sil</string>
<string name="wipe_external_storage">Harici depolamayı sil</string> <string name="wipe_external_storage">Harici depolamayı sil</string>
@@ -188,7 +188,6 @@
<string name="wipe_work_profile_warning">Your work profile will be DELETED</string> <!--TODO--> <string name="wipe_work_profile_warning">Your work profile will be DELETED</string> <!--TODO-->
<string name="encryption_status">Encryption status</string> <!--TODO--> <string name="encryption_status">Encryption status</string> <!--TODO-->
<string name="frp_policy">FRP politikası</string> <string name="frp_policy">FRP politikası</string>
<string name="factory_reset_protection_policy">Fabrika ayarlarına sıfırlama koruma politikası</string>
<string name="frp_policy_not_supported">FRP politikası bu cihazda desteklenmiyor</string> <string name="frp_policy_not_supported">FRP politikası bu cihazda desteklenmiyor</string>
<string name="enable_frp">FRP\'yi etkinleştir</string> <string name="enable_frp">FRP\'yi etkinleştir</string>
<string name="account_list_is">"Hesap listesi: "</string> <string name="account_list_is">"Hesap listesi: "</string>
@@ -237,12 +236,11 @@
<string name="specify_port">Specify port</string> <!--TODO--> <string name="specify_port">Specify port</string> <!--TODO-->
<string name="invalid_config">Invalid config</string> <!--TODO--> <string name="invalid_config">Invalid config</string> <!--TODO-->
<string name="exclude_hosts">Exclude hosts</string> <!--TODO--> <string name="exclude_hosts">Exclude hosts</string> <!--TODO-->
<string name="retrieve_net_logs">Ağ kayıtları</string> <string name="network_logging">Network logging</string> <!--TODO-->
<string name="log_file_size_is">Log file size: %1$s</string> <!--TODO--> <string name="log_file_size_is">Log file size: %1$s</string> <!--TODO-->
<string name="delete_logs">Delete logs</string> <!--TODO--> <string name="delete_logs">Delete logs</string> <!--TODO-->
<string name="export_logs">Export logs</string> <!--TODO--> <string name="export_logs">Export logs</string> <!--TODO-->
<string name="wifi_auth_keypair">Wi-Fi anahtar çifti</string> <string name="wifi_auth_keypair">Wi-Fi anahtar çifti</string>
<string name="keypair">Anahtar çifti</string>
<string name="preferential_network_service">Tercihli ağ hizmeti</string> <string name="preferential_network_service">Tercihli ağ hizmeti</string>
<string name="network_id">Network ID</string> <!--TODO--> <string name="network_id">Network ID</string> <!--TODO-->
<string name="allow_fallback_to_default_connection">Allow fallback to default connection</string> <!--TODO--> <string name="allow_fallback_to_default_connection">Allow fallback to default connection</string> <!--TODO-->
@@ -285,7 +283,6 @@
<string name="migrate_account">Migrate account</string> <!--TODO--> <string name="migrate_account">Migrate account</string> <!--TODO-->
<string name="account_name">Account name</string> <!--TODO--> <string name="account_name">Account name</string> <!--TODO-->
<string name="keep_account">Keep account</string> <!--TODO--> <string name="keep_account">Keep account</string> <!--TODO-->
<string name="is_org_owned_profile">Kuruluşa ait iş profili: %1$s</string>
<string name="org_owned_work_profile">Kuruluş iş profili</string> <string name="org_owned_work_profile">Kuruluş iş profili</string>
<string name="skip_encryption">Şifrelemeyi atla</string> <string name="skip_encryption">Şifrelemeyi atla</string>
<string name="create">Oluştur</string> <string name="create">Oluştur</string>
@@ -314,7 +311,7 @@
<string name="always_on_vpn">Her zaman açık VPN</string> <string name="always_on_vpn">Her zaman açık VPN</string>
<string name="enable_lockdown">Enable lockdown</string> <!--TODO--> <string name="enable_lockdown">Enable lockdown</string> <!--TODO-->
<string name="clear_current_config">Clear current config</string> <!--TODO--> <string name="clear_current_config">Clear current config</string> <!--TODO-->
<string name="permission">İzin</string> <string name="permissions">İzin</string>
<string name="scope_is_work_profile">Kapsam: iş profili</string> <string name="scope_is_work_profile">Kapsam: iş profili</string>
<string name="app_info">Uygulama bilgisi</string> <string name="app_info">Uygulama bilgisi</string>
<string name="not_installed">Yüklü değil</string> <string name="not_installed">Yüklü değil</string>
@@ -365,12 +362,12 @@
<string name="status_fail_timeout">Başarısız: zaman aşımı</string> <string name="status_fail_timeout">Başarısız: zaman aşımı</string>
<!--UserRestriction--> <!--UserRestriction-->
<string name="user_restrict">Kullanıcı kısıtlaması</string> <string name="user_restriction">Kullanıcı kısıtlaması</string>
<string name="profile_owner_is_restricted">Profil sahibi sınırlı işlev kullanabilir</string> <string name="profile_owner_is_restricted">Profil sahibi sınırlı işlev kullanabilir</string>
<string name="switch_to_disable_feature">Bu işlevi devre dışı bırakmak için bir anahtar açın. </string> <string name="switch_to_disable_feature">Bu işlevi devre dışı bırakmak için bir anahtar açın. </string>
<string name="some_features_invalid_in_work_profile">İş profilindeki işlevler sınırlıdır. </string> <string name="some_features_invalid_in_work_profile">İş profilindeki işlevler sınırlıdır. </string>
<string name="network_internet"></string> <string name="network_and_internet"></string>
<string name="more_connectivity">Diğer bağlantı</string> <string name="connectivity">Diğer bağlantı</string>
<string name="media">Medya</string> <string name="media">Medya</string>
<string name="other">Diğer</string> <string name="other">Diğer</string>
<string name="require_device_owner">Cihaz sahibi gerektirir</string> <string name="require_device_owner">Cihaz sahibi gerektirir</string>
@@ -476,7 +473,6 @@
<string name="change_user_icon">Kullanıcı simgesini değiştir</string> <string name="change_user_icon">Kullanıcı simgesini değiştir</string>
<string name="file_picker_instead_gallery">Galeri yerine dosya seçici kullan</string> <string name="file_picker_instead_gallery">Galeri yerine dosya seçici kullan</string>
<string name="select_picture" tools:ignore="TypographyEllipsis">Resim seç...</string> <string name="select_picture" tools:ignore="TypographyEllipsis">Resim seç...</string>
<string name="unknown_result">Bilinmeyen sonuç (başarısız olabilir)</string>
<string name="fail_managed_profile">Başarısız: yönetilen profil</string> <string name="fail_managed_profile">Başarısız: yönetilen profil</string>
<string name="fail_current_user">Başarısız: mevcut kullanıcı</string> <string name="fail_current_user">Başarısız: mevcut kullanıcı</string>
<string name="user_session_msg">Kullanıcı oturum mesajı</string> <string name="user_session_msg">Kullanıcı oturum mesajı</string>

View File

@@ -87,8 +87,8 @@
<string name="account_type">账号类型</string> <string name="account_type">账号类型</string>
<string name="transfer_ownership">转移所有权</string> <string name="transfer_ownership">转移所有权</string>
<string name="target_component_name">目标组件名</string> <string name="target_component_name">目标组件名</string>
<string name="device_owner_lock_screen_info">锁屏提示信息</string> <string name="lock_screen_info">锁屏提示信息</string>
<string name="support_msg">提供支持的消息</string> <string name="support_messages">提供支持的消息</string>
<string name="short_support_msg">提供支持的短消息</string> <string name="short_support_msg">提供支持的短消息</string>
<string name="long_support_msg">提供支持的长消息</string> <string name="long_support_msg">提供支持的长消息</string>
<string name="transfer">转移</string> <string name="transfer">转移</string>
@@ -172,7 +172,7 @@
<string name="cert_installed">证书已安装:%1$s</string> <string name="cert_installed">证书已安装:%1$s</string>
<string name="select_ca_cert" tools:ignore="TypographyEllipsis">选择证书...</string> <string name="select_ca_cert" tools:ignore="TypographyEllipsis">选择证书...</string>
<string name="uninstall_all_user_ca_cert">卸载所有用户证书</string> <string name="uninstall_all_user_ca_cert">卸载所有用户证书</string>
<string name="security_logs">安全日志</string> <string name="security_logging">安全日志</string>
<string name="pre_reboot_security_logs">重启前安全日志</string> <string name="pre_reboot_security_logs">重启前安全日志</string>
<string name="wipe_data">清除数据</string> <string name="wipe_data">清除数据</string>
<string name="wipe_external_storage">清除外部存储</string> <string name="wipe_external_storage">清除外部存储</string>
@@ -183,7 +183,6 @@
<string name="wipe_work_profile_warning">你的工作资料将会被删除</string> <string name="wipe_work_profile_warning">你的工作资料将会被删除</string>
<string name="encryption_status">加密状态</string> <string name="encryption_status">加密状态</string>
<string name="frp_policy">FRP策略</string> <string name="frp_policy">FRP策略</string>
<string name="factory_reset_protection_policy">恢复出厂设置保护策略</string>
<string name="frp_policy_not_supported">这个设备不支持恢复出厂设置保护策略</string> <string name="frp_policy_not_supported">这个设备不支持恢复出厂设置保护策略</string>
<string name="enable_frp">启用FRP</string> <string name="enable_frp">启用FRP</string>
<string name="account_list_is">账户列表:</string> <string name="account_list_is">账户列表:</string>
@@ -232,12 +231,11 @@
<string name="specify_port">指定端口</string> <string name="specify_port">指定端口</string>
<string name="invalid_config">无效配置</string> <string name="invalid_config">无效配置</string>
<string name="exclude_hosts">排除列表</string> <string name="exclude_hosts">排除列表</string>
<string name="retrieve_net_logs">收集网络日志</string> <string name="network_logging">网络日志</string>
<string name="log_file_size_is">日志文件大小:%1$s</string> <string name="log_file_size_is">日志文件大小:%1$s</string>
<string name="delete_logs">删除日志</string> <string name="delete_logs">删除日志</string>
<string name="export_logs">导出日志</string> <string name="export_logs">导出日志</string>
<string name="wifi_auth_keypair">Wi-Fi密钥对</string> <string name="wifi_auth_keypair">Wi-Fi密钥对</string>
<string name="keypair">密钥对</string>
<string name="preferential_network_service">首选网络服务</string> <string name="preferential_network_service">首选网络服务</string>
<string name="network_id">网络ID</string> <string name="network_id">网络ID</string>
<string name="allow_fallback_to_default_connection">允许回落到默认连接</string> <string name="allow_fallback_to_default_connection">允许回落到默认连接</string>
@@ -280,7 +278,6 @@
<string name="migrate_account">迁移账号</string> <string name="migrate_account">迁移账号</string>
<string name="account_name">账号名</string> <string name="account_name">账号名</string>
<string name="keep_account">保留账号</string> <string name="keep_account">保留账号</string>
<string name="is_org_owned_profile">由组织拥有的工作资料:%1$s</string>
<string name="org_owned_work_profile">组织拥有的工作资料</string> <string name="org_owned_work_profile">组织拥有的工作资料</string>
<string name="skip_encryption">跳过加密</string> <string name="skip_encryption">跳过加密</string>
<string name="create">创建</string> <string name="create">创建</string>
@@ -309,7 +306,7 @@
<string name="always_on_vpn">VPN保持打开</string> <string name="always_on_vpn">VPN保持打开</string>
<string name="enable_lockdown">启用锁定</string> <string name="enable_lockdown">启用锁定</string>
<string name="clear_current_config">清除当前配置</string> <string name="clear_current_config">清除当前配置</string>
<string name="permission">权限</string> <string name="permissions">权限</string>
<string name="scope_is_work_profile">作用域: 工作资料</string> <string name="scope_is_work_profile">作用域: 工作资料</string>
<string name="app_info">应用详情</string> <string name="app_info">应用详情</string>
<string name="not_installed">未安装</string> <string name="not_installed">未安装</string>
@@ -357,12 +354,12 @@
<string name="status_fail_timeout">超时</string> <string name="status_fail_timeout">超时</string>
<!--UserRestriction--> <!--UserRestriction-->
<string name="user_restrict">用户限制</string> <string name="user_restriction">用户限制</string>
<string name="profile_owner_is_restricted">Profile owner无法使用部分功能</string> <string name="profile_owner_is_restricted">Profile owner无法使用部分功能</string>
<string name="switch_to_disable_feature">打开开关后会禁用对应的功能</string> <string name="switch_to_disable_feature">打开开关后会禁用对应的功能</string>
<string name="some_features_invalid_in_work_profile">工作资料中部分功能无效</string> <string name="some_features_invalid_in_work_profile">工作资料中部分功能无效</string>
<string name="network_internet">网络和互联网</string> <string name="network_and_internet">网络和互联网</string>
<string name="more_connectivity">更多连接</string> <string name="connectivity">更多连接</string>
<string name="media">媒体</string> <string name="media">媒体</string>
<string name="other">其他</string> <string name="other">其他</string>
<string name="require_device_owner">需要DeviceOwner</string> <string name="require_device_owner">需要DeviceOwner</string>
@@ -468,7 +465,6 @@
<string name="change_user_icon">更换用户头像</string> <string name="change_user_icon">更换用户头像</string>
<string name="file_picker_instead_gallery">使用文件选择器而不是相册</string> <string name="file_picker_instead_gallery">使用文件选择器而不是相册</string>
<string name="select_picture" tools:ignore="TypographyEllipsis">选择图片...</string> <string name="select_picture" tools:ignore="TypographyEllipsis">选择图片...</string>
<string name="unknown_result">未知结果(失败)</string>
<string name="fail_managed_profile">失败:受管理的资料</string> <string name="fail_managed_profile">失败:受管理的资料</string>
<string name="fail_current_user">失败:当前用户</string> <string name="fail_current_user">失败:当前用户</string>
<string name="user_session_msg">用户会话消息</string> <string name="user_session_msg">用户会话消息</string>

View File

@@ -94,8 +94,8 @@
<string name="account_type">Account type</string> <string name="account_type">Account type</string>
<string name="transfer_ownership">Transfer Ownership</string> <string name="transfer_ownership">Transfer Ownership</string>
<string name="target_component_name">Target component name</string> <string name="target_component_name">Target component name</string>
<string name="device_owner_lock_screen_info">Lockscreen info</string> <string name="lock_screen_info">Lockscreen info</string>
<string name="support_msg">Support Message</string> <string name="support_messages">Support Messages</string>
<string name="short_support_msg">Short message</string> <string name="short_support_msg">Short message</string>
<string name="long_support_msg">Long message</string> <string name="long_support_msg">Long message</string>
<string name="transfer">Transfer</string> <string name="transfer">Transfer</string>
@@ -181,7 +181,7 @@
<string name="cert_installed">Certificate installed: %1$s</string> <string name="cert_installed">Certificate installed: %1$s</string>
<string name="select_ca_cert" tools:ignore="TypographyEllipsis">Select certificate...</string> <string name="select_ca_cert" tools:ignore="TypographyEllipsis">Select certificate...</string>
<string name="uninstall_all_user_ca_cert">Uninstall all user CA certificate</string> <string name="uninstall_all_user_ca_cert">Uninstall all user CA certificate</string>
<string name="security_logs">Security logs</string> <string name="security_logging">Security logging</string>
<string name="pre_reboot_security_logs">Pre-reboot security logs</string> <string name="pre_reboot_security_logs">Pre-reboot security logs</string>
<string name="wipe_data">Wipe data</string> <string name="wipe_data">Wipe data</string>
<string name="wipe_external_storage">Wipe external storage</string> <string name="wipe_external_storage">Wipe external storage</string>
@@ -192,7 +192,6 @@
<string name="wipe_work_profile_warning">Your work profile will be DELETED</string> <string name="wipe_work_profile_warning">Your work profile will be DELETED</string>
<string name="encryption_status">Encryption status</string> <string name="encryption_status">Encryption status</string>
<string name="frp_policy">FRP policy</string> <string name="frp_policy">FRP policy</string>
<string name="factory_reset_protection_policy">Factory reset protection policy</string>
<string name="frp_policy_not_supported">FRP policy is not supported on this device</string> <string name="frp_policy_not_supported">FRP policy is not supported on this device</string>
<string name="enable_frp">Enable FRP</string> <string name="enable_frp">Enable FRP</string>
<string name="account_list_is">"Account list: "</string> <string name="account_list_is">"Account list: "</string>
@@ -242,12 +241,11 @@
<string name="specify_port">Specify port</string> <string name="specify_port">Specify port</string>
<string name="invalid_config">Invalid config</string> <string name="invalid_config">Invalid config</string>
<string name="exclude_hosts">Exclude hosts</string> <string name="exclude_hosts">Exclude hosts</string>
<string name="retrieve_net_logs">Network logs</string> <string name="network_logging">Network logging</string>
<string name="log_file_size_is">Log file size: %1$s</string> <string name="log_file_size_is">Log file size: %1$s</string>
<string name="delete_logs">Delete logs</string> <string name="delete_logs">Delete logs</string>
<string name="export_logs">Export logs</string> <string name="export_logs">Export logs</string>
<string name="wifi_auth_keypair">Wi-Fi keypair</string> <string name="wifi_auth_keypair">Wi-Fi keypair</string>
<string name="keypair">Keypair</string>
<string name="preferential_network_service">Preferential network service</string> <string name="preferential_network_service">Preferential network service</string>
<string name="network_id">Network ID</string> <string name="network_id">Network ID</string>
<string name="allow_fallback_to_default_connection">Allow fallback to default connection</string> <string name="allow_fallback_to_default_connection">Allow fallback to default connection</string>
@@ -290,7 +288,6 @@
<string name="migrate_account">Migrate account</string> <string name="migrate_account">Migrate account</string>
<string name="account_name">Account name</string> <string name="account_name">Account name</string>
<string name="keep_account">Keep account</string> <string name="keep_account">Keep account</string>
<string name="is_org_owned_profile">Organization owned work profile: %1$s</string>
<string name="org_owned_work_profile">Organization work profile</string> <string name="org_owned_work_profile">Organization work profile</string>
<string name="activate_org_profile_command" tools:ignore="TypographyDashes" translatable="false"> <string name="activate_org_profile_command" tools:ignore="TypographyDashes" translatable="false">
dpm mark-profile-owner-on-organization-owned-device --user %1$s com.bintianqi.owndroid/com.bintianqi.owndroid.Receiver dpm mark-profile-owner-on-organization-owned-device --user %1$s com.bintianqi.owndroid/com.bintianqi.owndroid.Receiver
@@ -322,7 +319,7 @@
<string name="always_on_vpn">Always-on VPN</string> <string name="always_on_vpn">Always-on VPN</string>
<string name="enable_lockdown">Enable lockdown</string> <string name="enable_lockdown">Enable lockdown</string>
<string name="clear_current_config">Clear current config</string> <string name="clear_current_config">Clear current config</string>
<string name="permission">Permission</string> <string name="permissions">Permissions</string>
<string name="scope_is_work_profile">Scope: work profile</string> <string name="scope_is_work_profile">Scope: work profile</string>
<string name="app_info">App info</string> <string name="app_info">App info</string>
<string name="not_installed">Not installed</string> <string name="not_installed">Not installed</string>
@@ -371,12 +368,12 @@
<string name="status_fail_timeout">Fail: timeout</string> <string name="status_fail_timeout">Fail: timeout</string>
<!--UserRestriction--> <!--UserRestriction-->
<string name="user_restrict">User restriction</string> <string name="user_restriction">User restriction</string>
<string name="profile_owner_is_restricted">Profile owner can use limited function</string> <string name="profile_owner_is_restricted">Profile owner can use limited function</string>
<string name="switch_to_disable_feature">Turn on a switch to disable that function. </string> <string name="switch_to_disable_feature">Turn on a switch to disable that function. </string>
<string name="some_features_invalid_in_work_profile">Functions in work profile is limited. </string> <string name="some_features_invalid_in_work_profile">Functions in work profile is limited. </string>
<string name="network_internet">Network</string> <string name="network_and_internet">Network</string>
<string name="more_connectivity">Other connection</string> <string name="connectivity">Other connection</string>
<string name="media">Media</string> <string name="media">Media</string>
<string name="other">Other</string> <string name="other">Other</string>
<string name="require_device_owner">Require device owner</string> <string name="require_device_owner">Require device owner</string>
@@ -482,7 +479,6 @@
<string name="change_user_icon">Change user icon</string> <string name="change_user_icon">Change user icon</string>
<string name="file_picker_instead_gallery">Use file picker instead of gallery</string> <string name="file_picker_instead_gallery">Use file picker instead of gallery</string>
<string name="select_picture" tools:ignore="TypographyEllipsis">Select image...</string> <string name="select_picture" tools:ignore="TypographyEllipsis">Select image...</string>
<string name="unknown_result">Unknown result(may failed)</string>
<string name="fail_managed_profile">Failed: managed profile</string> <string name="fail_managed_profile">Failed: managed profile</string>
<string name="fail_current_user">Failed: current user</string> <string name="fail_current_user">Failed: current user</string>
<string name="user_session_msg">User session message</string> <string name="user_session_msg">User session message</string>
@@ -631,7 +627,7 @@
<string name="info_security_log">If a Device owner use this function, all users should be affiliated.</string> <string name="info_security_log">If a Device owner use this function, all users should be affiliated.</string>
<string name="info_pre_reboot_security_log">Not all devices support pre-reboot security logs.</string> <string name="info_pre_reboot_security_log">Not all devices support pre-reboot security logs.</string>
<string name="info_disable_account_management">When account management is disabled for an account type, adding or removing an account of that type will not be possible.</string> <string name="info_disable_account_management">When account management is disabled for an account type, adding or removing an account of that type will not be possible.</string>
<string name="info_frp_policy">FRP can protect the device after untrusted factory reset (in Recovery or Fastboot).\nTo enable this feature, the device must support persistent data block service.</string> <string name="info_frp_policy">Factory reset protection can protect the device after untrusted factory reset (in Recovery or Fastboot).\nTo enable this feature, the device must support persistent data block service.</string>
<string name="info_wipe_data_in_managed_user">All data of this user will be wiped, but that user won\'t be removed.</string> <string name="info_wipe_data_in_managed_user">All data of this user will be wiped, but that user won\'t be removed.</string>
<string name="info_lockdown_admin_configured_network">Control whether the user can change networks configured by the admin.\nWhen this lockdown is enabled, the user can still configure and connect to other Wi-Fi networks, or use other Wi-Fi capabilities such as tethering.</string> <string name="info_lockdown_admin_configured_network">Control whether the user can change networks configured by the admin.\nWhen this lockdown is enabled, the user can still configure and connect to other Wi-Fi networks, or use other Wi-Fi capabilities such as tethering.</string>
<string name="info_minimum_wifi_security_level">Specify the minimum security level required for Wi-Fi networks. The device may not connect to networks that do not meet the minimum security level. If the current network does not meet the minimum security level set, it will be disconnected.</string> <string name="info_minimum_wifi_security_level">Specify the minimum security level required for Wi-Fi networks. The device may not connect to networks that do not meet the minimum security level. If the current network does not meet the minimum security level set, it will be disconnected.</string>

View File

@@ -1,14 +1,14 @@
[versions] [versions]
agp = "8.7.2" agp = "8.7.3"
kotlin = "2.0.21" kotlin = "2.0.21"
navigation-compose = "2.8.3" navigation-compose = "2.8.4"
composeBom = "2024.10.01" composeBom = "2024.11.00"
accompanist-drawablepainter = "0.35.0-alpha" accompanist-drawablepainter = "0.35.0-alpha"
shizuku = "13.1.5" shizuku = "13.1.5"
biometric = "1.2.0-alpha05" biometric = "1.2.0-alpha05"
fragment = "1.8.0-beta01" fragment = "1.8.5"
dhizuku = "2.5.2" dhizuku = "2.5.3"
hiddenApiBypass = "4.3" hiddenApiBypass = "4.3"
serialization = "1.7.3" serialization = "1.7.3"