From b7e37a59d4279ba3b18106d42d378576b2dd842f Mon Sep 17 00:00:00 2001 From: BinTianqi Date: Sat, 15 Mar 2025 12:13:59 +0800 Subject: [PATCH] Disable metered data for specific apps, close #109 Update workflow file --- .github/workflows/build.yml | 1 + .../bintianqi/owndroid/dpm/Applications.kt | 58 ++++++++++++++++--- .../com/bintianqi/owndroid/dpm/Permissions.kt | 2 +- app/src/main/res/drawable/money_off_fill0.xml | 9 +++ app/src/main/res/values-ru/strings.xml | 4 +- app/src/main/res/values-tr/strings.xml | 4 +- app/src/main/res/values-zh-rCN/strings.xml | 4 +- app/src/main/res/values/strings.xml | 4 +- 8 files changed, 70 insertions(+), 16 deletions(-) create mode 100644 app/src/main/res/drawable/money_off_fill0.xml diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 97207f3..f919704 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -3,6 +3,7 @@ name: Build APK on: workflow_dispatch: push: + branches: ["master"] paths-ignore: - '**.md' tags-ignore: diff --git a/app/src/main/java/com/bintianqi/owndroid/dpm/Applications.kt b/app/src/main/java/com/bintianqi/owndroid/dpm/Applications.kt index 3af56a3..11acb6b 100644 --- a/app/src/main/java/com/bintianqi/owndroid/dpm/Applications.kt +++ b/app/src/main/java/com/bintianqi/owndroid/dpm/Applications.kt @@ -148,7 +148,8 @@ fun ApplicationsScreen(onNavigateUp: () -> Unit) { ) { composable { HomeScreen(pkgName) { navController.navigate(it) } } composable { UserControlDisabledPackagesScreen(pkgName) } - composable { PermissionManagerScreen(pkgName) } + composable { PermissionsScreen(pkgName) } + composable { DisableMeteredDataScreen(pkgName) } composable { CrossProfilePackagesScreen(pkgName) } composable { CrossProfileWidgetProvidersScreen(pkgName) } composable { CredentialManagerPolicyScreen(pkgName) } @@ -229,8 +230,11 @@ private fun HomeScreen(pkgName: String, onNavigate: (Any) -> Unit) { if(VERSION.SDK_INT >= 30 && (deviceOwner || (VERSION.SDK_INT >= 33 && profileOwner))) { FunctionItem(title = R.string.ucd, icon = R.drawable.do_not_touch_fill0) { onNavigate(UserControlDisabledPackages) } } - if(VERSION.SDK_INT>=23) { - FunctionItem(title = R.string.permission_manage, icon = R.drawable.key_fill0) { onNavigate(PermissionManager) } + if(VERSION.SDK_INT >= 23) { + FunctionItem(title = R.string.permissions, icon = R.drawable.key_fill0) { onNavigate(PermissionsManager) } + } + if(VERSION.SDK_INT >= 28) { + FunctionItem(R.string.disable_metered_data, icon = R.drawable.money_off_fill0) { onNavigate(DisableMeteredData) } } if(VERSION.SDK_INT >= 30 && profileOwner && dpm.isManagedProfile(receiver)) { FunctionItem(title = R.string.cross_profile_package, icon = R.drawable.work_fill0) { onNavigate(CrossProfilePackages) } @@ -239,7 +243,7 @@ private fun HomeScreen(pkgName: String, onNavigate: (Any) -> Unit) { FunctionItem(title = R.string.cross_profile_widget, icon = R.drawable.widgets_fill0) { onNavigate(CrossProfileWidgetProviders) } } if(VERSION.SDK_INT >= 34 && deviceOwner) { - FunctionItem(title = R.string.credential_manage_policy, icon = R.drawable.license_fill0) { onNavigate(CredentialManagerPolicy) } + FunctionItem(title = R.string.credential_manager_policy, icon = R.drawable.license_fill0) { onNavigate(CredentialManagerPolicy) } } FunctionItem(title = R.string.permitted_accessibility_services, icon = R.drawable.settings_accessibility_fill0) { onNavigate(PermittedAccessibilityServices) @@ -471,11 +475,11 @@ private fun UserControlDisabledPackagesScreen(pkgName:String) { } } -@Serializable private object PermissionManager +@Serializable private object PermissionsManager @RequiresApi(23) @Composable -private fun PermissionManagerScreen(pkgName: String) { +private fun PermissionsScreen(pkgName: String) { val context = LocalContext.current val dpm = context.getDPM() val receiver = context.getReceiver() @@ -573,6 +577,46 @@ private fun PermissionManagerScreen(pkgName: String) { } } +@Serializable private object DisableMeteredData + +@RequiresApi(28) +@Composable +private fun DisableMeteredDataScreen(pkgName: String) { + val context = LocalContext.current + val dpm = context.getDPM() + val receiver = context.getReceiver() + val packages = remember { mutableStateListOf() } + fun refresh() { + packages.clear() + packages.addAll(dpm.getMeteredDataDisabledPackages(receiver)) + } + LaunchedEffect(Unit) { refresh() } + Column(Modifier.fillMaxSize().padding(horizontal = 8.dp).verticalScroll(rememberScrollState())) { + Text(stringResource(R.string.disable_metered_data), Modifier.padding(vertical = 8.dp), style = typography.headlineLarge) + Column(Modifier.animateContentSize()) { + packages.forEach { pkg -> + ListItem(pkg) { packages -= pkg } + } + } + Button( + onClick = { packages += pkgName }, + modifier = Modifier.fillMaxWidth().padding(vertical = 4.dp), + enabled = pkgName.isNotBlank() + ) { + Text(stringResource(R.string.add)) + } + Button( + onClick = { + context.showOperationResultToast(dpm.setMeteredDataDisabledPackages(receiver, packages).isEmpty()) + refresh() + }, + modifier = Modifier.fillMaxWidth() + ) { + Text(stringResource(R.string.apply)) + } + } +} + @Serializable private object CrossProfilePackages @RequiresApi(30) @@ -676,7 +720,7 @@ private fun CredentialManagerPolicyScreen(pkgName: String) { // TODO: rename "ma LaunchedEffect(Unit) { refreshPolicy() } Column(modifier = Modifier.fillMaxSize().padding(horizontal = 8.dp).verticalScroll(rememberScrollState())) { Spacer(Modifier.padding(vertical = 10.dp)) - Text(text = stringResource(R.string.credential_manage_policy), style = typography.headlineLarge) + Text(text = stringResource(R.string.credential_manager_policy), style = typography.headlineLarge) Spacer(Modifier.padding(vertical = 5.dp)) RadioButtonItem(R.string.none, policyType == -1) { policyType = -1 } RadioButtonItem(R.string.blacklist, policyType == PACKAGE_POLICY_BLOCKLIST) { policyType = PACKAGE_POLICY_BLOCKLIST } diff --git a/app/src/main/java/com/bintianqi/owndroid/dpm/Permissions.kt b/app/src/main/java/com/bintianqi/owndroid/dpm/Permissions.kt index d2f0f77..dad9ae9 100644 --- a/app/src/main/java/com/bintianqi/owndroid/dpm/Permissions.kt +++ b/app/src/main/java/com/bintianqi/owndroid/dpm/Permissions.kt @@ -587,7 +587,7 @@ fun AddDelegatedAdminScreen(data: AddDelegatedAdmin, onNavigateUp: () -> Unit) { val choosePackage = rememberLauncherForActivityResult(ChoosePackageContract()) { result -> result?.let { input = it } } - MySmallTitleScaffold(if(updateMode) R.string.place_holder else R.string.add_delegated_admin, 0.dp, onNavigateUp,) { + MySmallTitleScaffold(if(updateMode) R.string.place_holder else R.string.add_delegated_admin, 0.dp, onNavigateUp) { OutlinedTextField( value = input, onValueChange = { input = it }, label = { Text(stringResource(R.string.package_name)) }, diff --git a/app/src/main/res/drawable/money_off_fill0.xml b/app/src/main/res/drawable/money_off_fill0.xml new file mode 100644 index 0000000..7ca26be --- /dev/null +++ b/app/src/main/res/drawable/money_off_fill0.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index 762c611..ad0372a 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -387,10 +387,10 @@ Отключить управление пользователем Если вы установите этот флажок, вы не сможете очистить хранилище этих приложений или принудительно остановить их. Список приложений: - Управление разрешениями + Disable metered data Кросс-профильный пакет Кросс-профильный виджет - Политика управления учетными данными + Credential manager policy Белый список и системные приложения Разрешенные пакеты: \n Разрешенные службы доступности diff --git a/app/src/main/res/values-tr/strings.xml b/app/src/main/res/values-tr/strings.xml index 1bf2a48..9079adc 100644 --- a/app/src/main/res/values-tr/strings.xml +++ b/app/src/main/res/values-tr/strings.xml @@ -395,10 +395,10 @@ Kullanıcı Kontrolünü Devre Dışı Bırak Bunu ayarlarsanız, bu uygulamaların depolamasını temizleyemez veya zorla durduramazsınız. Uygulama listesi: - İzin Yönetimi + Disable metered data Çapraz Profil Paketi Çapraz Profil Widget\'ı - Kimlik Yönetimi Politikası + Credential manager policy Beyaz Liste ve Sistem Uygulaması İzin Verilen Paketler: \n İzin Verilen Erişilebilirlik Servisleri diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index e30670d..8a25885 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -375,10 +375,10 @@ 禁止用户控制 用户将无法清除这些应用的存储空间或强制停止这些应用 应用列表: - 权限管理 + 禁用计量数据 跨资料应用 跨资料微件 - 凭据管理策略 + 凭据管理器策略 白名单和系统应用 许可的应用:\n 许可的无障碍服务 diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 7563be6..58ccda2 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -414,10 +414,10 @@ Disable user control If you set this, you cannot clear these apps\' storage or force stop them. App list: - Permission manage + Disable metered data Cross profile package Cross profile widget - Credential manage policy + Credential manager policy Whitelist and system app Permitted packages: \n Permitted accessibility services