From def43c87084bb53203c531315cdbef72d9a744b3 Mon Sep 17 00:00:00 2001 From: Sanmer Date: Thu, 23 May 2024 15:20:28 +0800 Subject: [PATCH] Optimize `compat` (#229) - Add `PowerManagerDelegate` - Remove unused code & res --- app/build.gradle.kts | 5 -- app/src/main/AndroidManifest.xml | 8 --- app/src/main/kotlin/com/sanmer/mrepo/App.kt | 6 -- .../main/kotlin/com/sanmer/mrepo/Compat.kt | 2 + .../sanmer/mrepo/ui/activity/InstallScreen.kt | 11 +-- .../ui/component/VersionItemBottomSheet.kt | 42 +++++------ .../repository/view/pages/OverviewPage.kt | 5 +- .../mrepo/ui/screens/settings/SettingsMenu.kt | 69 ------------------- .../ui/screens/settings/SettingsScreen.kt | 28 -------- .../kotlin/com/sanmer/mrepo/utils/Utils.kt | 10 --- .../mrepo/viewmodel/InstallViewModel.kt | 7 ++ app/src/main/res/values-ar/strings.xml | 6 -- app/src/main/res/values-de/strings.xml | 6 -- app/src/main/res/values-es/strings.xml | 6 -- app/src/main/res/values-fr/strings.xml | 6 -- app/src/main/res/values-hi/strings.xml | 6 -- app/src/main/res/values-in/strings.xml | 6 -- app/src/main/res/values-it/strings.xml | 6 -- app/src/main/res/values-ja/strings.xml | 6 -- app/src/main/res/values-pl/strings.xml | 6 -- app/src/main/res/values-pt/strings.xml | 6 -- app/src/main/res/values-ro/strings.xml | 6 -- app/src/main/res/values-ru/strings.xml | 6 -- app/src/main/res/values-tr/strings.xml | 6 -- app/src/main/res/values-vi/strings.xml | 6 -- app/src/main/res/values-zh-rCN/strings.xml | 7 -- app/src/main/res/values-zh-rTW/strings.xml | 6 -- app/src/main/res/values/strings.xml | 7 -- compat/build.gradle.kts | 9 ++- compat/src/main/AndroidManifest.xml | 12 ++++ .../mrepo/compat/stub/IPowerManager.aidl | 5 ++ .../mrepo/compat/stub/IServiceManager.aidl | 8 ++- .../dev/sanmer/mrepo/compat/BuildCompat.kt | 18 +++++ .../mrepo/compat/ServiceManagerCompat.kt | 11 ++- .../compat/delegate/PowerManagerDelegate.kt | 39 +++++++++++ .../mrepo/compat/impl/PowerManagerImpl.kt | 11 +++ .../mrepo/compat/impl/ServiceManagerImpl.kt | 19 ++++- gradle/libs.versions.toml | 5 ++ hidden-api/build.gradle.kts | 2 + .../main/java/android/os/IPowerManager.java | 12 ++++ .../java/android/os/PowerManagerHidden.java | 13 ++++ .../main/java/android/os/ServiceManager.java | 7 ++ 42 files changed, 198 insertions(+), 270 deletions(-) delete mode 100644 app/src/main/kotlin/com/sanmer/mrepo/ui/screens/settings/SettingsMenu.kt create mode 100644 compat/src/main/AndroidManifest.xml create mode 100644 compat/src/main/aidl/dev/sanmer/mrepo/compat/stub/IPowerManager.aidl create mode 100644 compat/src/main/kotlin/dev/sanmer/mrepo/compat/BuildCompat.kt create mode 100644 compat/src/main/kotlin/dev/sanmer/mrepo/compat/delegate/PowerManagerDelegate.kt create mode 100644 compat/src/main/kotlin/dev/sanmer/mrepo/compat/impl/PowerManagerImpl.kt create mode 100644 hidden-api/src/main/java/android/os/IPowerManager.java create mode 100644 hidden-api/src/main/java/android/os/PowerManagerHidden.java create mode 100644 hidden-api/src/main/java/android/os/ServiceManager.java diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 8adfb7ac..eb0c36e1 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -135,11 +135,6 @@ dependencies { implementation(libs.markwon.core) implementation(libs.timber) - implementation(libs.libsu.core) - implementation(libs.rikka.shizuku.api) - implementation(libs.rikka.shizuku.provider) - implementation(libs.hiddenApiBypass) - implementation(libs.square.retrofit) implementation(libs.square.retrofit.moshi) implementation(libs.square.okhttp) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index e7c08f8c..bc7c6e92 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -61,14 +61,6 @@ android:name=".service.DownloadService" android:foregroundServiceType="dataSync" android:exported="false" /> - - \ No newline at end of file diff --git a/app/src/main/kotlin/com/sanmer/mrepo/App.kt b/app/src/main/kotlin/com/sanmer/mrepo/App.kt index bd45b3d9..40afcd19 100644 --- a/app/src/main/kotlin/com/sanmer/mrepo/App.kt +++ b/app/src/main/kotlin/com/sanmer/mrepo/App.kt @@ -2,12 +2,10 @@ package com.sanmer.mrepo import android.app.Application import com.sanmer.mrepo.app.utils.NotificationUtils -import com.sanmer.mrepo.compat.BuildCompat import com.sanmer.mrepo.network.NetworkUtils import com.sanmer.mrepo.utils.timber.DebugTree import com.sanmer.mrepo.utils.timber.ReleaseTree import dagger.hilt.android.HiltAndroidApp -import org.lsposed.hiddenapibypass.HiddenApiBypass import timber.log.Timber @HiltAndroidApp @@ -23,10 +21,6 @@ class App : Application() { override fun onCreate() { super.onCreate() - if (BuildCompat.atLeastP) { - HiddenApiBypass.addHiddenApiExemptions("") - } - NotificationUtils.init(this) NetworkUtils.setCacheDir(cacheDir) } diff --git a/app/src/main/kotlin/com/sanmer/mrepo/Compat.kt b/app/src/main/kotlin/com/sanmer/mrepo/Compat.kt index 8be277bd..73daf47d 100644 --- a/app/src/main/kotlin/com/sanmer/mrepo/Compat.kt +++ b/app/src/main/kotlin/com/sanmer/mrepo/Compat.kt @@ -7,6 +7,7 @@ import com.sanmer.mrepo.datastore.WorkingMode import dev.sanmer.mrepo.compat.ServiceManagerCompat import dev.sanmer.mrepo.compat.stub.IFileManager import dev.sanmer.mrepo.compat.stub.IModuleManager +import dev.sanmer.mrepo.compat.stub.IPowerManager import dev.sanmer.mrepo.compat.stub.IServiceManager import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.asStateFlow @@ -26,6 +27,7 @@ object Compat { val moduleManager: IModuleManager get() = mService.moduleManager val fileManager: IFileManager get() = mService.fileManager + val powerManager: IPowerManager get() = mService.powerManager private fun state(alive: Boolean): Boolean { isAlive = alive diff --git a/app/src/main/kotlin/com/sanmer/mrepo/ui/activity/InstallScreen.kt b/app/src/main/kotlin/com/sanmer/mrepo/ui/activity/InstallScreen.kt index c143bb42..f6e6fe12 100644 --- a/app/src/main/kotlin/com/sanmer/mrepo/ui/activity/InstallScreen.kt +++ b/app/src/main/kotlin/com/sanmer/mrepo/ui/activity/InstallScreen.kt @@ -53,7 +53,6 @@ import com.sanmer.mrepo.app.Event.Companion.isLoading import com.sanmer.mrepo.app.Event.Companion.isSucceeded import com.sanmer.mrepo.ui.component.NavigateUpTopBar import com.sanmer.mrepo.ui.utils.isScrollingUp -import com.sanmer.mrepo.utils.Utils import com.sanmer.mrepo.viewmodel.InstallViewModel import kotlinx.coroutines.launch @@ -142,7 +141,9 @@ fun InstallScreen( targetScale = 0.8f ) ) { - FloatingButton() + FloatingButton( + reboot = viewModel::reboot + ) } }, snackbarHost = { SnackbarHost(snackbarHostState) } @@ -214,8 +215,10 @@ private fun TopBar( ) @Composable -private fun FloatingButton() = FloatingActionButton( - onClick = { Utils.reboot() } +private fun FloatingButton( + reboot: () -> Unit, +) = FloatingActionButton( + onClick = reboot ) { Icon( painter = painterResource(id = R.drawable.reload), diff --git a/app/src/main/kotlin/com/sanmer/mrepo/ui/component/VersionItemBottomSheet.kt b/app/src/main/kotlin/com/sanmer/mrepo/ui/component/VersionItemBottomSheet.kt index e6a0bc58..445b51ec 100644 --- a/app/src/main/kotlin/com/sanmer/mrepo/ui/component/VersionItemBottomSheet.kt +++ b/app/src/main/kotlin/com/sanmer/mrepo/ui/component/VersionItemBottomSheet.kt @@ -50,7 +50,6 @@ import com.sanmer.mrepo.app.Event.Companion.isLoading import com.sanmer.mrepo.app.Event.Companion.isSucceeded import com.sanmer.mrepo.model.online.VersionItem import com.sanmer.mrepo.network.compose.requestString -import com.sanmer.mrepo.ui.providable.LocalUserPreferences import com.sanmer.mrepo.ui.utils.expandedShape import kotlinx.coroutines.launch @@ -87,30 +86,27 @@ fun VersionItemBottomSheet( } } ) { - val userPreferences = LocalUserPreferences.current - val enableInstall by remember { - derivedStateOf { - userPreferences.isRoot && isProviderAlive + when { + hasChangelog -> { + ButtonRow( + isUpdate = isUpdate, + enableInstall = isProviderAlive, + state = state, + onDownload = onDownload, + onClose = onClose + ) + ChangelogItem(url = item.changelog) } - } - if (hasChangelog) { - ButtonRow( - isUpdate = isUpdate, - enableInstall = enableInstall, - state = state, - onDownload = onDownload, - onClose = onClose - ) - ChangelogItem(url = item.changelog) - } else { - ButtonColumn( - isUpdate = isUpdate, - enableInstall = enableInstall, - state = state, - downloader = onDownload, - onClose = onClose - ) + else -> { + ButtonColumn( + isUpdate = isUpdate, + enableInstall = isProviderAlive, + state = state, + downloader = onDownload, + onClose = onClose + ) + } } NavigationBarsSpacer() diff --git a/app/src/main/kotlin/com/sanmer/mrepo/ui/screens/repository/view/pages/OverviewPage.kt b/app/src/main/kotlin/com/sanmer/mrepo/ui/screens/repository/view/pages/OverviewPage.kt index 44cb0f04..c44a5562 100644 --- a/app/src/main/kotlin/com/sanmer/mrepo/ui/screens/repository/view/pages/OverviewPage.kt +++ b/app/src/main/kotlin/com/sanmer/mrepo/ui/screens/repository/view/pages/OverviewPage.kt @@ -30,7 +30,6 @@ import com.sanmer.mrepo.model.local.LocalModule import com.sanmer.mrepo.model.local.versionDisplay import com.sanmer.mrepo.model.online.OnlineModule import com.sanmer.mrepo.model.online.VersionItem -import com.sanmer.mrepo.ui.providable.LocalUserPreferences import com.sanmer.mrepo.utils.extensions.toDateTime @Composable @@ -100,8 +99,6 @@ private fun CloudItem( .fillMaxWidth(), verticalArrangement = Arrangement.spacedBy(16.dp) ) { - val userPreferences = LocalUserPreferences.current - Text( text = stringResource(id = R.string.view_module_cloud), style = MaterialTheme.typography.titleSmall, @@ -120,7 +117,7 @@ private fun CloudItem( ) ElevatedAssistChip( - enabled = userPreferences.isRoot && isProviderAlive, + enabled = isProviderAlive, onClick = { onInstall(item) }, label = { Text(text = stringResource(id = R.string.module_install)) }, leadingIcon = { diff --git a/app/src/main/kotlin/com/sanmer/mrepo/ui/screens/settings/SettingsMenu.kt b/app/src/main/kotlin/com/sanmer/mrepo/ui/screens/settings/SettingsMenu.kt deleted file mode 100644 index 65cdd7b8..00000000 --- a/app/src/main/kotlin/com/sanmer/mrepo/ui/screens/settings/SettingsMenu.kt +++ /dev/null @@ -1,69 +0,0 @@ -package com.sanmer.mrepo.ui.screens.settings - -import android.content.Context -import android.os.PowerManager -import androidx.annotation.StringRes -import androidx.compose.material3.DropdownMenuItem -import androidx.compose.material3.Text -import androidx.compose.runtime.Composable -import androidx.compose.runtime.derivedStateOf -import androidx.compose.runtime.getValue -import androidx.compose.runtime.remember -import androidx.compose.ui.platform.LocalContext -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.unit.DpOffset -import androidx.compose.ui.unit.dp -import com.sanmer.mrepo.R -import com.sanmer.mrepo.compat.BuildCompat -import com.sanmer.mrepo.ui.component.DropdownMenu -import com.sanmer.mrepo.utils.Utils - -private enum class Menu( - @StringRes val label: Int, - val reason: String, -) { - Reboot(label = R.string.settings_menu_reboot, reason = ""), - Userspace(label = R.string.settings_menu_reboot_userspace, reason = "userspace"), - Recovery(label = R.string.settings_menu_reboot_recovery, reason = "recovery"), - Bootloader(label = R.string.settings_menu_reboot_bootloader, reason = "bootloader"), - Download(label = R.string.settings_menu_reboot_download, reason = "download"), - EDL(label = R.string.settings_menu_reboot_edl, reason = "edl") -} - -@Composable -fun SettingsMenu( - expanded: Boolean, - onClose: () -> Unit -) = DropdownMenu( - expanded = expanded, - onDismissRequest = onClose, - offset = DpOffset(0.dp, 10.dp) -) { - val powerManager = LocalContext.current.getSystemService(Context.POWER_SERVICE) as PowerManager? - val hasUserspace by remember { - derivedStateOf { BuildCompat.atLeastR && powerManager?.isRebootingUserspaceSupported == true } - } - - MenuItem(value = Menu.Reboot, onClose = onClose) - - if (hasUserspace) { - MenuItem(value = Menu.Userspace, onClose = onClose) - } - - MenuItem(value = Menu.Recovery, onClose = onClose) - MenuItem(value = Menu.Bootloader, onClose = onClose) - MenuItem(value = Menu.Download, onClose = onClose) - MenuItem(value = Menu.EDL, onClose = onClose) -} - -@Composable -private fun MenuItem( - value: Menu, - onClose: () -> Unit -) = DropdownMenuItem( - text = { Text(text = stringResource(id = value.label)) }, - onClick = { - Utils.reboot(value.reason) - onClose() - } -) \ No newline at end of file diff --git a/app/src/main/kotlin/com/sanmer/mrepo/ui/screens/settings/SettingsScreen.kt b/app/src/main/kotlin/com/sanmer/mrepo/ui/screens/settings/SettingsScreen.kt index 1f85b160..f259dcf2 100644 --- a/app/src/main/kotlin/com/sanmer/mrepo/ui/screens/settings/SettingsScreen.kt +++ b/app/src/main/kotlin/com/sanmer/mrepo/ui/screens/settings/SettingsScreen.kt @@ -6,20 +6,13 @@ import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll -import androidx.compose.material3.Icon -import androidx.compose.material3.IconButton import androidx.compose.material3.Scaffold import androidx.compose.material3.TopAppBar import androidx.compose.material3.TopAppBarDefaults import androidx.compose.material3.TopAppBarScrollBehavior import androidx.compose.runtime.Composable -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import androidx.compose.ui.input.nestedscroll.nestedScroll -import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.hilt.navigation.compose.hiltViewModel import androidx.navigation.NavController @@ -42,14 +35,12 @@ fun SettingsScreen( viewModel: SettingsViewModel = hiltViewModel() ) { val userPreferences = LocalUserPreferences.current - val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior() Scaffold( modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection), topBar = { TopBar( - isRoot = userPreferences.isRoot, scrollBehavior = scrollBehavior ) }, @@ -115,29 +106,10 @@ fun SettingsScreen( @Composable private fun TopBar( - isRoot: Boolean, scrollBehavior: TopAppBarScrollBehavior ) = TopAppBar( title = { TopAppBarTitle(text = stringResource(id = R.string.page_settings)) }, - actions = { - var expanded by remember { mutableStateOf(false) } - - IconButton( - onClick = { expanded = true }, - enabled = isRoot - ) { - Icon( - painter = painterResource(id = R.drawable.reload), - contentDescription = null - ) - - SettingsMenu( - expanded = expanded, - onClose = { expanded = false } - ) - } - }, scrollBehavior = scrollBehavior ) \ No newline at end of file diff --git a/app/src/main/kotlin/com/sanmer/mrepo/utils/Utils.kt b/app/src/main/kotlin/com/sanmer/mrepo/utils/Utils.kt index 0cd95cd8..d4135a33 100644 --- a/app/src/main/kotlin/com/sanmer/mrepo/utils/Utils.kt +++ b/app/src/main/kotlin/com/sanmer/mrepo/utils/Utils.kt @@ -1,16 +1,6 @@ package com.sanmer.mrepo.utils -import com.topjohnwu.superuser.Shell - object Utils { - fun reboot(reason: String = "") { - if (reason == "recovery") { - // KEYCODE_POWER = 26, hide incorrect "Factory data reset" message - Shell.cmd("/system/bin/input keyevent 26").submit() - } - Shell.cmd("/system/bin/svc power reboot $reason || /system/bin/reboot $reason").submit() - } - fun getVersionDisplay(version: String, versionCode: Int): String { val included = "\\(.*?${versionCode}.*?\\)".toRegex() .containsMatchIn(version) diff --git a/app/src/main/kotlin/com/sanmer/mrepo/viewmodel/InstallViewModel.kt b/app/src/main/kotlin/com/sanmer/mrepo/viewmodel/InstallViewModel.kt index 79aad958..24ad9c20 100644 --- a/app/src/main/kotlin/com/sanmer/mrepo/viewmodel/InstallViewModel.kt +++ b/app/src/main/kotlin/com/sanmer/mrepo/viewmodel/InstallViewModel.kt @@ -18,6 +18,7 @@ import com.sanmer.mrepo.repository.UserPreferencesRepository import com.sanmer.mrepo.utils.extensions.tmpDir import dagger.hilt.android.lifecycle.HiltViewModel import dev.sanmer.mrepo.compat.content.State +import dev.sanmer.mrepo.compat.delegate.PowerManagerDelegate import dev.sanmer.mrepo.compat.stub.IInstallCallback import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.first @@ -44,6 +45,12 @@ class InstallViewModel @Inject constructor( Timber.d("InstallViewModel init") } + fun reboot() { + PowerManagerDelegate(Compat.powerManager).apply { + reboot() + } + } + suspend fun writeLogsTo(context: Context, uri: Uri) = withContext(Dispatchers.IO) { runCatching { val cr = context.contentResolver diff --git a/app/src/main/res/values-ar/strings.xml b/app/src/main/res/values-ar/strings.xml index d7a02a02..2bb974b3 100644 --- a/app/src/main/res/values-ar/strings.xml +++ b/app/src/main/res/values-ar/strings.xml @@ -18,12 +18,6 @@ غير متاح %1$sبواسطة%2$s FSF الحر - إعادة تشغيل - اعادة تشغيل النظام - اعادة التشغيل الى وضع الإسترداد - اعادة التشغيل الى محمل الإقلاع - اعادة التشغيل الى وضع التنزيل - اعادة التشغيل الى وضع EDL إزالة استرجاع تثبيت diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index f0da2c8d..65e901f8 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -44,12 +44,6 @@ Nicht verfügbar Keiner Funktionalität eingeschränkt - Neustart - Neustart (schnell) - Neustart ins Recovery - Neustart in den Bootloader - Neustart in den Download-Modus - Neustart in den EDL-Modus App Design Farben und Nacht-Modus ändern Download Pfad diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index 23f8dcca..1ec6a22c 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -1,8 +1,6 @@ Cambia la combinación de colores y el modo nocturno - Reiniciar a Bootloader - Reiniciar a EDL %1$s por %2$s Eliminar Restaurar @@ -14,14 +12,10 @@ Versiones Proporcionado por %s Temas de la App - Reiniciar a Download App Ruta de descarga Repositorio Gestionar los repositorios de módulos Magisk - Reiniciar - Reinicio suave - Reiniciar a Recovery Descargar Root Sin Root diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index f5927b0c..0fe3a42d 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -17,12 +17,6 @@ Non disponible Aucun Le fonctionnement est limité - Redémarrer - Rédémarrer en espace utilisateur - Redémarrer en mode de récupération - Redémarrer en mode amorçage - Redémarrer en mode téléchargement - Redémarrer en mode EDL %1$s par %2$s Supprimer Restaurer diff --git a/app/src/main/res/values-hi/strings.xml b/app/src/main/res/values-hi/strings.xml index 84bd8cfa..9e58c468 100644 --- a/app/src/main/res/values-hi/strings.xml +++ b/app/src/main/res/values-hi/strings.xml @@ -79,15 +79,11 @@ मेजिस्क के भागों के कोषों को व्यवस्थित करें \'एच टी टी पी एस\' के ऊपर \'डी एन एस\' संस्थापन सफल होने के पश्चात संपीडित भाग (माॅडयूल) को हटाएं, यह उच्चतम शक्ति उपयोगकर्ता (सुपरयुजर) द्वारा संचालित होगा - आभासी रूप से पुनरारम्भ करें - उपचारिका हेतु पुनरारम्भ करें - अभिधारण हेतु पुनरारम्भ करें नया मिलाएं %s के द्वारा ❤️ से निर्मित रद्द करें अभिधारण पथ रंगपट्टिका का रूप - इ डी एल हेतु पुनरारम्भ करें अनुप्रयोग का रूप (विषय) रात्रि स्थिति एवं रंगरूप बदले संपीडित सञ्चिका हटाएं @@ -99,11 +95,9 @@ असंगत हटाएं रिक्त - पुनरारम्भ करें अद्यतन नया कोष मिलाएं अज्ञात त्रुटि कार्यक्षमता सीमित है क्या आप वास्तव में %s हटाना चाहते हैं? - संस्थापिका हेतु पुनरारम्भ करें \ No newline at end of file diff --git a/app/src/main/res/values-in/strings.xml b/app/src/main/res/values-in/strings.xml index 895febf4..037d3b25 100644 --- a/app/src/main/res/values-in/strings.xml +++ b/app/src/main/res/values-in/strings.xml @@ -38,12 +38,6 @@ Tidak tersedia Tidak ada Fungsionalitas terbatas - Reboot - Soft Reboot - Reboot ke Recovery - Reboot ke Bootloader - Reboot ke Download - Reboot ke EDL Tema Aplikasi Mengubah skema warna dan mode malam Jalur Download diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml index 37b5a581..9226f1ba 100644 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -54,17 +54,12 @@ Concesso Non disponibile Nessuno - Riavvia - Riavvio leggero Non richiede permessi di root, è disponibile solo la funzione per scaricare i moduli Impossibile salvare: %s La repository è vuota Notifica Tipo: %s Impostazioni di MRepo - Riavvia in Bootloader - Riavvia per scaricare - Riavvia in EDL Tema App Percorso per i Download Elimina File Zip @@ -104,6 +99,5 @@ Elimina lo zip del modulo una volta completata l\'installazione, questa operazione verrà eseguita da Superuser Fornire e gestire repository di moduli per Magisk e KernelSU. Servizio di Download - Riavvia in Recovery Cambia la combinazione di colori e la modalità notturna \ No newline at end of file diff --git a/app/src/main/res/values-ja/strings.xml b/app/src/main/res/values-ja/strings.xml index 6eba2939..1aa3f4a5 100644 --- a/app/src/main/res/values-ja/strings.xml +++ b/app/src/main/res/values-ja/strings.xml @@ -16,7 +16,6 @@ 非 Root OSI Approved FSF Libre - 再起動 インストール ダウンロード モジュールが見つかりません @@ -34,11 +33,6 @@ ライト ダウンロード成功 読み込み中… - Recovery へ再起動 - EDL へ再起動 - Download へ再起動 - Bootloader へ再起動 - ソフトリブート カラースキームとナイトモードの変更 Magisk モジュールリポジトリを管理 テーマパレット diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml index bc3d7f1e..fc8d0d1b 100644 --- a/app/src/main/res/values-pl/strings.xml +++ b/app/src/main/res/values-pl/strings.xml @@ -6,7 +6,6 @@ Wersja Chcesz zainstalować czy pobrać tę wersję modułu\? Ustawienia aplikacji MRepo - Restartuj do Recovery Usuwaj plik zip Usuwa plik zip modułu (za pomocą roota) po pomyślnej instalacji Paleta barw @@ -43,11 +42,6 @@ Niedostępny Brak Funkcjonalność jest ograniczona - Restartuj - Szybki restart - Restartuj do Bootloadera - Restartuj do trybu Download - Restartuj do trybu EDL Motyw aplikacji Zmień paletę barw i kolor tła motywu Tło aplikacji diff --git a/app/src/main/res/values-pt/strings.xml b/app/src/main/res/values-pt/strings.xml index 1ad9203d..54914382 100644 --- a/app/src/main/res/values-pt/strings.xml +++ b/app/src/main/res/values-pt/strings.xml @@ -1,6 +1,5 @@ - Reiniciar em Recuperação O Repositório está vazio Modo de Operação Enraizado @@ -18,11 +17,6 @@ Indisponível Nenhum Funcionalidades limitadas - Reiniciar - Reinício Rápido - Reiniciar em Bootloader - Reiniciar em Download - Reiniciar em EDL %1$s por %2$s Remover Restaurar diff --git a/app/src/main/res/values-ro/strings.xml b/app/src/main/res/values-ro/strings.xml index 1d3e0c40..3944b5a4 100644 --- a/app/src/main/res/values-ro/strings.xml +++ b/app/src/main/res/values-ro/strings.xml @@ -6,10 +6,6 @@ Acordat Indisponibil Nimic - Repornire - Repornire în recuperare - Repornire în Download - Repornire în EDL %1$s de %2$s Elimină Restabilește @@ -37,8 +33,6 @@ Actualizare Mod de funcționare Funcționalitatea este limitată - Repornire rapidă - Repornire în Bootloader Descarcă Căutare… Versiuni diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index 98264b4e..e86f72d2 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -33,11 +33,6 @@ предоставлен Недоступно Нету - Перезагрузка - Перезагрузка оболочки - Перезагрузка в рекавери - Перезагрузка в бутлоадер - Перезагрузка в EDL Тема приложения Путь для загрузки Удалить zip файл @@ -61,7 +56,6 @@ Управление репозиториями модулей Magisk Одобрено OSI Функциональность ограничена - Перезагрузка в режим загрузки Обновить Убрать Вы уверены что хотите удалить %s\? diff --git a/app/src/main/res/values-tr/strings.xml b/app/src/main/res/values-tr/strings.xml index d4e798b7..d1e4ae42 100644 --- a/app/src/main/res/values-tr/strings.xml +++ b/app/src/main/res/values-tr/strings.xml @@ -37,10 +37,6 @@ Mevcut Yok İşlevsellik sınırlı - Yeniden başlat - Download modunda başlat - Recovery modunda başlat - EDL modunda başlat İndirme Yolu Renk paleti ve gece modunu değiştirin Uygulama Teması @@ -71,8 +67,6 @@ Yükleme başarıyla tamamlandıktan sonra modülün zip dosyasını sil, bu Superuser ile gerçekleştirilir MRepo uygulamasının ayarları Mevcut değil - Arayüzü yeniden başlat - Bootloader modunda başlat Son güncelleme Bulut Anaysayfa diff --git a/app/src/main/res/values-vi/strings.xml b/app/src/main/res/values-vi/strings.xml index 18c68874..26f98b52 100644 --- a/app/src/main/res/values-vi/strings.xml +++ b/app/src/main/res/values-vi/strings.xml @@ -51,11 +51,6 @@ Không có sẵn Không có Chức năng bị hạn chế - Khởi động lại - Khởi động lại mềm - Khởi động lại vào Bootloader - Khởi động lại vào Recovery - Khởi động lại vào EDL Chủ đề ứng dụng Xóa tệp Zip Xóa zip của mô-đun sau khi cài đặt thành công, việc này sẽ được thực thi bởi Superuser @@ -98,7 +93,6 @@ Đã lưu nhật ký Được cung cấp bởi %s Không tìm thấy mô-đun nào - Khởi động lại vào Tải xuống Cập nhật mới nhất Cách giải quyết ngộ độc DNS ở một số quốc gia Đang flash diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index 138a4c61..86fbbecf 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -78,13 +78,6 @@ 功能受到限制 - - 重启 - 软重启 - 重启到 Recovery - 重启到 BootLoader - 重启到 Download - 重启到 EDL 主题 更改主题配色和深色模式 diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml index f8c5c84d..1b9be172 100644 --- a/app/src/main/res/values-zh-rTW/strings.xml +++ b/app/src/main/res/values-zh-rTW/strings.xml @@ -20,12 +20,6 @@ 不可用 功能受到限制 - 重新啟動 - 軟重啟 - 重啟到 Recovery - 重啟到 BootLoader - 重啟到 Download - 重啟到 EDL %1$s,作者 %2$s 移除 還原 diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 9a4a2f7c..e8dc044f 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -79,13 +79,6 @@ None Functionality is limited - - Reboot - Soft Reboot - Reboot to Recovery - Reboot to Bootloader - Reboot to Download - Reboot to EDL App Theme Change color scheme and night mode diff --git a/compat/build.gradle.kts b/compat/build.gradle.kts index d01f9bb5..f4e16784 100644 --- a/compat/build.gradle.kts +++ b/compat/build.gradle.kts @@ -1,6 +1,7 @@ plugins { alias(libs.plugins.self.library) alias(libs.plugins.kotlin.parcelize) + alias(libs.plugins.rikka.refine) } android { @@ -13,13 +14,15 @@ android { dependencies { compileOnly(projects.hiddenApi) - - implementation(libs.androidx.annotation) - implementation(libs.kotlinx.coroutines.android) + implementation(libs.hiddenApiBypass) + implementation(libs.rikka.refine.runtime) implementation(libs.libsu.core) implementation(libs.libsu.service) implementation(libs.rikka.shizuku.api) implementation(libs.rikka.shizuku.provider) + + implementation(libs.androidx.annotation) + implementation(libs.kotlinx.coroutines.android) } \ No newline at end of file diff --git a/compat/src/main/AndroidManifest.xml b/compat/src/main/AndroidManifest.xml new file mode 100644 index 00000000..1ac33631 --- /dev/null +++ b/compat/src/main/AndroidManifest.xml @@ -0,0 +1,12 @@ + + + + + + \ No newline at end of file diff --git a/compat/src/main/aidl/dev/sanmer/mrepo/compat/stub/IPowerManager.aidl b/compat/src/main/aidl/dev/sanmer/mrepo/compat/stub/IPowerManager.aidl new file mode 100644 index 00000000..c602c848 --- /dev/null +++ b/compat/src/main/aidl/dev/sanmer/mrepo/compat/stub/IPowerManager.aidl @@ -0,0 +1,5 @@ +package dev.sanmer.mrepo.compat.stub; + +interface IPowerManager { + void reboot(boolean confirm, String reason, boolean wait); +} \ No newline at end of file diff --git a/compat/src/main/aidl/dev/sanmer/mrepo/compat/stub/IServiceManager.aidl b/compat/src/main/aidl/dev/sanmer/mrepo/compat/stub/IServiceManager.aidl index d522d8f1..9202cdbc 100644 --- a/compat/src/main/aidl/dev/sanmer/mrepo/compat/stub/IServiceManager.aidl +++ b/compat/src/main/aidl/dev/sanmer/mrepo/compat/stub/IServiceManager.aidl @@ -2,14 +2,16 @@ package dev.sanmer.mrepo.compat.stub; import dev.sanmer.mrepo.compat.stub.IFileManager; import dev.sanmer.mrepo.compat.stub.IModuleManager; +import dev.sanmer.mrepo.compat.stub.IPowerManager; interface IServiceManager { int getUid() = 0; int getPid() = 1; String getSELinuxContext() = 2; - IModuleManager getModuleManager() = 3; - IFileManager getFileManager() = 4; - String currentPlatform() = 5; + String currentPlatform() = 3; + IModuleManager getModuleManager() = 4; + IFileManager getFileManager() = 5; + IPowerManager getPowerManager() = 6; void destroy() = 16777114; // Only for Shizuku } \ No newline at end of file diff --git a/compat/src/main/kotlin/dev/sanmer/mrepo/compat/BuildCompat.kt b/compat/src/main/kotlin/dev/sanmer/mrepo/compat/BuildCompat.kt new file mode 100644 index 00000000..1707d39e --- /dev/null +++ b/compat/src/main/kotlin/dev/sanmer/mrepo/compat/BuildCompat.kt @@ -0,0 +1,18 @@ +package dev.sanmer.mrepo.compat + +import android.os.Build +import androidx.annotation.ChecksSdkIntAtLeast + +internal object BuildCompat { + @get:ChecksSdkIntAtLeast(api = Build.VERSION_CODES.TIRAMISU) + val atLeastT get() = Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU + + @get:ChecksSdkIntAtLeast(api = Build.VERSION_CODES.S) + val atLeastS get() = Build.VERSION.SDK_INT >= Build.VERSION_CODES.S + + @get:ChecksSdkIntAtLeast(api = Build.VERSION_CODES.R) + val atLeastR get() = Build.VERSION.SDK_INT >= Build.VERSION_CODES.R + + @get:ChecksSdkIntAtLeast(api = Build.VERSION_CODES.P) + val atLeastP get() = Build.VERSION.SDK_INT >= Build.VERSION_CODES.P +} \ No newline at end of file diff --git a/compat/src/main/kotlin/dev/sanmer/mrepo/compat/ServiceManagerCompat.kt b/compat/src/main/kotlin/dev/sanmer/mrepo/compat/ServiceManagerCompat.kt index 84db97b8..e3259251 100644 --- a/compat/src/main/kotlin/dev/sanmer/mrepo/compat/ServiceManagerCompat.kt +++ b/compat/src/main/kotlin/dev/sanmer/mrepo/compat/ServiceManagerCompat.kt @@ -15,6 +15,7 @@ import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.suspendCancellableCoroutine import kotlinx.coroutines.withContext import kotlinx.coroutines.withTimeout +import org.lsposed.hiddenapibypass.HiddenApiBypass import rikka.shizuku.Shizuku import kotlin.coroutines.resume import kotlin.coroutines.resumeWithException @@ -26,6 +27,12 @@ object ServiceManagerCompat { private val context by lazy { ContextDelegate.getContext() } + init { + if (BuildCompat.atLeastP) { + HiddenApiBypass.addHiddenApiExemptions("") + } + } + interface IProvider { val name: String fun isAvailable(): Boolean @@ -89,7 +96,9 @@ object ServiceManagerCompat { private class ShizukuProvider : IProvider { override val name = "Shizuku" - override fun isAvailable() = Shizuku.pingBinder() + override fun isAvailable(): Boolean { + return Shizuku.pingBinder() && Shizuku.getUid() == 0 + } override suspend fun isAuthorized() = when { isGranted -> true diff --git a/compat/src/main/kotlin/dev/sanmer/mrepo/compat/delegate/PowerManagerDelegate.kt b/compat/src/main/kotlin/dev/sanmer/mrepo/compat/delegate/PowerManagerDelegate.kt new file mode 100644 index 00000000..479bb96e --- /dev/null +++ b/compat/src/main/kotlin/dev/sanmer/mrepo/compat/delegate/PowerManagerDelegate.kt @@ -0,0 +1,39 @@ +package dev.sanmer.mrepo.compat.delegate + +import android.os.Build +import android.os.PowerManagerHidden +import androidx.annotation.RequiresApi +import dev.sanmer.mrepo.compat.BuildCompat +import dev.sanmer.mrepo.compat.stub.IPowerManager + +class PowerManagerDelegate( + private val powerManager: IPowerManager +) { + fun reboot(reason: Reason = Reason.UserRequested) { + powerManager.reboot(false, reason.reason, true) + } + + enum class Reason( + internal val reason: String + ) { + UserRequested(SHUTDOWN_USER_REQUESTED), + @RequiresApi(Build.VERSION_CODES.R) + Userspace(REBOOT_USERSPACE), + Recovery(REBOOT_RECOVERY), + Bootloader(REBOOT_BOOTLOADER) + } + + companion object { + const val SHUTDOWN_USER_REQUESTED = "userrequested" + + @RequiresApi(Build.VERSION_CODES.R) + const val REBOOT_USERSPACE = "userspace" + + const val REBOOT_RECOVERY = "recovery" + + const val REBOOT_BOOTLOADER = "bootloader" + + fun isRebootingUserspaceSupported() = + BuildCompat.atLeastR && PowerManagerHidden.isRebootingUserspaceSupportedImpl() + } +} \ No newline at end of file diff --git a/compat/src/main/kotlin/dev/sanmer/mrepo/compat/impl/PowerManagerImpl.kt b/compat/src/main/kotlin/dev/sanmer/mrepo/compat/impl/PowerManagerImpl.kt new file mode 100644 index 00000000..845b6989 --- /dev/null +++ b/compat/src/main/kotlin/dev/sanmer/mrepo/compat/impl/PowerManagerImpl.kt @@ -0,0 +1,11 @@ +package dev.sanmer.mrepo.compat.impl + +import dev.sanmer.mrepo.compat.stub.IPowerManager + +internal class PowerManagerImpl( + private val original: android.os.IPowerManager +) : IPowerManager.Stub() { + override fun reboot(confirm: Boolean, reason: String?, wait: Boolean) { + original.reboot(confirm, reason, wait) + } +} \ No newline at end of file diff --git a/compat/src/main/kotlin/dev/sanmer/mrepo/compat/impl/ServiceManagerImpl.kt b/compat/src/main/kotlin/dev/sanmer/mrepo/compat/impl/ServiceManagerImpl.kt index b7392270..05ead478 100644 --- a/compat/src/main/kotlin/dev/sanmer/mrepo/compat/impl/ServiceManagerImpl.kt +++ b/compat/src/main/kotlin/dev/sanmer/mrepo/compat/impl/ServiceManagerImpl.kt @@ -1,11 +1,14 @@ package dev.sanmer.mrepo.compat.impl +import android.content.Context import android.os.SELinux +import android.os.ServiceManager import android.system.Os import com.topjohnwu.superuser.Shell import com.topjohnwu.superuser.ShellUtils import dev.sanmer.mrepo.compat.stub.IFileManager import dev.sanmer.mrepo.compat.stub.IModuleManager +import dev.sanmer.mrepo.compat.stub.IPowerManager import dev.sanmer.mrepo.compat.stub.IServiceManager import kotlin.system.exitProcess @@ -36,6 +39,14 @@ internal class ServiceManagerImpl : IServiceManager.Stub() { FileManagerImpl() } + private val powerManager by lazy { + PowerManagerImpl( + android.os.IPowerManager.Stub.asInterface( + ServiceManager.getService(Context.POWER_SERVICE) + ) + ) + } + override fun getUid(): Int { return Os.getuid() } @@ -48,6 +59,10 @@ internal class ServiceManagerImpl : IServiceManager.Stub() { return SELinux.getContext() } + override fun currentPlatform(): String { + return platform.name + } + override fun getModuleManager(): IModuleManager { return moduleManager } @@ -56,8 +71,8 @@ internal class ServiceManagerImpl : IServiceManager.Stub() { return fileManager } - override fun currentPlatform(): String { - return platform.name + override fun getPowerManager(): IPowerManager { + return powerManager } override fun destroy() { diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 8bf7409d..6af3dd4e 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -13,6 +13,7 @@ androidxHiltNavigationCompose = "1.2.0" androidxLifecycle = "2.8.0" androidxNavigation = "2.7.7" androidxRoom = "2.6.1" +hiddenApiRefine = "4.4.0" hilt = "2.51.1" kotlin = "2.0.0" kotlinxCoroutines = "1.8.1" @@ -56,6 +57,9 @@ libsu-core = { group = "com.github.topjohnwu.libsu", name = "core", version.ref libsu-service = { group = "com.github.topjohnwu.libsu", name = "service", version.ref = "libsu" } protobuf-kotlin-lite = { group = "com.google.protobuf", name = "protobuf-kotlin-lite", version.ref = "protobuf" } protobuf-protoc = { group = "com.google.protobuf", name = "protoc", version.ref = "protobuf" } +rikka-refine-annotation = { module = "dev.rikka.tools.refine:annotation", version.ref = "hiddenApiRefine" } +rikka-refine-compiler = { module = "dev.rikka.tools.refine:annotation-processor", version.ref = "hiddenApiRefine" } +rikka-refine-runtime = { module = "dev.rikka.tools.refine:runtime", version.ref = "hiddenApiRefine" } rikka-shizuku-api = { module = "dev.rikka.shizuku:api", version.ref = "shizuku" } rikka-shizuku-provider = { module = "dev.rikka.shizuku:provider", version.ref = "shizuku" } square-retrofit = { group = "com.squareup.retrofit2", name = "retrofit", version.ref = "squareRetrofit" } @@ -84,6 +88,7 @@ hilt = { id = "com.google.dagger.hilt.android", version.ref = "hilt" } kotlin-jvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" } kotlin-parcelize = { id = "org.jetbrains.kotlin.plugin.parcelize", version.ref = "kotlin" } ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" } +rikka-refine = { id = "dev.rikka.tools.refine", version.ref = "hiddenApiRefine" } protobuf = { id = "com.google.protobuf", version.ref = "protobufPlugin" } # Plugins defined by this project diff --git a/hidden-api/build.gradle.kts b/hidden-api/build.gradle.kts index 880978df..bc1925fa 100644 --- a/hidden-api/build.gradle.kts +++ b/hidden-api/build.gradle.kts @@ -7,5 +7,7 @@ android { } dependencies { + annotationProcessor(libs.rikka.refine.compiler) + compileOnly(libs.rikka.refine.annotation) compileOnly(libs.androidx.annotation) } \ No newline at end of file diff --git a/hidden-api/src/main/java/android/os/IPowerManager.java b/hidden-api/src/main/java/android/os/IPowerManager.java new file mode 100644 index 00000000..e6f23a29 --- /dev/null +++ b/hidden-api/src/main/java/android/os/IPowerManager.java @@ -0,0 +1,12 @@ +package android.os; + +public interface IPowerManager extends IInterface { + void reboot(boolean confirm, String reason, boolean wait) throws RemoteException; + + abstract class Stub extends Binder implements IPowerManager { + + public static IPowerManager asInterface(IBinder binder) { + throw new RuntimeException("Stub!"); + } + } +} diff --git a/hidden-api/src/main/java/android/os/PowerManagerHidden.java b/hidden-api/src/main/java/android/os/PowerManagerHidden.java new file mode 100644 index 00000000..6b8ec379 --- /dev/null +++ b/hidden-api/src/main/java/android/os/PowerManagerHidden.java @@ -0,0 +1,13 @@ +package android.os; + +import androidx.annotation.RequiresApi; + +import dev.rikka.tools.refine.RefineAs; + +@RefineAs(PowerManager.class) +public class PowerManagerHidden { + @RequiresApi(30) + public static boolean isRebootingUserspaceSupportedImpl() { + throw new RuntimeException("Stub!"); + } +} diff --git a/hidden-api/src/main/java/android/os/ServiceManager.java b/hidden-api/src/main/java/android/os/ServiceManager.java new file mode 100644 index 00000000..6718fb30 --- /dev/null +++ b/hidden-api/src/main/java/android/os/ServiceManager.java @@ -0,0 +1,7 @@ +package android.os; + +public class ServiceManager { + public static IBinder getService(String name) { + throw new RuntimeException("Stub!"); + } +} \ No newline at end of file