mirror of
https://github.com/awfixers-stuff/OwnDroid.git
synced 2026-03-23 11:05:59 +00:00
@@ -95,6 +95,7 @@ dependencies {
|
|||||||
implementation(libs.androidx.fragment)
|
implementation(libs.androidx.fragment)
|
||||||
implementation(libs.hiddenApiBypass)
|
implementation(libs.hiddenApiBypass)
|
||||||
implementation(libs.libsu)
|
implementation(libs.libsu)
|
||||||
|
implementation(libs.libsu.service)
|
||||||
implementation(libs.serialization)
|
implementation(libs.serialization)
|
||||||
implementation(kotlin("reflect"))
|
implementation(kotlin("reflect"))
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
package com.bintianqi.owndroid;
|
package com.bintianqi.owndroid;
|
||||||
|
|
||||||
import android.accounts.Account;
|
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
|
||||||
interface IUserService {
|
interface IUserService {
|
||||||
|
|||||||
@@ -534,7 +534,6 @@ private fun HomeScreen(onNavigate: (Any) -> Unit) {
|
|||||||
}
|
}
|
||||||
) {
|
) {
|
||||||
Column(Modifier.fillMaxSize().padding(it).verticalScroll(rememberScrollState())) {
|
Column(Modifier.fillMaxSize().padding(it).verticalScroll(rememberScrollState())) {
|
||||||
Spacer(Modifier.padding(vertical = 6.dp))
|
|
||||||
if(privilege.device || privilege.profile) {
|
if(privilege.device || privilege.profile) {
|
||||||
HomePageItem(R.string.system, R.drawable.android_fill0) { onNavigate(SystemManager) }
|
HomePageItem(R.string.system, R.drawable.android_fill0) { onNavigate(SystemManager) }
|
||||||
HomePageItem(R.string.network, R.drawable.wifi_fill0) { onNavigate(Network) }
|
HomePageItem(R.string.network, R.drawable.wifi_fill0) { onNavigate(Network) }
|
||||||
|
|||||||
@@ -47,6 +47,7 @@ import androidx.compose.runtime.mutableFloatStateOf
|
|||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.runtime.rememberCoroutineScope
|
import androidx.compose.runtime.rememberCoroutineScope
|
||||||
|
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
|
||||||
@@ -107,9 +108,9 @@ fun AppChooserScreen(params: ApplicationsList, onChoosePackage: (String?) -> Uni
|
|||||||
val coroutine = rememberCoroutineScope()
|
val coroutine = rememberCoroutineScope()
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
var progress by remember { mutableFloatStateOf(1F) }
|
var progress by remember { mutableFloatStateOf(1F) }
|
||||||
var system by remember { mutableStateOf(false) }
|
var system by rememberSaveable { mutableStateOf(false) }
|
||||||
var query by remember { mutableStateOf("") }
|
var query by rememberSaveable { mutableStateOf("") }
|
||||||
var searchMode by remember { mutableStateOf(false) }
|
var searchMode by rememberSaveable { mutableStateOf(false) }
|
||||||
val filteredPackages = packages.filter {
|
val filteredPackages = packages.filter {
|
||||||
system == (it.flags and ApplicationInfo.FLAG_SYSTEM != 0) &&
|
system == (it.flags and ApplicationInfo.FLAG_SYSTEM != 0) &&
|
||||||
(query.isEmpty() || (searchInString(query, it.label) || searchInString(query, it.name)))
|
(query.isEmpty() || (searchInString(query, it.label) || searchInString(query, it.name)))
|
||||||
@@ -189,7 +190,10 @@ fun AppChooserScreen(params: ApplicationsList, onChoosePackage: (String?) -> Uni
|
|||||||
verticalAlignment = Alignment.CenterVertically,
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.clickable { onChoosePackage(it.name) }
|
.clickable {
|
||||||
|
focusMgr.clearFocus()
|
||||||
|
onChoosePackage(it.name)
|
||||||
|
}
|
||||||
.padding(horizontal = 8.dp, vertical = 10.dp)
|
.padding(horizontal = 8.dp, vertical = 10.dp)
|
||||||
.animateItem()
|
.animateItem()
|
||||||
) {
|
) {
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ class SharedPrefs(context: Context) {
|
|||||||
var biometricsUnlock by BooleanSharedPref("lock.biometrics")
|
var biometricsUnlock by BooleanSharedPref("lock.biometrics")
|
||||||
var lockWhenLeaving by BooleanSharedPref("lock.onleave")
|
var lockWhenLeaving by BooleanSharedPref("lock.onleave")
|
||||||
var applicationsListView by BooleanSharedPref("applications.list_view", true)
|
var applicationsListView by BooleanSharedPref("applications.list_view", true)
|
||||||
var shortcuts by BooleanSharedPref("shortcuts", true)
|
var shortcuts by BooleanSharedPref("shortcuts", false)
|
||||||
}
|
}
|
||||||
|
|
||||||
private class BooleanSharedPref(val key: String, val defValue: Boolean = false): ReadWriteProperty<SharedPrefs, Boolean> {
|
private class BooleanSharedPref(val key: String, val defValue: Boolean = false): ReadWriteProperty<SharedPrefs, Boolean> {
|
||||||
|
|||||||
@@ -115,7 +115,7 @@ fun LazyItemScope.ApplicationItem(info: AppInfo, onClear: () -> Unit) {
|
|||||||
Modifier.fillMaxWidth().padding(horizontal = 8.dp, vertical = 6.dp).animateItem(),
|
Modifier.fillMaxWidth().padding(horizontal = 8.dp, vertical = 6.dp).animateItem(),
|
||||||
Arrangement.SpaceBetween, Alignment.CenterVertically
|
Arrangement.SpaceBetween, Alignment.CenterVertically
|
||||||
) {
|
) {
|
||||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
Row(Modifier.fillMaxWidth(0.87F), verticalAlignment = Alignment.CenterVertically) {
|
||||||
Image(
|
Image(
|
||||||
painter = rememberDrawablePainter(info.icon), contentDescription = null,
|
painter = rememberDrawablePainter(info.icon), contentDescription = null,
|
||||||
modifier = Modifier.padding(start = 12.dp, end = 18.dp).size(30.dp)
|
modifier = Modifier.padding(start = 12.dp, end = 18.dp).size(30.dp)
|
||||||
|
|||||||
@@ -1,10 +1,19 @@
|
|||||||
package com.bintianqi.owndroid.dpm
|
package com.bintianqi.owndroid.dpm
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
import android.app.admin.DevicePolicyManager
|
import android.app.admin.DevicePolicyManager
|
||||||
import android.content.ComponentName
|
import android.content.ComponentName
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import android.content.ServiceConnection
|
||||||
import android.content.pm.PackageManager
|
import android.content.pm.PackageManager
|
||||||
import android.os.Build.VERSION
|
import android.os.Build.VERSION
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.os.Handler
|
||||||
|
import android.os.IBinder
|
||||||
|
import android.os.Looper
|
||||||
|
import android.os.Message
|
||||||
|
import android.os.Messenger
|
||||||
import android.os.PersistableBundle
|
import android.os.PersistableBundle
|
||||||
import androidx.activity.compose.rememberLauncherForActivityResult
|
import androidx.activity.compose.rememberLauncherForActivityResult
|
||||||
import androidx.annotation.Keep
|
import androidx.annotation.Keep
|
||||||
@@ -15,6 +24,8 @@ 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.ExperimentalLayoutApi
|
||||||
|
import androidx.compose.foundation.layout.FlowRow
|
||||||
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.fillMaxSize
|
||||||
@@ -37,7 +48,6 @@ 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.Checkbox
|
import androidx.compose.material3.Checkbox
|
||||||
import androidx.compose.material3.CircularProgressIndicator
|
|
||||||
import androidx.compose.material3.DropdownMenu
|
import androidx.compose.material3.DropdownMenu
|
||||||
import androidx.compose.material3.DropdownMenuItem
|
import androidx.compose.material3.DropdownMenuItem
|
||||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
@@ -71,7 +81,7 @@ import androidx.compose.ui.res.stringResource
|
|||||||
import androidx.compose.ui.text.input.ImeAction
|
import androidx.compose.ui.text.input.ImeAction
|
||||||
import androidx.compose.ui.text.input.KeyboardType
|
import androidx.compose.ui.text.input.KeyboardType
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.compose.ui.window.Dialog
|
import androidx.core.os.bundleOf
|
||||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||||
import com.bintianqi.owndroid.ChoosePackageContract
|
import com.bintianqi.owndroid.ChoosePackageContract
|
||||||
import com.bintianqi.owndroid.HorizontalPadding
|
import com.bintianqi.owndroid.HorizontalPadding
|
||||||
@@ -82,6 +92,7 @@ import com.bintianqi.owndroid.Settings
|
|||||||
import com.bintianqi.owndroid.SharedPrefs
|
import com.bintianqi.owndroid.SharedPrefs
|
||||||
import com.bintianqi.owndroid.myPrivilege
|
import com.bintianqi.owndroid.myPrivilege
|
||||||
import com.bintianqi.owndroid.showOperationResultToast
|
import com.bintianqi.owndroid.showOperationResultToast
|
||||||
|
import com.bintianqi.owndroid.ui.CircularProgressDialog
|
||||||
import com.bintianqi.owndroid.ui.InfoItem
|
import com.bintianqi.owndroid.ui.InfoItem
|
||||||
import com.bintianqi.owndroid.ui.MyScaffold
|
import com.bintianqi.owndroid.ui.MyScaffold
|
||||||
import com.bintianqi.owndroid.ui.MySmallTitleScaffold
|
import com.bintianqi.owndroid.ui.MySmallTitleScaffold
|
||||||
@@ -93,12 +104,16 @@ import com.bintianqi.owndroid.yesOrNo
|
|||||||
import com.rosan.dhizuku.api.Dhizuku
|
import com.rosan.dhizuku.api.Dhizuku
|
||||||
import com.rosan.dhizuku.api.DhizukuRequestPermissionListener
|
import com.rosan.dhizuku.api.DhizukuRequestPermissionListener
|
||||||
import com.topjohnwu.superuser.Shell
|
import com.topjohnwu.superuser.Shell
|
||||||
|
import com.topjohnwu.superuser.ipc.RootService
|
||||||
|
import dalvik.system.DexClassLoader
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
|
import java.lang.invoke.MethodHandles
|
||||||
|
import java.lang.reflect.Proxy
|
||||||
|
|
||||||
@Serializable data class WorkModes(val canNavigateUp: Boolean)
|
@Serializable data class WorkModes(val canNavigateUp: Boolean)
|
||||||
|
|
||||||
@OptIn(ExperimentalMaterial3Api::class)
|
@OptIn(ExperimentalMaterial3Api::class, ExperimentalLayoutApi::class)
|
||||||
@Composable
|
@Composable
|
||||||
fun WorkModesScreen(
|
fun WorkModesScreen(
|
||||||
params: WorkModes, onNavigateUp: () -> Unit, onActivate: () -> Unit, onDeactivate: () -> Unit,
|
params: WorkModes, onNavigateUp: () -> Unit, onActivate: () -> Unit, onDeactivate: () -> Unit,
|
||||||
@@ -107,7 +122,7 @@ fun WorkModesScreen(
|
|||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
val coroutine = rememberCoroutineScope()
|
val coroutine = rememberCoroutineScope()
|
||||||
val privilege by myPrivilege.collectAsStateWithLifecycle()
|
val privilege by myPrivilege.collectAsStateWithLifecycle()
|
||||||
/** 0: none, 1: device owner, 2: circular progress indicator, 3: result, 4: deactivate, 5: command */
|
/** 0: none, 1: device owner, 2: circular progress indicator, 3: result, 4: deactivate, 5: command, 6: force activating warning */
|
||||||
var dialog by remember { mutableIntStateOf(0) }
|
var dialog by remember { mutableIntStateOf(0) }
|
||||||
Scaffold(
|
Scaffold(
|
||||||
topBar = {
|
topBar = {
|
||||||
@@ -160,6 +175,7 @@ fun WorkModesScreen(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
) { paddingValues ->
|
) { paddingValues ->
|
||||||
|
var navigateUpOnSucceed by remember { mutableStateOf(true) }
|
||||||
var operationSucceed by remember { mutableStateOf(false) }
|
var operationSucceed by remember { mutableStateOf(false) }
|
||||||
var resultText by remember { mutableStateOf("") }
|
var resultText by remember { mutableStateOf("") }
|
||||||
fun handleResult(succeeded: Boolean, activateSucceeded: Boolean, output: String?) {
|
fun handleResult(succeeded: Boolean, activateSucceeded: Boolean, output: String?) {
|
||||||
@@ -253,7 +269,7 @@ fun WorkModesScreen(
|
|||||||
if(dialog == 1) AlertDialog(
|
if(dialog == 1) AlertDialog(
|
||||||
title = { Text(stringResource(R.string.activate_method)) },
|
title = { Text(stringResource(R.string.activate_method)) },
|
||||||
text = {
|
text = {
|
||||||
Column(Modifier.fillMaxWidth(), horizontalAlignment = Alignment.CenterHorizontally) {
|
FlowRow(Modifier.fillMaxWidth()) {
|
||||||
if(!privilege.dhizuku) Button({
|
if(!privilege.dhizuku) Button({
|
||||||
dialog = 2
|
dialog = 2
|
||||||
coroutine.launch {
|
coroutine.launch {
|
||||||
@@ -262,19 +278,28 @@ fun WorkModesScreen(
|
|||||||
}) {
|
}) {
|
||||||
Text(stringResource(R.string.shizuku))
|
Text(stringResource(R.string.shizuku))
|
||||||
}
|
}
|
||||||
|
Spacer(Modifier.padding(horizontal = 2.dp))
|
||||||
if(!privilege.dhizuku) Button({
|
if(!privilege.dhizuku) Button({
|
||||||
dialog = 2
|
dialog = 2
|
||||||
activateUsingRoot(context, ::handleResult)
|
activateUsingRoot(context, ::handleResult)
|
||||||
}) {
|
}) {
|
||||||
Text("Root")
|
Text("Root")
|
||||||
}
|
}
|
||||||
|
Spacer(Modifier.padding(horizontal = 2.dp))
|
||||||
if(VERSION.SDK_INT >= 28) Button({
|
if(VERSION.SDK_INT >= 28) Button({
|
||||||
dialog = 2
|
dialog = 2
|
||||||
activateUsingDhizuku(context, ::handleResult)
|
activateUsingDhizuku(context, ::handleResult)
|
||||||
}) {
|
}) {
|
||||||
Text(stringResource(R.string.dhizuku))
|
Text(stringResource(R.string.dhizuku))
|
||||||
}
|
}
|
||||||
|
Spacer(Modifier.padding(horizontal = 2.dp))
|
||||||
Button({ dialog = 5 }) { Text(stringResource(R.string.adb_command)) }
|
Button({ dialog = 5 }) { Text(stringResource(R.string.adb_command)) }
|
||||||
|
Spacer(Modifier.padding(horizontal = 2.dp))
|
||||||
|
if (VERSION.SDK_INT == 35) Button({
|
||||||
|
dialog = 6
|
||||||
|
}) {
|
||||||
|
Text(stringResource(R.string.root_force_activate))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
confirmButton = {
|
confirmButton = {
|
||||||
@@ -282,9 +307,7 @@ fun WorkModesScreen(
|
|||||||
},
|
},
|
||||||
onDismissRequest = { dialog = 0 }
|
onDismissRequest = { dialog = 0 }
|
||||||
)
|
)
|
||||||
if(dialog == 2) Dialog({}) {
|
if(dialog == 2) CircularProgressDialog { }
|
||||||
CircularProgressIndicator()
|
|
||||||
}
|
|
||||||
if(dialog == 3) AlertDialog(
|
if(dialog == 3) AlertDialog(
|
||||||
title = { Text(stringResource(if(operationSucceed) R.string.succeeded else R.string.failed)) },
|
title = { Text(stringResource(if(operationSucceed) R.string.succeeded else R.string.failed)) },
|
||||||
text = {
|
text = {
|
||||||
@@ -295,15 +318,12 @@ fun WorkModesScreen(
|
|||||||
confirmButton = {
|
confirmButton = {
|
||||||
TextButton({
|
TextButton({
|
||||||
dialog = 0
|
dialog = 0
|
||||||
if(operationSucceed && !params.canNavigateUp) onActivate()
|
if(navigateUpOnSucceed && operationSucceed && !params.canNavigateUp) onActivate()
|
||||||
}) {
|
}) {
|
||||||
Text(stringResource(R.string.confirm))
|
Text(stringResource(R.string.confirm))
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onDismissRequest = {
|
onDismissRequest = {}
|
||||||
dialog = 0
|
|
||||||
if(operationSucceed && !params.canNavigateUp) onActivate()
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
if(dialog == 4) AlertDialog(
|
if(dialog == 4) AlertDialog(
|
||||||
title = { Text(stringResource(R.string.deactivate)) },
|
title = { Text(stringResource(R.string.deactivate)) },
|
||||||
@@ -345,6 +365,23 @@ fun WorkModesScreen(
|
|||||||
},
|
},
|
||||||
onDismissRequest = { dialog = 0 }
|
onDismissRequest = { dialog = 0 }
|
||||||
)
|
)
|
||||||
|
if (dialog == 6) AlertDialog(
|
||||||
|
title = { Text(stringResource(R.string.warning)) },
|
||||||
|
text = { Text(stringResource(R.string.info_force_activate)) },
|
||||||
|
confirmButton = {
|
||||||
|
TextButton({
|
||||||
|
dialog = 2
|
||||||
|
navigateUpOnSucceed = false
|
||||||
|
forceActivateUsingRoot(context, ::handleResult)
|
||||||
|
}) {
|
||||||
|
Text(stringResource(R.string.continue_str))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
dismissButton = {
|
||||||
|
TextButton({ dialog = 0 }) { Text(stringResource(R.string.cancel)) }
|
||||||
|
},
|
||||||
|
onDismissRequest = { dialog = 0 }
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -414,6 +451,75 @@ fun activateUsingDhizuku(context: Context, callback: (Boolean, Boolean, String?)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun forceActivateUsingRoot(context: Context, callback: (Boolean, Boolean, String?) -> Unit) {
|
||||||
|
val connection = object : ServiceConnection {
|
||||||
|
override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
|
||||||
|
val handler = Handler(Looper.getMainLooper()) { msg ->
|
||||||
|
RootService.unbind(this)
|
||||||
|
val data = msg.data
|
||||||
|
val output = if (data.getBoolean("succeed")) context.getString(R.string.please_reboot) else null
|
||||||
|
callback(!data.getBoolean("error"), data.getBoolean("succeed"), output)
|
||||||
|
return@Handler true
|
||||||
|
}
|
||||||
|
val msg = Message()
|
||||||
|
msg.replyTo = Messenger(handler)
|
||||||
|
Messenger(service).send(msg)
|
||||||
|
}
|
||||||
|
override fun onServiceDisconnected(name: ComponentName?) {}
|
||||||
|
}
|
||||||
|
val intent = Intent(context, ForceActivateService::class.java)
|
||||||
|
RootService.bind(intent, connection)
|
||||||
|
}
|
||||||
|
|
||||||
|
@RequiresApi(26)
|
||||||
|
class ForceActivateService(): RootService() {
|
||||||
|
override fun onBind(intent: Intent): IBinder = messenger.binder
|
||||||
|
val handler = Handler(Looper.getMainLooper()) { msg ->
|
||||||
|
val replyMessage = Message()
|
||||||
|
try {
|
||||||
|
replyMessage.data = activateDeviceOwnerAsRoot(getReceiver()).apply { putBoolean("error", false) }
|
||||||
|
} catch (e: Exception) {
|
||||||
|
e.printStackTrace()
|
||||||
|
replyMessage.data = bundleOf("error" to true, "succeed" to false)
|
||||||
|
}
|
||||||
|
msg.replyTo.send(replyMessage)
|
||||||
|
return@Handler false
|
||||||
|
}
|
||||||
|
val messenger = Messenger(handler)
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressLint("PrivateApi")
|
||||||
|
@RequiresApi(26)
|
||||||
|
fun activateDeviceOwnerAsRoot(cn: ComponentName): Bundle {
|
||||||
|
val dcl = DexClassLoader(
|
||||||
|
"/system/framework/services.jar", "/data/local/tmp", null, ClassLoader.getSystemClassLoader()
|
||||||
|
)
|
||||||
|
val ppp = dcl.loadClass("com.android.server.devicepolicy.PolicyPathProvider")
|
||||||
|
val pppProxy = Proxy.newProxyInstance(ppp.classLoader, arrayOf(ppp)) { obj, method, args ->
|
||||||
|
method.isAccessible = true
|
||||||
|
val mh = MethodHandles.lookup().`in`(ppp).unreflectSpecial(method, ppp).bindTo(obj)
|
||||||
|
return@newProxyInstance if (args == null) {
|
||||||
|
mh.invokeWithArguments()
|
||||||
|
} else {
|
||||||
|
mh.invokeWithArguments(*args)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val od = dcl.loadClass("com.android.server.devicepolicy.OwnersData")
|
||||||
|
val odIns = od.getConstructor(ppp).apply { isAccessible = true }.newInstance(pppProxy)
|
||||||
|
val oi = dcl.loadClass("com.android.server.devicepolicy.OwnersData\$OwnerInfo")
|
||||||
|
val oiIns = oi.constructors[0].apply { isAccessible = true }.newInstance(cn, null, null, true)
|
||||||
|
od.getField("mDeviceOwner").apply { isAccessible = true }.set(odIns, oiIns)
|
||||||
|
od.getField("mDeviceOwnerUserId").apply { isAccessible = true }.set(odIns, 0)
|
||||||
|
val setDoResult = od.getMethod("writeDeviceOwner").apply { isAccessible = true }.invoke(odIns) as Boolean
|
||||||
|
return if (setDoResult) {
|
||||||
|
val proc = Runtime.getRuntime().exec("dpm set-active-admin ${cn.flattenToShortString()}")
|
||||||
|
proc.waitFor()
|
||||||
|
bundleOf("succeed" to true)
|
||||||
|
} else {
|
||||||
|
bundleOf("succeed" to false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun activateDhizukuMode(context: Context, callback: (Boolean, Boolean, String?) -> Unit) {
|
fun activateDhizukuMode(context: Context, callback: (Boolean, Boolean, String?) -> Unit) {
|
||||||
fun onSucceed() {
|
fun onSucceed() {
|
||||||
SharedPrefs(context).dhizuku = true
|
SharedPrefs(context).dhizuku = true
|
||||||
|
|||||||
@@ -33,7 +33,6 @@ import androidx.compose.material.icons.filled.Delete
|
|||||||
import androidx.compose.material.icons.filled.PlayArrow
|
import androidx.compose.material.icons.filled.PlayArrow
|
||||||
import androidx.compose.material3.AlertDialog
|
import androidx.compose.material3.AlertDialog
|
||||||
import androidx.compose.material3.Button
|
import androidx.compose.material3.Button
|
||||||
import androidx.compose.material3.CircularProgressIndicator
|
|
||||||
import androidx.compose.material3.Icon
|
import androidx.compose.material3.Icon
|
||||||
import androidx.compose.material3.IconButton
|
import androidx.compose.material3.IconButton
|
||||||
import androidx.compose.material3.OutlinedTextField
|
import androidx.compose.material3.OutlinedTextField
|
||||||
@@ -62,14 +61,13 @@ import androidx.compose.ui.res.stringResource
|
|||||||
import androidx.compose.ui.text.input.ImeAction
|
import androidx.compose.ui.text.input.ImeAction
|
||||||
import androidx.compose.ui.text.input.KeyboardType
|
import androidx.compose.ui.text.input.KeyboardType
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.compose.ui.window.Dialog
|
|
||||||
import androidx.compose.ui.window.DialogProperties
|
|
||||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||||
import com.bintianqi.owndroid.HorizontalPadding
|
import com.bintianqi.owndroid.HorizontalPadding
|
||||||
import com.bintianqi.owndroid.R
|
import com.bintianqi.owndroid.R
|
||||||
import com.bintianqi.owndroid.myPrivilege
|
import com.bintianqi.owndroid.myPrivilege
|
||||||
import com.bintianqi.owndroid.parseTimestamp
|
import com.bintianqi.owndroid.parseTimestamp
|
||||||
import com.bintianqi.owndroid.showOperationResultToast
|
import com.bintianqi.owndroid.showOperationResultToast
|
||||||
|
import com.bintianqi.owndroid.ui.CircularProgressDialog
|
||||||
import com.bintianqi.owndroid.ui.FullWidthCheckBoxItem
|
import com.bintianqi.owndroid.ui.FullWidthCheckBoxItem
|
||||||
import com.bintianqi.owndroid.ui.FunctionItem
|
import com.bintianqi.owndroid.ui.FunctionItem
|
||||||
import com.bintianqi.owndroid.ui.InfoItem
|
import com.bintianqi.owndroid.ui.InfoItem
|
||||||
@@ -393,9 +391,7 @@ fun CreateUserScreen(onNavigateUp: () -> Unit) {
|
|||||||
},
|
},
|
||||||
onDismissRequest = { createdUserSerialNumber = -1 }
|
onDismissRequest = { createdUserSerialNumber = -1 }
|
||||||
)
|
)
|
||||||
if(creating) Dialog({}, DialogProperties(false, false)) {
|
if(creating) CircularProgressDialog { }
|
||||||
CircularProgressIndicator()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -24,7 +24,9 @@ import androidx.compose.material.icons.automirrored.filled.ArrowBack
|
|||||||
import androidx.compose.material.icons.filled.ArrowDropDown
|
import androidx.compose.material.icons.filled.ArrowDropDown
|
||||||
import androidx.compose.material.icons.outlined.Info
|
import androidx.compose.material.icons.outlined.Info
|
||||||
import androidx.compose.material3.AlertDialog
|
import androidx.compose.material3.AlertDialog
|
||||||
|
import androidx.compose.material3.Card
|
||||||
import androidx.compose.material3.Checkbox
|
import androidx.compose.material3.Checkbox
|
||||||
|
import androidx.compose.material3.CircularProgressIndicator
|
||||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
import androidx.compose.material3.Icon
|
import androidx.compose.material3.Icon
|
||||||
import androidx.compose.material3.IconButton
|
import androidx.compose.material3.IconButton
|
||||||
@@ -53,6 +55,7 @@ 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.compose.ui.unit.dp
|
||||||
|
import androidx.compose.ui.window.Dialog
|
||||||
import com.bintianqi.owndroid.HorizontalPadding
|
import com.bintianqi.owndroid.HorizontalPadding
|
||||||
import com.bintianqi.owndroid.R
|
import com.bintianqi.owndroid.R
|
||||||
import com.bintianqi.owndroid.zhCN
|
import com.bintianqi.owndroid.zhCN
|
||||||
@@ -378,3 +381,12 @@ fun ErrorDialog(message: String?, onDismiss: () -> Unit) {
|
|||||||
onDismissRequest = onDismiss
|
onDismissRequest = onDismiss
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun CircularProgressDialog(onDismiss: () -> Unit) {
|
||||||
|
Dialog(onDismiss) {
|
||||||
|
Card {
|
||||||
|
CircularProgressIndicator(Modifier.padding(16.dp))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -67,6 +67,7 @@
|
|||||||
<string name="features">功能</string>
|
<string name="features">功能</string>
|
||||||
<string name="default_str">默认</string>
|
<string name="default_str">默认</string>
|
||||||
<string name="timeout">超时</string>
|
<string name="timeout">超时</string>
|
||||||
|
<string name="continue_str">继续</string>
|
||||||
|
|
||||||
<!--Permissions-->
|
<!--Permissions-->
|
||||||
<string name="profile_owner">Profile owner</string>
|
<string name="profile_owner">Profile owner</string>
|
||||||
@@ -685,11 +686,14 @@
|
|||||||
<string name="info_max_failed_password_other_user">如果设置为大于零的值,将会在输入一定次数的错误的锁屏密码后清除当前用户的所有数据</string>
|
<string name="info_max_failed_password_other_user">如果设置为大于零的值,将会在输入一定次数的错误的锁屏密码后清除当前用户的所有数据</string>
|
||||||
<string name="info_password_history_length">设置后,用户将无法输入与历史记录中任何密码相同的新密码。当前密码将保留,直到用户设置新密码为止,因此更改不会立即生效。值为0表示不做限制。</string>
|
<string name="info_password_history_length">设置后,用户将无法输入与历史记录中任何密码相同的新密码。当前密码将保留,直到用户设置新密码为止,因此更改不会立即生效。值为0表示不做限制。</string>
|
||||||
<string name="info_required_strong_auth_timeout">如果用户在这段时间内没有使用强认证(密码、PIN或图案)解锁设备,则要求使用强认证解锁设备。值为0表示OwnDroid不参与控制超时。一般来说,最少1小时,最多72小时。</string>
|
<string name="info_required_strong_auth_timeout">如果用户在这段时间内没有使用强认证(密码、PIN或图案)解锁设备,则要求使用强认证解锁设备。值为0表示OwnDroid不参与控制超时。一般来说,最少1小时,最多72小时。</string>
|
||||||
<string name="info_deactivate">OwnDroid will lost its privilege</string>
|
<string name="info_deactivate">OwnDroid将会丢失特权</string>
|
||||||
|
<string name="info_force_activate">强行激活可能无法在你的设备上使用,它甚至有可能会损坏你的设备,你应该仅在其他方法无法使用时尝试此方法。</string>
|
||||||
|
|
||||||
<string name="choose_work_mode">选择一个工作模式</string>
|
<string name="choose_work_mode">选择一个工作模式</string>
|
||||||
<string name="recommended">推荐</string>
|
<string name="recommended">推荐</string>
|
||||||
<string name="activate_method">激活方法</string>
|
<string name="activate_method">激活方法</string>
|
||||||
<string name="adb_command">ADB命令</string>
|
<string name="adb_command">ADB命令</string>
|
||||||
<string name="owndroid_warning">此应用使用Device owner和Profile owner特权。这些特权十分危险,请谨慎使用。如果操作不当,可能会造成严重损失。开发者将不会对此负责。</string>
|
<string name="root_force_activate">Root (强行激活)</string>
|
||||||
|
<string name="owndroid_warning">此应用使用Device owner或Profile owner特权。这些特权十分危险,请谨慎使用。如果操作不当,可能会造成严重损失。开发者将不会对此负责。</string>
|
||||||
|
<string name="please_reboot">请重启你的设备</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -72,6 +72,7 @@
|
|||||||
<string name="features">Features</string>
|
<string name="features">Features</string>
|
||||||
<string name="default_str">Default</string>
|
<string name="default_str">Default</string>
|
||||||
<string name="timeout">Timeout</string>
|
<string name="timeout">Timeout</string>
|
||||||
|
<string name="continue_str">Continue</string>
|
||||||
|
|
||||||
<!--Permissions-->
|
<!--Permissions-->
|
||||||
<string name="profile_owner">Profile owner</string>
|
<string name="profile_owner">Profile owner</string>
|
||||||
@@ -720,10 +721,13 @@
|
|||||||
<string name="info_password_history_length">After setting this, the user will not be able to enter a new password that is the same as any password in the history. Note that the current password will remain until the user has set a new one, so the change does not take place immediately.\nA value of 0 means there is no restriction.</string>
|
<string name="info_password_history_length">After setting this, the user will not be able to enter a new password that is the same as any password in the history. Note that the current password will remain until the user has set a new one, so the change does not take place immediately.\nA value of 0 means there is no restriction.</string>
|
||||||
<string name="info_required_strong_auth_timeout">Determine for how long the user will be able to use secondary, non strong auth for authentication, since last strong method authentication (password, pin or pattern) was used. After the returned timeout the user is required to use strong authentication method.\nA value of 0 means the admin is not participating in controlling the timeout. The minimum and maximum timeouts are platform-defined and are typically 1 hour and 72 hours, respectively.</string>
|
<string name="info_required_strong_auth_timeout">Determine for how long the user will be able to use secondary, non strong auth for authentication, since last strong method authentication (password, pin or pattern) was used. After the returned timeout the user is required to use strong authentication method.\nA value of 0 means the admin is not participating in controlling the timeout. The minimum and maximum timeouts are platform-defined and are typically 1 hour and 72 hours, respectively.</string>
|
||||||
<string name="info_deactivate">OwnDroid will lost its privilege</string>
|
<string name="info_deactivate">OwnDroid will lost its privilege</string>
|
||||||
|
<string name="info_force_activate">Force activation may not work and it may damage your device. This method should only be used when you can\'t use other methods.</string>
|
||||||
|
|
||||||
<string name="choose_work_mode">Choose a work mode</string>
|
<string name="choose_work_mode">Choose a work mode</string>
|
||||||
<string name="recommended">Recommended</string>
|
<string name="recommended">Recommended</string>
|
||||||
<string name="activate_method">Activate method</string>
|
<string name="activate_method">Activate method</string>
|
||||||
<string name="adb_command">ADB command</string>
|
<string name="adb_command">ADB command</string>
|
||||||
<string name="owndroid_warning">This app uses Device owner and Profile owner privileges. These privileges are extremely dangerous, please use them with caution. If used improperly, they may result in severe losses. The developers will not be responsible for this.</string>
|
<string name="root_force_activate">Root (force activate)</string>
|
||||||
|
<string name="owndroid_warning">This app uses Device owner or Profile owner privileges. These privileges are extremely dangerous, please use them with caution. If used improperly, they may result in severe losses. The developers will not be responsible for this.</string>
|
||||||
|
<string name="please_reboot">Please reboot your device</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ shizuku-api = { module = "dev.rikka.shizuku:api", version.ref = "shizuku" }
|
|||||||
dhizuku-api = { module = "io.github.iamr0s:Dhizuku-API", version.ref = "dhizuku" }
|
dhizuku-api = { module = "io.github.iamr0s:Dhizuku-API", version.ref = "dhizuku" }
|
||||||
hiddenApiBypass = { module = "org.lsposed.hiddenapibypass:hiddenapibypass", version.ref = "hiddenApiBypass" }
|
hiddenApiBypass = { module = "org.lsposed.hiddenapibypass:hiddenapibypass", version.ref = "hiddenApiBypass" }
|
||||||
libsu = { module = "com.github.topjohnwu.libsu:core", version.ref = "libsu" }
|
libsu = { module = "com.github.topjohnwu.libsu:core", version.ref = "libsu" }
|
||||||
|
libsu-service = { module = "com.github.topjohnwu.libsu:service", version.ref = "libsu" }
|
||||||
|
|
||||||
serialization = { group = "org.jetbrains.kotlinx", name = "kotlinx-serialization-json", version.ref = "serialization" }
|
serialization = { group = "org.jetbrains.kotlinx", name = "kotlinx-serialization-json", version.ref = "serialization" }
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user