From 3fb4fb078fd1fe04d6eaca1e2ea6cd2853d31fd1 Mon Sep 17 00:00:00 2001 From: BinTianqi Date: Sun, 15 Dec 2024 12:01:09 +0800 Subject: [PATCH] Request Shizuku permission before enter Shizuku screen Bind Shizuku service automatically after enter Shizuku functions page --- .../com/bintianqi/owndroid/IUserService.aidl | 1 - .../com/bintianqi/owndroid/MainActivity.kt | 2 +- .../com/bintianqi/owndroid/MyViewModel.kt | 2 + .../com/bintianqi/owndroid/dpm/Permissions.kt | 27 +++- .../com/bintianqi/owndroid/dpm/Shizuku.kt | 133 +++++------------- .../bintianqi/owndroid/dpm/ShizukuService.kt | 12 +- app/src/main/res/values-ru/strings.xml | 17 +-- app/src/main/res/values-tr/strings.xml | 29 ++-- app/src/main/res/values-zh-rCN/strings.xml | 8 +- app/src/main/res/values/strings.xml | 8 +- 10 files changed, 84 insertions(+), 155 deletions(-) diff --git a/app/src/main/aidl/com/bintianqi/owndroid/IUserService.aidl b/app/src/main/aidl/com/bintianqi/owndroid/IUserService.aidl index f53e85e..2175af9 100644 --- a/app/src/main/aidl/com/bintianqi/owndroid/IUserService.aidl +++ b/app/src/main/aidl/com/bintianqi/owndroid/IUserService.aidl @@ -1,7 +1,6 @@ package com.bintianqi.owndroid; interface IUserService { - void destroy() = 16777114; String execute(String command) = 1; int getUid() = 2; } diff --git a/app/src/main/java/com/bintianqi/owndroid/MainActivity.kt b/app/src/main/java/com/bintianqi/owndroid/MainActivity.kt index b3fe7fe..80a1cda 100644 --- a/app/src/main/java/com/bintianqi/owndroid/MainActivity.kt +++ b/app/src/main/java/com/bintianqi/owndroid/MainActivity.kt @@ -210,7 +210,7 @@ fun Home(activity: FragmentActivity, vm: MyViewModel) { composable(route = "HomePage") { HomePage(navCtrl) } composable(route = "Permissions") { Permissions(navCtrl) } - composable(route = "Shizuku") { Shizuku(navCtrl) } + composable(route = "Shizuku") { Shizuku(vm, navCtrl) } composable(route = "DeviceAdmin") { DeviceAdmin(navCtrl) } composable(route = "ProfileOwner") { ProfileOwner(navCtrl) } composable(route = "DeviceOwner") { DeviceOwner(navCtrl) } diff --git a/app/src/main/java/com/bintianqi/owndroid/MyViewModel.kt b/app/src/main/java/com/bintianqi/owndroid/MyViewModel.kt index 0c5dc74..b4af388 100644 --- a/app/src/main/java/com/bintianqi/owndroid/MyViewModel.kt +++ b/app/src/main/java/com/bintianqi/owndroid/MyViewModel.kt @@ -2,6 +2,7 @@ package com.bintianqi.owndroid import android.content.Context import android.os.Build +import android.os.IBinder import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import kotlinx.coroutines.flow.MutableStateFlow @@ -9,6 +10,7 @@ import kotlinx.coroutines.launch class MyViewModel: ViewModel() { val theme = MutableStateFlow(ThemeSettings()) + val shizukuBinder = MutableStateFlow(null) var initialized = false fun initialize(context: Context) { diff --git a/app/src/main/java/com/bintianqi/owndroid/dpm/Permissions.kt b/app/src/main/java/com/bintianqi/owndroid/dpm/Permissions.kt index 2e4a93f..bdb7df6 100644 --- a/app/src/main/java/com/bintianqi/owndroid/dpm/Permissions.kt +++ b/app/src/main/java/com/bintianqi/owndroid/dpm/Permissions.kt @@ -37,6 +37,8 @@ import com.bintianqi.owndroid.yesOrNo import com.rosan.dhizuku.api.Dhizuku import com.rosan.dhizuku.api.DhizukuRequestPermissionListener import kotlinx.coroutines.launch +import rikka.shizuku.Shizuku +import rikka.sui.Sui @SuppressLint("NewApi") @Composable @@ -76,7 +78,30 @@ fun Permissions(navCtrl: NavHostController) { operation = { navCtrl.navigate("DeviceOwner") } ) } - FunctionItem(R.string.shizuku,"") { navCtrl.navigate("Shizuku") } + FunctionItem(R.string.shizuku,"") { + try { + if(Shizuku.checkSelfPermission() == PackageManager.PERMISSION_GRANTED) { navCtrl.navigate("Shizuku") } + else if(Shizuku.shouldShowRequestPermissionRationale()) { + Toast.makeText(context, R.string.permission_denied, Toast.LENGTH_SHORT).show() + } else { + Sui.init(context.packageName) + val listener = object: Shizuku.OnRequestPermissionResultListener { + override fun onRequestPermissionResult(requestCode: Int, grantResult: Int) { + if(grantResult == PackageManager.PERMISSION_GRANTED) { + navCtrl.navigate("Shizuku") + } else { + Toast.makeText(context, R.string.permission_denied, Toast.LENGTH_SHORT).show() + } + Shizuku.removeRequestPermissionResultListener(this) + } + } + Shizuku.addRequestPermissionResultListener(listener) + Shizuku.requestPermission(0) + } + } catch(_: IllegalStateException) { + Toast.makeText(context, R.string.shizuku_not_started, Toast.LENGTH_SHORT).show() + } + } 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)) { FunctionItem(R.string.org_name, "", R.drawable.corporate_fare_fill0) { dialog = 2 } diff --git a/app/src/main/java/com/bintianqi/owndroid/dpm/Shizuku.kt b/app/src/main/java/com/bintianqi/owndroid/dpm/Shizuku.kt index a7c11b3..42422b4 100644 --- a/app/src/main/java/com/bintianqi/owndroid/dpm/Shizuku.kt +++ b/app/src/main/java/com/bintianqi/owndroid/dpm/Shizuku.kt @@ -3,7 +3,6 @@ package com.bintianqi.owndroid.dpm import android.content.ComponentName import android.content.Context import android.content.ServiceConnection -import android.content.pm.PackageManager import android.os.Binder import android.os.Build.VERSION import android.os.IBinder @@ -13,14 +12,14 @@ import androidx.compose.foundation.horizontalScroll import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.wrapContentWidth import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.text.selection.SelectionContainer import androidx.compose.material3.Button +import androidx.compose.material3.CircularProgressIndicator +import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect -import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember @@ -32,74 +31,53 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp +import androidx.compose.ui.window.Dialog +import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.navigation.NavHostController import com.bintianqi.owndroid.IUserService +import com.bintianqi.owndroid.MyViewModel import com.bintianqi.owndroid.R import com.bintianqi.owndroid.ui.MyScaffold import kotlinx.coroutines.delay +import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.launch import rikka.shizuku.Shizuku -private var waitGrantPermission = false - +@OptIn(ExperimentalMaterial3Api::class) @Composable -fun Shizuku(navCtrl: NavHostController) { +fun Shizuku(vm: MyViewModel, navCtrl: NavHostController) { val context = LocalContext.current val dpm = context.getDPM() val receiver = context.getReceiver() val coScope = rememberCoroutineScope() val outputTextScrollState = rememberScrollState() - var enabled by remember { mutableStateOf(false) } - var bindShizuku by remember { mutableStateOf(false) } var outputText by rememberSaveable { mutableStateOf("") } var showDeviceAdminButton by remember { mutableStateOf(!context.isDeviceAdmin) } var showDeviceOwnerButton by remember { mutableStateOf(!context.isDeviceOwner) } var showOrgProfileOwnerButton by remember { mutableStateOf(true) } - val service by shizukuService.collectAsState() - LaunchedEffect(service) { - if(service == null) { - enabled = false - bindShizuku = checkShizukuStatus() == 1 + val binder by vm.shizukuBinder.collectAsStateWithLifecycle() + var service by remember { mutableStateOf(null) } + var loading by remember { mutableStateOf(true) } + LaunchedEffect(binder) { + if(binder != null && binder!!.pingBinder()) { + service = IUserService.Stub.asInterface(binder) + loading = false } else { - enabled = true - bindShizuku = false + service = null } } + LaunchedEffect(service) { + if(service == null && !loading) navCtrl.navigateUp() + } LaunchedEffect(Unit) { - shizukuService.value = null - userServiceControl(context, true) + if(binder == null) bindShizukuService(context, vm.shizukuBinder) } MyScaffold(R.string.shizuku, 0.dp, navCtrl, false) { - AnimatedVisibility(visible = bindShizuku, modifier = Modifier.fillMaxWidth()) { - Button( - onClick = { - userServiceControl(context, true) - outputText = "" - }, - modifier = Modifier.wrapContentWidth(Alignment.CenterHorizontally) - ) { - Text(stringResource(R.string.bind_shizuku)) + if(loading) { + Dialog(onDismissRequest = { navCtrl.navigateUp() }) { + CircularProgressIndicator() } } - - Button( - onClick = { - outputText = checkPermission(context) - if(service != null) { - enabled = true - bindShizuku = false - } else { - enabled = false - bindShizuku = checkShizukuStatus() == 1 - } - coScope.launch { - outputTextScrollState.animateScrollTo(0) - } - }, - modifier = Modifier.align(Alignment.CenterHorizontally) - ) { - Text(text = stringResource(R.string.check_shizuku)) - } Button( onClick = { @@ -108,7 +86,6 @@ fun Shizuku(navCtrl: NavHostController) { outputTextScrollState.animateScrollTo(0) } }, - enabled = enabled, modifier = Modifier.align(Alignment.CenterHorizontally) ) { Text(text = stringResource(R.string.list_owners)) @@ -120,7 +97,6 @@ fun Shizuku(navCtrl: NavHostController) { outputTextScrollState.animateScrollTo(0) } }, - enabled = enabled, modifier = Modifier.align(Alignment.CenterHorizontally) ) { Text(text = stringResource(R.string.list_users)) @@ -132,7 +108,6 @@ fun Shizuku(navCtrl: NavHostController) { outputTextScrollState.animateScrollTo(0) } }, - enabled = enabled, modifier = Modifier.align(Alignment.CenterHorizontally) ) { Text(text = stringResource(R.string.list_accounts)) @@ -149,7 +124,6 @@ fun Shizuku(navCtrl: NavHostController) { showDeviceAdminButton = !context.isDeviceAdmin } }, - enabled = enabled, modifier = Modifier.align(Alignment.CenterHorizontally) ) { Text(text = stringResource(R.string.activate_device_admin)) @@ -166,7 +140,6 @@ fun Shizuku(navCtrl: NavHostController) { showDeviceOwnerButton = !context.isDeviceOwner } }, - enabled = enabled, modifier = Modifier.align(Alignment.CenterHorizontally) ) { Text(text = stringResource(R.string.activate_device_owner)) @@ -187,7 +160,6 @@ fun Shizuku(navCtrl: NavHostController) { showOrgProfileOwnerButton = !dpm.isOrganizationOwnedDeviceWithManagedProfile } }, - enabled = enabled, modifier = Modifier.align(Alignment.CenterHorizontally) ) { Text(text = stringResource(R.string.activate_org_profile)) @@ -201,63 +173,24 @@ fun Shizuku(navCtrl: NavHostController) { } } -private fun checkPermission(context: Context): String { - if(checkShizukuStatus() == -1) { return context.getString(R.string.shizuku_not_started) } - return shizukuService.value.let { - if(it == null) { - context.getString(R.string.shizuku_not_bind) - } else { - when(it.uid) { - 2000 -> context.getString(R.string.shizuku_activated_shell) - 0 -> context.getString(R.string.shizuku_activated_root) - else -> context.getString(R.string.unknown_status) + "\nUID: ${it.uid}" - } - } - } -} - -fun checkShizukuStatus(): Int { - val status = try { - if(Shizuku.checkSelfPermission() == PackageManager.PERMISSION_GRANTED) { waitGrantPermission = false; 1 } - else if(Shizuku.shouldShowRequestPermissionRationale()) { 0 } - else{ - if(!waitGrantPermission) { Shizuku.requestPermission(0) } - waitGrantPermission = true - 0 - } - } catch(_: Exception) { -1 } - return status -} - -fun userServiceControl(context:Context, status:Boolean) { - if(checkShizukuStatus() != 1) { return } +fun bindShizukuService(context: Context, shizukuBinder: MutableStateFlow) { val userServiceConnection = object : ServiceConnection { override fun onServiceConnected(componentName: ComponentName, binder: IBinder) { - if (binder.pingBinder()) { - shizukuService.value = IUserService.Stub.asInterface(binder) - } else { - Toast.makeText(context, R.string.invalid_binder, Toast.LENGTH_SHORT).show() - } + shizukuBinder.value = binder } override fun onServiceDisconnected(componentName: ComponentName) { - shizukuService.value = null + shizukuBinder.value = null Toast.makeText(context, R.string.shizuku_service_disconnected, Toast.LENGTH_SHORT).show() } } - val userServiceArgs = Shizuku.UserServiceArgs( - ComponentName( - context.packageName,ShizukuService::class.java.name - ) - ) + val userServiceArgs = Shizuku.UserServiceArgs(ComponentName(context, ShizukuService::class.java)) .daemon(false) - .processNameSuffix("service") - .debuggable(true) + .processNameSuffix("shizuku-service") + .debuggable(false) .version(26) try { - if(status) { - Shizuku.bindUserService(userServiceArgs, userServiceConnection) - }else{ - Shizuku.unbindUserService(userServiceArgs, userServiceConnection, false) - } - } catch(_: Exception) { } + Shizuku.bindUserService(userServiceArgs, userServiceConnection) + } catch(e: Exception) { + e.printStackTrace() + } } diff --git a/app/src/main/java/com/bintianqi/owndroid/dpm/ShizukuService.kt b/app/src/main/java/com/bintianqi/owndroid/dpm/ShizukuService.kt index 5eda5f0..7871433 100644 --- a/app/src/main/java/com/bintianqi/owndroid/dpm/ShizukuService.kt +++ b/app/src/main/java/com/bintianqi/owndroid/dpm/ShizukuService.kt @@ -3,23 +3,18 @@ package com.bintianqi.owndroid.dpm import android.system.Os import androidx.annotation.Keep import com.bintianqi.owndroid.IUserService -import kotlinx.coroutines.flow.MutableStateFlow import java.io.BufferedReader import java.io.InputStreamReader -val shizukuService = MutableStateFlow(null) - @Keep class ShizukuService: IUserService.Stub() { - override fun destroy() { } - override fun execute(command: String): String { var result = "" val process: Process try { process = Runtime.getRuntime().exec(command) val exitCode = process.waitFor() - if(exitCode != 0){ result += "Error: $exitCode" } + if(exitCode != 0) { result += "Error: $exitCode" } } catch(e: Exception) { e.printStackTrace() return e.toString() @@ -34,11 +29,8 @@ class ShizukuService: IUserService.Stub() { } catch(e: NullPointerException) { e.printStackTrace() } - if(result == "") { return "No result" } return result } - override fun getUid(): Int { - return Os.getuid() - } + override fun getUid(): Int = Os.getuid() } diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index 4dd6219..c826eb1 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -43,7 +43,6 @@ Копировать команду Имя пакета Не существует - Неизвестный статус Копировать Файл не существует Ошибка ввода/вывода @@ -58,10 +57,12 @@ Нет Предыдущий Следующий - On - Off - Alias - Unknown error + + On + Off + Alias + Unknown error + Permission denied @@ -109,19 +110,13 @@ Разрешение Dhizuku не предоставлено Режим Dhizuku отключен - Проверить разрешение Список владельцев Список пользователей Список аккаунтов Shizuku не запущен. - Разрешение предоставлено (Shell) - Разрешение предоставлено (Root) Активировать владельца устройства Активировать рабочий профиль, принадлежащий организации Служба Shizuku отключена - Неверный binder - Подключить Shizuku - Shizuku отключен diff --git a/app/src/main/res/values-tr/strings.xml b/app/src/main/res/values-tr/strings.xml index ab987bb..f837cf3 100644 --- a/app/src/main/res/values-tr/strings.xml +++ b/app/src/main/res/values-tr/strings.xml @@ -44,7 +44,6 @@ Komutu Kopyala Paket Adı Mevcut Değil - Bilinmeyen Durum Kopyala Dosya Mevcut Değil G/Ç Hatası @@ -53,16 +52,18 @@ Tümünü İzin Ver Politika Kullan Hesap - Warning - Delete - Yes - No - Previous - Next - On - Off - Alias - Unknown error + + Warning + Delete + Yes + No + Previous + Next + On + Off + Alias + Unknown error + Permission denied Etkinleştirmek İçin Tıklayın @@ -111,19 +112,13 @@ Dhizuku mode disabled - İzni Kontrol Et Sahipleri Listele List users List accounts Shizuku Başlatılmadı. - İzin Verildi (Kabuk) - İzin Verildi (Root) Cihaz Sahibini Etkinleştir Kuruluş Profili Sahibini Etkinleştir Shizuku Hizmeti Bağlantısı Kesildi - Geçersiz Bağlayıcı - Shizuku\'ya Bağlan - Shizuku Bağlantısı Kesildi Sistem diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index bcdf09a..333c0e9 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -41,7 +41,6 @@ 功能开发中 选项 复制代码 - 未知状态 复制 文件不存在 IO异常 @@ -60,6 +59,7 @@ 关闭 别名 未知错误 + 无权限 点击以激活 @@ -106,19 +106,13 @@ Dhizuku模式已禁用 - 检查Shizuku 列出Owners 列出用户 列出账号 服务未启动 - 已授权(Shell) - 已授权(Root) 激活Device owner 激活由组织拥有的工作资料 Shizuku服务断开连接 - Shizuku未连接 - 无效Binder - 连接Shizuku 系统 diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 286d2fb..c97bc09 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -44,7 +44,6 @@ Copy Command Package name Not exist - Unknown status Copy File not exist IO Exception @@ -63,6 +62,7 @@ Off Alias Unknown error + Permission denied Click to activate @@ -114,21 +114,15 @@ Dhizuku mode disabled Shizuku - Check permission List owners List users List accounts Shizuku not started. dpm set-device-owner com.bintianqi.owndroid/com.bintianqi.owndroid.Receiver dpm set-active-admin com.bintianqi.owndroid/com.bintianqi.owndroid.Receiver - Permission granted (Shell) - Permission granted (Root) Activate Device owner Activate organization-owned work profile Shizuku service disconnected - Invalid binder - Connect Shizuku - Shizuku disconnected System