diff --git a/manager/build.gradle.kts b/manager/build.gradle.kts index 1647b25..38e5638 100644 --- a/manager/build.gradle.kts +++ b/manager/build.gradle.kts @@ -104,4 +104,6 @@ dependencies { implementation("com.google.accompanist:accompanist-permissions:0.24.2-alpha") implementation("com.google.accompanist:accompanist-swiperefresh:0.24.2-alpha") implementation("com.google.android.material:material:1.5.0") + implementation("dev.rikka.shizuku:api:12.1.0") + implementation("dev.rikka.shizuku:provider:12.1.0") } diff --git a/manager/src/main/AndroidManifest.xml b/manager/src/main/AndroidManifest.xml index bac011f..c7c1d1f 100644 --- a/manager/src/main/AndroidManifest.xml +++ b/manager/src/main/AndroidManifest.xml @@ -34,6 +34,14 @@ android:authorities="org.lsposed.lspatch.provider" android:enabled="true" android:exported="true" /> + + diff --git a/manager/src/main/java/org/lsposed/lspatch/LSPApplication.kt b/manager/src/main/java/org/lsposed/lspatch/LSPApplication.kt index 5ef0139..97679b1 100644 --- a/manager/src/main/java/org/lsposed/lspatch/LSPApplication.kt +++ b/manager/src/main/java/org/lsposed/lspatch/LSPApplication.kt @@ -1,11 +1,20 @@ package org.lsposed.lspatch import android.app.Application +import android.content.pm.PackageManager +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.setValue +import rikka.shizuku.Shizuku const val TAG = "LSPatch Manager" class LSPApplication : Application() { + companion object { + var shizukuGranted by mutableStateOf(Shizuku.checkSelfPermission() == PackageManager.PERMISSION_GRANTED) + } + override fun onCreate() { super.onCreate() diff --git a/manager/src/main/java/org/lsposed/lspatch/ui/page/HomePage.kt b/manager/src/main/java/org/lsposed/lspatch/ui/page/HomePage.kt index dc0d084..0d59e6d 100644 --- a/manager/src/main/java/org/lsposed/lspatch/ui/page/HomePage.kt +++ b/manager/src/main/java/org/lsposed/lspatch/ui/page/HomePage.kt @@ -3,14 +3,17 @@ package org.lsposed.lspatch.ui.page import android.content.ClipData import android.content.ClipboardManager import android.content.Context +import android.content.pm.PackageManager import android.os.Build +import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.* import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.outlined.CheckCircle +import androidx.compose.material.icons.outlined.Warning import androidx.compose.material3.* -import androidx.compose.runtime.Composable -import androidx.compose.runtime.remember -import androidx.compose.runtime.rememberCoroutineScope +import androidx.compose.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext @@ -21,8 +24,10 @@ import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import kotlinx.coroutines.launch import org.lsposed.lspatch.BuildConfig +import org.lsposed.lspatch.LSPApplication import org.lsposed.lspatch.R import org.lsposed.lspatch.ui.util.HtmlText +import rikka.shizuku.Shizuku @OptIn(ExperimentalMaterial3Api::class) @Composable @@ -38,6 +43,8 @@ fun HomePage() { .padding(horizontal = 16.dp) .verticalScroll(rememberScrollState()) ) { + ShizukuCard() + Spacer(Modifier.height(16.dp)) InfoCard(snackbarHostState) Spacer(Modifier.height(16.dp)) SupportCard() @@ -61,6 +68,73 @@ private fun TopBar() { ) } +private val listener: (Int, Int) -> Unit = { _, grantResult -> + LSPApplication.shizukuGranted = grantResult == PackageManager.PERMISSION_GRANTED +} + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +private fun ShizukuCard() { + val key = remember { true } + LaunchedEffect(key) { + Shizuku.addRequestPermissionResultListener(listener) + } + DisposableEffect(key) { + onDispose { + Shizuku.removeRequestPermissionResultListener(listener) + } + } + + ElevatedCard( + modifier = Modifier.clickable { + if (!LSPApplication.shizukuGranted) { + Shizuku.requestPermission(114514) + } + }, + containerColor = run { + if (LSPApplication.shizukuGranted) MaterialTheme.colorScheme.secondaryContainer + else MaterialTheme.colorScheme.errorContainer + } + ) { + Row( + modifier = Modifier + .fillMaxWidth() + .padding(24.dp), + verticalAlignment = Alignment.CenterVertically + ) { + if (LSPApplication.shizukuGranted) { + Icon(Icons.Outlined.CheckCircle, stringResource(R.string.home_shizuku_available)) + Column(Modifier.padding(start = 20.dp)) { + Text( + text = stringResource(R.string.home_shizuku_available), + fontFamily = FontFamily.Serif, + style = MaterialTheme.typography.titleMedium + ) + Spacer(Modifier.height(4.dp)) + Text( + text = "API " + Shizuku.getVersion(), + style = MaterialTheme.typography.bodyMedium + ) + } + } else { + Icon(Icons.Outlined.Warning, stringResource(R.string.home_shizuku_unavailable)) + Column(Modifier.padding(start = 20.dp)) { + Text( + text = stringResource(R.string.home_shizuku_unavailable), + fontFamily = FontFamily.Serif, + style = MaterialTheme.typography.titleMedium + ) + Spacer(Modifier.height(4.dp)) + Text( + text = stringResource(R.string.home_shizuku_warning), + style = MaterialTheme.typography.bodyMedium + ) + } + } + } + } +} + private val apiVersion = if (Build.VERSION.PREVIEW_SDK_INT != 0) { "${Build.VERSION.CODENAME} Preview (API ${Build.VERSION.PREVIEW_SDK_INT})" } else { diff --git a/manager/src/main/res/values/strings.xml b/manager/src/main/res/values/strings.xml index 66a04e0..ff32840 100644 --- a/manager/src/main/res/values/strings.xml +++ b/manager/src/main/res/values/strings.xml @@ -7,6 +7,9 @@ Settings + Shizuku service available + Shizuku service not connected + Some functions unavailable API Version LSPatch Version Framework Version