diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 43294d4..97207f3 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -3,7 +3,6 @@ name: Build APK on: workflow_dispatch: push: - branches: ["master", "dev"] paths-ignore: - '**.md' tags-ignore: @@ -63,13 +62,11 @@ jobs: path: app/build/outputs/apk/release/app-release.apk - name: Generate and submit dependency graph - if: github.ref_name == 'master' uses: gradle/actions/dependency-submission@v4 upload-telegram: name: Upload Builds runs-on: ubuntu-latest - if: github.ref_name == 'dev' needs: build steps: - name: Download Artifacts diff --git a/Readme-en.md b/Readme-en.md index 0e484e1..944c2b8 100644 --- a/Readme-en.md +++ b/Readme-en.md @@ -6,8 +6,8 @@ Use Android Device owner privilege to manage your device. ## Download -[IzzyOnDroid F-Droid Repository](https://apt.izzysoft.de/fdroid/index/apk/com.bintianqi.owndroid) -[Releases on GitHub](https://github.com/BinTianqi/OwnDroid/releases) +- [IzzyOnDroid F-Droid Repository](https://apt.izzysoft.de/fdroid/index/apk/com.bintianqi.owndroid) +- [Releases on GitHub](https://github.com/BinTianqi/OwnDroid/releases) > [!NOTE] > ColorOS users should download testkey version from releases on GitHub @@ -16,7 +16,6 @@ Use Android Device owner privilege to manage your device. - System - Options: disable camera, disable screenshot, master volume mute, disable USB signal... - - Permission policy - Manage CA certificates - _Wipe data_ - ... @@ -35,6 +34,7 @@ Use Android Device owner privilege to manage your device. - Suspend/hide app - Block app uninstallation - Install/uninstall app + - Grant/revoke permissions - ... - User restriction - Network: disable configuring mobile network, disable configuring Wi-Fi, disable SMS, disable outgoing calls... diff --git a/Readme-ja.md b/Readme-ja.md index 2145e23..b357570 100644 --- a/Readme-ja.md +++ b/Readme-ja.md @@ -6,8 +6,8 @@ AndroidのDevice owner特権を使用してデバイスを管理します。 ## ダウンロード -[IzzyOnDroid F-Droid Repository](https://apt.izzysoft.de/fdroid/index/apk/com.bintianqi.owndroid) -[Releases on GitHub](https://github.com/BinTianqi/OwnDroid/releases) +- [IzzyOnDroid F-Droid Repository](https://apt.izzysoft.de/fdroid/index/apk/com.bintianqi.owndroid) +- [Releases on GitHub](https://github.com/BinTianqi/OwnDroid/releases) > [!NOTE] > ColorOSユーザーはGitHubのリリースからtestkeyバージョンをダウンロードしてください diff --git a/Readme.md b/Readme.md index 65d2f60..c75f0c6 100644 --- a/Readme.md +++ b/Readme.md @@ -6,8 +6,8 @@ ## 下载 -[IzzyOnDroid F-Droid Repository](https://apt.izzysoft.de/fdroid/index/apk/com.bintianqi.owndroid) -[Releases on GitHub](https://github.com/BinTianqi/OwnDroid/releases) +- [IzzyOnDroid F-Droid Repository](https://apt.izzysoft.de/fdroid/index/apk/com.bintianqi.owndroid) +- [Releases on GitHub](https://github.com/BinTianqi/OwnDroid/releases) > [!NOTE] > ColorOS用户应在GitHub上的releases下载testkey版本 @@ -16,7 +16,6 @@ - 系统 - 选项:禁用摄像头、禁止截屏、全局静音、禁用USB信号... - - 权限策略 - 管理CA证书 - _清除数据_ - ... @@ -35,6 +34,7 @@ - 挂起/隐藏应用 - 阻止应用卸载 - 安装/卸载应用 + - 授予/撤销权限 - ... - 用户限制 - 网络:禁止配置移动网络、禁止配置Wi-Fi、禁用短信、禁止拨出电话... diff --git a/app/src/main/java/com/bintianqi/owndroid/Receiver.kt b/app/src/main/java/com/bintianqi/owndroid/Receiver.kt index bf63c73..2a3b249 100644 --- a/app/src/main/java/com/bintianqi/owndroid/Receiver.kt +++ b/app/src/main/java/com/bintianqi/owndroid/Receiver.kt @@ -14,6 +14,7 @@ import com.bintianqi.owndroid.dpm.handleNetworkLogs import com.bintianqi.owndroid.dpm.isDeviceOwner import com.bintianqi.owndroid.dpm.isProfileOwner import com.bintianqi.owndroid.dpm.processSecurityLogs +import com.bintianqi.owndroid.dpm.setDefaultAffiliationID import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch @@ -34,6 +35,7 @@ class Receiver : DeviceAdminReceiver() { override fun onEnabled(context: Context, intent: Intent) { super.onEnabled(context, intent) if(context.isProfileOwner || context.isDeviceOwner){ + setDefaultAffiliationID(context) Toast.makeText(context, context.getString(R.string.onEnabled), Toast.LENGTH_SHORT).show() } } @@ -41,6 +43,7 @@ class Receiver : DeviceAdminReceiver() { override fun onDisabled(context: Context, intent: Intent) { super.onDisabled(context, intent) Toast.makeText(context, R.string.onDisabled, Toast.LENGTH_SHORT).show() + SharedPrefs(context).isDefaultAffiliationIdSet = false } override fun onProfileProvisioningComplete(context: Context, intent: Intent) { 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 6d69891..3af56a3 100644 --- a/app/src/main/java/com/bintianqi/owndroid/dpm/Applications.kt +++ b/app/src/main/java/com/bintianqi/owndroid/dpm/Applications.kt @@ -1,6 +1,5 @@ package com.bintianqi.owndroid.dpm -import android.app.AlertDialog import android.app.PendingIntent import android.app.admin.DevicePolicyManager.PERMISSION_GRANT_STATE_DEFAULT import android.app.admin.DevicePolicyManager.PERMISSION_GRANT_STATE_DENIED @@ -91,9 +90,9 @@ import com.bintianqi.owndroid.R import com.bintianqi.owndroid.showOperationResultToast import com.bintianqi.owndroid.ui.Animations import com.bintianqi.owndroid.ui.FunctionItem -import com.bintianqi.owndroid.ui.Notes import com.bintianqi.owndroid.ui.ListItem import com.bintianqi.owndroid.ui.NavIcon +import com.bintianqi.owndroid.ui.Notes import com.bintianqi.owndroid.ui.RadioButtonItem import com.bintianqi.owndroid.ui.SwitchItem import kotlinx.serialization.Serializable @@ -901,6 +900,7 @@ private fun KeepUninstalledPackagesScreen(pkgName: String) { @Composable private fun UninstallPackageScreen(pkgName: String) { val context = LocalContext.current + var errorMessage by remember { mutableStateOf(null) } Column(modifier = Modifier.fillMaxSize().padding(horizontal = 8.dp).verticalScroll(rememberScrollState())) { Spacer(Modifier.padding(vertical = 10.dp)) Text(text = stringResource(R.string.uninstall_app), style = typography.headlineLarge) @@ -919,11 +919,7 @@ private fun UninstallPackageScreen(pkgName: String) { if(statusExtra == PackageInstaller.STATUS_SUCCESS) { context.showOperationResultToast(true) } else { - AlertDialog.Builder(context) - .setTitle(R.string.failure) - .setMessage(parsePackageInstallerMessage(context, intent)) - .setPositiveButton(R.string.confirm) { dialog, _ -> dialog.dismiss() } - .show() + errorMessage = parsePackageInstallerMessage(context, intent) } } } @@ -960,5 +956,13 @@ private fun UninstallPackageScreen(pkgName: String) { } } } + if(errorMessage != null) AlertDialog( + title = { Text(stringResource(R.string.failure)) }, + text = { Text(errorMessage!!) }, + confirmButton = { + TextButton({ errorMessage = null }) { Text(stringResource(R.string.confirm)) } + }, + onDismissRequest = { errorMessage = null } + ) } diff --git a/app/src/main/java/com/bintianqi/owndroid/dpm/Network.kt b/app/src/main/java/com/bintianqi/owndroid/dpm/Network.kt index fa819ad..de195c5 100644 --- a/app/src/main/java/com/bintianqi/owndroid/dpm/Network.kt +++ b/app/src/main/java/com/bintianqi/owndroid/dpm/Network.kt @@ -2,7 +2,6 @@ package com.bintianqi.owndroid.dpm import android.Manifest import android.annotation.SuppressLint -import android.app.AlertDialog import android.app.admin.DevicePolicyManager.PRIVATE_DNS_MODE_OFF import android.app.admin.DevicePolicyManager.PRIVATE_DNS_MODE_OPPORTUNISTIC import android.app.admin.DevicePolicyManager.PRIVATE_DNS_MODE_PROVIDER_HOSTNAME @@ -133,14 +132,15 @@ import com.bintianqi.owndroid.humanReadableDate import com.bintianqi.owndroid.humanReadableDateTime import com.bintianqi.owndroid.showOperationResultToast import com.bintianqi.owndroid.ui.CheckBoxItem +import com.bintianqi.owndroid.ui.ErrorDialog import com.bintianqi.owndroid.ui.ExpandExposedTextFieldIcon import com.bintianqi.owndroid.ui.FullWidthRadioButtonItem import com.bintianqi.owndroid.ui.FunctionItem -import com.bintianqi.owndroid.ui.Notes import com.bintianqi.owndroid.ui.ListItem import com.bintianqi.owndroid.ui.MyScaffold import com.bintianqi.owndroid.ui.MySmallTitleScaffold import com.bintianqi.owndroid.ui.NavIcon +import com.bintianqi.owndroid.ui.Notes import com.bintianqi.owndroid.ui.RadioButtonItem import com.bintianqi.owndroid.ui.SwitchItem import com.bintianqi.owndroid.writeClipBoard @@ -507,6 +507,7 @@ private fun AddNetworkScreen(wifiConfig: WifiConfiguration? = null, onNavigateUp ssid = wifiConfig.SSID.removeSurrounding("\"") } } + var errorMessage by remember { mutableStateOf(null) } Column( modifier = (if(wifiConfig == null) Modifier.fillMaxSize().verticalScroll(rememberScrollState()).padding(bottom = 60.dp) else Modifier) .padding(start = 8.dp, end = 8.dp, top = 12.dp) @@ -721,11 +722,7 @@ private fun AddNetworkScreen(wifiConfig: WifiConfiguration? = null, onNavigateUp resultDialog = true } catch(e: Exception) { e.printStackTrace() - AlertDialog.Builder(context) - .setTitle(R.string.error) - .setPositiveButton(R.string.confirm) { dialog, _ -> dialog.cancel() } - .setMessage(e.message ?: "") - .show() + errorMessage = e.message } }, modifier = Modifier.fillMaxWidth().padding(vertical = 4.dp) @@ -755,6 +752,7 @@ private fun AddNetworkScreen(wifiConfig: WifiConfiguration? = null, onNavigateUp onDismissRequest = { resultDialog = false } ) } + ErrorDialog(errorMessage) { errorMessage = null } } @Serializable object WifiSecurityLevel @@ -914,6 +912,7 @@ fun NetworkStatsScreen(onNavigateUp: () -> Unit, onNavigateToViewer: (NetworkSta val endTimeTextFieldInteractionSource = remember { MutableInteractionSource() } if(startTimeTextFieldInteractionSource.collectIsPressedAsState().value) activeTextField = NetworkStatsActiveTextField.StartTime if(endTimeTextFieldInteractionSource.collectIsPressedAsState().value) activeTextField = NetworkStatsActiveTextField.EndTime + var errorMessage by remember { mutableStateOf(null) } MyScaffold(R.string.network_stats, 8.dp, onNavigateUp) { ExposedDropdownMenuBox( activeTextField == NetworkStatsActiveTextField.Type, @@ -1202,14 +1201,10 @@ fun NetworkStatsScreen(onNavigateUp: () -> Unit, onNavigateToViewer: (NetworkSta e.printStackTrace() withContext(Dispatchers.Main) { querying = false - AlertDialog.Builder(context) - .setTitle(R.string.error) - .setMessage(e.message ?: "") - .setPositiveButton(R.string.confirm) { dialog, _ -> dialog.dismiss() } - .show() + errorMessage = e.message } return@launch - } + }.filterNot { it == null } if(buckets.isEmpty()) { withContext(Dispatchers.Main) { querying = false @@ -1263,6 +1258,7 @@ fun NetworkStatsScreen(onNavigateUp: () -> Unit, onNavigateToViewer: (NetworkSta } } } + ErrorDialog(errorMessage) { errorMessage = null } } @Serializable diff --git a/app/src/main/java/com/bintianqi/owndroid/dpm/System.kt b/app/src/main/java/com/bintianqi/owndroid/dpm/System.kt index 856d5d9..faafe9d 100644 --- a/app/src/main/java/com/bintianqi/owndroid/dpm/System.kt +++ b/app/src/main/java/com/bintianqi/owndroid/dpm/System.kt @@ -2,7 +2,6 @@ package com.bintianqi.owndroid.dpm import android.annotation.SuppressLint import android.app.ActivityOptions -import android.app.AlertDialog import android.app.admin.DevicePolicyManager import android.app.admin.DevicePolicyManager.FLAG_EVICT_CREDENTIAL_ENCRYPTION_KEY import android.app.admin.DevicePolicyManager.InstallSystemUpdateCallback @@ -126,6 +125,7 @@ import com.bintianqi.owndroid.humanReadableDate import com.bintianqi.owndroid.parseDate import com.bintianqi.owndroid.showOperationResultToast import com.bintianqi.owndroid.ui.CheckBoxItem +import com.bintianqi.owndroid.ui.ErrorDialog import com.bintianqi.owndroid.ui.FullWidthCheckBoxItem import com.bintianqi.owndroid.ui.FullWidthRadioButtonItem import com.bintianqi.owndroid.ui.FunctionItem @@ -286,7 +286,7 @@ fun SystemOptionsScreen(onNavigateUp: () -> Unit) { } } if(deviceOwner || profileOwner) { - SwitchItem(R.string.master_mute, icon = R.drawable.volume_up_fill0, + SwitchItem(R.string.master_mute, icon = R.drawable.volume_off_fill0, getState = { dpm.isMasterVolumeMuted(receiver) }, onCheckedChange = { dpm.setMasterVolumeMuted(receiver,it) } ) } @@ -1197,6 +1197,7 @@ private fun ColumnScope.LockTaskFeatures() { val receiver = context.getReceiver() var flags by remember { mutableIntStateOf(0) } var custom by rememberSaveable { mutableStateOf(false) } + var errorMessage by remember { mutableStateOf(null) } fun refresh() { flags = dpm.getLockTaskFeatures(receiver) custom = flags != 0 @@ -1230,17 +1231,14 @@ private fun ColumnScope.LockTaskFeatures() { dpm.setLockTaskFeatures(receiver, flags) context.showOperationResultToast(true) } catch (e: IllegalArgumentException) { - AlertDialog.Builder(context) - .setTitle(R.string.error) - .setMessage(e.message) - .setPositiveButton(R.string.confirm) { dialog, _ -> dialog.dismiss() } - .show() + errorMessage = e.message } refresh() } ) { Text(stringResource(R.string.apply)) } + ErrorDialog(errorMessage) { errorMessage = null } } data class CaCertInfo( diff --git a/app/src/main/java/com/bintianqi/owndroid/ui/Components.kt b/app/src/main/java/com/bintianqi/owndroid/ui/Components.kt index b390b0b..28ca8cf 100644 --- a/app/src/main/java/com/bintianqi/owndroid/ui/Components.kt +++ b/app/src/main/java/com/bintianqi/owndroid/ui/Components.kt @@ -357,3 +357,15 @@ fun ExpandExposedTextFieldIcon(active: Boolean) { modifier = Modifier.rotate(degrees) ) } + +@Composable +fun ErrorDialog(message: String?, onDismiss: () -> Unit) { + if(!message.isNullOrEmpty()) AlertDialog( + title = { Text(stringResource(R.string.error)) }, + text = { Text(message) }, + confirmButton = { + TextButton(onDismiss) { Text(stringResource(R.string.confirm)) } + }, + onDismissRequest = onDismiss + ) +} diff --git a/app/src/main/res/drawable/volume_off_fill0.xml b/app/src/main/res/drawable/volume_off_fill0.xml new file mode 100644 index 0000000..84c6f82 --- /dev/null +++ b/app/src/main/res/drawable/volume_off_fill0.xml @@ -0,0 +1,9 @@ + + +