mirror of
https://github.com/awfixers-stuff/OwnDroid.git
synced 2026-03-23 19:15:58 +00:00
Add MyViewModel to keep ThemeSettings state Use ListItem to display SSIDs in WiFi SSID Policy Use green color scheme as default color scheme Add Compose BOM dependency, update dependencies
317 lines
14 KiB
Kotlin
317 lines
14 KiB
Kotlin
package com.bintianqi.owndroid
|
|
|
|
import android.app.admin.DevicePolicyManager
|
|
import android.content.Context
|
|
import android.os.Build.VERSION
|
|
import android.os.Bundle
|
|
import android.widget.Toast
|
|
import androidx.activity.compose.setContent
|
|
import androidx.activity.enableEdgeToEdge
|
|
import androidx.activity.viewModels
|
|
import androidx.compose.foundation.background
|
|
import androidx.compose.foundation.clickable
|
|
import androidx.compose.foundation.gestures.detectTapGestures
|
|
import androidx.compose.foundation.layout.Column
|
|
import androidx.compose.foundation.layout.Row
|
|
import androidx.compose.foundation.layout.Spacer
|
|
import androidx.compose.foundation.layout.fillMaxSize
|
|
import androidx.compose.foundation.layout.fillMaxWidth
|
|
import androidx.compose.foundation.layout.imePadding
|
|
import androidx.compose.foundation.layout.padding
|
|
import androidx.compose.foundation.layout.statusBarsPadding
|
|
import androidx.compose.foundation.rememberScrollState
|
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
|
import androidx.compose.foundation.verticalScroll
|
|
import androidx.compose.material3.AlertDialog
|
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
|
import androidx.compose.material3.Icon
|
|
import androidx.compose.material3.MaterialTheme.colorScheme
|
|
import androidx.compose.material3.MaterialTheme.typography
|
|
import androidx.compose.material3.Text
|
|
import androidx.compose.material3.TextButton
|
|
import androidx.compose.runtime.Composable
|
|
import androidx.compose.runtime.LaunchedEffect
|
|
import androidx.compose.runtime.collectAsState
|
|
import androidx.compose.runtime.getValue
|
|
import androidx.compose.runtime.mutableIntStateOf
|
|
import androidx.compose.runtime.mutableStateOf
|
|
import androidx.compose.runtime.remember
|
|
import androidx.compose.runtime.setValue
|
|
import androidx.compose.ui.Alignment
|
|
import androidx.compose.ui.Modifier
|
|
import androidx.compose.ui.draw.clip
|
|
import androidx.compose.ui.input.pointer.pointerInput
|
|
import androidx.compose.ui.platform.LocalContext
|
|
import androidx.compose.ui.platform.LocalFocusManager
|
|
import androidx.compose.ui.res.painterResource
|
|
import androidx.compose.ui.res.stringResource
|
|
import androidx.compose.ui.unit.dp
|
|
import androidx.core.view.WindowCompat
|
|
import androidx.fragment.app.FragmentActivity
|
|
import androidx.navigation.NavHostController
|
|
import androidx.navigation.compose.NavHost
|
|
import androidx.navigation.compose.composable
|
|
import androidx.navigation.compose.rememberNavController
|
|
import com.bintianqi.owndroid.dpm.ApplicationManage
|
|
import com.bintianqi.owndroid.dpm.DpmPermissions
|
|
import com.bintianqi.owndroid.dpm.ManagedProfile
|
|
import com.bintianqi.owndroid.dpm.Network
|
|
import com.bintianqi.owndroid.dpm.Password
|
|
import com.bintianqi.owndroid.dpm.SystemManage
|
|
import com.bintianqi.owndroid.dpm.UserManage
|
|
import com.bintianqi.owndroid.dpm.UserRestriction
|
|
import com.bintianqi.owndroid.dpm.dhizukuErrorStatus
|
|
import com.bintianqi.owndroid.dpm.getDPM
|
|
import com.bintianqi.owndroid.dpm.getReceiver
|
|
import com.bintianqi.owndroid.dpm.isDeviceAdmin
|
|
import com.bintianqi.owndroid.dpm.isDeviceOwner
|
|
import com.bintianqi.owndroid.dpm.isProfileOwner
|
|
import com.bintianqi.owndroid.dpm.toggleInstallAppActivity
|
|
import com.bintianqi.owndroid.ui.Animations
|
|
import com.bintianqi.owndroid.ui.theme.OwnDroidTheme
|
|
import com.rosan.dhizuku.api.Dhizuku
|
|
import kotlinx.coroutines.delay
|
|
import kotlinx.coroutines.flow.MutableStateFlow
|
|
import org.lsposed.hiddenapibypass.HiddenApiBypass
|
|
import java.util.Locale
|
|
|
|
var backToHomeStateFlow = MutableStateFlow(false)
|
|
@ExperimentalMaterial3Api
|
|
class MainActivity : FragmentActivity() {
|
|
private val showAuth = mutableStateOf(false)
|
|
|
|
override fun onCreate(savedInstanceState: Bundle?) {
|
|
registerActivityResult(this)
|
|
enableEdgeToEdge()
|
|
WindowCompat.setDecorFitsSystemWindows(window, false)
|
|
super.onCreate(savedInstanceState)
|
|
val sharedPref = applicationContext.getSharedPreferences("data", MODE_PRIVATE)
|
|
if (VERSION.SDK_INT >= 28) HiddenApiBypass.setHiddenApiExemptions("")
|
|
if(sharedPref.getBoolean("auth", false)) {
|
|
showAuth.value = true
|
|
}
|
|
val locale = applicationContext.resources?.configuration?.locale
|
|
zhCN = locale == Locale.SIMPLIFIED_CHINESE || locale == Locale.CHINESE || locale == Locale.CHINA
|
|
toggleInstallAppActivity()
|
|
val vm by viewModels<MyViewModel>()
|
|
if(!vm.initialized) vm.initialize(applicationContext)
|
|
setContent {
|
|
OwnDroidTheme(vm) {
|
|
Home(vm)
|
|
if(showAuth.value) {
|
|
AuthScreen(this, showAuth)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
override fun onResume() {
|
|
super.onResume()
|
|
val sharedPref = applicationContext.getSharedPreferences("data", MODE_PRIVATE)
|
|
if(
|
|
sharedPref.getBoolean("auth", false) &&
|
|
sharedPref.getBoolean("lock_in_background", false)
|
|
) {
|
|
showAuth.value = true
|
|
}
|
|
if (sharedPref.getBoolean("dhizuku", false)) {
|
|
if (Dhizuku.init(applicationContext)) {
|
|
if (!Dhizuku.isPermissionGranted()) { dhizukuErrorStatus.value = 2 }
|
|
} else {
|
|
sharedPref.edit().putBoolean("dhizuku", false).apply()
|
|
dhizukuErrorStatus.value = 1
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
@ExperimentalMaterial3Api
|
|
@Composable
|
|
fun Home(vm: MyViewModel) {
|
|
val navCtrl = rememberNavController()
|
|
val context = LocalContext.current
|
|
val dpm = context.getDPM()
|
|
val receiver = context.getReceiver()
|
|
val sharedPref = context.getSharedPreferences("data", Context.MODE_PRIVATE)
|
|
val focusMgr = LocalFocusManager.current
|
|
val dialogStatus = remember { mutableIntStateOf(0) }
|
|
val backToHome by backToHomeStateFlow.collectAsState()
|
|
LaunchedEffect(backToHome) {
|
|
if(backToHome) { navCtrl.navigateUp(); backToHomeStateFlow.value = false }
|
|
}
|
|
NavHost(
|
|
navController = navCtrl,
|
|
startDestination = "HomePage",
|
|
modifier = Modifier
|
|
.fillMaxSize()
|
|
.background(colorScheme.background)
|
|
.imePadding()
|
|
.pointerInput(Unit) { detectTapGestures(onTap = { focusMgr.clearFocus() }) },
|
|
enterTransition = Animations.navHostEnterTransition,
|
|
exitTransition = Animations.navHostExitTransition,
|
|
popEnterTransition = Animations.navHostPopEnterTransition,
|
|
popExitTransition = Animations.navHostPopExitTransition
|
|
) {
|
|
composable(route = "HomePage") { HomePage(navCtrl) }
|
|
composable(route = "SystemManage") { SystemManage(navCtrl) }
|
|
composable(route = "ManagedProfile") { ManagedProfile(navCtrl) }
|
|
composable(route = "Permissions") { DpmPermissions(navCtrl) }
|
|
composable(route = "ApplicationManage") { ApplicationManage(navCtrl, dialogStatus) }
|
|
composable(route = "UserRestriction") { UserRestriction(navCtrl) }
|
|
composable(route = "UserManage") { UserManage(navCtrl) }
|
|
composable(route = "Password") { Password(navCtrl) }
|
|
composable(route = "AppSetting") { AppSetting(navCtrl, vm) }
|
|
composable(route = "Network") { Network(navCtrl) }
|
|
composable(route = "PackageSelector") { PackageSelector(navCtrl) }
|
|
}
|
|
LaunchedEffect(Unit) {
|
|
val profileInited = sharedPref.getBoolean("ManagedProfileActivated", false)
|
|
val profileNotActivated = !profileInited && context.isProfileOwner && (VERSION.SDK_INT < 24 || (VERSION.SDK_INT >= 24 && dpm.isManagedProfile(receiver)))
|
|
if(profileNotActivated) {
|
|
dpm.setProfileEnabled(receiver)
|
|
sharedPref.edit().putBoolean("ManagedProfileActivated", true).apply()
|
|
Toast.makeText(context, R.string.work_profile_activated, Toast.LENGTH_SHORT).show()
|
|
}
|
|
}
|
|
DhizukuErrorDialog()
|
|
}
|
|
|
|
@Composable
|
|
private fun HomePage(navCtrl:NavHostController) {
|
|
val context = LocalContext.current
|
|
val dpm = context.getDPM()
|
|
val receiver = context.getReceiver()
|
|
val sharedPref = context.getSharedPreferences("data", Context.MODE_PRIVATE)
|
|
var activated by remember { mutableStateOf(false) }
|
|
var activateType by remember { mutableStateOf("") }
|
|
val deviceAdmin = context.isDeviceAdmin
|
|
val deviceOwner = context.isDeviceOwner
|
|
val profileOwner = context.isProfileOwner
|
|
val refreshStatus by dhizukuErrorStatus.collectAsState()
|
|
LaunchedEffect(refreshStatus) {
|
|
activated = context.isDeviceAdmin
|
|
activateType = if(sharedPref.getBoolean("dhizuku", false)) context.getString(R.string.dhizuku) + " - " else ""
|
|
activateType += context.getString(
|
|
if(deviceOwner) { R.string.device_owner }
|
|
else if(profileOwner) {
|
|
if(VERSION.SDK_INT >= 24 && dpm.isManagedProfile(receiver)) R.string.work_profile_owner else R.string.profile_owner
|
|
}
|
|
else if(deviceAdmin) R.string.device_admin else R.string.click_to_activate
|
|
)
|
|
}
|
|
Column(modifier = Modifier.background(colorScheme.background).statusBarsPadding().verticalScroll(rememberScrollState())) {
|
|
Spacer(Modifier.padding(vertical = 25.dp))
|
|
Text(
|
|
text = stringResource(R.string.app_name), style = typography.headlineLarge,
|
|
modifier = Modifier.padding(start = 10.dp), color = colorScheme.onBackground
|
|
)
|
|
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))
|
|
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_manage, R.drawable.mobile_phone_fill0, "SystemManage", 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.app_manager, R.drawable.apps_fill0, "ApplicationManage", navCtrl)
|
|
if(VERSION.SDK_INT >= 24 && (profileOwner || deviceOwner)) {
|
|
HomePageItem(R.string.user_restrict, R.drawable.person_off, "UserRestriction", navCtrl)
|
|
}
|
|
HomePageItem(R.string.user_manager,R.drawable.manage_accounts_fill0,"UserManage", navCtrl)
|
|
HomePageItem(R.string.password_and_keyguard, R.drawable.password_fill0, "Password", navCtrl)
|
|
HomePageItem(R.string.setting, R.drawable.settings_fill0, "AppSetting", navCtrl)
|
|
Spacer(Modifier.padding(vertical = 20.dp))
|
|
}
|
|
}
|
|
|
|
@Composable
|
|
fun HomePageItem(name: Int, imgVector: Int, navTo: String, navCtrl: NavHostController) {
|
|
Row(
|
|
modifier = Modifier
|
|
.fillMaxWidth()
|
|
.clip(RoundedCornerShape(25))
|
|
.clickable(onClick = { navCtrl.navigate(navTo) })
|
|
.padding(vertical = 13.dp),
|
|
verticalAlignment = Alignment.CenterVertically
|
|
) {
|
|
Spacer(Modifier.padding(start = 30.dp))
|
|
Icon(
|
|
painter = painterResource(imgVector),
|
|
contentDescription = null,
|
|
tint = colorScheme.onBackground
|
|
)
|
|
Spacer(Modifier.padding(start = 15.dp))
|
|
Text(
|
|
text = stringResource(name),
|
|
style = typography.headlineSmall,
|
|
color = colorScheme.onBackground,
|
|
modifier = Modifier.padding(bottom = if(zhCN) { 2 } else { 0 }.dp)
|
|
)
|
|
}
|
|
}
|
|
|
|
@Composable
|
|
private fun DhizukuErrorDialog() {
|
|
val status by dhizukuErrorStatus.collectAsState()
|
|
if (status != 0) {
|
|
val context = LocalContext.current
|
|
val sharedPref = context.getSharedPreferences("data", Context.MODE_PRIVATE)
|
|
LaunchedEffect(Unit) {
|
|
context.toggleInstallAppActivity()
|
|
delay(200)
|
|
sharedPref.edit().putBoolean("dhizuku", false).apply()
|
|
}
|
|
AlertDialog(
|
|
onDismissRequest = { dhizukuErrorStatus.value = 0 },
|
|
confirmButton = {
|
|
TextButton(onClick = { dhizukuErrorStatus.value = 0 }) {
|
|
Text(stringResource(R.string.confirm))
|
|
}
|
|
},
|
|
title = { Text(stringResource(R.string.dhizuku)) },
|
|
text = {
|
|
var text = stringResource(
|
|
when(status){
|
|
1 -> R.string.failed_to_init_dhizuku
|
|
2 -> R.string.dhizuku_permission_not_granted
|
|
else -> R.string.failed_to_init_dhizuku
|
|
}
|
|
)
|
|
if(sharedPref.getBoolean("dhizuku", false)) text += "\n" + stringResource(R.string.dhizuku_mode_disabled)
|
|
Text(text)
|
|
}
|
|
)
|
|
}
|
|
}
|