From 0788634049edd6d0b58e1c4e89c9acbcd098821f Mon Sep 17 00:00:00 2001 From: BinTianqi Date: Sat, 28 Sep 2024 10:45:48 +0800 Subject: [PATCH] Show preview when changing user icon Refresh activate status when ownership transferred to OwnDroid Set Start user session message and End user session message separately Set Long support message and Short support message separately Simplify code --- app/build.gradle.kts | 4 +- .../bintianqi/owndroid/AutomationReceiver.kt | 4 +- .../java/com/bintianqi/owndroid/Receiver.kt | 8 + .../main/java/com/bintianqi/owndroid/Utils.kt | 22 +-- .../owndroid/dpm/ApplicationManage.kt | 15 +- .../java/com/bintianqi/owndroid/dpm/DPM.kt | 2 +- .../bintianqi/owndroid/dpm/ManagedProfile.kt | 1 - .../com/bintianqi/owndroid/dpm/Network.kt | 3 +- .../com/bintianqi/owndroid/dpm/Permissions.kt | 88 ++++++---- .../bintianqi/owndroid/dpm/SystemManager.kt | 3 +- .../com/bintianqi/owndroid/dpm/UserManager.kt | 151 +++++++++++------- .../bintianqi/owndroid/dpm/UserRestriction.kt | 18 +-- gradle/libs.versions.toml | 4 +- 13 files changed, 180 insertions(+), 143 deletions(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 387d5eb..22b23ec 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -1,7 +1,7 @@ plugins { alias(libs.plugins.android.application) alias(libs.plugins.kotlin.android) - alias(libs.plugins.cc) + alias(libs.plugins.compose) kotlin("plugin.serialization") version "2.0.0" } @@ -76,8 +76,6 @@ gradle.taskGraph.whenReady { dependencies { implementation(libs.androidx.activity.compose) - implementation(libs.androidx.ui) - implementation(libs.androidx.ui.graphics) implementation(libs.accompanist.drawablepainter) implementation(libs.androidx.material3) implementation(libs.androidx.navigation.compose) diff --git a/app/src/main/java/com/bintianqi/owndroid/AutomationReceiver.kt b/app/src/main/java/com/bintianqi/owndroid/AutomationReceiver.kt index 77549ff..c151e09 100644 --- a/app/src/main/java/com/bintianqi/owndroid/AutomationReceiver.kt +++ b/app/src/main/java/com/bintianqi/owndroid/AutomationReceiver.kt @@ -16,8 +16,8 @@ class AutomationReceiver: BroadcastReceiver() { @SuppressLint("NewApi") fun handleTask(context: Context, intent: Intent): String { val sharedPrefs = context.getSharedPreferences("data", Context.MODE_PRIVATE) - val key = sharedPrefs.getString("automation_key", "") ?: "" - if(key != intent.getStringExtra("key")) { + val key = sharedPrefs.getString("automation_key", "") + if(key == null || key != intent.getStringExtra("key")) { return "Wrong key" } val operation = intent.getStringExtra("operation") diff --git a/app/src/main/java/com/bintianqi/owndroid/Receiver.kt b/app/src/main/java/com/bintianqi/owndroid/Receiver.kt index 1192d1d..c929794 100644 --- a/app/src/main/java/com/bintianqi/owndroid/Receiver.kt +++ b/app/src/main/java/com/bintianqi/owndroid/Receiver.kt @@ -18,6 +18,7 @@ import android.content.pm.PackageInstaller.STATUS_FAILURE_TIMEOUT import android.content.pm.PackageInstaller.STATUS_PENDING_USER_ACTION import android.content.pm.PackageInstaller.STATUS_SUCCESS import android.os.Build.VERSION +import android.os.PersistableBundle import android.util.Log import android.widget.Toast import com.bintianqi.owndroid.dpm.getDPM @@ -68,6 +69,13 @@ class Receiver : DeviceAdminReceiver() { handleSecurityLogs(context) } } + + override fun onTransferOwnershipComplete(context: Context, bundle: PersistableBundle?) { + super.onTransferOwnershipComplete(context, bundle) + val sp = context.getSharedPreferences("data", Context.MODE_PRIVATE) + sp.edit().putBoolean("dhizuku", false).apply() + context.toggleInstallAppActivity() + } } val installAppDone = MutableStateFlow(false) diff --git a/app/src/main/java/com/bintianqi/owndroid/Utils.kt b/app/src/main/java/com/bintianqi/owndroid/Utils.kt index 384ce79..aea2e6d 100644 --- a/app/src/main/java/com/bintianqi/owndroid/Utils.kt +++ b/app/src/main/java/com/bintianqi/owndroid/Utils.kt @@ -34,7 +34,7 @@ fun uriToStream( operation: (stream: InputStream)->Unit ){ if(uri!=null){ - try{ + try { val stream = context.contentResolver.openInputStream(uri) if(stream != null) { operation(stream) } stream?.close() @@ -44,26 +44,6 @@ fun uriToStream( } } -fun List.toText():String{ - var output = "" - var isFirst = true - for(each in listIterator()){ - if(isFirst) { isFirst = false } else { output+="\n" } - output+=each - } - return output -} - -fun Set.toText(): String{ - var output = "" - var isFirst = true - for(each in iterator()){ - if(isFirst) { isFirst = false } else { output+="\n" } - output += each - } - return output -} - fun MutableList.toggle(status: Boolean, element: Int) { if(status) add(element) else remove(element) } diff --git a/app/src/main/java/com/bintianqi/owndroid/dpm/ApplicationManage.kt b/app/src/main/java/com/bintianqi/owndroid/dpm/ApplicationManage.kt index 2478be7..c5d750a 100644 --- a/app/src/main/java/com/bintianqi/owndroid/dpm/ApplicationManage.kt +++ b/app/src/main/java/com/bintianqi/owndroid/dpm/ApplicationManage.kt @@ -85,7 +85,6 @@ import com.bintianqi.owndroid.R import com.bintianqi.owndroid.fileUriFlow import com.bintianqi.owndroid.getFile import com.bintianqi.owndroid.selectedPackage -import com.bintianqi.owndroid.toText import com.bintianqi.owndroid.ui.Animations import com.bintianqi.owndroid.ui.Information import com.bintianqi.owndroid.ui.NavIcon @@ -358,7 +357,7 @@ private fun UserCtrlDisabledPkg(pkgName:String) { Spacer(Modifier.padding(vertical = 5.dp)) Text(text = stringResource(R.string.app_list_is)) SelectionContainer(modifier = Modifier.horizontalScroll(rememberScrollState()).animateContentSize()) { - Text(text = if(pkgList.isEmpty()) stringResource(R.string.none) else pkgList.toText()) + Text(text = if(pkgList.isEmpty()) stringResource(R.string.none) else pkgList.joinToString(separator = "\n")) } Spacer(Modifier.padding(vertical = 5.dp)) Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween) { @@ -510,7 +509,7 @@ private fun CrossProfilePkg(pkgName: String) { Text(text = stringResource(R.string.cross_profile_package), style = typography.headlineLarge) Text(text = stringResource(R.string.app_list_is)) SelectionContainer(modifier = Modifier.horizontalScroll(rememberScrollState()).animateContentSize()) { - Text(text = if(crossProfilePkg.isEmpty()) stringResource(R.string.none) else crossProfilePkg.toText()) + Text(text = if(crossProfilePkg.isEmpty()) stringResource(R.string.none) else crossProfilePkg.joinToString(separator = "\n")) } Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween) { Button( @@ -567,7 +566,7 @@ private fun CrossProfileWidget(pkgName: String) { Spacer(Modifier.padding(vertical = 5.dp)) Text(text = stringResource(R.string.app_list_is)) SelectionContainer(modifier = Modifier.horizontalScroll(rememberScrollState()).animateContentSize()) { - Text(text = if(pkgList.isEmpty()) stringResource(R.string.none) else pkgList.toText()) + Text(text = if(pkgList.isEmpty()) stringResource(R.string.none) else pkgList.joinToString(separator = "\n")) } Spacer(Modifier.padding(vertical = 5.dp)) Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween) { @@ -660,7 +659,7 @@ private fun CredentialManagePolicy(pkgName: String) { Column { Text(stringResource(R.string.app_list_is)) SelectionContainer(modifier = Modifier.horizontalScroll(rememberScrollState()).animateContentSize()) { - Text(text = if(credentialList.isEmpty()) stringResource(R.string.none) else credentialList.toText()) + Text(text = if(credentialList.isEmpty()) stringResource(R.string.none) else credentialList.joinToString(separator = "\n")) } Spacer(Modifier.padding(vertical = 10.dp)) Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween) { @@ -739,7 +738,7 @@ private fun PermittedAccessibility(pkgName: String) { if (pkgList.isEmpty()) { Text(stringResource(R.string.only_system_accessibility_allowed)) } else { - Text(stringResource(R.string.permitted_packages_is) + pkgList.toText()) + Text(stringResource(R.string.permitted_packages_is) + pkgList.joinToString(separator = "\n")) } } Spacer(Modifier.padding(vertical = 5.dp)) @@ -819,7 +818,7 @@ private fun PermittedIME(pkgName: String) { if(permittedIme.isEmpty()) { Text(stringResource(R.string.only_system_ime_allowed)) } else { - Text(stringResource(R.string.permitted_packages_is) + permittedIme.toText()) + Text(stringResource(R.string.permitted_packages_is) + permittedIme.joinToString(separator = "\n")) } } Spacer(Modifier.padding(vertical = 5.dp)) @@ -882,7 +881,7 @@ private fun KeepUninstalledApp(pkgName: String) { Spacer(Modifier.padding(vertical = 5.dp)) Text(text = stringResource(R.string.app_list_is)) SelectionContainer(modifier = Modifier.horizontalScroll(rememberScrollState()).animateContentSize()) { - Text(text = if(pkgList.isEmpty()) stringResource(R.string.none) else pkgList.toText()) + Text(text = if(pkgList.isEmpty()) stringResource(R.string.none) else pkgList.joinToString(separator = "\n")) } Spacer(Modifier.padding(vertical = 5.dp)) Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween) { diff --git a/app/src/main/java/com/bintianqi/owndroid/dpm/DPM.kt b/app/src/main/java/com/bintianqi/owndroid/dpm/DPM.kt index edd5d0f..84e5dfc 100644 --- a/app/src/main/java/com/bintianqi/owndroid/dpm/DPM.kt +++ b/app/src/main/java/com/bintianqi/owndroid/dpm/DPM.kt @@ -183,7 +183,7 @@ val dhizukuErrorStatus = MutableStateFlow(0) fun Context.resetDevicePolicy() { val dpm = getDPM() val receiver = getReceiver() - RestrictionData.getAllRestrictions(this).forEach { + RestrictionData.getAllRestrictions().forEach { dpm.clearUserRestriction(receiver, it) } dpm.accountTypesWithManagementDisabled?.forEach { diff --git a/app/src/main/java/com/bintianqi/owndroid/dpm/ManagedProfile.kt b/app/src/main/java/com/bintianqi/owndroid/dpm/ManagedProfile.kt index e14c1fe..2c6fca0 100644 --- a/app/src/main/java/com/bintianqi/owndroid/dpm/ManagedProfile.kt +++ b/app/src/main/java/com/bintianqi/owndroid/dpm/ManagedProfile.kt @@ -12,7 +12,6 @@ import android.app.admin.DevicePolicyManager.PERSONAL_APPS_NOT_SUSPENDED import android.app.admin.DevicePolicyManager.PERSONAL_APPS_SUSPENDED_PROFILE_TIMEOUT import android.app.admin.DevicePolicyManager.WIPE_EUICC import android.app.admin.DevicePolicyManager.WIPE_EXTERNAL_STORAGE -import android.app.admin.DevicePolicyManager.WIPE_SILENTLY import android.content.* import android.os.Binder import android.os.Build.VERSION 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 94fab02..fed6e39 100644 --- a/app/src/main/java/com/bintianqi/owndroid/dpm/Network.kt +++ b/app/src/main/java/com/bintianqi/owndroid/dpm/Network.kt @@ -104,7 +104,6 @@ import com.bintianqi.owndroid.exportFile import com.bintianqi.owndroid.exportFilePath import com.bintianqi.owndroid.formatFileSize import com.bintianqi.owndroid.selectedPackage -import com.bintianqi.owndroid.toText import com.bintianqi.owndroid.ui.Animations import com.bintianqi.owndroid.ui.CheckBoxItem import com.bintianqi.owndroid.ui.RadioButtonItem @@ -332,7 +331,7 @@ private fun WifiSsidPolicy() { Spacer(Modifier.padding(vertical = 5.dp)) Text(stringResource(R.string.ssid_list_is)) SelectionContainer(modifier = Modifier.animateContentSize().horizontalScroll(rememberScrollState())) { - Text(if(ssidList.isEmpty()) stringResource(R.string.none) else ssidList.toText()) + Text(if(ssidList.isEmpty()) stringResource(R.string.none) else ssidList.joinToString(separator = "\n")) } } Spacer(Modifier.padding(vertical = 5.dp)) 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 c33da36..f6dc8e7 100644 --- a/app/src/main/java/com/bintianqi/owndroid/dpm/Permissions.kt +++ b/app/src/main/java/com/bintianqi/owndroid/dpm/Permissions.kt @@ -559,9 +559,13 @@ private fun SupportMsg() { val context = LocalContext.current val dpm = context.getDPM() val receiver = context.getReceiver() - val focusMgr = LocalFocusManager.current - var shortMsg by remember { mutableStateOf(dpm.getShortSupportMessage(receiver)?.toString() ?: "") } - var longMsg by remember { mutableStateOf(dpm.getLongSupportMessage(receiver)?.toString() ?: "") } + var shortMsg by remember { mutableStateOf("") } + var longMsg by remember { mutableStateOf("") } + val refreshMsg = { + shortMsg = dpm.getShortSupportMessage(receiver)?.toString() ?: "" + longMsg = dpm.getLongSupportMessage(receiver)?.toString() ?: "" + } + LaunchedEffect(Unit) { refreshMsg() } Column(modifier = Modifier.fillMaxSize().verticalScroll(rememberScrollState()).padding(horizontal = 8.dp)) { Spacer(Modifier.padding(vertical = 10.dp)) Text(text = stringResource(R.string.support_msg), style = typography.headlineLarge) @@ -570,45 +574,59 @@ private fun SupportMsg() { value = shortMsg, label = { Text(stringResource(R.string.short_support_msg)) }, onValueChange = { shortMsg = it }, - modifier = Modifier.fillMaxWidth() + modifier = Modifier.fillMaxWidth().padding(bottom = 2.dp) ) - Spacer(Modifier.padding(vertical = 2.dp)) + Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween) { + Button( + onClick = { + dpm.setShortSupportMessage(receiver, shortMsg) + refreshMsg() + Toast.makeText(context, R.string.success, Toast.LENGTH_SHORT).show() + }, + modifier = Modifier.fillMaxWidth(0.49F) + ) { + Text(text = stringResource(R.string.apply)) + } + Button( + onClick = { + dpm.setShortSupportMessage(receiver, null) + refreshMsg() + Toast.makeText(context, R.string.success, Toast.LENGTH_SHORT).show() + }, + modifier = Modifier.fillMaxWidth(0.96F) + ) { + Text(text = stringResource(R.string.reset)) + } + } + Spacer(Modifier.padding(vertical = 8.dp)) OutlinedTextField( value = longMsg, label = { Text(stringResource(R.string.long_support_msg)) }, onValueChange = { longMsg = it }, - modifier = Modifier.fillMaxWidth() + modifier = Modifier.fillMaxWidth().padding(bottom = 2.dp) ) - Spacer(Modifier.padding(vertical = 5.dp)) - Button( - onClick = { - focusMgr.clearFocus() - dpm.setShortSupportMessage(receiver, shortMsg) - dpm.setLongSupportMessage(receiver, longMsg) - shortMsg = dpm.getShortSupportMessage(receiver)?.toString() ?: "" - longMsg = dpm.getLongSupportMessage(receiver)?.toString() ?: "" - Toast.makeText(context, R.string.success, Toast.LENGTH_SHORT).show() - }, - modifier = Modifier.fillMaxWidth() - ) { - Text(text = stringResource(R.string.apply)) - } - Spacer(Modifier.padding(vertical = 1.dp)) - Button( - onClick = { - focusMgr.clearFocus() - dpm.setShortSupportMessage(receiver, null) - dpm.setLongSupportMessage(receiver, null) - shortMsg = dpm.getShortSupportMessage(receiver)?.toString() ?: "" - longMsg = dpm.getLongSupportMessage(receiver)?.toString() ?: "" - Toast.makeText(context, R.string.success, Toast.LENGTH_SHORT).show() - }, - modifier = Modifier.fillMaxWidth() - ) { - Text(text = stringResource(R.string.reset)) + Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween) { + Button( + onClick = { + dpm.setLongSupportMessage(receiver, longMsg) + refreshMsg() + Toast.makeText(context, R.string.success, Toast.LENGTH_SHORT).show() + }, + modifier = Modifier.fillMaxWidth(0.49F) + ) { + Text(text = stringResource(R.string.apply)) + } + Button( + onClick = { + dpm.setLongSupportMessage(receiver, null) + refreshMsg() + Toast.makeText(context, R.string.success, Toast.LENGTH_SHORT).show() + }, + modifier = Modifier.fillMaxWidth(0.96F) + ) { + Text(text = stringResource(R.string.reset)) + } } - Spacer(Modifier.padding(vertical = 5.dp)) - Information{ Text(text = stringResource(R.string.support_msg_desc)) } Spacer(Modifier.padding(vertical = 30.dp)) } } diff --git a/app/src/main/java/com/bintianqi/owndroid/dpm/SystemManager.kt b/app/src/main/java/com/bintianqi/owndroid/dpm/SystemManager.kt index d009373..66f38cf 100644 --- a/app/src/main/java/com/bintianqi/owndroid/dpm/SystemManager.kt +++ b/app/src/main/java/com/bintianqi/owndroid/dpm/SystemManager.kt @@ -110,7 +110,6 @@ import com.bintianqi.owndroid.formatFileSize import com.bintianqi.owndroid.getFile import com.bintianqi.owndroid.prepareForNotification import com.bintianqi.owndroid.selectedPackage -import com.bintianqi.owndroid.toText import com.bintianqi.owndroid.toggle import com.bintianqi.owndroid.ui.Animations import com.bintianqi.owndroid.ui.CheckBoxItem @@ -1115,7 +1114,7 @@ fun FactoryResetProtection() { CheckBoxItem(R.string.enable_frp, enabled, { enabled = it }) Text(stringResource(R.string.account_list_is)) Text( - text = if(accountList.isEmpty()) stringResource(R.string.none) else accountList.toText(), + text = if(accountList.isEmpty()) stringResource(R.string.none) else accountList.joinToString(separator = "\n"), modifier = Modifier.animateContentSize() ) OutlinedTextField( diff --git a/app/src/main/java/com/bintianqi/owndroid/dpm/UserManager.kt b/app/src/main/java/com/bintianqi/owndroid/dpm/UserManager.kt index 20eb547..70f03dc 100644 --- a/app/src/main/java/com/bintianqi/owndroid/dpm/UserManager.kt +++ b/app/src/main/java/com/bintianqi/owndroid/dpm/UserManager.kt @@ -4,6 +4,7 @@ import android.annotation.SuppressLint import android.app.admin.DevicePolicyManager import android.content.Context import android.content.Intent +import android.graphics.Bitmap import android.graphics.BitmapFactory import android.net.Uri import android.os.Binder @@ -14,6 +15,7 @@ import android.os.UserManager import android.provider.MediaStore import android.widget.Toast import androidx.compose.animation.AnimatedVisibility +import androidx.compose.foundation.Image import androidx.compose.foundation.ScrollState import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column @@ -22,12 +24,15 @@ import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.text.KeyboardActions import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.foundation.text.selection.SelectionContainer import androidx.compose.foundation.verticalScroll import androidx.compose.material3.Button +import androidx.compose.material3.Card import androidx.compose.material3.MaterialTheme.typography import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.Scaffold @@ -37,11 +42,15 @@ import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableIntStateOf +import androidx.compose.runtime.mutableStateListOf import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.alpha +import androidx.compose.ui.draw.clip +import androidx.compose.ui.graphics.asImageBitmap import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalFocusManager import androidx.compose.ui.res.stringResource @@ -57,7 +66,6 @@ import androidx.navigation.compose.rememberNavController import com.bintianqi.owndroid.R import com.bintianqi.owndroid.fileUriFlow import com.bintianqi.owndroid.getFile -import com.bintianqi.owndroid.toText import com.bintianqi.owndroid.ui.Animations import com.bintianqi.owndroid.ui.CheckBoxItem import com.bintianqi.owndroid.ui.RadioButtonItem @@ -65,7 +73,6 @@ import com.bintianqi.owndroid.ui.SubPageItem import com.bintianqi.owndroid.ui.TopBar import com.bintianqi.owndroid.uriToStream -var affiliationID = mutableSetOf() @Composable fun UserManage(navCtrl: NavHostController) { val localNavCtrl = rememberNavController() @@ -341,11 +348,13 @@ private fun AffiliationID() { val receiver = context.getReceiver() val focusMgr = LocalFocusManager.current var input by remember { mutableStateOf("") } - var list by remember { mutableStateOf("") } - LaunchedEffect(Unit) { - affiliationID = dpm.getAffiliationIds(receiver) - list = affiliationID.toText() + val affiliationID = remember { mutableStateListOf() } + val list = affiliationID.joinToString(separator = "\n") + val refreshIds = { + affiliationID.clear() + affiliationID.addAll(dpm.getAffiliationIds(receiver)) } + LaunchedEffect(Unit) { refreshIds() } Column(modifier = Modifier.fillMaxSize().padding(horizontal = 8.dp).verticalScroll(rememberScrollState())) { Spacer(Modifier.padding(vertical = 10.dp)) Text(text = stringResource(R.string.affiliation_id), style = typography.headlineLarge) @@ -367,13 +376,13 @@ private fun AffiliationID() { Spacer(Modifier.padding(vertical = 5.dp)) Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween) { Button( - onClick = { affiliationID.add(input); list = affiliationID.toText() }, + onClick = { affiliationID.add(input) }, modifier = Modifier.fillMaxWidth(0.49F) ) { Text(stringResource(R.string.add)) } Button( - onClick = { affiliationID.remove(input); list = affiliationID.toText() }, + onClick = { affiliationID.remove(input) }, modifier = Modifier.fillMaxWidth(0.96F) ) { Text(stringResource(R.string.remove)) @@ -383,12 +392,11 @@ private fun AffiliationID() { onClick = { if("" in affiliationID) { Toast.makeText(context, R.string.include_empty_string, Toast.LENGTH_SHORT).show() - }else if(affiliationID.isEmpty()) { + } else if(affiliationID.isEmpty()) { Toast.makeText(context, R.string.cannot_be_empty, Toast.LENGTH_SHORT).show() - }else{ - dpm.setAffiliationIds(receiver, affiliationID) - affiliationID = dpm.getAffiliationIds(receiver) - list = affiliationID.toText() + } else { + dpm.setAffiliationIds(receiver, affiliationID.toSet()) + refreshIds() Toast.makeText(context, R.string.success, Toast.LENGTH_SHORT).show() } }, @@ -445,10 +453,13 @@ private fun UserSessionMessage() { val dpm = context.getDPM() val receiver = context.getReceiver() val focusMgr = LocalFocusManager.current - val getStart = dpm.getStartUserSessionMessage(receiver)?:"" - val getEnd = dpm.getEndUserSessionMessage(receiver)?:"" - var start by remember { mutableStateOf(getStart.toString()) } - var end by remember { mutableStateOf(getEnd.toString()) } + var start by remember { mutableStateOf("") } + var end by remember { mutableStateOf("") } + val refreshMsg = { + start = dpm.getStartUserSessionMessage(receiver)?.toString() ?: "" + end = dpm.getEndUserSessionMessage(receiver)?.toString() ?: "" + } + LaunchedEffect(Unit) { refreshMsg() } Column(modifier = Modifier.fillMaxSize().padding(horizontal = 8.dp).verticalScroll(rememberScrollState())) { Spacer(Modifier.padding(vertical = 10.dp)) Text(text = stringResource(R.string.user_session_msg), style = typography.headlineLarge) @@ -459,37 +470,60 @@ private fun UserSessionMessage() { label = { Text(stringResource(R.string.start_user_session_msg)) }, keyboardOptions = KeyboardOptions(imeAction = ImeAction.Done), keyboardActions = KeyboardActions(onDone = {focusMgr.clearFocus() }), - modifier = Modifier.fillMaxWidth() + modifier = Modifier.fillMaxWidth().padding(bottom = 2.dp) ) - Spacer(Modifier.padding(vertical = 2.dp)) + Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween) { + Button( + onClick = { + dpm.setStartUserSessionMessage(receiver,start) + refreshMsg() + Toast.makeText(context, R.string.success, Toast.LENGTH_SHORT).show() + }, + modifier = Modifier.fillMaxWidth(0.49F) + ) { + Text(stringResource(R.string.apply)) + } + Button( + onClick = { + dpm.setStartUserSessionMessage(receiver,null) + refreshMsg() + Toast.makeText(context, R.string.success, Toast.LENGTH_SHORT).show() + }, + modifier = Modifier.fillMaxWidth(0.96F) + ) { + Text(stringResource(R.string.reset)) + } + } + Spacer(Modifier.padding(vertical = 8.dp)) OutlinedTextField( value = end, onValueChange = { end= it }, label = { Text(stringResource(R.string.end_user_session_msg)) }, keyboardOptions = KeyboardOptions(imeAction = ImeAction.Done), keyboardActions = KeyboardActions(onDone = { focusMgr.clearFocus() }), - modifier = Modifier.fillMaxWidth() + modifier = Modifier.fillMaxWidth().padding(bottom = 2.dp) ) - Spacer(Modifier.padding(vertical = 5.dp)) - Button( - onClick = { - dpm.setStartUserSessionMessage(receiver,start) - dpm.setEndUserSessionMessage(receiver,end) - Toast.makeText(context, R.string.success, Toast.LENGTH_SHORT).show() - }, - modifier = Modifier.fillMaxWidth() - ) { - Text(stringResource(R.string.apply)) - } - Button( - onClick = { - dpm.setStartUserSessionMessage(receiver,null) - dpm.setEndUserSessionMessage(receiver,null) - Toast.makeText(context, R.string.success, Toast.LENGTH_SHORT).show() - }, - modifier = Modifier.fillMaxWidth() - ) { - Text(stringResource(R.string.reset)) + Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween) { + Button( + onClick = { + dpm.setEndUserSessionMessage(receiver,end) + refreshMsg() + Toast.makeText(context, R.string.success, Toast.LENGTH_SHORT).show() + }, + modifier = Modifier.fillMaxWidth(0.49F) + ) { + Text(stringResource(R.string.apply)) + } + Button( + onClick = { + dpm.setEndUserSessionMessage(receiver,null) + refreshMsg() + Toast.makeText(context, R.string.success, Toast.LENGTH_SHORT).show() + }, + modifier = Modifier.fillMaxWidth(0.96F) + ) { + Text(stringResource(R.string.reset)) + } } Spacer(Modifier.padding(vertical = 30.dp)) } @@ -502,13 +536,18 @@ private fun UserIcon() { val dpm = context.getDPM() val receiver = context.getReceiver() var getContent by remember { mutableStateOf(false) } - val canApply = fileUriFlow.collectAsState().value != Uri.parse("") + var bitmap by remember { mutableStateOf(null) } + val uriState by fileUriFlow.collectAsState() + LaunchedEffect(uriState) { + if(uriState == Uri.parse("")) return@LaunchedEffect + uriToStream(context, fileUriFlow.value) { stream -> + bitmap = BitmapFactory.decodeStream(stream) + } + } Column(modifier = Modifier.fillMaxSize().padding(horizontal = 8.dp).verticalScroll(rememberScrollState())) { Spacer(Modifier.padding(vertical = 10.dp)) Text(text = stringResource(R.string.change_user_icon), style = typography.headlineLarge) Spacer(Modifier.padding(vertical = 5.dp)) - Text(text = stringResource(R.string.pick_a_square_image)) - Spacer(Modifier.padding(vertical = 5.dp)) CheckBoxItem(R.string.file_picker_instead_gallery, getContent, { getContent = it }) Spacer(Modifier.padding(vertical = 5.dp)) Button( @@ -522,18 +561,22 @@ private fun UserIcon() { ) { Text(stringResource(R.string.select_picture)) } - AnimatedVisibility(canApply) { - Button( - onClick = { - uriToStream(context, fileUriFlow.value) {stream -> - val bitmap = BitmapFactory.decodeStream(stream) - dpm.setUserIcon(receiver, bitmap) - Toast.makeText(context, R.string.success, Toast.LENGTH_SHORT).show() + AnimatedVisibility(visible = bitmap != null, modifier = Modifier.align(Alignment.CenterHorizontally)) { + Card(modifier = Modifier.padding(top = 8.dp)) { + Row(verticalAlignment = Alignment.CenterVertically, modifier = Modifier.padding(10.dp)) { + Image( + bitmap = bitmap!!.asImageBitmap(), contentDescription = "User icon", + modifier = Modifier.padding(end = 12.dp).size(80.dp).clip(RoundedCornerShape(50)) + ) + Button( + onClick = { + dpm.setUserIcon(receiver, bitmap) + Toast.makeText(context, R.string.success, Toast.LENGTH_SHORT).show() + } + ) { + Text(stringResource(R.string.apply)) } - }, - modifier = Modifier.fillMaxWidth() - ) { - Text(stringResource(R.string.apply)) + } } } } 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 f0ec4f2..da7ae55 100644 --- a/app/src/main/java/com/bintianqi/owndroid/dpm/UserRestriction.kt +++ b/app/src/main/java/com/bintianqi/owndroid/dpm/UserRestriction.kt @@ -1,7 +1,6 @@ package com.bintianqi.owndroid.dpm import android.annotation.SuppressLint -import android.content.Context import android.os.Build.VERSION import android.os.UserManager import android.widget.Toast @@ -12,7 +11,6 @@ import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.offset import androidx.compose.foundation.layout.padding import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll @@ -143,9 +141,8 @@ private fun Connectivity() { @Composable fun Application() { - val context = LocalContext.current Column(modifier = Modifier.fillMaxSize().verticalScroll(rememberScrollState())) { - for(applicationItem in RestrictionData.application(context)) { + for(applicationItem in RestrictionData.application()) { UserRestrictionItem(applicationItem.restriction, applicationItem.name, applicationItem.desc, applicationItem.ico) } Spacer(Modifier.padding(vertical = 30.dp)) @@ -174,9 +171,8 @@ private fun Media() { @Composable private fun Other() { - val context = LocalContext.current Column(modifier = Modifier.fillMaxSize().verticalScroll(rememberScrollState())) { - for(otherItem in RestrictionData.other(context)) { + for(otherItem in RestrictionData.other()) { UserRestrictionItem(otherItem.restriction, otherItem.name, otherItem.desc, otherItem.ico) } Spacer(Modifier.padding(vertical = 30.dp)) @@ -255,7 +251,7 @@ object RestrictionData { if(VERSION.SDK_INT>=28) { list += Restriction(UserManager.DISALLOW_PRINTING, R.string.printing, "", R.drawable.print_fill0) } return list } - fun application(context: Context): List{ + fun application(): List{ val list:MutableList = mutableListOf() list += Restriction(UserManager.DISALLOW_INSTALL_APPS, R.string.install_app, "", R.drawable.android_fill0) if(VERSION.SDK_INT>=29) { list += Restriction(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES_GLOBALLY, R.string.install_unknown_src_globally, "", R.drawable.android_fill0) } @@ -293,7 +289,7 @@ object RestrictionData { } return list } - fun other(context: Context): List{ + fun other(): List{ val list:MutableList = mutableListOf() if(VERSION.SDK_INT>=26) { list += Restriction(UserManager.DISALLOW_AUTOFILL, R.string.autofill, "", R.drawable.password_fill0) } list += Restriction(UserManager.DISALLOW_CONFIG_CREDENTIALS, R.string.config_credentials, "", R.drawable.android_fill0) @@ -316,14 +312,14 @@ object RestrictionData { list += Restriction(UserManager.DISALLOW_DEBUGGING_FEATURES, R.string.debug_features, "", R.drawable.adb_fill0) return list } - fun getAllRestrictions(context: Context): List { + fun getAllRestrictions(): List { val result = mutableListOf() internet().forEach { result.add(it.restriction) } connectivity().forEach { result.add(it.restriction) } media().forEach { result.add(it.restriction) } - application(context).forEach { result.add(it.restriction) } + application().forEach { result.add(it.restriction) } user().forEach { result.add(it.restriction) } - other(context).forEach { result.add(it.restriction) } + other().forEach { result.add(it.restriction) } return result } } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 793b9f2..e424ea9 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -17,8 +17,6 @@ serialization = "1.7.1" androidx-activity-compose = { module = "androidx.activity:activity-compose", version.ref = "androidx-activity-compose" } androidx-material3 = { module = "androidx.compose.material3:material3", version.ref = "material3" } androidx-navigation-compose = { module = "androidx.navigation:navigation-compose", version.ref = "navigation-compose" } -androidx-ui-graphics = { module = "androidx.compose.ui:ui-graphics" } -androidx-ui = { module = "androidx.compose.ui:ui" } accompanist-drawablepainter = { module = "com.google.accompanist:accompanist-drawablepainter", version.ref = "accompanist-drawablepainter" } androidx-biometric = { group = "androidx.biometric", name = "biometric", version.ref = "biometric" } @@ -34,4 +32,4 @@ serialization = { group = "org.jetbrains.kotlinx", name = "kotlinx-serialization [plugins] android-application = { id = "com.android.application", version.ref = "agp" } kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" } -cc = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" } +compose = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" }