diff --git a/manager/src/main/AndroidManifest.xml b/manager/src/main/AndroidManifest.xml index 5828490..5ef34f9 100644 --- a/manager/src/main/AndroidManifest.xml +++ b/manager/src/main/AndroidManifest.xml @@ -6,6 +6,7 @@ + () + val snackbarHost = LocalSnackbarHost.current val navController = LocalNavController.current val scope = rememberCoroutineScope() @@ -250,23 +252,8 @@ private fun Body() { icon = LSPPackageManager.getIcon(it.first), label = it.first.label, packageName = it.first.app.packageName, - onClick = { - scope.launch { - scopeApp = it.first.app.packageName - val activated = ConfigManager.getModulesForApp(scopeApp).map { it.pkgName }.toSet() - navController.currentBackStackEntry!!.setState( - "selected", - SnapshotStateList().apply { - LSPPackageManager.appList.filterTo(this) { activated.contains(it.app.packageName) } - } - ) - navController.navigate(PageList.SelectApps.name + "?multiSelect=true") - } - }, - onLongClick = { - // expanded = true - }, - rightIcon = { if (it.second.useManager) Icon(Icons.Filled.ArrowForwardIos, null) }, + onClick = { expanded = true }, + onLongClick = { expanded = true }, additionalContent = { val text = buildAnnotatedString { val (text, color) = @@ -284,9 +271,66 @@ private fun Body() { ) } ) - } - DropdownMenu(expanded = expanded, onDismissRequest = { expanded = false }) { - /* TODO */ + DropdownMenu(expanded = expanded, onDismissRequest = { expanded = false }) { + if (it.second.useManager) { + DropdownMenuItem( + text = { Text(stringResource(R.string.manage_module_scope)) }, + onClick = { + expanded = false + scope.launch { + scopeApp = it.first.app.packageName + val activated = ConfigManager.getModulesForApp(scopeApp).map { it.pkgName }.toSet() + navController.currentBackStackEntry!!.setState( + "selected", + SnapshotStateList().apply { + LSPPackageManager.appList.filterTo(this) { activated.contains(it.app.packageName) } + } + ) + navController.navigate(PageList.SelectApps.name + "?multiSelect=true") + } + } + ) + } + val shizukuUnavailable = stringResource(R.string.shizuku_unavailable) + val optimizeSucceed = stringResource(R.string.manage_optimize_successfully) + val optimizeFailed = stringResource(R.string.manage_optimize_failed) + DropdownMenuItem( + text = { Text(stringResource(R.string.manage_optimize)) }, + onClick = { + expanded = false + if (!ShizukuApi.isPermissionGranted) { + scope.launch { + snackbarHost.showSnackbar(shizukuUnavailable) + } + } else { + scope.launch { + val result = ShizukuApi.performDexOptMode(it.first.app.packageName) + snackbarHost.showSnackbar(if (result) optimizeSucceed else optimizeFailed) + } + } + } + ) + val uninstallSuccessfully = stringResource(R.string.manage_uninstall_successfully) + val launcher = rememberLauncherForActivityResult(ActivityResultContracts.StartActivityForResult()) { + if (it.resultCode == Activity.RESULT_OK) { + scope.launch { + LSPPackageManager.fetchAppList() + snackbarHost.showSnackbar(uninstallSuccessfully) + } + } + } + DropdownMenuItem( + text = { Text(stringResource(R.string.uninstall)) }, + onClick = { + expanded = false + val intent = Intent(Intent.ACTION_DELETE).apply { + data = Uri.parse("package:${it.first.app.packageName}") + putExtra(Intent.EXTRA_RETURN_RESULT, true) + } + launcher.launch(intent) + } + ) + } } } } diff --git a/manager/src/main/java/org/lsposed/lspatch/ui/page/NewPatchPage.kt b/manager/src/main/java/org/lsposed/lspatch/ui/page/NewPatchPage.kt index a2321aa..cf3a9a4 100644 --- a/manager/src/main/java/org/lsposed/lspatch/ui/page/NewPatchPage.kt +++ b/manager/src/main/java/org/lsposed/lspatch/ui/page/NewPatchPage.kt @@ -359,7 +359,7 @@ private fun DoPatchBody(modifier: Modifier) { installing = true } }, - content = { Text(stringResource(R.string.patch_install)) } + content = { Text(stringResource(R.string.install)) } ) } } @@ -439,7 +439,7 @@ private fun InstallDialog(patchApp: AppInfo, onFinish: (Int, String?) -> Unit) { title = { Text( modifier = Modifier.fillMaxWidth(), - text = stringResource(R.string.patch_uninstall), + text = stringResource(R.string.uninstall), textAlign = TextAlign.Center ) }, @@ -454,7 +454,7 @@ private fun InstallDialog(patchApp: AppInfo, onFinish: (Int, String?) -> Unit) { title = { Text( modifier = Modifier.fillMaxWidth(), - text = stringResource(if (installing == 1) R.string.patch_installing else R.string.patch_uninstalling), + text = stringResource(if (installing == 1) R.string.installing else R.string.uninstalling), fontFamily = FontFamily.Serif, textAlign = TextAlign.Center ) diff --git a/manager/src/main/java/org/lsposed/lspatch/ui/page/SettingsPage.kt b/manager/src/main/java/org/lsposed/lspatch/ui/page/SettingsPage.kt index 0d185a2..b405bc8 100644 --- a/manager/src/main/java/org/lsposed/lspatch/ui/page/SettingsPage.kt +++ b/manager/src/main/java/org/lsposed/lspatch/ui/page/SettingsPage.kt @@ -57,28 +57,28 @@ private fun TopBar() { private fun KeyStore() { val context = LocalContext.current val scope = rememberCoroutineScope() - var dropDownExpanded by remember { mutableStateOf(false) } + var dropdownExpanded by remember { mutableStateOf(false) } var showDialog by remember { mutableStateOf(false) } Box { SettingsItem( - onClick = { dropDownExpanded = !dropDownExpanded }, + onClick = { dropdownExpanded = !dropdownExpanded }, icon = Icons.Outlined.Ballot, title = stringResource(R.string.settings_keystore), desc = stringResource(if (MyKeyStore.useDefault) R.string.settings_keystore_default else R.string.settings_keystore_custom) ) - DropdownMenu(expanded = dropDownExpanded, onDismissRequest = { dropDownExpanded = false }) { + DropdownMenu(expanded = dropdownExpanded, onDismissRequest = { dropdownExpanded = false }) { DropdownMenuItem( text = { Text(stringResource(R.string.settings_keystore_default)) }, onClick = { scope.launch { MyKeyStore.reset() } - dropDownExpanded = false + dropdownExpanded = false } ) DropdownMenuItem( text = { Text(stringResource(R.string.settings_keystore_custom)) }, onClick = { - dropDownExpanded = false + dropdownExpanded = false showDialog = true } ) @@ -107,7 +107,7 @@ private fun KeyStore() { } AlertDialog( - onDismissRequest = { dropDownExpanded = false; showDialog = false }, + onDismissRequest = { dropdownExpanded = false; showDialog = false }, confirmButton = { TextButton( content = { Text(stringResource(android.R.string.ok)) }, @@ -145,14 +145,14 @@ private fun KeyStore() { } scope.launch { MyKeyStore.setCustom(password, alias, aliasPassword) } - dropDownExpanded = false + dropdownExpanded = false showDialog = false }) }, dismissButton = { TextButton( content = { Text(stringResource(android.R.string.cancel)) }, - onClick = { dropDownExpanded = false; showDialog = false } + onClick = { dropdownExpanded = false; showDialog = false } ) }, title = { diff --git a/manager/src/main/java/org/lsposed/lspatch/util/ShizukuApi.kt b/manager/src/main/java/org/lsposed/lspatch/util/ShizukuApi.kt index 47423fc..7d1bc91 100644 --- a/manager/src/main/java/org/lsposed/lspatch/util/ShizukuApi.kt +++ b/manager/src/main/java/org/lsposed/lspatch/util/ShizukuApi.kt @@ -5,6 +5,7 @@ import android.content.pm.* import android.os.Build import android.os.IBinder import android.os.IInterface +import android.os.SystemProperties import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.setValue @@ -71,4 +72,12 @@ object ShizukuApi { fun uninstallPackage(packageName: String, intentSender: IntentSender) { packageInstaller.uninstall(packageName, intentSender) } + + fun performDexOptMode(packageName: String): Boolean { + return iPackageManager.performDexOptMode( + packageName, + SystemProperties.getBoolean("dalvik.vm.usejitprofiles", false), + "verify", true, true, null + ) + } } diff --git a/manager/src/main/res/values/strings.xml b/manager/src/main/res/values/strings.xml index 4759d90..c121e63 100644 --- a/manager/src/main/res/values/strings.xml +++ b/manager/src/main/res/values/strings.xml @@ -1,8 +1,11 @@ Add + Install + Installing + Uninstall + Uninstalling Shizuku service available Shizuku service not connected - Repo Logs @@ -23,6 +26,11 @@ Manage Loading No patched apps yet + Module scope + Optimize + Optimize successfully + Optimize failed + Uninstall successfully New Patch @@ -47,11 +55,7 @@ Override the patched app\'s version code to 1\nThis allows downgrade installation in the future, and generally this will not affect the version code actually perceived by the application Start Patch Return - Install - Installing - Uninstall Due to different signatures, you need to uninstall the original app before installing the patched one.\nMake sure you have backed up personal data. - Uninstalling Install successfully Install failed Copy error