From 6b420f57937c10c489cd15334961092ca76ae52e Mon Sep 17 00:00:00 2001 From: rcmiku Date: Sun, 1 Dec 2024 11:45:31 +0800 Subject: [PATCH] Initial commit Signed-off-by: rcmiku --- .gitignore | 37 ++++ README.md | 14 ++ app/.gitignore | 2 + app/build.gradle.kts | 77 ++++++++ app/proguard-rules.pro | 24 +++ .../freeze/monitor/ExampleInstrumentedTest.kt | 25 +++ app/src/main/AndroidManifest.xml | 30 +++ app/src/main/ic_launcher-playstore.png | Bin 0 -> 14041 bytes .../com/rcmiku/freeze/monitor/MainActivity.kt | 31 +++ .../rcmiku/freeze/monitor/model/AppInfo.kt | 13 ++ .../com/rcmiku/freeze/monitor/ui/FmApp.kt | 178 +++++++++++++++++ .../monitor/ui/components/AboutDialog.kt | 154 +++++++++++++++ .../freeze/monitor/ui/components/AppItem.kt | 85 ++++++++ .../monitor/ui/components/RootDialog.kt | 45 +++++ .../rcmiku/freeze/monitor/ui/theme/Color.kt | 11 ++ .../rcmiku/freeze/monitor/ui/theme/Theme.kt | 56 ++++++ .../rcmiku/freeze/monitor/ui/theme/Type.kt | 34 ++++ .../com/rcmiku/freeze/monitor/util/Shell.kt | 27 +++ .../monitor/viewModel/AppListViewModel.kt | 162 +++++++++++++++ .../res/drawable/ic_launcher_foreground.xml | 59 ++++++ app/src/main/res/drawable/ic_setting.xml | 11 ++ .../res/mipmap-anydpi-v26/ic_launcher.xml | 6 + .../mipmap-anydpi-v26/ic_launcher_round.xml | 6 + app/src/main/res/mipmap-hdpi/ic_launcher.webp | Bin 0 -> 1108 bytes .../res/mipmap-hdpi/ic_launcher_round.webp | Bin 0 -> 2894 bytes app/src/main/res/mipmap-mdpi/ic_launcher.webp | Bin 0 -> 790 bytes .../res/mipmap-mdpi/ic_launcher_round.webp | Bin 0 -> 1818 bytes .../main/res/mipmap-xhdpi/ic_launcher.webp | Bin 0 -> 1314 bytes .../res/mipmap-xhdpi/ic_launcher_round.webp | Bin 0 -> 3828 bytes .../main/res/mipmap-xxhdpi/ic_launcher.webp | Bin 0 -> 2388 bytes .../res/mipmap-xxhdpi/ic_launcher_round.webp | Bin 0 -> 6482 bytes .../main/res/mipmap-xxxhdpi/ic_launcher.webp | Bin 0 -> 2792 bytes .../res/mipmap-xxxhdpi/ic_launcher_round.webp | Bin 0 -> 8516 bytes app/src/main/res/values-zh-rCN/strings.xml | 24 +++ app/src/main/res/values/colors.xml | 10 + .../res/values/ic_launcher_background.xml | 4 + app/src/main/res/values/strings.xml | 24 +++ app/src/main/res/values/themes.xml | 5 + app/src/main/res/xml/backup_rules.xml | 13 ++ .../main/res/xml/data_extraction_rules.xml | 19 ++ .../rcmiku/freeze/monitor/ExampleUnitTest.kt | 17 ++ build.gradle.kts | 6 + gradle.properties | 25 +++ gradle/libs.versions.toml | 38 ++++ gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 59203 bytes gradle/wrapper/gradle-wrapper.properties | 6 + gradlew | 185 ++++++++++++++++++ gradlew.bat | 89 +++++++++ screenshot/screenshot.jpg | Bin 0 -> 646824 bytes settings.gradle.kts | 23 +++ 50 files changed, 1575 insertions(+) create mode 100644 .gitignore create mode 100644 README.md create mode 100644 app/.gitignore create mode 100644 app/build.gradle.kts create mode 100644 app/proguard-rules.pro create mode 100644 app/src/androidTest/java/com/rcmiku/freeze/monitor/ExampleInstrumentedTest.kt create mode 100644 app/src/main/AndroidManifest.xml create mode 100644 app/src/main/ic_launcher-playstore.png create mode 100644 app/src/main/java/com/rcmiku/freeze/monitor/MainActivity.kt create mode 100644 app/src/main/java/com/rcmiku/freeze/monitor/model/AppInfo.kt create mode 100644 app/src/main/java/com/rcmiku/freeze/monitor/ui/FmApp.kt create mode 100644 app/src/main/java/com/rcmiku/freeze/monitor/ui/components/AboutDialog.kt create mode 100644 app/src/main/java/com/rcmiku/freeze/monitor/ui/components/AppItem.kt create mode 100644 app/src/main/java/com/rcmiku/freeze/monitor/ui/components/RootDialog.kt create mode 100644 app/src/main/java/com/rcmiku/freeze/monitor/ui/theme/Color.kt create mode 100644 app/src/main/java/com/rcmiku/freeze/monitor/ui/theme/Theme.kt create mode 100644 app/src/main/java/com/rcmiku/freeze/monitor/ui/theme/Type.kt create mode 100644 app/src/main/java/com/rcmiku/freeze/monitor/util/Shell.kt create mode 100644 app/src/main/java/com/rcmiku/freeze/monitor/viewModel/AppListViewModel.kt create mode 100644 app/src/main/res/drawable/ic_launcher_foreground.xml create mode 100644 app/src/main/res/drawable/ic_setting.xml create mode 100644 app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml create mode 100644 app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml create mode 100644 app/src/main/res/mipmap-hdpi/ic_launcher.webp create mode 100644 app/src/main/res/mipmap-hdpi/ic_launcher_round.webp create mode 100644 app/src/main/res/mipmap-mdpi/ic_launcher.webp create mode 100644 app/src/main/res/mipmap-mdpi/ic_launcher_round.webp create mode 100644 app/src/main/res/mipmap-xhdpi/ic_launcher.webp create mode 100644 app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp create mode 100644 app/src/main/res/mipmap-xxhdpi/ic_launcher.webp create mode 100644 app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp create mode 100644 app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp create mode 100644 app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp create mode 100644 app/src/main/res/values-zh-rCN/strings.xml create mode 100644 app/src/main/res/values/colors.xml create mode 100644 app/src/main/res/values/ic_launcher_background.xml create mode 100644 app/src/main/res/values/strings.xml create mode 100644 app/src/main/res/values/themes.xml create mode 100644 app/src/main/res/xml/backup_rules.xml create mode 100644 app/src/main/res/xml/data_extraction_rules.xml create mode 100644 app/src/test/java/com/rcmiku/freeze/monitor/ExampleUnitTest.kt create mode 100644 build.gradle.kts create mode 100644 gradle.properties create mode 100644 gradle/libs.versions.toml create mode 100644 gradle/wrapper/gradle-wrapper.jar create mode 100644 gradle/wrapper/gradle-wrapper.properties create mode 100644 gradlew create mode 100644 gradlew.bat create mode 100644 screenshot/screenshot.jpg create mode 100644 settings.gradle.kts diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..fd5376d --- /dev/null +++ b/.gitignore @@ -0,0 +1,37 @@ +# built application files +*.apk +*.ap_ + +# Mac files +.DS_Store + +# files for the dex VM +*.dex + +# Java class files +*.class + +# generated files +bin/ +gen/ + +# Ignore gradle files +.gradle/ +build/ + +# Local configuration file (sdk path, etc) +local.properties + +# Proguard folder generated by Eclipse +proguard/ +proguard-project.txt + +# Eclipse files +.project +.classpath +.settings/ + +# Android Studio/IDEA +*.iml +.idea +.kotlin/ \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..3485d12 --- /dev/null +++ b/README.md @@ -0,0 +1,14 @@ +## Freeze Monitor + +Freeze Monitor is a sample Android application process freeze monitor, built with +[Jetpack Compose](https://developer.android.com/jetpack/compose). + +## Screenshot: + +Screenshot + +### Credits: + +- [Accompanist](https://github.com/google/accompanist) library licensed under Apache License 2.0 +- [Haze](https://github.com/chrisbanes/haze) library licensed under Apache License 2.0 +- [Miuix](https://github.com/miuix-kotlin-multiplatform/miuix) library licensed under Apache License 2.0 \ No newline at end of file diff --git a/app/.gitignore b/app/.gitignore new file mode 100644 index 0000000..956c004 --- /dev/null +++ b/app/.gitignore @@ -0,0 +1,2 @@ +/build +/release \ No newline at end of file diff --git a/app/build.gradle.kts b/app/build.gradle.kts new file mode 100644 index 0000000..86c92e6 --- /dev/null +++ b/app/build.gradle.kts @@ -0,0 +1,77 @@ +plugins { + alias(libs.plugins.android.application) + alias(libs.plugins.kotlin.android) + alias(libs.plugins.kotlin.compose) +} + +android { + namespace = "com.rcmiku.freeze.monitor" + compileSdk = 35 + + defaultConfig { + applicationId = "com.rcmiku.freeze.monitor" + minSdk = 31 + targetSdk = 35 + versionCode = 1 + versionName = "1.0" + resourceConfigurations += listOf("en","zh-rCN") + testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" + } + signingConfigs { + register("release") { + enableV1Signing = true + enableV2Signing = true + enableV3Signing = true + enableV4Signing = true + } + } + + buildTypes { + release { + isMinifyEnabled = true + isShrinkResources = true + proguardFiles( + getDefaultProguardFile("proguard-android-optimize.txt"), + "proguard-rules.pro" + ) + signingConfig = signingConfigs.findByName("release") + } + debug { + applicationIdSuffix = ".debug" + } + } + compileOptions { + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 + } + kotlinOptions { + jvmTarget = "17" + } + + buildFeatures { + compose = true + buildConfig = true + } +} + +dependencies { + implementation(libs.androidx.core.ktx) + implementation(libs.androidx.lifecycle.runtime.ktx) + implementation(libs.androidx.activity.compose) + implementation(platform(libs.androidx.compose.bom)) + implementation(libs.androidx.ui) + implementation(libs.androidx.ui.graphics) + implementation(libs.androidx.ui.tooling.preview) + implementation(libs.androidx.material3) + implementation(libs.kmp.miuix) + implementation(libs.lifecycle.viewmodel.compose) + implementation(libs.accompanist.drawablepainter) + implementation(libs.haze) + testImplementation(libs.junit) + androidTestImplementation(libs.androidx.junit) + androidTestImplementation(libs.androidx.espresso.core) + androidTestImplementation(platform(libs.androidx.compose.bom)) + androidTestImplementation(libs.androidx.ui.test.junit4) + debugImplementation(libs.androidx.ui.tooling) + debugImplementation(libs.androidx.ui.test.manifest) +} \ No newline at end of file diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro new file mode 100644 index 0000000..adc923a --- /dev/null +++ b/app/proguard-rules.pro @@ -0,0 +1,24 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +-renamesourcefileattribute SourceFile + +# Repackage classes into the top-level. +-repackageclasses \ No newline at end of file diff --git a/app/src/androidTest/java/com/rcmiku/freeze/monitor/ExampleInstrumentedTest.kt b/app/src/androidTest/java/com/rcmiku/freeze/monitor/ExampleInstrumentedTest.kt new file mode 100644 index 0000000..50ef6f1 --- /dev/null +++ b/app/src/androidTest/java/com/rcmiku/freeze/monitor/ExampleInstrumentedTest.kt @@ -0,0 +1,25 @@ +package com.rcmiku.freeze.monitor + +import androidx.test.platform.app.InstrumentationRegistry +import androidx.test.ext.junit.runners.AndroidJUnit4 +import com.rcmiku.freeze.monitor.util.Shell + +import org.junit.Test +import org.junit.runner.RunWith + +import org.junit.Assert.* + +/** + * Instrumented test, which will execute on an Android device. + * + * See [testing documentation](http://d.android.com/tools/testing). + */ +@RunWith(AndroidJUnit4::class) +class ExampleInstrumentedTest { + @Test + fun useAppContext() { + // Context of the app under test. + val appContext = InstrumentationRegistry.getInstrumentation().targetContext + assertEquals("com.rcmiku.freeze.monitor", appContext.packageName) + } +} \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..277b6ec --- /dev/null +++ b/app/src/main/AndroidManifest.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/ic_launcher-playstore.png b/app/src/main/ic_launcher-playstore.png new file mode 100644 index 0000000000000000000000000000000000000000..a98b0960b246931ee4a6b9034b8b51b461668dc9 GIT binary patch literal 14041 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 -1) Color.Transparent else MiuixTheme.colorScheme.background, + tint = HazeTint( + MiuixTheme.colorScheme.background.copy( + if (scrollBehavior.state.heightOffset > -1) 1f + else lerp(1f, 0.67f, (scrollBehavior.state.heightOffset + 1) / -143f) + ) + ) + ) + + Scaffold( + topBar = { + TopAppBar( + color = Color.Transparent, + modifier = Modifier.hazeChild( + state = hazeState, + style = hazeStyleTopAppBar, + ) { + progressive = + HazeProgressive.verticalGradient(startIntensity = 0.6f, endIntensity = 0f) + }, + title = "", + largeTitle = stringResource(R.string.app_name), + scrollBehavior = scrollBehavior, + actions = { + AboutDialog(context = context) + } + ) + } + ) { padding -> + LazyColumn( + modifier = Modifier + .fillMaxHeight() + .windowInsetsPadding( + WindowInsets.displayCutout.only( + WindowInsetsSides.Horizontal + ) + ) + .haze(state = hazeState), + topAppBarScrollBehavior = scrollBehavior, + contentPadding = PaddingValues(top = padding.calculateTopPadding()) + ) { + item { + SearchBar( + modifier = Modifier + .padding(start = 12.dp, end = 12.dp, top = 12.dp, bottom = 6.dp), + inputField = { + InputField( + query = searchValue.value, + onQueryChange = { viewModel.updateBySearch(it) }, + onSearch = { + keyboardController?.hide() + }, + expanded = expanded, + onExpandedChange = { expanded = it }, + label = stringResource(R.string.search), + leadingIcon = { + Icon( + modifier = Modifier.padding(start = 12.dp, end = 8.dp), + imageVector = MiuixIcons.Search, + tint = MiuixTheme.colorScheme.onSurfaceContainer, + contentDescription = "Search" + ) + }, + ) + }, + outsideRightAction = { + Text( + modifier = Modifier + .padding(start = 12.dp) + .clickable( + interactionSource = null, + indication = null + ) { + expanded = false + viewModel.updateBySearch("") + }, + text = stringResource(R.string.cancel), + color = MiuixTheme.colorScheme.primary + ) + }, + expanded = expanded, + onExpandedChange = { expanded = it } + ) { + + } + SmallTitle(text = stringResource(R.string.app_list)) + if (appList.value.isNotEmpty()) + Card( + modifier = Modifier + .padding(horizontal = 12.dp) + .windowInsetsPadding(WindowInsets.navigationBars), + insideMargin = PaddingValues(horizontal = 12.dp, vertical = 4.dp) + ) { + for (app in appList.value) { + AppItem(appInfo = app) + } + } + } + } + } + RootDialog(showRootDialog) +} \ No newline at end of file diff --git a/app/src/main/java/com/rcmiku/freeze/monitor/ui/components/AboutDialog.kt b/app/src/main/java/com/rcmiku/freeze/monitor/ui/components/AboutDialog.kt new file mode 100644 index 0000000..4aa86e5 --- /dev/null +++ b/app/src/main/java/com/rcmiku/freeze/monitor/ui/components/AboutDialog.kt @@ -0,0 +1,154 @@ +package com.rcmiku.freeze.monitor.ui.components + +import android.content.Context +import android.content.pm.PackageManager +import androidx.compose.foundation.Image +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.width +import androidx.compose.runtime.Composable +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalUriHandler +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.AnnotatedString +import androidx.compose.ui.text.SpanStyle +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.style.TextDecoration +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import com.google.accompanist.drawablepainter.rememberDrawablePainter +import com.rcmiku.freeze.monitor.BuildConfig +import com.rcmiku.freeze.monitor.R +import com.rcmiku.freeze.monitor.util.Shell +import top.yukonga.miuix.kmp.basic.Icon +import top.yukonga.miuix.kmp.basic.IconButton +import top.yukonga.miuix.kmp.basic.Text +import top.yukonga.miuix.kmp.extra.SuperDialog +import top.yukonga.miuix.kmp.theme.MiuixTheme +import top.yukonga.miuix.kmp.utils.MiuixPopupUtil.Companion.dismissDialog + +@Composable +fun AboutDialog(context: Context) { + + val showDialog = remember { mutableStateOf(false) } + val packageManager: PackageManager = context.packageManager + val applicationInfo = context.applicationInfo + val icon = packageManager.getApplicationIcon(applicationInfo) + val v1frozen = Shell.cmd("ls /sys/fs/cgroup/freezer/perf/frozen/freezer.state").first + val v2UID = Shell.cmd("ls /sys/fs/cgroup/uid_0/cgroup.freeze").first + val v2frozen = Shell.cmd("ls /sys/fs/cgroup/frozen/cgroup.freeze").first + val uriHandler = LocalUriHandler.current + + IconButton( + modifier = Modifier.padding(end = 18.dp), + onClick = { + showDialog.value = true + }, + ) { + Icon( + painter = painterResource(R.drawable.ic_setting), + contentDescription = "Setting" + ) + } + + SuperDialog( + show = showDialog, + title = stringResource(R.string.about), + onDismissRequest = { + dismissDialog(showDialog) + } + ) { + Row( + modifier = Modifier.padding(bottom = 10.dp), + horizontalArrangement = Arrangement.spacedBy(16.dp), + verticalAlignment = Alignment.CenterVertically + ) { + Image( + painter = rememberDrawablePainter(icon), + contentDescription = null, + modifier = Modifier.size(48.dp) + ) + + Column { + Text( + text = stringResource(R.string.app_name), + fontSize = 22.sp, + fontWeight = FontWeight.SemiBold + ) + Text( + text = "v${BuildConfig.VERSION_NAME}", + ) + } + } + Row( + verticalAlignment = Alignment.CenterVertically + ) { + Text( + text = stringResource(R.string.mounted_freezer), + ) + Spacer(Modifier.width(6.dp)) + Text( + text = buildString { + if (v1frozen == 0) { + append("V1(FROZEN) ") + } + if (v2UID == 0) { + append("V2(UID) ") + } + if (v2frozen == 0) { + append("V2(FROZEN)") + } + ifEmpty { + append(stringResource(R.string.mount_freezer_empty)) + } + } + ) + } + Row( + verticalAlignment = Alignment.CenterVertically + ) { + Text( + text = stringResource(R.string.developer), + ) + Spacer(Modifier.width(6.dp)) + Text( + text = stringResource(R.string.author) + ) + } + Row( + verticalAlignment = Alignment.CenterVertically + ) { + Text( + text = stringResource(R.string.source_code), + ) + Spacer(Modifier.width(6.dp)) + Text( + text = AnnotatedString( + text = "GitHub", + spanStyle = SpanStyle( + textDecoration = TextDecoration.Underline, + color = MiuixTheme.colorScheme.primary + ) + ), + modifier = Modifier.clickable( + onClick = { + uriHandler.openUri("https://github.com/rcmiku/Freeze-Monitor") + } + ) + ) + } + Text( + modifier = Modifier.padding(top = 10.dp), + text = stringResource(R.string.app_info) + ) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/rcmiku/freeze/monitor/ui/components/AppItem.kt b/app/src/main/java/com/rcmiku/freeze/monitor/ui/components/AppItem.kt new file mode 100644 index 0000000..5323066 --- /dev/null +++ b/app/src/main/java/com/rcmiku/freeze/monitor/ui/components/AppItem.kt @@ -0,0 +1,85 @@ +package com.rcmiku.freeze.monitor.ui.components + +import androidx.compose.foundation.Image +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.width +import androidx.compose.material3.Badge +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.pluralStringResource +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.unit.dp +import com.google.accompanist.drawablepainter.rememberDrawablePainter +import com.rcmiku.freeze.monitor.R +import com.rcmiku.freeze.monitor.model.AppInfo +import top.yukonga.miuix.kmp.basic.Text +import top.yukonga.miuix.kmp.theme.MiuixTheme + +@Composable +fun AppItem(appInfo: AppInfo) { + + Row( + modifier = Modifier + .fillMaxWidth() + .padding(vertical = 4.dp), + verticalAlignment = Alignment.CenterVertically + ) { + Image( + painter = rememberDrawablePainter(drawable = appInfo.appIcon), + contentDescription = appInfo.appName, + modifier = Modifier.size(48.dp) + ) + Spacer(modifier = Modifier.width(12.dp)) + Column( + modifier = Modifier.weight(1f) + ) { + Text( + text = appInfo.appName, + style = MiuixTheme.textStyles.title4, + ) + Text( + text = buildString { + append(pluralStringResource(R.plurals.process,appInfo.runningProcess,appInfo.runningProcess)) + if (appInfo.frozenProcess > 0) { + append(" ") + append(stringResource(R.string.frozen, appInfo.frozenProcess)) + } + }, + style = MiuixTheme.textStyles.subtitle, + color = MiuixTheme.colorScheme.onSurfaceContainerVariant + ) + Text( + text = buildString { + if (appInfo.appRes < 1024) { + append(stringResource(R.string.size_in_mb, appInfo.appRes)) + } else { + append( + stringResource(R.string.size_in_gb, appInfo.appRes / 1024f), + ) + } + }, + style = MiuixTheme.textStyles.footnote1, + color = MiuixTheme.colorScheme.onSurfaceContainerVariant, + ) + } + if (appInfo.freezeType.isNotEmpty()) + Badge( + containerColor = MiuixTheme.colorScheme.onPrimaryVariant + ) { + Text( + text = stringResource(R.string.freeze_badge, appInfo.freezeType), + style = MiuixTheme.textStyles.footnote2, + color = MiuixTheme.colorScheme.primaryVariant, + fontWeight = FontWeight.SemiBold + ) + } + } +} + diff --git a/app/src/main/java/com/rcmiku/freeze/monitor/ui/components/RootDialog.kt b/app/src/main/java/com/rcmiku/freeze/monitor/ui/components/RootDialog.kt new file mode 100644 index 0000000..d1e0138 --- /dev/null +++ b/app/src/main/java/com/rcmiku/freeze/monitor/ui/components/RootDialog.kt @@ -0,0 +1,45 @@ +package com.rcmiku.freeze.monitor.ui.components + +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Row +import androidx.compose.runtime.Composable +import androidx.compose.runtime.MutableState +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.saveable.rememberSaveable +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource +import com.rcmiku.freeze.monitor.R +import top.yukonga.miuix.kmp.basic.ButtonDefaults +import top.yukonga.miuix.kmp.basic.TextButton +import top.yukonga.miuix.kmp.extra.SuperDialog +import top.yukonga.miuix.kmp.utils.MiuixPopupUtil.Companion.dismissDialog + +@Composable +fun RootDialog(showDialog: MutableState) { + + val isShow = rememberSaveable { mutableStateOf(false) } + if (showDialog.value && !isShow.value) { + isShow.value = !isShow.value + SuperDialog( + title = stringResource(R.string.root_title), + summary = stringResource(R.string.root_message), + show = showDialog, + onDismissRequest = { + dismissDialog(showDialog) + }, + ) { + Row( + horizontalArrangement = Arrangement.SpaceBetween + ) { + TextButton( + modifier = Modifier.weight(1f), + text = stringResource(R.string.confirm), + colors = ButtonDefaults.textButtonColorsPrimary(), + onClick = { + dismissDialog(showDialog) + } + ) + } + } + } +} diff --git a/app/src/main/java/com/rcmiku/freeze/monitor/ui/theme/Color.kt b/app/src/main/java/com/rcmiku/freeze/monitor/ui/theme/Color.kt new file mode 100644 index 0000000..dc55513 --- /dev/null +++ b/app/src/main/java/com/rcmiku/freeze/monitor/ui/theme/Color.kt @@ -0,0 +1,11 @@ +package com.rcmiku.freeze.monitor.ui.theme + +import androidx.compose.ui.graphics.Color + +val Purple80 = Color(0xFFD0BCFF) +val PurpleGrey80 = Color(0xFFCCC2DC) +val Pink80 = Color(0xFFEFB8C8) + +val Purple40 = Color(0xFF6650a4) +val PurpleGrey40 = Color(0xFF625b71) +val Pink40 = Color(0xFF7D5260) \ No newline at end of file diff --git a/app/src/main/java/com/rcmiku/freeze/monitor/ui/theme/Theme.kt b/app/src/main/java/com/rcmiku/freeze/monitor/ui/theme/Theme.kt new file mode 100644 index 0000000..4b42995 --- /dev/null +++ b/app/src/main/java/com/rcmiku/freeze/monitor/ui/theme/Theme.kt @@ -0,0 +1,56 @@ +package com.rcmiku.freeze.monitor.ui.theme + +import androidx.compose.foundation.isSystemInDarkTheme +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.darkColorScheme +import androidx.compose.material3.dynamicDarkColorScheme +import androidx.compose.material3.dynamicLightColorScheme +import androidx.compose.material3.lightColorScheme +import androidx.compose.runtime.Composable +import androidx.compose.ui.platform.LocalContext + +private val DarkColorScheme = darkColorScheme( + primary = Purple80, + secondary = PurpleGrey80, + tertiary = Pink80 +) + +private val LightColorScheme = lightColorScheme( + primary = Purple40, + secondary = PurpleGrey40, + tertiary = Pink40 + + /* Other default colors to override + background = Color(0xFFFFFBFE), + surface = Color(0xFFFFFBFE), + onPrimary = Color.White, + onSecondary = Color.White, + onTertiary = Color.White, + onBackground = Color(0xFF1C1B1F), + onSurface = Color(0xFF1C1B1F), + */ +) + +@Composable +fun FreezeMonitorTheme( + darkTheme: Boolean = isSystemInDarkTheme(), + // Dynamic color is available on Android 12+ + dynamicColor: Boolean = true, + content: @Composable () -> Unit +) { + val colorScheme = when { + dynamicColor -> { + val context = LocalContext.current + if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context) + } + + darkTheme -> DarkColorScheme + else -> LightColorScheme + } + + MaterialTheme( + colorScheme = colorScheme, + typography = Typography, + content = content + ) +} diff --git a/app/src/main/java/com/rcmiku/freeze/monitor/ui/theme/Type.kt b/app/src/main/java/com/rcmiku/freeze/monitor/ui/theme/Type.kt new file mode 100644 index 0000000..3f534e9 --- /dev/null +++ b/app/src/main/java/com/rcmiku/freeze/monitor/ui/theme/Type.kt @@ -0,0 +1,34 @@ +package com.rcmiku.freeze.monitor.ui.theme + +import androidx.compose.material3.Typography +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.text.font.FontFamily +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.unit.sp + +// Set of Material typography styles to start with +val Typography = Typography( + bodyLarge = TextStyle( + fontFamily = FontFamily.Default, + fontWeight = FontWeight.Normal, + fontSize = 16.sp, + lineHeight = 24.sp, + letterSpacing = 0.5.sp + ) + /* Other default text styles to override + titleLarge = TextStyle( + fontFamily = FontFamily.Default, + fontWeight = FontWeight.Normal, + fontSize = 22.sp, + lineHeight = 28.sp, + letterSpacing = 0.sp + ), + labelSmall = TextStyle( + fontFamily = FontFamily.Default, + fontWeight = FontWeight.Medium, + fontSize = 11.sp, + lineHeight = 16.sp, + letterSpacing = 0.5.sp + ) + */ +) \ No newline at end of file diff --git a/app/src/main/java/com/rcmiku/freeze/monitor/util/Shell.kt b/app/src/main/java/com/rcmiku/freeze/monitor/util/Shell.kt new file mode 100644 index 0000000..bcf6f3d --- /dev/null +++ b/app/src/main/java/com/rcmiku/freeze/monitor/util/Shell.kt @@ -0,0 +1,27 @@ +package com.rcmiku.freeze.monitor.util + +object Shell { + + private fun execute(command: String): Pair = runCatching { + Runtime.getRuntime().exec("su").run { + outputStream.use { + it.write(command.toByteArray()) + } + waitFor() to (inputStream.takeIf { it.available() > 0 } ?: errorStream).use { + it.bufferedReader().readText() + } + } + }.getOrElse { -1 to it.message } + + fun cmd(command: String) = execute(command) + + fun isGranted(command: String = "whoami"): Boolean = + (cmd(command = command).second?.trimEnd() ?: false) == "root" + + fun getFreezeStatus(command: String = "ps -e | grep -E 'refrigerator|do_freezer|signal' | awk '{print \$6 \" \" \$9}'") = + cmd(command = command).second + + fun getRunningProcess(command: String = "ps -e | awk '{print \$6 \" \" \$9 \" \" \$5}'") = + cmd(command = command).second + +} \ No newline at end of file diff --git a/app/src/main/java/com/rcmiku/freeze/monitor/viewModel/AppListViewModel.kt b/app/src/main/java/com/rcmiku/freeze/monitor/viewModel/AppListViewModel.kt new file mode 100644 index 0000000..1eafe66 --- /dev/null +++ b/app/src/main/java/com/rcmiku/freeze/monitor/viewModel/AppListViewModel.kt @@ -0,0 +1,162 @@ +package com.rcmiku.freeze.monitor.viewModel + +import android.content.Context +import android.content.pm.ApplicationInfo +import android.content.pm.PackageManager +import android.os.Build +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.rcmiku.freeze.monitor.model.AppInfo +import com.rcmiku.freeze.monitor.util.Shell +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext + +class AppListViewModel : ViewModel() { + + private val _filterApps = MutableStateFlow>(emptyList()) + private val _cacheFilterApps = MutableStateFlow>(emptyList()) + private val _installedApps = MutableStateFlow>(emptyList()) + private val _freezeType = listOf("V1", "V2", "SIGSTOP") + var filterApps: StateFlow> = _filterApps + private val _search = MutableStateFlow("") + private val _rootState = MutableStateFlow(false) + val rootState = _rootState + val search: StateFlow = _search + + fun updateFilterApps(context: Context) { + viewModelScope.launch { + _filterApps.value = getFilterApps(context) + } + } + + private fun getRootGrantState() { + _rootState.value = Shell.isGranted() + } + + fun updateBySearch(string: String) { + viewModelScope.launch { + _search.value = string + _filterApps.value = _cacheFilterApps.value.filter { + if (search.value.isNotEmpty()) + it.appName.contains(search.value, ignoreCase = true) + else + true + } + } + } + + fun updateInstalledApps(context: Context) { + viewModelScope.launch { + _installedApps.value = getInstalledApps(context) + } + } + + private fun getInstalledApps(context: Context): List { + val packageManager: PackageManager = context.packageManager + val installedPackages = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + packageManager.getInstalledApplications( + PackageManager.ApplicationInfoFlags.of( + PackageManager.MATCH_UNINSTALLED_PACKAGES.toLong() + ) + ) + } else { + packageManager.getInstalledApplications(PackageManager.MATCH_UNINSTALLED_PACKAGES) + } + return installedPackages + } + + private suspend fun getFilterApps(context: Context): List { + return withContext(Dispatchers.IO) { + if (!_rootState.value) + return@withContext emptyList() + val packageManager: PackageManager = context.packageManager + var apps = mutableListOf() + val freezeStatus = Shell.getFreezeStatus().toString() + val runningServices = + Shell.getRunningProcess().toString().lines() + .filter { it.isNotBlank() } + .map { it.split(" ") } + .toList() + val freezeStateList = freezeStatus.lines() + .filter { it.isNotBlank() } + .map { it.split(" ") } + .toList() + + apps.addAll(_installedApps.value + .filter { it.flags and ApplicationInfo.FLAG_SYSTEM == 0 } + .filter { countProcess(runningServices, it.packageName) != 0 } + .map { app -> + AppInfo( + app.loadLabel(packageManager).toString(), + app.packageName, + app.loadIcon(packageManager), + countProcess(freezeStatus, app.packageName), + countProcess(runningServices, app.packageName), + sumProcessRes(runningServices, app.packageName), + getFreezeType(freezeStateList, app.packageName) ?: "" + ) + }) + apps.sortWith( + (compareBy( + { it.frozenProcess.inv() }, + { it.appName })) + ) + _cacheFilterApps.value = apps + apps = apps.filter { + if (search.value.isNotEmpty()) + it.appName.contains(search.value, ignoreCase = true) + else + true + }.toMutableList() + apps + } + } + + init { + getRootGrantState() + } + + private fun countProcess(source: String, target: String): Int { + val regex = Regex("${Regex.escape(target)}[:\\s]") + return regex.findAll(source).count() + } + + private fun countProcess(source: List>, target: String): Int { + val regex = Regex("${Regex.escape(target)}(:|$)") + return source.count { + it.getOrNull(1)?.let { indexValue -> + regex.containsMatchIn(indexValue) + } ?: false + } + } + + private fun sumProcessRes(source: List>, target: String): Int { + val regex = Regex("${Regex.escape(target)}(:|$)") + return source.sumOf { row -> + if (row.getOrNull(1)?.let { regex.containsMatchIn(it) } == true) { + row.getOrNull(2)?.toIntOrNull() ?: 0 + } else { + 0 + }.div(1024) + } + } + + private fun getFreezeType(source: List>, target: String): String? { + val regex = Regex("${Regex.escape(target)}(:|$)") + for (list in source) { + if (regex.containsMatchIn(list[1])) { + return when (list[0]) { + "__refrigerator" -> _freezeType[0] + "do_freezer_trap" -> _freezeType[1] + "get_signal" -> _freezeType[1] + "do_signal_stop" -> _freezeType[2] + else -> null + } + } + } + return null + } +} \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_launcher_foreground.xml b/app/src/main/res/drawable/ic_launcher_foreground.xml new file mode 100644 index 0000000..8800850 --- /dev/null +++ b/app/src/main/res/drawable/ic_launcher_foreground.xml @@ -0,0 +1,59 @@ + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/ic_setting.xml b/app/src/main/res/drawable/ic_setting.xml new file mode 100644 index 0000000..e2e46d5 --- /dev/null +++ b/app/src/main/res/drawable/ic_setting.xml @@ -0,0 +1,11 @@ + + + + diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml new file mode 100644 index 0000000..ef49c99 --- /dev/null +++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml new file mode 100644 index 0000000..ef49c99 --- /dev/null +++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher.webp b/app/src/main/res/mipmap-hdpi/ic_launcher.webp new file mode 100644 index 0000000000000000000000000000000000000000..fc6c6075154f1c15d14cdfafce482a33a40ba1c4 GIT binary patch literal 1108 zcmV-a1grZ}Nk&FY1ONb6MM6+kP&iCL1ONapN5ByfZ|69YBuA;!ZkMVtbkq99OgUChu2LvYISAif^gaVO`vVjT$ zlgrQtDIKW_$xc4z)Ba1f9uH?Y7!C^$YiW_vkuX6>c%E!{YY)eDJI`sZgP!$85|e@= z*_n)Uda0r_KA>)1bw|p7N2E~FX}|CLcXQjX(e?3vv2)7R{jn_H>*MC(e6@F}9H{k{ zIa(!mnnRn(bj<%w`}!L7g%58E`P;S`c5_bbY;31)>e#lEI!)c!PHLpK-5#TAGdW;Rrl8xg3S(&cCA7g`E_{uZFGDwTx2cG7q-7E_BZPZ%-l94OW2Hl-DVt zsi2h8NEYNZf>+{Xo4bipN#QA*^X#2UAoO0IM7WRH%+`U6J&43*P)3o=jJE4p=u}SQ zIJB2-)C>u%$+p#m*bsCC4zAt?VKO=MbXYqsw4KrsI(9Ad1d;=!NRMaPb?bLfcCKaF z$qA_nfQtORvX?1!3ZLukR|JqCEK2e4AF-OTbEme;>DG+&_efd@cobP%lw;q?TdAtn z*{OyqTc-p#M7GMnPbRGmAOcq_g=sDW20FDXh1EesK(z$MjARY{i6NvG=Rt!Vnn{5~ zzd9*+@~P2|y(ey=)}Yz}Rna;o^}$i?a=?~kc=`-uj?&h`Sn1WneLd0^gQO_#=9Rfr zsZ;n&>|Z1YC^>HWP9@z2+6wR+l=Sd8J_+P`yHm!ziY7!%rA!SUzm9p_cS5*7Y_AU^ znD+-1T7zLd7i6f3x%BFr!(AO+IURFi zI~%cWYhrY4tk~IS!nIG#iEURwj%{02tm{m0cX#J;pWJgkOgo8|1KGA|Tl2m5e|n>D z+qP}nwrw-CZQHhO>)Phg-e*d%ZQHb?@vYdlZQHhO+qTmM+qRulbs@HG-G3msZ6isN zl2mnFbI73H@q_d4KrL8OQae1m$ z#ZD?GUDCO9vUZhcVz+P{03aB>sfQLqjv-s1Bm4hp<8W@9@5 z>VL_uk*2zsrHk#FxT%Z#x_GC_eAi@tfAfbf^X|OspR6Nho^lZY$2Jp(1NDC7*2HjK z9MdaaYcfG-k`PoO7S+Yk4gUkUW7-M}(7)8JBR1(3AB12UCDJ7RTut&%b%7!pCEaUe z$voFhFeaYQZvj}gIio-w(L@*LbrA&1b0f^qh?~clIO0RVgh9(foi9aov0n=2CK#m& zmoahkMzE|9nT;d>bt)$7;-^UX_vkwbri)*7DkcN@A!b98S(7;-G)Yh;ep$%=!h|k! zaxvtGl&Ywpi$~&@2s6RRFHEO-luJ!9gm9p_VSTI!7&T*1qx{P8lnor}z9QivnafPm zWhw<^c+4C5l&R3L@=Fs#s5Bro2kfZAfhtYmSYMhO9@oB7vsHy+(t`RU)11PaW{0Pw zk1N|}R&0f76cfQu>wh=POyOw)U@XHig?dsrk}*~CSD^+;(UD;=WJAr0h%WPkMd&al zYs8l@)RP}~kWrWVCW zCKx5jeOrnw%{%uxCgoz~?sAPAyzwZBK`t3P{%qfH=1Uq)=UO&H5 z-5eTJm&oG^R1P2F{Tn;(p*ljdS{ISfQh&YcPuu$fH8ylj0Cl$pz?xp5dUHhmjfB?e zh?8qa>l6X7HUN&Y;W?X1aY^^yHzj3BZ++v}Hx*V?Ac8Y{C*!XC8Kg6Jq51E zI&9$ej=)A*@|p_TQw%YAD>e(}Cy9SQCN}4fZyrZzd~8GU?y6 z^6BCo9iD}R=@BdtIRS7UD(gllg&Y0K4mb%%a{MsTQBbDOuSgSpbVX9MZ4-dVIY-ZE zK~|{kGNZGcM9oevx4OD%PE(K+GwRJ&mzOU&i#XMix(I2>v)?(&GlE-~U=^A?G@6;njMSybyvU(({tcv_n`x=IL7X<%2Rz;9e7peE{`og>>||$V@gD3iF{0W+Nk7X`o|?{ zIyhGf)Cf^~v5!PHcIRmON0!*p$0s2Q){f*HW&G1RWgnC6kBMnAURZ>tIE%{+ba?q# zeZf)C_eXrif>@R5<9#^t7kwOCcF;w#5R*umIrKW(a)lf$ji4l%NH%f`lgAQR~^TG*0%PENs!_QHainYED#>ee} z;8xd6+Ku?SiCLZ5P(|Y{UV7iY0PnNL%p@GKQju|+cN2WVWbVCVBL&}=M&(*pwUD* zo`NaPCvylut-!Yg0N?~5^grn@>+#GD#bwE^Zoi`3;6Oybn;bWP>p^%sHM;Kl7`9cp zo5SZ6;WUu|Y_;uAJH=(biprBdrsJr-`F6ss{MBGJSExgo$HV>&3j_Wh*m>OjMu!rS zF#KF=L!dq$FYV*n;DrE6<%-F3Bda; z0%%GA#Ki{L=dLHY22j)jRqQI=E#fCC{Z~64t!Q7oBgG)VK>uDN5%>~f;sYW1^J1*1UkpN=V!spqN1(?}3 z(q#UYlzBW_B!GBn9Kk(;0IVI?3M(f?>puI%Y<>~dK3@(xsuff}b1;k}z{tVYw^xfL9^b|zqhAUIdg+|^ii6(%c z6{jFR@URC90Yt{zZ%9mwek2!YWZI5jWbv50wW-$(FzC!mlR!a_gC?xeQMW51l9Th9 z?b^t!(?o6i|1$DsVRW?nenYkbfG+y(wPq)P=zxnMPSrm@4z^xLr9fuz>^cfHsQUhN z(Ep^b>vjom(nf#%_G|beN_ZHfzS+qWTmp*}b zucJ211mGut!X&4Cl}XX|q)-EIC&buzP!2@hKe%RC;=*0Mimb2$oiU@|~alIv;6ED@+}f6vN19?fj{+Y{0ER$mvU zxo&BfohsaW5&id{5I8V+>`F>|`veTjZlJov}W##`%*M+GT^o}y59tTZW?!=YGu1>{&{WGa%(JJbV^Hk_Y;2}eo&79I?5M* zINJssNs<&vu^`d&?*Gc^yu4lRHj-qgYIG9hZx9oncHwKekYd|b9j!;BFlb;uu@EIO z5O+LfY~~Jv1QJOhfkcu>=YIXR!a=NG?iWA+gF%SF?9UpL;)gGafTr#~cK>zXJN%Rl_uKUnll z7fZhT*6@FwTV-F*_BwM)O5ad@rYdS>s>r$Byv~>Z@8{8@-&1-u;v1q2<2}9puH%^A z?pUw=jS|*+?BXAfOTYLu{JcK|hx~2Zj!Bu#cCBqYV<*?zHnVMev)lP+KO8-8&F|m) zesg^j(SHVR8!1Ybj`{kBP_!7iDK_HHf;I}&+U*pKxpD2f&_Elr;8L&NI(1sCxqUUH zo!pt7QQ_SLI}!8rJZH|G73vW@c^&dCZklHoXX1#B2an$y-_Dy0iumY)s^(J^Gc^GO zS|ME-KxU^xI@is>hPMBc!P;gA8$D>L8xS*IyrI6w(e&2GibmxVlgF|XYiv{|W*wbG ziU*7zNZmREiOKs%fk_#M^E)O1eG+IK0X)CppopQ;b@lzz0D}O;cj(eV;q2D@&3h*x zyebaCzAd>e3ZDC}6}1emUbE7$eZ@`?(^j}?_ZWnA!wlnlHs`kr87^O2(`TD)e?R(a z*Omn$j^wr5HfsT58t~fl4=H%=;j}~`DWxGMf9}B4iJWcKw)d(cG5h!wNEt0%U)Ak+ zZ+ogYl#GfQs&91tE}G0>)PJV{bfp6sohtuJ<3LPD-+%Jo{pa7RYChYEm=Bi%6*)Ec z;7e%Uo`Z{@U!Ds*p@Dbh#S&+3F8cNI(Y^b=Nc@MdelKzf<|WI2eEkOB|60KRxqOLh U@c&u5Ost9PkgN0W#Cj%5G&fCq-2eap literal 0 HcmV?d00001 diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp new file mode 100644 index 0000000000000000000000000000000000000000..c2404412660c28d99cd746608e94a1398ab98174 GIT binary patch literal 1818 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 YeFt+4^FzV7q&eKm+6H@w;Lt<8 literal 0 HcmV?d00001 diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp new file mode 100644 index 0000000000000000000000000000000000000000..24094fb3671a2a6e9abb8524d917e844f717e2ba GIT binary patch literal 3828 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 literal 0 HcmV?d00001 diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp new file mode 100644 index 0000000000000000000000000000000000000000..ba5c5cb68d151d72f09c197e768dd0537d900c3e GIT binary patch literal 6482 zcmV-Y8Lj40Nk&FW82|uRMM6+kP&iCI82|t;kH8}k>R`||lA|$y*xSAkh=>WuhxO6O z8geWS5%rR@f9T&KDeNL^DGW%fM$K$YwIct&YFkc^qgaIdQL$yl6U#Hm2&id?8C4`%1{aOCaSYGLJr~O`fH?M?sAt2;bwR~+2Jr?E z&Z`w>W{zXLI`!0*P43w++VlV-Uo*LI(maPSOMDfbxa-2nUo@(~2$&Pw0|-Z6Bg?jJ z)2?m}k|N~GJZH@v+qP}nwr$(CZRgpxZMFtGl5JHLN%2LTq(Tt@Poi*l_tR(O*xGjN zm2G$GY$ug7gH%}=Ln>CNQl+w!Gl0|Cwr$(?_icx^?b6Y`tV)EwhJ?-+*paq>bu8yU z&@jx*%*@Qp)2+S?4b#lbf~B9m(_e z(ESo}QY|%1vHVc3LKjs+6smSnbvrxTm*)DyiDn?dKc58uZHWY4iG*(S zdTrb1^HNRU`0#-aFpgze^EhU=pC^Q`Q$n)@-B;=e=6|2LzHf5MpYZ1Jm{egm{C5dXy_S)k)^DETT{=K|7Sv;@ki( zt`r6hWwlw>Jbu$aF1eH{+Nux)g;R6G=v!2Xt!~e<<}r=dPhgm!FG3ud8%jGMj<8R^ zIg~-m+V8`)`;k|h5OhIq6qGv!QL&aKv8IH0otK+{-l>IHT)q)`@4QxsLd6m~B5S!x zC@Y`3Z$hrSvSV4<^P``j&*F8etqgB8wYYh4_Rb-QqvhE{Voj@PO{5eS|2Y7L$*sja zmP@KQiRO0k%Pn)0(H_qTv*$~a=3|JT%BjCg>NV?~s%ECLDlWd5jDgD}4wOsolK(Cu z=$0VpFE=H{CD6x-#G8{9WD4S^2IOqnZ#h9Pm2B3OJ^jASgg>tWPX`h%?zfDfcYGpm(hW)fSNWExs!z^5i(QBrcQzU#hM+i z^H>lc^k_olnP{;Dqq%=@lk;=ByxANlxID)}+mNdXUR;77OQz|QNc@mJYrg?tM^r=7 zcu@(Q;_NyP;9FuWbP5% znaP_?P1~7#HPHyeBw-#AQ*#gDVM6gi)~t*I03o|)o;Vl%Ps&CfLwjL%KuX}9=YJ}5 zhivJq8Q4f-gsYLGCZWoxBPu>=8d#gW*$A2G-?eL5p|k>_7D^ zqmH_lz?SZkwGrn&gPA!uFcX&|=yfdU*+L;em#BbJp7u&Q9OL6T$c zmq~KsGN-EoLi3~W!lL|Q5ZnJk(Lt!8NPpV@3}VGq052|>?4)V#X%kfZ(K6I$lxVDq zskvuCcUVz&L5kxQ;@9ARh&dZPs8F|PSOoV>1^N9FFBeONzE7TFz#vKhZ&P6 z?jOz3rH=W@?8kX^o(G*bXVyaaGkaob!_llrYJPB%5*WZET4PdR`)iIaWz0?nXO45@ z5jU5e)X-g}`jsv;vO@9QMZ_6$Kp=Fu1h#N-?0|8+$<2T&Tc~f1($k58MW_->*1JZPZCrsFBB=pMAqVmoGen!> zqinQPptLvO zoJRAtrjdO*`v=PG_!pJck(W6T$kU8UYp_w~ZW=jYi=3VH?}&BfcQsenlm**&M6m=i z;oQM<(WSgXTDs3=5V6z0v~-UFCu2n}I+Rz$_8dgKOv?`_zldD)0P*Hj>cr1o<#P`` z&aWkBC$%5P=-`ap4XLP{j(&g&n>eSq2-xthCeA>G9sT4Yxf{V@$nDit$4%A}5AYQ( zj??fqy)=0klcb&ZQ1{rtCPnxYqKID1R)jD0Z?ImJ5j|xdCJ+YL)YlYkif;a4*BUYa zXrcHbIEb(K&rqlbm%azeZ2K*>&v5bz%g}?wxfxR16pNwEdo+20LOqEBoQi*(=o#^8 z2^NWQesz}_W2;r-5^QCl-lJ|?N+M03)9F8`LQ@yfgQl<0)*Ddfh(nZ|z-?iDRa%s^ zrz^6qnNf8rK3$U&HFE{@hG2XtNi=^GRHy?qH(6Q=@f?&pB`C;T{!TZQvRWhX1RAqq zE6ldbLc;jZp}E|3+xft5^kO&BRkgDmyzhKUlr4NyaszPz$l%2y{ zxhe~AAZCpTTpx2cX33njVS_{?6q!lUzs=*jk0x3^p)j1jj3}MSEy|gYml@kbyOuGw z$PHvZ)+DiUqQA2l{_?<%I%!pnspv;bc)7(vp4J82@3B`oa+zlRxGTVGb_5CDgZ738k zMB6fd0Pqh(vo64^m_2V@MECfAa5|>~%#8b{5^R}X% zRXX?zHK6KQVKVo{moksUw)+uf9@?-Qa@L`)McVre%2;*1tK?(N9yuH`qO51F^KCaX zif597Ct($rU@x;cKkT+);n!wEF-k`WO=55JGc1(p^UvU>+x-UhDRw|Zr7p_KM+cWdA0#e9~((bj+m)ywZ*pEW9 z)$OBRTmo&37YchmcU!MPh2QO0)#O*S$%21ZGbtgOCNF{te^+$}lR?2nBjD1asD0JL z87C|@xZF{Rq^2GgJzuJwcQ}*}EHeuYuakN~>S9uBc(yV!Sdi}M_$i<|N)5usWp=wQ zXf8*t@ViSS5^otCl9m|D5SLMIt@YcO~b*OuokEZ$ZU5KdiQ!a8;OhFC&H= zf5YBrmOJgo13=B1)wgBkdd*yec0^^Q1GduD+6tqGeRJ1givub89o?SEuUyyWQLJ(~ zg#&<+61e-JoReF9Ld8`W7AL2usFM3a#K{*4Q{fjXumFG@W%B27i?bnb3sRx|t^DlZ z1~NZeY8l7ImLD=J<2oWMsbI6m+jTVhHLsS#~2g}LNgN`2mo;M7PEig+XmozH4H$l z(^po*X{dGj8qR9~w8ro;C$fH4I^#723U;yWIwAnf^htb0z+=NzH1k;f`xx!Kr-~Lv zg$6}mqmzz)?07qi!E&c%ctgbSe=+zciumytWZUPtWU0x-1H+pc6|m{;^=8A(G2rKC z5vF35?P;5+_#5HAkTF}y@icLYgEEeAZ9VwaV<~U8p)-ak0J@FAB?e~8lH09b6?^j- zEXNqsw6rDzAShVOp)idzT&1xisC~l6)-lI&`t}J&U9s(Vpv(@x(fA2hnE?(%jS*vZ zJOJVm$6-Kd7TQc90l-c1th4Y)v*DVCq3+XeXon&L(7liPr;j$cjZHnLnnoBk0!mir z&ISloA@}|B|4txl2n^UI_wxykt-2qRv<#&3hR;e_;I;c@+h=wQ1Mg8$1sjG6N>eAn zz?#P^3ml7WXA)T~`1$FJaRDIBU(Bg+!k){?=fc!Je5&$G=$UmNKJ^n)QTy-{m0Q4` zLF6Atj`=wNs9fzlCcZhprqTcqBwEI0DCA?!%c-g5GTZnd#CM9nzvQdbq|?wY7Kj|$ z|9#}0{c{rChk#iCfW686#W;0ur-*HCmotk!P83jU4p16H0?@!Os zBNa?oatfL;-k6=V(J;a`9PIE1hbhPv$nRVQxp13%pi@ON>`)tfj#()HC~iZt*zmSX zdBcbQ`;=RacS39#P*=YD?5{fr8*>HV559`Db3XZsk>c!n&ii!(5UsGs|7 zrZq2Hsu{e#PpXTx<#n^S6J7MvGk_$^TH?&_qgVh);vMCY5})rQQ*`dEhfo#ru4Sh8 z;cV$^^~U!BfWP|j;@HB)-pjf1$S1i3N9|i-w|9EgH1wvFtkx2(GrslW03c8D>~Bgf z4x#94bXGC`mG7}iU27T7{yBsWfN<^Wov8)c*3Y={hg(ueNC@wv~I{c8^%0Lpk*{aGkp(Bck?zDNg6{5|{kCQT_ISo4&0rK?sx937W88#);re$FS} zR&_18+d4xv1zi|s#I5Jhf4a86;Or=q|9D?5&YFTcXHVPq74}EDwLAW&YL3@& zPMJwoN%g}QLzPjkpk~%~q=#w>Iy2FowL9+r?B=j8bpJIZg&dUY=je7GjTi%atV*2( zu+jDDsb+N4RqdLDMj`;TagG|cuc!q2p)%{8F(p@JBE0i4K=WbO==zM013-5_7rL&i zlNsK6asiMpyV*A}Bg(rd1?10RhN__9CxQQmsnEsPvhF2+H_fP&?o!%d1Ashr(^Cq7 zro#|b$VVhQ!i`Rzol?WB}-+ZBf8Gw0N2HxK7Wg@Ev|( zXhlWcO(vx+uX)CHm|JpSR~WT8nZ?-+5hlB8hGvj=^Q5%pW318Lq~b#7y4PFFGA7v| zrN9FUF2PdYbW8PkoclIyMae2j@dw zBr6@6Z46U29pulLvF+=Yp~T_cthg6b@6^mWOYTW}qMHXZw7or_aSH>6iP^^FIO&jd zgjXFIN*q31`_yL6>5FZjq%E}UK4i*OSCzw5VuDGw{s6E}>i%aLNbK&Iw!u!1yr=X; zH}|j8{YfYHx51hO!P)>I>aVfGjBOu}o?~X>VA@?KAC-Phr)N~^3{5Yu9j>vHPb>Zj zFg?dV#j1-M07F1k&%T>Z3d)Ew7_X+voT~7qO(GEVpc?r0eDvQ8>GFeUKdyu-@O_Ch5GHiW5= zkm;MAK0~IdyBSrE{-_n;MVko#1^}YT>yG*-88^MZJ|E{QI>vd2QYI)3^?oAC7IbWQ zeSF#Yq}}SuP14hdg3sCj06&Ok>dER>Cd;DhRZ}|axQLX%g?(wG8&L}SyeD_mMAX9T zCDSdVFIm-K^~qjkic@R+07xgVI~a%b+VJw|NR-JdznPMD%Q2zcG?N+S5I$yAu6Mq5 zyw?!x8~sP1;!p#V*;5XHFoyY{*%8sW;Cj(iLHF-_yszpRtfPlg&;^Pb zN=pg}kS^#C#9CL#NKk3$?6WK0Ge1V zy$)S!y?N1Q_gA+%>6pl9Q&juEtfYb_CC63KM?Ug)BO|?UlBwv|Z>W~0t2mDO$>7w9 z58Iid+Ri#Q;<`(&w=4;$>N)kY?0(a`wAc-vR#aBTl2%WH9sprwAWikoKWo|FA{(9`icb&TF;y26Nkg>CUj-N2+&(ulx zI^&#g>>5zjb3XLfCEoU1Isb9x+B!t>wAwV%nQ03pc0?%m1Hf0+2GKy(_7CUORTt|Y zb`PMQ#bU7-k%4r&!|s3B-}#TWSJbMi{N;#J;+M|KzF>Ne%W$$C06|?#ZDsQ-uH4pk z{`qZfSAIovWo=8H*M73W^&Atnf(Jq4vys;Ro*I{-+;OtrZ%2k-f3l<8;HvTTw~{uW s21~(D39Z|3U+PVu2N|W^_X+^<@|t`@7es*gm7-#Hudb-cArjdS|`6C zz0umPY}>YN+qP}vo&)E$wPVg2+qUi4wo#{3l~lI#2h`hD(%H6E+4XqlVZt_&qhxol zqWcD)Q`ffb&|Bqicc@#^o#ox2c%7F+qTX6Y}>YN+qP}n_RSz`v5SH>u|M2>w7xq)AT`f5p2(x z&mpoKE`A*4^B6n`=OHuzl*E6B`LPNLd2DC&VRlSbjc0uFuEhTicpH@{44)8tT)F^2 zJSh-?#M6c!CS;<-8<*0EHo^ZOVOaaL&Ek!+D9^#*z;md@-c1s9pHU`}L=@Cy)u)pN7^f*9E|vMF=DBK_50^KFfD1&!gewa6az+f z8y)8v{Rx;xz0;_jv~ps?QA#X0_P%>yTDdm(2PNfB95mq@E`w><162!2!ay18*K7dO zsc*%j?g7FM|<69&ylgoCBQ3e$$|Z8(MOsVJrL; zE=Cf##R~7W3pkDbK&tkjZjB`XoVJEr`aF>RDG*HK|F~2n6ip^B77gXn_&>l1{ABC5 z+({{*b`8Uy;CJe>%>S{G$mCsKFK)h*iU0pyR^ay<{z&a=OkJ0oRwgY?y156YQE#*y zBD0>?a!A3Y^$5W8eX_nTG8>2p=PO!IGHS8(UhXf?>7>&<2AGCDQn#Ko5~NANqwP2V zusBqjmu|x!;e!n)HZ7;Xx5PnHB$Pgf@Md>U#cUo+5Y%o8aB4S+RQLGQ9^L}?IbcU5 z6}~GGmGbEfx`N+eYrz2G;gQn=J5%rxtsfrQ%5ULSKAl7qDDjQSxzwsc@D<#499JO; zNwl2+QyBitaqepFiL^+!8AtGCzce`)YJ6{c6>Y}gzlDDZ$?ppn58RVM&4?EOAY4fC zDEM#s=X*A9rU!$gL=-~uc_ZK!!$*=W93;)OpC$<%c{6VkkP!KZZjqQFbCV#Mn|x-_ zcAyo)UhaW*@du*0-26&Lxfu&VCLIcWOXwD$^(gXu%PA?}LYQwnQ^219wS42Wm~XcV z_|bb0=T&c_zuv0fxWOvT;|9(9SqG+aDd>-qu{fK!O>8u}joa8wx-oig<80z)MZIo#_eU~ZHmY3rvmLJQ-gLZ z+S?7EEM`o5w%d9XkHSlXcJrw~-on%%Z)939Z^xrT7MkWw#lt}XWs}f0Z>>xcgy#*e zp(Ahbe{J(NbGbmmCc#?f%?8t-cRkxG122%5xA~2t#75Gn4Zx9L3oF-!|)vd(XIs;;!a`!0D8f@8TCxoayi;wNhLCu3-E0k7S0^_gN1o-*0eK$ zO>3FNe}IerAEeQLbK-|(uu5X9&&+u>r{m!9A0zZg0N4QJY17e3k$(e{@K#Z$MIvwZ zdJFz->n#A)a|3k9e{gI8fEqV?H01)2IOjR#H+Pp)XHMe35P6sc^CYUK-|)ehHx2-W z1ps(0)EFvgN&sjAnvRjQ=?EnL8!WG)OTLL67QnU4pKTsE{tXB0BmgV`sw&z-07?L6 z|F&&0dE9}b@C6^o$(=AD4%#|`h6JuzJvmLUKd0KUeJwibX< z!DMV^QADkO*LFYlCvSU(JE8<|;%$GOzr8~GdFdIgiQxxR1$$_3m! zo(2F5fLIX~y&_7MTM8xRmrl+Ur>vJ$wb_Gao|69Zj7e^fCE4|)31b_R?T#6_Y_RVpTzyQ+^$-;~_@)PDN>?KOfij!(}w0Ms-60Mv@en$%3ku6?iL zP%s&L$r}n-(s5bUbQ}+^^`AfF2z}+E7AH5wa{$88W&nCcWG!l@ZdWz!5G^wZ)iQ%H z!gU*0Gj-eH3(ccPo=@q`S1u}c0B``v02lzcKLN-9D6TaF&=PO+wa(8!t1f+5!}Th5 zGA}2fxPA5AHYcFk@RN8q_-=c5_4Wg=O@bchq?cpaw?hj6(5I&_5o};!;DSTnmN~rm ur7Cx?%uS(Byw)7}M!0L%cs&W-WWHj(789nqi2|A?o6=6ND4@$6F2n#$)Knq> literal 0 HcmV?d00001 diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp new file mode 100644 index 0000000000000000000000000000000000000000..87012d8dde05cad4d2a1ebbf3fc0bb19e27a038c GIT binary patch literal 8516 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 literal 0 HcmV?d00001 diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml new file mode 100644 index 0000000..41b6b58 --- /dev/null +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -0,0 +1,24 @@ + + + Freeze Monitor + 提示 + 未获取到Root权限,软件无法使用 + 确定 + 关于 + 已挂载: + 源代码: + 开发者: + rcmiku + Android 应用进程冻结监视器 + 暂无 + 搜索 + 取消 + 应用列表 + %s冻结中 + + %1$d个进程 + + 已冻结%s个 + %dMB + %.2fGB + \ No newline at end of file diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml new file mode 100644 index 0000000..f8c6127 --- /dev/null +++ b/app/src/main/res/values/colors.xml @@ -0,0 +1,10 @@ + + + #FFBB86FC + #FF6200EE + #FF3700B3 + #FF03DAC5 + #FF018786 + #FF000000 + #FFFFFFFF + \ No newline at end of file diff --git a/app/src/main/res/values/ic_launcher_background.xml b/app/src/main/res/values/ic_launcher_background.xml new file mode 100644 index 0000000..9423d63 --- /dev/null +++ b/app/src/main/res/values/ic_launcher_background.xml @@ -0,0 +1,4 @@ + + + #3482FF + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml new file mode 100644 index 0000000..828b22f --- /dev/null +++ b/app/src/main/res/values/strings.xml @@ -0,0 +1,24 @@ + + Freeze Monitor + Prompt + Root access not obtained, the app cannot be used + OK + About + Mounted: + Source Code: + Developer: + rcmiku + Android App Process Freezer Monitor + None + Search + Cancel + App List + %s Freezing + + %1$d Process + %1$d Processes + + Frozen %s + %dMB + %.2fGB + diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml new file mode 100644 index 0000000..1eaca17 --- /dev/null +++ b/app/src/main/res/values/themes.xml @@ -0,0 +1,5 @@ + + + +