mirror of
https://github.com/awfixers-stuff/OwnDroid.git
synced 2026-03-23 19:15:58 +00:00
optimize shizuku coroutine
This commit is contained in:
@@ -36,6 +36,9 @@ import androidx.compose.ui.res.stringResource
|
|||||||
import androidx.compose.ui.text.input.ImeAction
|
import androidx.compose.ui.text.input.ImeAction
|
||||||
import androidx.compose.ui.text.input.KeyboardType
|
import androidx.compose.ui.text.input.KeyboardType
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
import org.apache.commons.io.IOUtils
|
import org.apache.commons.io.IOUtils
|
||||||
import rikka.shizuku.Shizuku
|
import rikka.shizuku.Shizuku
|
||||||
import java.io.*
|
import java.io.*
|
||||||
@@ -50,9 +53,10 @@ fun ShizukuActivate(){
|
|||||||
val isWear = sharedPref.getBoolean("isWear",false)
|
val isWear = sharedPref.getBoolean("isWear",false)
|
||||||
val bodyTextStyle = if(isWear){ typography.bodyMedium }else{ typography.bodyLarge }
|
val bodyTextStyle = if(isWear){ typography.bodyMedium }else{ typography.bodyLarge }
|
||||||
val filesDir = myContext.filesDir
|
val filesDir = myContext.filesDir
|
||||||
var launchExtractRish by remember{mutableStateOf(true)}
|
LaunchedEffect(Unit){ extractRish(myContext) }
|
||||||
LaunchedEffect(launchExtractRish){ if(launchExtractRish){ extractRish(myContext);launchExtractRish=false } }
|
val coScope = rememberCoroutineScope()
|
||||||
val scrollState = rememberScrollState()
|
val scrollState = rememberScrollState()
|
||||||
|
val outputTextScrollState = rememberScrollState()
|
||||||
Column(modifier = Modifier.verticalScroll(scrollState)){
|
Column(modifier = Modifier.verticalScroll(scrollState)){
|
||||||
var outputText by remember{mutableStateOf("")}
|
var outputText by remember{mutableStateOf("")}
|
||||||
if(Binder.getCallingUid()/100000!=0){
|
if(Binder.getCallingUid()/100000!=0){
|
||||||
@@ -82,40 +86,40 @@ fun ShizukuActivate(){
|
|||||||
Text(text = stringResource(R.string.activate), style = typography.titleLarge, color = colorScheme.onPrimaryContainer)
|
Text(text = stringResource(R.string.activate), style = typography.titleLarge, color = colorScheme.onPrimaryContainer)
|
||||||
|
|
||||||
if(!myDpm.isAdminActive(myComponent)){
|
if(!myDpm.isAdminActive(myComponent)){
|
||||||
var launchActivateDA by remember{mutableStateOf(false)}
|
Button(
|
||||||
LaunchedEffect(launchActivateDA){
|
onClick = {
|
||||||
if(launchActivateDA){
|
coScope.launch{
|
||||||
outputText = executeCommand("sh rish.sh", "dpm set-active-admin com.binbin.androidowner/com.binbin.androidowner.MyDeviceAdminReceiver", null, filesDir)
|
outputText = executeCommand(myContext, "sh rish.sh", myContext.getString(R.string.dpm_activate_da_command), null, filesDir)
|
||||||
scrollState.animateScrollTo(scrollState.maxValue, scrollAnim())
|
scrollState.animateScrollTo(scrollState.maxValue, scrollAnim())
|
||||||
launchActivateDA=false
|
outputTextScrollState.animateScrollTo(0, scrollAnim())
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
Button(onClick = {launchActivateDA=true}, modifier = Modifier.fillMaxWidth()) {
|
modifier = Modifier.fillMaxWidth()) {
|
||||||
Text(text = "Device admin")
|
Text(text = "Device admin")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var launchActivatePO by remember{mutableStateOf(false)}
|
Button(
|
||||||
LaunchedEffect(launchActivatePO){
|
onClick = {
|
||||||
if(launchActivatePO){
|
coScope.launch{
|
||||||
outputText = executeCommand("sh rish.sh", "dpm set-profile-owner com.binbin.androidowner/com.binbin.androidowner.MyDeviceAdminReceiver", null, filesDir)
|
outputText = executeCommand(myContext, "sh rish.sh", myContext.getString(R.string.dpm_activate_po_command), null, filesDir)
|
||||||
scrollState.animateScrollTo(scrollState.maxValue, scrollAnim())
|
scrollState.animateScrollTo(scrollState.maxValue, scrollAnim())
|
||||||
launchActivatePO=false
|
outputTextScrollState.animateScrollTo(0, scrollAnim())
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
Button(onClick = {launchActivatePO=true}, modifier = Modifier.fillMaxWidth()) {
|
modifier = Modifier.fillMaxWidth()) {
|
||||||
Text(text = "Profile owner")
|
Text(text = "Profile owner")
|
||||||
}
|
}
|
||||||
|
|
||||||
var launchActivateDO by remember{mutableStateOf(false)}
|
Button(
|
||||||
LaunchedEffect(launchActivateDO){
|
onClick = {
|
||||||
if(launchActivateDO){
|
coScope.launch{
|
||||||
outputText = executeCommand("sh rish.sh", "dpm set-device-owner com.binbin.androidowner/com.binbin.androidowner.MyDeviceAdminReceiver", null, filesDir)
|
outputText = executeCommand(myContext, "sh rish.sh", myContext.getString(R.string.dpm_activate_do_command), null, filesDir)
|
||||||
scrollState.animateScrollTo(scrollState.maxValue, scrollAnim())
|
scrollState.animateScrollTo(scrollState.maxValue, scrollAnim())
|
||||||
launchActivateDO=false
|
outputTextScrollState.animateScrollTo(0, scrollAnim())
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
Button(onClick = {launchActivateDO=true}, modifier = Modifier.fillMaxWidth()) {
|
modifier = Modifier.fillMaxWidth()) {
|
||||||
Text(text = "Device owner")
|
Text(text = "Device owner")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -134,25 +138,20 @@ fun ShizukuActivate(){
|
|||||||
keyboardActions = KeyboardActions(onDone = {focusMgr.clearFocus()}),
|
keyboardActions = KeyboardActions(onDone = {focusMgr.clearFocus()}),
|
||||||
modifier = Modifier.focusable().fillMaxWidth().padding(vertical = 2.dp)
|
modifier = Modifier.focusable().fillMaxWidth().padding(vertical = 2.dp)
|
||||||
)
|
)
|
||||||
var launchActivateOrgProfile by remember{mutableStateOf(false)}
|
Button(
|
||||||
LaunchedEffect(launchActivateOrgProfile){
|
onClick = {
|
||||||
if(launchActivateOrgProfile){
|
coScope.launch{
|
||||||
focusMgr.clearFocus()
|
focusMgr.clearFocus()
|
||||||
outputText = executeCommand(
|
outputText = executeCommand(
|
||||||
"sh rish.sh",
|
myContext, "sh rish.sh", myContext.getString(R.string.activate_org_profile_command_with_user_id, inputUserID),
|
||||||
"dpm mark-profile-owner-on-organization-owned-device --user $inputUserID com.binbin.androidowner/com.binbin.androidowner.MyDeviceAdminReceiver",
|
|
||||||
null, filesDir
|
null, filesDir
|
||||||
)
|
)
|
||||||
scrollState.animateScrollTo(scrollState.maxValue, scrollAnim())
|
scrollState.animateScrollTo(scrollState.maxValue, scrollAnim())
|
||||||
launchActivateOrgProfile=false
|
outputTextScrollState.animateScrollTo(0, scrollAnim())
|
||||||
}
|
|
||||||
}
|
|
||||||
Button(
|
|
||||||
onClick = {
|
|
||||||
launchActivateOrgProfile=true
|
|
||||||
if(myDpm.isOrganizationOwnedDeviceWithManagedProfile){
|
if(myDpm.isOrganizationOwnedDeviceWithManagedProfile){
|
||||||
Toast.makeText(myContext, myContext.getString(R.string.success),Toast.LENGTH_SHORT).show()
|
Toast.makeText(myContext, myContext.getString(R.string.success),Toast.LENGTH_SHORT).show()
|
||||||
}
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
modifier = Modifier.fillMaxWidth()
|
modifier = Modifier.fillMaxWidth()
|
||||||
) {
|
) {
|
||||||
@@ -161,36 +160,35 @@ fun ShizukuActivate(){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var launchListOwners by remember{mutableStateOf(false)}
|
|
||||||
LaunchedEffect(launchListOwners){
|
|
||||||
if(launchListOwners){
|
|
||||||
outputText=executeCommand("sh rish.sh","dpm list-owners",null,filesDir)
|
|
||||||
scrollState.animateScrollTo(scrollState.maxValue, scrollAnim())
|
|
||||||
launchListOwners=false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Button(
|
Button(
|
||||||
onClick = {launchListOwners=true}, modifier = Modifier.fillMaxWidth().padding(horizontal = 8.dp)
|
onClick = {
|
||||||
|
coScope.launch{
|
||||||
|
outputText=executeCommand(myContext, "sh rish.sh","dpm list-owners",null,filesDir)
|
||||||
|
scrollState.animateScrollTo(scrollState.maxValue, scrollAnim())
|
||||||
|
outputTextScrollState.animateScrollTo(0, scrollAnim())
|
||||||
|
}
|
||||||
|
},
|
||||||
|
modifier = Modifier.fillMaxWidth().padding(horizontal = 8.dp)
|
||||||
) {
|
) {
|
||||||
Text(text = stringResource(R.string.list_owners))
|
Text(text = stringResource(R.string.list_owners))
|
||||||
}
|
}
|
||||||
|
|
||||||
var launchTest by remember{mutableStateOf(false)}
|
Button(
|
||||||
LaunchedEffect(launchTest){
|
onClick = {
|
||||||
if(launchTest){
|
coScope.launch {
|
||||||
outputText= myContext.getString(R.string.should_contain_2000_or_0)
|
outputText= myContext.getString(R.string.should_contain_2000_or_0)
|
||||||
scrollState.animateScrollTo(scrollState.maxValue, scrollAnim())
|
scrollState.animateScrollTo(scrollState.maxValue, scrollAnim())
|
||||||
outputText+=executeCommand("sh rish.sh","id",null,filesDir)
|
outputTextScrollState.animateScrollTo(0, scrollAnim())
|
||||||
launchTest=false
|
outputText+=executeCommand(myContext, "sh rish.sh","id",null,filesDir)
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
Button(
|
modifier = Modifier.align(Alignment.CenterHorizontally)
|
||||||
onClick = {launchTest=true}, modifier = Modifier.align(Alignment.CenterHorizontally)
|
|
||||||
) {
|
) {
|
||||||
Text(text = stringResource(R.string.test_rish))
|
Text(text = stringResource(R.string.test_rish))
|
||||||
}
|
}
|
||||||
|
|
||||||
SelectionContainer(modifier = Modifier.horizontalScroll(rememberScrollState())){
|
SelectionContainer(modifier = Modifier.horizontalScroll(outputTextScrollState)){
|
||||||
Text(text = outputText, style = bodyTextStyle, softWrap = false, modifier = Modifier.padding(4.dp))
|
Text(text = outputText, style = bodyTextStyle, softWrap = false, modifier = Modifier.padding(4.dp))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -227,25 +225,25 @@ private fun checkPermission(myContext: Context):String {
|
|||||||
try{
|
try{
|
||||||
if(Shizuku.checkSelfPermission()==PackageManager.PERMISSION_GRANTED) {
|
if(Shizuku.checkSelfPermission()==PackageManager.PERMISSION_GRANTED) {
|
||||||
val permission = when(Shizuku.getUid()){ 0->"Root"; 2000->"Shell"; else->myContext.getString(R.string.unknown) }
|
val permission = when(Shizuku.getUid()){ 0->"Root"; 2000->"Shell"; else->myContext.getString(R.string.unknown) }
|
||||||
myContext.getString(R.string.shizuku_permission_granted, Shizuku.getVersion(), permission)
|
myContext.getString(R.string.shizuku_permission_granted, Shizuku.getVersion().toString(), permission)
|
||||||
}else if(Shizuku.shouldShowRequestPermissionRationale()){ myContext.getString(R.string.denied) }
|
}else if(Shizuku.shouldShowRequestPermissionRationale()){ myContext.getString(R.string.denied) }
|
||||||
else{ Shizuku.requestPermission(0); myContext.getString(R.string.request_permission) }
|
else{ Shizuku.requestPermission(0); myContext.getString(R.string.request_permission) }
|
||||||
}catch(e: Throwable){ myContext.getString(R.string.shizuku_not_started) }
|
}catch(e: Throwable){ myContext.getString(R.string.shizuku_not_started) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun executeCommand(command: String, subCommand:String, env: Array<String>?, dir:File?): String {
|
suspend fun executeCommand(myContext: Context, command: String, subCommand:String, env: Array<String>?, dir:File?): String {
|
||||||
var result = ""
|
var result = ""
|
||||||
val tunnel:ByteArrayInputStream
|
val tunnel:ByteArrayInputStream
|
||||||
val process:Process
|
val process:Process
|
||||||
val outputStream:OutputStream
|
val outputStream:OutputStream
|
||||||
try {
|
try {
|
||||||
tunnel = ByteArrayInputStream(subCommand.toByteArray())
|
tunnel = ByteArrayInputStream(subCommand.toByteArray())
|
||||||
process = Runtime.getRuntime().exec(command,env,dir)
|
process = withContext(Dispatchers.IO){Runtime.getRuntime().exec(command, env, dir)}
|
||||||
outputStream = process.outputStream
|
outputStream = process.outputStream
|
||||||
IOUtils.copy(tunnel,outputStream)
|
IOUtils.copy(tunnel,outputStream)
|
||||||
outputStream.close()
|
withContext(Dispatchers.IO){ outputStream.close() }
|
||||||
val exitCode = process.waitFor()
|
val exitCode = withContext(Dispatchers.IO){ process.waitFor() }
|
||||||
if(exitCode!=0){ result+="Error: $exitCode" }
|
if(exitCode!=0){ result+="Error: $exitCode" }
|
||||||
}catch(e:Exception){
|
}catch(e:Exception){
|
||||||
e.printStackTrace()
|
e.printStackTrace()
|
||||||
@@ -254,12 +252,13 @@ fun executeCommand(command: String, subCommand:String, env: Array<String>?, dir:
|
|||||||
try {
|
try {
|
||||||
val outputReader = BufferedReader(InputStreamReader(process.inputStream))
|
val outputReader = BufferedReader(InputStreamReader(process.inputStream))
|
||||||
var outputLine: String
|
var outputLine: String
|
||||||
while(outputReader.readLine().also {outputLine = it}!=null) { result+="$outputLine\n" }
|
while(withContext(Dispatchers.IO){ outputReader.readLine() }.also {outputLine = it}!=null) { result+="$outputLine\n" }
|
||||||
val errorReader = BufferedReader(InputStreamReader(process.errorStream))
|
val errorReader = BufferedReader(InputStreamReader(process.errorStream))
|
||||||
var errorLine: String
|
var errorLine: String
|
||||||
while(errorReader.readLine().also {errorLine = it}!=null) { result+="$errorLine\n" }
|
while(withContext(Dispatchers.IO){ errorReader.readLine() }.also {errorLine = it}!=null) { result+="$errorLine\n" }
|
||||||
} catch(e: NullPointerException) {
|
} catch(e: NullPointerException) {
|
||||||
e.printStackTrace()
|
e.printStackTrace()
|
||||||
}
|
}
|
||||||
|
if(result==""){ return myContext.getString(R.string.try_again) }
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,6 +39,7 @@
|
|||||||
<string name="unsupported">不支持</string>
|
<string name="unsupported">不支持</string>
|
||||||
<string name="developing">功能开发中</string>
|
<string name="developing">功能开发中</string>
|
||||||
<string name="place_holder" />
|
<string name="place_holder" />
|
||||||
|
<string name="try_again">请再试一次</string>
|
||||||
|
|
||||||
<!--Permissions-->
|
<!--Permissions-->
|
||||||
<string name="activate_device_admin">激活Device admin</string>
|
<string name="activate_device_admin">激活Device admin</string>
|
||||||
@@ -85,9 +86,15 @@
|
|||||||
<string name="should_contain_2000_or_0">下面应该出现一行包含“2000”或“0”的文本\n</string>
|
<string name="should_contain_2000_or_0">下面应该出现一行包含“2000”或“0”的文本\n</string>
|
||||||
<string name="test_rish">测试rish</string>
|
<string name="test_rish">测试rish</string>
|
||||||
<string name="please_update_shizuku">请更新Shizuku</string>
|
<string name="please_update_shizuku">请更新Shizuku</string>
|
||||||
<string name="shizuku_permission_granted">Shizuku v%1$i\n已授权(%2$s)</string>
|
<string name="shizuku_permission_granted">Shizuku v%1$s\n已授权(%2$s)</string>
|
||||||
<string name="request_permission">请求授权</string>
|
<string name="request_permission">请求授权</string>
|
||||||
<string name="shizuku_not_started">服务未启动</string>
|
<string name="shizuku_not_started">服务未启动</string>
|
||||||
|
<string name="activate_org_profile_command_with_user_id" tools:ignore="TypographyDashes">
|
||||||
|
dpm mark-profile-owner-on-organization-owned-device --user %1$s com.binbin.androidowner/com.binbin.androidowner.MyDeviceAdminReceiver
|
||||||
|
</string>
|
||||||
|
<string name="dpm_activate_do_command">dpm set-device-owner com.binbin.androidowner/com.binbin.androidowner.MyDeviceAdminReceiver</string>
|
||||||
|
<string name="dpm_activate_po_command">dpm set-profile-owner com.binbin.androidowner/com.binbin.androidowner.MyDeviceAdminReceiver</string>
|
||||||
|
<string name="dpm_activate_da_command">dpm set-active-admin com.binbin.androidowner/com.binbin.androidowner.MyDeviceAdminReceiver</string>
|
||||||
|
|
||||||
<!--System-->
|
<!--System-->
|
||||||
<string name="device_ctrl">系统</string>
|
<string name="device_ctrl">系统</string>
|
||||||
|
|||||||
Reference in New Issue
Block a user