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)) + 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 = 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)) - } - 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" }