diff --git a/Readme-en.md b/Readme-en.md index 76ce03f..0545fee 100644 --- a/Readme-en.md +++ b/Readme-en.md @@ -57,7 +57,7 @@ Solutions: > [!NOTE] > Some systems have features such as app cloning and children space, which are usually users. -### MIUI +### MIUI & HyperOS ```text java.lang.SecurityException: Neither user 2000 nor current process has android.permission.MANAGE_DEVICE_ADMINS. @@ -65,7 +65,7 @@ java.lang.SecurityException: Neither user 2000 nor current process has android.p Solutions: - Enable `USB debugging (Security setting)` in developer options. -- Execute activating command in root shell. +- Or execute activating command in root shell. ### ColorOS @@ -75,6 +75,14 @@ java.lang.IllegalStateException: Unexpected @ProvisioningPreCondition Solution: Use OwnDroid testkey version +### Samsung + +```text +user limit reached +``` + +Samsung restricts Android's multiple users feature. There is currently no solution. + ## API | ID | Extras | Minimum Android version | diff --git a/Readme.md b/Readme.md index ef68db8..81d0a7c 100644 --- a/Readme.md +++ b/Readme.md @@ -57,15 +57,13 @@ java.lang.IllegalStateException: Not allowed to set the device owner because the > [!NOTE] > 一些系统有应用克隆、儿童空间等功能,它们通常是用户。 -### MIUI +### MIUI & HyperOS ```text java.lang.SecurityException: Neither user 2000 nor current process has android.permission.MANAGE_DEVICE_ADMINS. ``` -解决办法: -- 在开发者设置中打开`USB调试(安全设置)`。 -- 在root命令行中执行激活命令 +解决办法: 在开发者设置中打开`USB调试(安全设置)`,或在root命令行中执行激活命令。 ### ColorOS @@ -75,6 +73,14 @@ java.lang.IllegalStateException: Unexpected @ProvisioningPreCondition 解决办法:使用 OwnDroid testkey 版本 +### 三星 + +```text +user limit reached +``` + +三星限制了多用户功能,暂无解决办法。 + ## API | ID | Extra | 最小安卓版本 | diff --git a/app/src/main/java/com/bintianqi/owndroid/MainActivity.kt b/app/src/main/java/com/bintianqi/owndroid/MainActivity.kt index 4a33159..521f6dd 100644 --- a/app/src/main/java/com/bintianqi/owndroid/MainActivity.kt +++ b/app/src/main/java/com/bintianqi/owndroid/MainActivity.kt @@ -2,7 +2,6 @@ package com.bintianqi.owndroid import android.os.Build.VERSION import android.os.Bundle -import android.widget.Toast import androidx.activity.compose.setContent import androidx.activity.enableEdgeToEdge import androidx.activity.viewModels @@ -481,7 +480,7 @@ fun Home(vm: MyViewModel, onLock: () -> Unit) { if(profileNotActivated) { dpm.setProfileEnabled(receiver) sp.managedProfileActivated = true - Toast.makeText(context, R.string.work_profile_activated, Toast.LENGTH_SHORT).show() + context.popToast(R.string.work_profile_activated) } } DhizukuErrorDialog { diff --git a/app/src/main/java/com/bintianqi/owndroid/PackageChooser.kt b/app/src/main/java/com/bintianqi/owndroid/PackageChooser.kt index 7f96ea7..c63cf79 100644 --- a/app/src/main/java/com/bintianqi/owndroid/PackageChooser.kt +++ b/app/src/main/java/com/bintianqi/owndroid/PackageChooser.kt @@ -7,7 +7,6 @@ import android.content.pm.PackageManager import android.graphics.drawable.Drawable import android.os.Build import android.os.Bundle -import android.widget.Toast import androidx.activity.ComponentActivity import androidx.activity.compose.setContent import androidx.activity.enableEdgeToEdge @@ -132,7 +131,7 @@ fun AppChooserScreen(params: ApplicationsList, onChoosePackage: (String?) -> Uni } IconButton({ system = !system - Toast.makeText(context, if(system) R.string.show_system_app else R.string.show_user_app, Toast.LENGTH_SHORT).show() + context.popToast(if(system) R.string.show_system_app else R.string.show_user_app) }) { Icon(painter = painterResource(R.drawable.filter_alt_fill0), contentDescription = null) } diff --git a/app/src/main/java/com/bintianqi/owndroid/Receiver.kt b/app/src/main/java/com/bintianqi/owndroid/Receiver.kt index 2d7c43e..016feeb 100644 --- a/app/src/main/java/com/bintianqi/owndroid/Receiver.kt +++ b/app/src/main/java/com/bintianqi/owndroid/Receiver.kt @@ -10,7 +10,6 @@ import android.os.Build.VERSION import android.os.PersistableBundle import android.os.UserHandle import android.os.UserManager -import android.widget.Toast import androidx.core.app.NotificationCompat import com.bintianqi.owndroid.dpm.handleNetworkLogs import com.bintianqi.owndroid.dpm.handlePrivilegeChange @@ -48,7 +47,7 @@ class Receiver : DeviceAdminReceiver() { override fun onProfileProvisioningComplete(context: Context, intent: Intent) { super.onProfileProvisioningComplete(context, intent) - Toast.makeText(context, R.string.create_work_profile_success, Toast.LENGTH_SHORT).show() + context.popToast(R.string.create_work_profile_success) } override fun onNetworkLogsAvailable(context: Context, intent: Intent, batchToken: Long, networkLogsCount: Int) { diff --git a/app/src/main/java/com/bintianqi/owndroid/ShizukuService.kt b/app/src/main/java/com/bintianqi/owndroid/ShizukuService.kt index c19c106..a70eecf 100644 --- a/app/src/main/java/com/bintianqi/owndroid/ShizukuService.kt +++ b/app/src/main/java/com/bintianqi/owndroid/ShizukuService.kt @@ -6,7 +6,6 @@ import android.content.ServiceConnection import android.content.pm.PackageManager import android.os.Bundle import android.os.IBinder -import android.widget.Toast import androidx.annotation.Keep import rikka.shizuku.Shizuku import rikka.sui.Sui @@ -54,12 +53,12 @@ fun useShizuku(context: Context, action: (IBinder?) -> Unit) { if (Shizuku.checkSelfPermission() == PackageManager.PERMISSION_GRANTED) { Shizuku.bindUserService(getShizukuArgs(context), connection) } else if(Shizuku.shouldShowRequestPermissionRationale()) { - Toast.makeText(context, R.string.permission_denied, Toast.LENGTH_SHORT).show() + context.popToast(R.string.permission_denied) } else { Sui.init(context.packageName) fun requestPermissionResultListener(requestCode: Int, grantResult: Int) { if(grantResult != PackageManager.PERMISSION_GRANTED) { - Toast.makeText(context, R.string.permission_denied, Toast.LENGTH_SHORT).show() + context.popToast(R.string.permission_denied) } Shizuku.removeRequestPermissionResultListener(::requestPermissionResultListener) } diff --git a/app/src/main/java/com/bintianqi/owndroid/Utils.kt b/app/src/main/java/com/bintianqi/owndroid/Utils.kt index ff080fe..fded7d3 100644 --- a/app/src/main/java/com/bintianqi/owndroid/Utils.kt +++ b/app/src/main/java/com/bintianqi/owndroid/Utils.kt @@ -43,8 +43,8 @@ fun uriToStream( operation(it) } } - catch(_: FileNotFoundException) { Toast.makeText(context, R.string.file_not_exist, Toast.LENGTH_SHORT).show() } - catch(_: IOException) { Toast.makeText(context, R.string.io_exception, Toast.LENGTH_SHORT).show() } + catch(_: FileNotFoundException) { context.popToast(R.string.file_not_exist) } + catch(_: IOException) { context.popToast(R.string.io_exception) } } fun writeClipBoard(context: Context, string: String):Boolean{ @@ -88,7 +88,7 @@ fun formatDate(pattern: String, value: Long): String = SimpleDateFormat(pattern, Locale.getDefault()).format(Date(value)) fun Context.showOperationResultToast(success: Boolean) { - Toast.makeText(this, if(success) R.string.success else R.string.failed, Toast.LENGTH_SHORT).show() + popToast(if(success) R.string.success else R.string.failed) } const val APK_MIME = "application/vnd.android.package-archive" @@ -143,3 +143,11 @@ fun getPackageSignature(info: PackageInfo): String? { return signatures?.firstOrNull()?.toByteArray() ?.let { MessageDigest.getInstance("SHA-256").digest(it) }?.toHexString() } + +fun Context.popToast(resId: Int) { + Toast.makeText(this, resId, Toast.LENGTH_SHORT).show() +} + +fun Context.popToast(str: String) { + Toast.makeText(this, str, Toast.LENGTH_SHORT).show() +} 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 0c85efb..875d0fd 100644 --- a/app/src/main/java/com/bintianqi/owndroid/dpm/Network.kt +++ b/app/src/main/java/com/bintianqi/owndroid/dpm/Network.kt @@ -32,7 +32,6 @@ import android.net.wifi.WifiSsid import android.os.Build.VERSION import android.os.Bundle import android.telephony.data.ApnSetting -import android.widget.Toast import androidx.activity.compose.rememberLauncherForActivityResult import androidx.activity.result.contract.ActivityResultContracts import androidx.annotation.RequiresApi @@ -135,6 +134,7 @@ import com.bintianqi.owndroid.formatDate import com.bintianqi.owndroid.formatFileSize import com.bintianqi.owndroid.humanReadableDate import com.bintianqi.owndroid.myPrivilege +import com.bintianqi.owndroid.popToast import com.bintianqi.owndroid.showOperationResultToast import com.bintianqi.owndroid.ui.CheckBoxItem import com.bintianqi.owndroid.ui.ErrorDialog @@ -1396,27 +1396,29 @@ fun PrivateDnsScreen(onNavigateUp: () -> Unit) { val receiver = context.getReceiver() val focusMgr = LocalFocusManager.current MyScaffold(R.string.private_dns, onNavigateUp) { - val dnsStatus = mapOf( - PRIVATE_DNS_MODE_UNKNOWN to stringResource(R.string.unknown), - PRIVATE_DNS_MODE_OFF to stringResource(R.string.disabled), - PRIVATE_DNS_MODE_OPPORTUNISTIC to stringResource(R.string.auto), - PRIVATE_DNS_MODE_PROVIDER_HOSTNAME to stringResource(R.string.dns_provide_hostname) - ) - val operationResult = mapOf( - PRIVATE_DNS_SET_NO_ERROR to stringResource(R.string.success), - PRIVATE_DNS_SET_ERROR_HOST_NOT_SERVING to stringResource(R.string.host_not_serving_dns_tls), - PRIVATE_DNS_SET_ERROR_FAILURE_SETTING to stringResource(R.string.failed) - ) - var status by remember { mutableStateOf(dnsStatus[dpm.getGlobalPrivateDnsMode(receiver)]) } + fun getDnsStatus(code: Int) = when (code) { + PRIVATE_DNS_MODE_UNKNOWN -> R.string.unknown + PRIVATE_DNS_MODE_OFF -> R.string.disabled + PRIVATE_DNS_MODE_OPPORTUNISTIC -> R.string.auto + PRIVATE_DNS_MODE_PROVIDER_HOSTNAME -> R.string.dns_provide_hostname + else -> R.string.place_holder + } + fun getOperationResult(code: Int) = when (code) { + PRIVATE_DNS_SET_NO_ERROR -> R.string.success + PRIVATE_DNS_SET_ERROR_HOST_NOT_SERVING -> R.string.host_not_serving_dns_tls + PRIVATE_DNS_SET_ERROR_FAILURE_SETTING -> R.string.failed + else -> R.string.place_holder + } + var dnsMode by remember { mutableIntStateOf(dpm.getGlobalPrivateDnsMode(receiver)) } Spacer(Modifier.padding(vertical = 5.dp)) - Text(text = stringResource(R.string.current_state, status?:stringResource(R.string.unknown))) + Text(stringResource(R.string.current_state, stringResource(getDnsStatus(dnsMode)))) AnimatedVisibility(visible = dpm.getGlobalPrivateDnsMode(receiver)!=PRIVATE_DNS_MODE_OPPORTUNISTIC) { Spacer(Modifier.padding(vertical = 5.dp)) Button( onClick = { val result = dpm.setGlobalPrivateDnsModeOpportunistic(receiver) - Toast.makeText(context, operationResult[result], Toast.LENGTH_SHORT).show() - status = dnsStatus[dpm.getGlobalPrivateDnsMode(receiver)] + context.popToast(getOperationResult(result)) + dnsMode = dpm.getGlobalPrivateDnsMode(receiver) }, modifier = Modifier.fillMaxWidth() ) { @@ -1438,18 +1440,17 @@ fun PrivateDnsScreen(onNavigateUp: () -> Unit) { Button( onClick = { focusMgr.clearFocus() - val result: Int try { - result = dpm.setGlobalPrivateDnsModeSpecifiedHost(receiver,inputHost) - Toast.makeText(context, operationResult[result], Toast.LENGTH_SHORT).show() + val result = dpm.setGlobalPrivateDnsModeSpecifiedHost(receiver,inputHost) + context.popToast(getOperationResult(result)) } catch(e: IllegalArgumentException) { e.printStackTrace() - Toast.makeText(context, R.string.invalid_hostname, Toast.LENGTH_SHORT).show() + context.popToast(R.string.invalid_hostname) } catch(e: SecurityException) { e.printStackTrace() - Toast.makeText(context, R.string.security_exception, Toast.LENGTH_SHORT).show() + context.popToast(R.string.security_exception) } finally { - status = dnsStatus[dpm.getGlobalPrivateDnsMode(receiver)] + dnsMode = dpm.getGlobalPrivateDnsMode(receiver) } }, modifier = Modifier.fillMaxWidth() @@ -1483,11 +1484,11 @@ fun AlwaysOnVpnPackageScreen(onNavigateUp: () -> Unit) { true } catch(e: UnsupportedOperationException) { e.printStackTrace() - Toast.makeText(context, R.string.unsupported, Toast.LENGTH_SHORT).show() + context.popToast(R.string.unsupported) false } catch(e: NameNotFoundException) { e.printStackTrace() - Toast.makeText(context, R.string.not_installed, Toast.LENGTH_SHORT).show() + context.popToast(R.string.not_installed) false } } @@ -1588,7 +1589,7 @@ fun RecommendedGlobalProxyScreen(onNavigateUp: () -> Unit) { return@Button } if(proxyUri == "") { - Toast.makeText(context, R.string.invalid_config, Toast.LENGTH_SHORT).show() + context.popToast(R.string.invalid_config) return@Button } val uri = proxyUri.toUri() @@ -1597,7 +1598,7 @@ fun RecommendedGlobalProxyScreen(onNavigateUp: () -> Unit) { port = proxyPort.toInt() } catch(e: NumberFormatException) { e.printStackTrace() - Toast.makeText(context, R.string.invalid_config, Toast.LENGTH_SHORT).show() + context.popToast(R.string.invalid_config) return@Button } val proxyInfo = @@ -1611,7 +1612,7 @@ fun RecommendedGlobalProxyScreen(onNavigateUp: () -> Unit) { ProxyInfo.buildDirectProxy(proxyUri, port, exclList.lines()) } if(VERSION.SDK_INT >= 30 && !proxyInfo.isValid) { - Toast.makeText(context, R.string.invalid_config, Toast.LENGTH_SHORT).show() + context.popToast(R.string.invalid_config) return@Button } dpm.setRecommendedGlobalProxy(receiver, proxyInfo) diff --git a/app/src/main/java/com/bintianqi/owndroid/dpm/Password.kt b/app/src/main/java/com/bintianqi/owndroid/dpm/Password.kt index f660d38..01c78dd 100644 --- a/app/src/main/java/com/bintianqi/owndroid/dpm/Password.kt +++ b/app/src/main/java/com/bintianqi/owndroid/dpm/Password.kt @@ -30,7 +30,6 @@ import android.app.admin.DevicePolicyManager.RESET_PASSWORD_REQUIRE_ENTRY import android.content.Context import android.os.Build.VERSION import android.os.UserManager -import android.widget.Toast import androidx.annotation.RequiresApi import androidx.compose.animation.AnimatedVisibility import androidx.compose.foundation.layout.Arrangement @@ -70,6 +69,7 @@ import com.bintianqi.owndroid.HorizontalPadding import com.bintianqi.owndroid.R import com.bintianqi.owndroid.SharedPrefs import com.bintianqi.owndroid.myPrivilege +import com.bintianqi.owndroid.popToast import com.bintianqi.owndroid.showOperationResultToast import com.bintianqi.owndroid.ui.CheckBoxItem import com.bintianqi.owndroid.ui.FullWidthCheckBoxItem @@ -269,7 +269,7 @@ fun ResetPasswordTokenScreen(onNavigateUp: () -> Unit) { try { context.showOperationResultToast(dpm.setResetPasswordToken(receiver, tokenByteArray)) } catch(_:SecurityException) { - Toast.makeText(context, R.string.security_exception, Toast.LENGTH_SHORT).show() + context.popToast(R.string.security_exception) } }, modifier = Modifier.fillMaxWidth().padding(bottom = 10.dp), @@ -285,8 +285,8 @@ fun ResetPasswordTokenScreen(onNavigateUp: () -> Unit) { onClick = { if(!dpm.isResetPasswordTokenActive(receiver)) { try { activateToken(context) } - catch(_:NullPointerException) { Toast.makeText(context, R.string.please_set_a_token, Toast.LENGTH_SHORT).show() } - } else { Toast.makeText(context, R.string.token_already_activated, Toast.LENGTH_SHORT).show() } + catch(_:NullPointerException) { context.popToast(R.string.please_set_a_token) } + } else { context.popToast(R.string.token_already_activated) } }, modifier = Modifier.fillMaxWidth(0.49F) ) { @@ -560,6 +560,6 @@ private fun activateToken(context: Context) { if (confirmIntent != null) { startActivity(context,confirmIntent, null) } else { - Toast.makeText(context, R.string.failed, Toast.LENGTH_SHORT).show() + context.showOperationResultToast(false) } } 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 9dd3328..53b43ff 100644 --- a/app/src/main/java/com/bintianqi/owndroid/dpm/System.kt +++ b/app/src/main/java/com/bintianqi/owndroid/dpm/System.kt @@ -32,7 +32,6 @@ import android.net.Uri import android.os.Build.VERSION import android.os.HardwarePropertiesManager import android.os.UserManager -import android.widget.Toast import androidx.activity.compose.rememberLauncherForActivityResult import androidx.activity.result.contract.ActivityResultContracts import androidx.annotation.RequiresApi @@ -129,6 +128,7 @@ import com.bintianqi.owndroid.formatFileSize import com.bintianqi.owndroid.humanReadableDate import com.bintianqi.owndroid.myPrivilege import com.bintianqi.owndroid.parseDate +import com.bintianqi.owndroid.popToast import com.bintianqi.owndroid.showOperationResultToast import com.bintianqi.owndroid.ui.CheckBoxItem import com.bintianqi.owndroid.ui.ErrorDialog @@ -313,7 +313,7 @@ fun SystemManagerScreen(onNavigateUp: () -> Unit, onNavigate: (Any) -> Unit) { } dialog = 0 } catch(_: IllegalStateException) { - Toast.makeText(context, R.string.failed, Toast.LENGTH_SHORT).show() + context.showOperationResultToast(false) } }, enabled = dialog != 4 || input.length in 6..64 @@ -362,7 +362,7 @@ fun SystemOptionsScreen(onNavigateUp: () -> Unit) { getState = { dpm.autoTimeRequired }, onCheckedChange = { dpm.setAutoTimeRequired(receiver,it) }, padding = false) } } - SwitchItem(R.string.master_mute, icon = R.drawable.volume_off_fill0, + if (!privilege.work) SwitchItem(R.string.master_mute, icon = R.drawable.volume_off_fill0, getState = { dpm.isMasterVolumeMuted(receiver) }, onCheckedChange = { dpm.setMasterVolumeMuted(receiver,it) createShortcuts(context) @@ -1056,7 +1056,7 @@ fun MtePolicyScreen(onNavigateUp: () -> Unit) { dpm.mtePolicy = selectedMtePolicy context.showOperationResultToast(true) } catch(_: java.lang.UnsupportedOperationException) { - Toast.makeText(context, R.string.unsupported, Toast.LENGTH_SHORT).show() + context.popToast(R.string.unsupported) } selectedMtePolicy = dpm.mtePolicy }, @@ -1257,7 +1257,7 @@ private fun ColumnScope.StartLockTaskMode() { onClick = { if(!NotificationUtils.checkPermission(context)) return@Button if(!dpm.isLockTaskPermitted(startLockTaskApp)) { - Toast.makeText(context, R.string.app_not_allowed, Toast.LENGTH_SHORT).show() + context.popToast(R.string.app_not_allowed) return@Button } val options = ActivityOptions.makeBasic().setLockTaskEnabled(true) @@ -1267,7 +1267,7 @@ private fun ColumnScope.StartLockTaskMode() { if (launchIntent != null) { context.startActivity(launchIntent, options.toBundle()) } else { - Toast.makeText(context, R.string.failed, Toast.LENGTH_SHORT).show() + context.showOperationResultToast(false) } }, enabled = startLockTaskApp.isNotBlank() && (!specifyActivity || startLockTaskActivity.isNotBlank()) @@ -1457,7 +1457,7 @@ fun CaCertScreen(onNavigateUp: () -> Unit) { }, floatingActionButton = { FloatingActionButton({ - Toast.makeText(context, R.string.select_ca_cert, Toast.LENGTH_SHORT).show() + context.popToast(R.string.select_ca_cert) getCertLauncher.launch(arrayOf("*/*")) }) { Icon(Icons.Default.Add, stringResource(R.string.install)) @@ -1628,7 +1628,7 @@ fun SecurityLoggingScreen(onNavigateUp: () -> Unit) { onClick = { val logs = dpm.retrievePreRebootSecurityLogs(receiver) if(logs == null) { - Toast.makeText(context, R.string.no_logs, Toast.LENGTH_SHORT).show() + context.popToast(R.string.no_logs) return@Button } else { val outputStream = ByteArrayOutputStream() @@ -2021,7 +2021,7 @@ fun InstallSystemUpdateScreen(onNavigateUp: () -> Unit) { else -> R.string.unknown } val errMsg = context.getString(R.string.install_system_update_failed) + context.getString(errDetail) - Toast.makeText(context, errMsg, Toast.LENGTH_SHORT).show() + context.popToast(errMsg) } } var uri by remember { mutableStateOf(null) } @@ -2044,7 +2044,7 @@ fun InstallSystemUpdateScreen(onNavigateUp: () -> Unit) { val executor = Executors.newCachedThreadPool() try { dpm.installSystemUpdate(receiver, uri!!, executor, callback) - Toast.makeText(context, R.string.start_install_system_update, Toast.LENGTH_SHORT).show() + context.popToast(R.string.start_install_system_update) } catch(e: Exception) { errorMessage = e.message } diff --git a/app/src/main/java/com/bintianqi/owndroid/dpm/UserRestriction.kt b/app/src/main/java/com/bintianqi/owndroid/dpm/UserRestriction.kt index b9dc2c3..b796be5 100644 --- a/app/src/main/java/com/bintianqi/owndroid/dpm/UserRestriction.kt +++ b/app/src/main/java/com/bintianqi/owndroid/dpm/UserRestriction.kt @@ -1,14 +1,11 @@ package com.bintianqi.owndroid.dpm import android.os.Build -import android.os.Bundle import android.os.UserManager import androidx.annotation.DrawableRes import androidx.annotation.RequiresApi import androidx.annotation.StringRes -import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer @@ -16,8 +13,6 @@ import androidx.compose.foundation.layout.WindowInsets import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.ime -import androidx.compose.foundation.layout.imePadding -import androidx.compose.foundation.layout.offset import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items @@ -27,14 +22,12 @@ import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.foundation.verticalScroll import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Add -import androidx.compose.material.icons.filled.Check import androidx.compose.material.icons.filled.Edit import androidx.compose.material.icons.outlined.Delete import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.LargeTopAppBar -import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme.colorScheme import androidx.compose.material3.MaterialTheme.typography import androidx.compose.material3.OutlinedTextField @@ -66,10 +59,7 @@ import com.bintianqi.owndroid.R import com.bintianqi.owndroid.myPrivilege import com.bintianqi.owndroid.ui.FunctionItem import com.bintianqi.owndroid.ui.MyLazyScaffold -import com.bintianqi.owndroid.ui.MyScaffold import com.bintianqi.owndroid.ui.NavIcon -import com.bintianqi.owndroid.ui.SwitchItem -import com.bintianqi.owndroid.zhCN import kotlinx.serialization.Serializable @Serializable diff --git a/app/src/main/java/com/bintianqi/owndroid/dpm/Users.kt b/app/src/main/java/com/bintianqi/owndroid/dpm/Users.kt index b0c66b2..2d8ccab 100644 --- a/app/src/main/java/com/bintianqi/owndroid/dpm/Users.kt +++ b/app/src/main/java/com/bintianqi/owndroid/dpm/Users.kt @@ -9,7 +9,6 @@ import android.os.Build.VERSION import android.os.Process import android.os.UserHandle import android.os.UserManager -import android.widget.Toast import androidx.activity.compose.rememberLauncherForActivityResult import androidx.activity.result.contract.ActivityResultContracts import androidx.annotation.RequiresApi @@ -66,6 +65,7 @@ import com.bintianqi.owndroid.HorizontalPadding import com.bintianqi.owndroid.R import com.bintianqi.owndroid.myPrivilege import com.bintianqi.owndroid.parseTimestamp +import com.bintianqi.owndroid.popToast import com.bintianqi.owndroid.showOperationResultToast import com.bintianqi.owndroid.ui.CircularProgressDialog import com.bintianqi.owndroid.ui.FullWidthCheckBoxItem @@ -117,7 +117,7 @@ fun UsersScreen(onNavigateUp: () -> Unit, onNavigate: (Any) -> Unit) { } } FunctionItem(R.string.change_user_icon, icon = R.drawable.account_circle_fill0) { - Toast.makeText(context, R.string.select_an_image, Toast.LENGTH_SHORT).show() + context.popToast(R.string.select_an_image) launcher.launch("image/*") } if(changeUserIconDialog) ChangeUserIconDialog(bitmap!!) { changeUserIconDialog = false } @@ -149,7 +149,7 @@ fun UsersScreen(onNavigateUp: () -> Unit, onNavigate: (Any) -> Unit) { onClick = { if(dialog == 2) { val result = dpm.logoutUser(receiver) - Toast.makeText(context, userOperationResultCode(result), Toast.LENGTH_SHORT).show() + context.popToast(userOperationResultCode(result)) } dialog = 0 } @@ -238,7 +238,7 @@ fun UserOperationScreen(onNavigateUp: () -> Unit) { userManager.getUserForSerialNumber(input.toLong()) } if(userHandle == null) { - Toast.makeText(context, R.string.user_not_exist, Toast.LENGTH_SHORT).show() + context.popToast(R.string.user_not_exist) } else { operation(userHandle) } @@ -267,7 +267,7 @@ fun UserOperationScreen(onNavigateUp: () -> Unit) { focusMgr.clearFocus() withUserHandle { val result = dpm.startUserInBackground(receiver, it) - Toast.makeText(context, userOperationResultCode(result), Toast.LENGTH_SHORT).show() + context.popToast(userOperationResultCode(result)) } }, enabled = legalInput, @@ -294,7 +294,7 @@ fun UserOperationScreen(onNavigateUp: () -> Unit) { focusMgr.clearFocus() withUserHandle { val result = dpm.stopUser(receiver, it) - Toast.makeText(context, userOperationResultCode(result), Toast.LENGTH_SHORT).show() + context.popToast(userOperationResultCode(result)) } }, enabled = legalInput, @@ -312,7 +312,7 @@ fun UserOperationScreen(onNavigateUp: () -> Unit) { context.showOperationResultToast(true) input = "" } else { - Toast.makeText(context, R.string.failed, Toast.LENGTH_SHORT).show() + context.showOperationResultToast(false) } } }, @@ -373,8 +373,15 @@ fun CreateUserScreen(onNavigateUp: () -> Unit) { withContext(Dispatchers.Main) { createdUserSerialNumber = userManager.getSerialNumberForUser(uh) } - } catch(_: Exception) { - context.showOperationResultToast(false) + } catch(e: Exception) { + e.printStackTrace() + withContext(Dispatchers.Main) { + if (VERSION.SDK_INT >= 28 && e is UserManager.UserOperationException) { + context.popToast(e.message ?: context.getString(R.string.error)) + } else { + context.showOperationResultToast(false) + } + } } withContext(Dispatchers.Main) { creating = false } } diff --git a/app/src/main/java/com/bintianqi/owndroid/dpm/WorkProfile.kt b/app/src/main/java/com/bintianqi/owndroid/dpm/WorkProfile.kt index 1d6873f..545623a 100644 --- a/app/src/main/java/com/bintianqi/owndroid/dpm/WorkProfile.kt +++ b/app/src/main/java/com/bintianqi/owndroid/dpm/WorkProfile.kt @@ -19,7 +19,6 @@ import android.content.Intent import android.content.IntentFilter import android.os.Binder import android.os.Build.VERSION -import android.widget.Toast import androidx.activity.compose.rememberLauncherForActivityResult import androidx.activity.result.contract.ActivityResultContracts import androidx.annotation.RequiresApi @@ -59,6 +58,7 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.bintianqi.owndroid.IUserService import com.bintianqi.owndroid.R import com.bintianqi.owndroid.myPrivilege +import com.bintianqi.owndroid.popToast import com.bintianqi.owndroid.showOperationResultToast import com.bintianqi.owndroid.ui.CheckBoxItem import com.bintianqi.owndroid.ui.FunctionItem @@ -147,7 +147,7 @@ fun CreateWorkProfileScreen(onNavigateUp: () -> Unit) { if(VERSION.SDK_INT >= 33) { intent.putExtra(EXTRA_PROVISIONING_ALLOW_OFFLINE, offlineProvisioning) } launcher.launch(intent) } catch(_: ActivityNotFoundException) { - Toast.makeText(context, R.string.unsupported, Toast.LENGTH_SHORT).show() + context.popToast(R.string.unsupported) } }, modifier = Modifier.fillMaxWidth()