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
This commit is contained in:
BinTianqi
2024-09-28 10:45:48 +08:00
parent 47a965e6c0
commit 0788634049
13 changed files with 180 additions and 143 deletions

View File

@@ -1,7 +1,7 @@
plugins { plugins {
alias(libs.plugins.android.application) alias(libs.plugins.android.application)
alias(libs.plugins.kotlin.android) alias(libs.plugins.kotlin.android)
alias(libs.plugins.cc) alias(libs.plugins.compose)
kotlin("plugin.serialization") version "2.0.0" kotlin("plugin.serialization") version "2.0.0"
} }
@@ -76,8 +76,6 @@ gradle.taskGraph.whenReady {
dependencies { dependencies {
implementation(libs.androidx.activity.compose) implementation(libs.androidx.activity.compose)
implementation(libs.androidx.ui)
implementation(libs.androidx.ui.graphics)
implementation(libs.accompanist.drawablepainter) implementation(libs.accompanist.drawablepainter)
implementation(libs.androidx.material3) implementation(libs.androidx.material3)
implementation(libs.androidx.navigation.compose) implementation(libs.androidx.navigation.compose)

View File

@@ -16,8 +16,8 @@ class AutomationReceiver: BroadcastReceiver() {
@SuppressLint("NewApi") @SuppressLint("NewApi")
fun handleTask(context: Context, intent: Intent): String { fun handleTask(context: Context, intent: Intent): String {
val sharedPrefs = context.getSharedPreferences("data", Context.MODE_PRIVATE) val sharedPrefs = context.getSharedPreferences("data", Context.MODE_PRIVATE)
val key = sharedPrefs.getString("automation_key", "") ?: "" val key = sharedPrefs.getString("automation_key", "")
if(key != intent.getStringExtra("key")) { if(key == null || key != intent.getStringExtra("key")) {
return "Wrong key" return "Wrong key"
} }
val operation = intent.getStringExtra("operation") val operation = intent.getStringExtra("operation")

View File

@@ -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_PENDING_USER_ACTION
import android.content.pm.PackageInstaller.STATUS_SUCCESS import android.content.pm.PackageInstaller.STATUS_SUCCESS
import android.os.Build.VERSION import android.os.Build.VERSION
import android.os.PersistableBundle
import android.util.Log import android.util.Log
import android.widget.Toast import android.widget.Toast
import com.bintianqi.owndroid.dpm.getDPM import com.bintianqi.owndroid.dpm.getDPM
@@ -68,6 +69,13 @@ class Receiver : DeviceAdminReceiver() {
handleSecurityLogs(context) 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) val installAppDone = MutableStateFlow(false)

View File

@@ -34,7 +34,7 @@ fun uriToStream(
operation: (stream: InputStream)->Unit operation: (stream: InputStream)->Unit
){ ){
if(uri!=null){ if(uri!=null){
try{ try {
val stream = context.contentResolver.openInputStream(uri) val stream = context.contentResolver.openInputStream(uri)
if(stream != null) { operation(stream) } if(stream != null) { operation(stream) }
stream?.close() stream?.close()
@@ -44,26 +44,6 @@ fun uriToStream(
} }
} }
fun List<Any>.toText():String{
var output = ""
var isFirst = true
for(each in listIterator()){
if(isFirst) { isFirst = false } else { output+="\n" }
output+=each
}
return output
}
fun Set<Any>.toText(): String{
var output = ""
var isFirst = true
for(each in iterator()){
if(isFirst) { isFirst = false } else { output+="\n" }
output += each
}
return output
}
fun MutableList<Int>.toggle(status: Boolean, element: Int) { fun MutableList<Int>.toggle(status: Boolean, element: Int) {
if(status) add(element) else remove(element) if(status) add(element) else remove(element)
} }

View File

@@ -85,7 +85,6 @@ import com.bintianqi.owndroid.R
import com.bintianqi.owndroid.fileUriFlow import com.bintianqi.owndroid.fileUriFlow
import com.bintianqi.owndroid.getFile import com.bintianqi.owndroid.getFile
import com.bintianqi.owndroid.selectedPackage import com.bintianqi.owndroid.selectedPackage
import com.bintianqi.owndroid.toText
import com.bintianqi.owndroid.ui.Animations import com.bintianqi.owndroid.ui.Animations
import com.bintianqi.owndroid.ui.Information import com.bintianqi.owndroid.ui.Information
import com.bintianqi.owndroid.ui.NavIcon import com.bintianqi.owndroid.ui.NavIcon
@@ -358,7 +357,7 @@ private fun UserCtrlDisabledPkg(pkgName:String) {
Spacer(Modifier.padding(vertical = 5.dp)) Spacer(Modifier.padding(vertical = 5.dp))
Text(text = stringResource(R.string.app_list_is)) Text(text = stringResource(R.string.app_list_is))
SelectionContainer(modifier = Modifier.horizontalScroll(rememberScrollState()).animateContentSize()) { 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)) Spacer(Modifier.padding(vertical = 5.dp))
Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween) { 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.cross_profile_package), style = typography.headlineLarge)
Text(text = stringResource(R.string.app_list_is)) Text(text = stringResource(R.string.app_list_is))
SelectionContainer(modifier = Modifier.horizontalScroll(rememberScrollState()).animateContentSize()) { 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) { Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween) {
Button( Button(
@@ -567,7 +566,7 @@ private fun CrossProfileWidget(pkgName: String) {
Spacer(Modifier.padding(vertical = 5.dp)) Spacer(Modifier.padding(vertical = 5.dp))
Text(text = stringResource(R.string.app_list_is)) Text(text = stringResource(R.string.app_list_is))
SelectionContainer(modifier = Modifier.horizontalScroll(rememberScrollState()).animateContentSize()) { 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)) Spacer(Modifier.padding(vertical = 5.dp))
Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween) { Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween) {
@@ -660,7 +659,7 @@ private fun CredentialManagePolicy(pkgName: String) {
Column { Column {
Text(stringResource(R.string.app_list_is)) Text(stringResource(R.string.app_list_is))
SelectionContainer(modifier = Modifier.horizontalScroll(rememberScrollState()).animateContentSize()) { 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)) Spacer(Modifier.padding(vertical = 10.dp))
Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween) { Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween) {
@@ -739,7 +738,7 @@ private fun PermittedAccessibility(pkgName: String) {
if (pkgList.isEmpty()) { if (pkgList.isEmpty()) {
Text(stringResource(R.string.only_system_accessibility_allowed)) Text(stringResource(R.string.only_system_accessibility_allowed))
} else { } 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)) Spacer(Modifier.padding(vertical = 5.dp))
@@ -819,7 +818,7 @@ private fun PermittedIME(pkgName: String) {
if(permittedIme.isEmpty()) { if(permittedIme.isEmpty()) {
Text(stringResource(R.string.only_system_ime_allowed)) Text(stringResource(R.string.only_system_ime_allowed))
} else { } 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)) Spacer(Modifier.padding(vertical = 5.dp))
@@ -882,7 +881,7 @@ private fun KeepUninstalledApp(pkgName: String) {
Spacer(Modifier.padding(vertical = 5.dp)) Spacer(Modifier.padding(vertical = 5.dp))
Text(text = stringResource(R.string.app_list_is)) Text(text = stringResource(R.string.app_list_is))
SelectionContainer(modifier = Modifier.horizontalScroll(rememberScrollState()).animateContentSize()) { 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)) Spacer(Modifier.padding(vertical = 5.dp))
Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween) { Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween) {

View File

@@ -183,7 +183,7 @@ val dhizukuErrorStatus = MutableStateFlow(0)
fun Context.resetDevicePolicy() { fun Context.resetDevicePolicy() {
val dpm = getDPM() val dpm = getDPM()
val receiver = getReceiver() val receiver = getReceiver()
RestrictionData.getAllRestrictions(this).forEach { RestrictionData.getAllRestrictions().forEach {
dpm.clearUserRestriction(receiver, it) dpm.clearUserRestriction(receiver, it)
} }
dpm.accountTypesWithManagementDisabled?.forEach { dpm.accountTypesWithManagementDisabled?.forEach {

View File

@@ -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.PERSONAL_APPS_SUSPENDED_PROFILE_TIMEOUT
import android.app.admin.DevicePolicyManager.WIPE_EUICC import android.app.admin.DevicePolicyManager.WIPE_EUICC
import android.app.admin.DevicePolicyManager.WIPE_EXTERNAL_STORAGE import android.app.admin.DevicePolicyManager.WIPE_EXTERNAL_STORAGE
import android.app.admin.DevicePolicyManager.WIPE_SILENTLY
import android.content.* import android.content.*
import android.os.Binder import android.os.Binder
import android.os.Build.VERSION import android.os.Build.VERSION

View File

@@ -104,7 +104,6 @@ import com.bintianqi.owndroid.exportFile
import com.bintianqi.owndroid.exportFilePath import com.bintianqi.owndroid.exportFilePath
import com.bintianqi.owndroid.formatFileSize import com.bintianqi.owndroid.formatFileSize
import com.bintianqi.owndroid.selectedPackage import com.bintianqi.owndroid.selectedPackage
import com.bintianqi.owndroid.toText
import com.bintianqi.owndroid.ui.Animations import com.bintianqi.owndroid.ui.Animations
import com.bintianqi.owndroid.ui.CheckBoxItem import com.bintianqi.owndroid.ui.CheckBoxItem
import com.bintianqi.owndroid.ui.RadioButtonItem import com.bintianqi.owndroid.ui.RadioButtonItem
@@ -332,7 +331,7 @@ private fun WifiSsidPolicy() {
Spacer(Modifier.padding(vertical = 5.dp)) Spacer(Modifier.padding(vertical = 5.dp))
Text(stringResource(R.string.ssid_list_is)) Text(stringResource(R.string.ssid_list_is))
SelectionContainer(modifier = Modifier.animateContentSize().horizontalScroll(rememberScrollState())) { 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)) Spacer(Modifier.padding(vertical = 5.dp))

View File

@@ -559,9 +559,13 @@ private fun SupportMsg() {
val context = LocalContext.current val context = LocalContext.current
val dpm = context.getDPM() val dpm = context.getDPM()
val receiver = context.getReceiver() val receiver = context.getReceiver()
val focusMgr = LocalFocusManager.current var shortMsg by remember { mutableStateOf("") }
var shortMsg by remember { mutableStateOf(dpm.getShortSupportMessage(receiver)?.toString() ?: "") } var longMsg by remember { mutableStateOf("") }
var longMsg by remember { mutableStateOf(dpm.getLongSupportMessage(receiver)?.toString() ?: "") } 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)) { Column(modifier = Modifier.fillMaxSize().verticalScroll(rememberScrollState()).padding(horizontal = 8.dp)) {
Spacer(Modifier.padding(vertical = 10.dp)) Spacer(Modifier.padding(vertical = 10.dp))
Text(text = stringResource(R.string.support_msg), style = typography.headlineLarge) Text(text = stringResource(R.string.support_msg), style = typography.headlineLarge)
@@ -570,45 +574,59 @@ private fun SupportMsg() {
value = shortMsg, value = shortMsg,
label = { Text(stringResource(R.string.short_support_msg)) }, label = { Text(stringResource(R.string.short_support_msg)) },
onValueChange = { shortMsg = it }, 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( OutlinedTextField(
value = longMsg, value = longMsg,
label = { Text(stringResource(R.string.long_support_msg)) }, label = { Text(stringResource(R.string.long_support_msg)) },
onValueChange = { longMsg = it }, onValueChange = { longMsg = it },
modifier = Modifier.fillMaxWidth() modifier = Modifier.fillMaxWidth().padding(bottom = 2.dp)
) )
Spacer(Modifier.padding(vertical = 5.dp)) Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween) {
Button( Button(
onClick = { onClick = {
focusMgr.clearFocus() dpm.setLongSupportMessage(receiver, longMsg)
dpm.setShortSupportMessage(receiver, shortMsg) refreshMsg()
dpm.setLongSupportMessage(receiver, longMsg) Toast.makeText(context, R.string.success, Toast.LENGTH_SHORT).show()
shortMsg = dpm.getShortSupportMessage(receiver)?.toString() ?: "" },
longMsg = dpm.getLongSupportMessage(receiver)?.toString() ?: "" modifier = Modifier.fillMaxWidth(0.49F)
Toast.makeText(context, R.string.success, Toast.LENGTH_SHORT).show() ) {
}, Text(text = stringResource(R.string.apply))
modifier = Modifier.fillMaxWidth() }
) { Button(
Text(text = stringResource(R.string.apply)) 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)) Spacer(Modifier.padding(vertical = 30.dp))
} }
} }

View File

@@ -110,7 +110,6 @@ import com.bintianqi.owndroid.formatFileSize
import com.bintianqi.owndroid.getFile import com.bintianqi.owndroid.getFile
import com.bintianqi.owndroid.prepareForNotification import com.bintianqi.owndroid.prepareForNotification
import com.bintianqi.owndroid.selectedPackage import com.bintianqi.owndroid.selectedPackage
import com.bintianqi.owndroid.toText
import com.bintianqi.owndroid.toggle import com.bintianqi.owndroid.toggle
import com.bintianqi.owndroid.ui.Animations import com.bintianqi.owndroid.ui.Animations
import com.bintianqi.owndroid.ui.CheckBoxItem import com.bintianqi.owndroid.ui.CheckBoxItem
@@ -1115,7 +1114,7 @@ fun FactoryResetProtection() {
CheckBoxItem(R.string.enable_frp, enabled, { enabled = it }) CheckBoxItem(R.string.enable_frp, enabled, { enabled = it })
Text(stringResource(R.string.account_list_is)) Text(stringResource(R.string.account_list_is))
Text( 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() modifier = Modifier.animateContentSize()
) )
OutlinedTextField( OutlinedTextField(

View File

@@ -4,6 +4,7 @@ import android.annotation.SuppressLint
import android.app.admin.DevicePolicyManager import android.app.admin.DevicePolicyManager
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.graphics.Bitmap
import android.graphics.BitmapFactory import android.graphics.BitmapFactory
import android.net.Uri import android.net.Uri
import android.os.Binder import android.os.Binder
@@ -14,6 +15,7 @@ import android.os.UserManager
import android.provider.MediaStore import android.provider.MediaStore
import android.widget.Toast import android.widget.Toast
import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.AnimatedVisibility
import androidx.compose.foundation.Image
import androidx.compose.foundation.ScrollState import androidx.compose.foundation.ScrollState
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column 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.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.text.KeyboardActions import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.foundation.text.selection.SelectionContainer import androidx.compose.foundation.text.selection.SelectionContainer
import androidx.compose.foundation.verticalScroll import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.Button import androidx.compose.material3.Button
import androidx.compose.material3.Card
import androidx.compose.material3.MaterialTheme.typography import androidx.compose.material3.MaterialTheme.typography
import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Scaffold import androidx.compose.material3.Scaffold
@@ -37,11 +42,15 @@ import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableIntStateOf import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.mutableStateListOf
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.alpha 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.LocalContext
import androidx.compose.ui.platform.LocalFocusManager import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
@@ -57,7 +66,6 @@ import androidx.navigation.compose.rememberNavController
import com.bintianqi.owndroid.R import com.bintianqi.owndroid.R
import com.bintianqi.owndroid.fileUriFlow import com.bintianqi.owndroid.fileUriFlow
import com.bintianqi.owndroid.getFile import com.bintianqi.owndroid.getFile
import com.bintianqi.owndroid.toText
import com.bintianqi.owndroid.ui.Animations import com.bintianqi.owndroid.ui.Animations
import com.bintianqi.owndroid.ui.CheckBoxItem import com.bintianqi.owndroid.ui.CheckBoxItem
import com.bintianqi.owndroid.ui.RadioButtonItem 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.ui.TopBar
import com.bintianqi.owndroid.uriToStream import com.bintianqi.owndroid.uriToStream
var affiliationID = mutableSetOf<String>()
@Composable @Composable
fun UserManage(navCtrl: NavHostController) { fun UserManage(navCtrl: NavHostController) {
val localNavCtrl = rememberNavController() val localNavCtrl = rememberNavController()
@@ -341,11 +348,13 @@ private fun AffiliationID() {
val receiver = context.getReceiver() val receiver = context.getReceiver()
val focusMgr = LocalFocusManager.current val focusMgr = LocalFocusManager.current
var input by remember { mutableStateOf("") } var input by remember { mutableStateOf("") }
var list by remember { mutableStateOf("") } val affiliationID = remember { mutableStateListOf<String>() }
LaunchedEffect(Unit) { val list = affiliationID.joinToString(separator = "\n")
affiliationID = dpm.getAffiliationIds(receiver) val refreshIds = {
list = affiliationID.toText() affiliationID.clear()
affiliationID.addAll(dpm.getAffiliationIds(receiver))
} }
LaunchedEffect(Unit) { refreshIds() }
Column(modifier = Modifier.fillMaxSize().padding(horizontal = 8.dp).verticalScroll(rememberScrollState())) { Column(modifier = Modifier.fillMaxSize().padding(horizontal = 8.dp).verticalScroll(rememberScrollState())) {
Spacer(Modifier.padding(vertical = 10.dp)) Spacer(Modifier.padding(vertical = 10.dp))
Text(text = stringResource(R.string.affiliation_id), style = typography.headlineLarge) Text(text = stringResource(R.string.affiliation_id), style = typography.headlineLarge)
@@ -367,13 +376,13 @@ private fun AffiliationID() {
Spacer(Modifier.padding(vertical = 5.dp)) Spacer(Modifier.padding(vertical = 5.dp))
Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween) { Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween) {
Button( Button(
onClick = { affiliationID.add(input); list = affiliationID.toText() }, onClick = { affiliationID.add(input) },
modifier = Modifier.fillMaxWidth(0.49F) modifier = Modifier.fillMaxWidth(0.49F)
) { ) {
Text(stringResource(R.string.add)) Text(stringResource(R.string.add))
} }
Button( Button(
onClick = { affiliationID.remove(input); list = affiliationID.toText() }, onClick = { affiliationID.remove(input) },
modifier = Modifier.fillMaxWidth(0.96F) modifier = Modifier.fillMaxWidth(0.96F)
) { ) {
Text(stringResource(R.string.remove)) Text(stringResource(R.string.remove))
@@ -383,12 +392,11 @@ private fun AffiliationID() {
onClick = { onClick = {
if("" in affiliationID) { if("" in affiliationID) {
Toast.makeText(context, R.string.include_empty_string, Toast.LENGTH_SHORT).show() 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() Toast.makeText(context, R.string.cannot_be_empty, Toast.LENGTH_SHORT).show()
}else{ } else {
dpm.setAffiliationIds(receiver, affiliationID) dpm.setAffiliationIds(receiver, affiliationID.toSet())
affiliationID = dpm.getAffiliationIds(receiver) refreshIds()
list = affiliationID.toText()
Toast.makeText(context, R.string.success, Toast.LENGTH_SHORT).show() Toast.makeText(context, R.string.success, Toast.LENGTH_SHORT).show()
} }
}, },
@@ -445,10 +453,13 @@ private fun UserSessionMessage() {
val dpm = context.getDPM() val dpm = context.getDPM()
val receiver = context.getReceiver() val receiver = context.getReceiver()
val focusMgr = LocalFocusManager.current val focusMgr = LocalFocusManager.current
val getStart = dpm.getStartUserSessionMessage(receiver)?:"" var start by remember { mutableStateOf("") }
val getEnd = dpm.getEndUserSessionMessage(receiver)?:"" var end by remember { mutableStateOf("") }
var start by remember { mutableStateOf(getStart.toString()) } val refreshMsg = {
var end by remember { mutableStateOf(getEnd.toString()) } start = dpm.getStartUserSessionMessage(receiver)?.toString() ?: ""
end = dpm.getEndUserSessionMessage(receiver)?.toString() ?: ""
}
LaunchedEffect(Unit) { refreshMsg() }
Column(modifier = Modifier.fillMaxSize().padding(horizontal = 8.dp).verticalScroll(rememberScrollState())) { Column(modifier = Modifier.fillMaxSize().padding(horizontal = 8.dp).verticalScroll(rememberScrollState())) {
Spacer(Modifier.padding(vertical = 10.dp)) Spacer(Modifier.padding(vertical = 10.dp))
Text(text = stringResource(R.string.user_session_msg), style = typography.headlineLarge) 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)) }, label = { Text(stringResource(R.string.start_user_session_msg)) },
keyboardOptions = KeyboardOptions(imeAction = ImeAction.Done), keyboardOptions = KeyboardOptions(imeAction = ImeAction.Done),
keyboardActions = KeyboardActions(onDone = {focusMgr.clearFocus() }), 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( OutlinedTextField(
value = end, value = end,
onValueChange = { end= it }, onValueChange = { end= it },
label = { Text(stringResource(R.string.end_user_session_msg)) }, label = { Text(stringResource(R.string.end_user_session_msg)) },
keyboardOptions = KeyboardOptions(imeAction = ImeAction.Done), keyboardOptions = KeyboardOptions(imeAction = ImeAction.Done),
keyboardActions = KeyboardActions(onDone = { focusMgr.clearFocus() }), keyboardActions = KeyboardActions(onDone = { focusMgr.clearFocus() }),
modifier = Modifier.fillMaxWidth() modifier = Modifier.fillMaxWidth().padding(bottom = 2.dp)
) )
Spacer(Modifier.padding(vertical = 5.dp)) Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween) {
Button( Button(
onClick = { onClick = {
dpm.setStartUserSessionMessage(receiver,start) dpm.setEndUserSessionMessage(receiver,end)
dpm.setEndUserSessionMessage(receiver,end) refreshMsg()
Toast.makeText(context, R.string.success, Toast.LENGTH_SHORT).show() Toast.makeText(context, R.string.success, Toast.LENGTH_SHORT).show()
}, },
modifier = Modifier.fillMaxWidth() modifier = Modifier.fillMaxWidth(0.49F)
) { ) {
Text(stringResource(R.string.apply)) Text(stringResource(R.string.apply))
} }
Button( Button(
onClick = { onClick = {
dpm.setStartUserSessionMessage(receiver,null) dpm.setEndUserSessionMessage(receiver,null)
dpm.setEndUserSessionMessage(receiver,null) refreshMsg()
Toast.makeText(context, R.string.success, Toast.LENGTH_SHORT).show() Toast.makeText(context, R.string.success, Toast.LENGTH_SHORT).show()
}, },
modifier = Modifier.fillMaxWidth() modifier = Modifier.fillMaxWidth(0.96F)
) { ) {
Text(stringResource(R.string.reset)) Text(stringResource(R.string.reset))
}
} }
Spacer(Modifier.padding(vertical = 30.dp)) Spacer(Modifier.padding(vertical = 30.dp))
} }
@@ -502,13 +536,18 @@ private fun UserIcon() {
val dpm = context.getDPM() val dpm = context.getDPM()
val receiver = context.getReceiver() val receiver = context.getReceiver()
var getContent by remember { mutableStateOf(false) } var getContent by remember { mutableStateOf(false) }
val canApply = fileUriFlow.collectAsState().value != Uri.parse("") var bitmap by remember { mutableStateOf<Bitmap?>(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())) { Column(modifier = Modifier.fillMaxSize().padding(horizontal = 8.dp).verticalScroll(rememberScrollState())) {
Spacer(Modifier.padding(vertical = 10.dp)) Spacer(Modifier.padding(vertical = 10.dp))
Text(text = stringResource(R.string.change_user_icon), style = typography.headlineLarge) Text(text = stringResource(R.string.change_user_icon), style = typography.headlineLarge)
Spacer(Modifier.padding(vertical = 5.dp)) 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 }) CheckBoxItem(R.string.file_picker_instead_gallery, getContent, { getContent = it })
Spacer(Modifier.padding(vertical = 5.dp)) Spacer(Modifier.padding(vertical = 5.dp))
Button( Button(
@@ -522,18 +561,22 @@ private fun UserIcon() {
) { ) {
Text(stringResource(R.string.select_picture)) Text(stringResource(R.string.select_picture))
} }
AnimatedVisibility(canApply) { AnimatedVisibility(visible = bitmap != null, modifier = Modifier.align(Alignment.CenterHorizontally)) {
Button( Card(modifier = Modifier.padding(top = 8.dp)) {
onClick = { Row(verticalAlignment = Alignment.CenterVertically, modifier = Modifier.padding(10.dp)) {
uriToStream(context, fileUriFlow.value) {stream -> Image(
val bitmap = BitmapFactory.decodeStream(stream) bitmap = bitmap!!.asImageBitmap(), contentDescription = "User icon",
dpm.setUserIcon(receiver, bitmap) modifier = Modifier.padding(end = 12.dp).size(80.dp).clip(RoundedCornerShape(50))
Toast.makeText(context, R.string.success, Toast.LENGTH_SHORT).show() )
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))
} }
} }
} }

View File

@@ -1,7 +1,6 @@
package com.bintianqi.owndroid.dpm package com.bintianqi.owndroid.dpm
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.content.Context
import android.os.Build.VERSION import android.os.Build.VERSION
import android.os.UserManager import android.os.UserManager
import android.widget.Toast 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.Column
import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.offset
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll import androidx.compose.foundation.verticalScroll
@@ -143,9 +141,8 @@ private fun Connectivity() {
@Composable @Composable
fun Application() { fun Application() {
val context = LocalContext.current
Column(modifier = Modifier.fillMaxSize().verticalScroll(rememberScrollState())) { 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) UserRestrictionItem(applicationItem.restriction, applicationItem.name, applicationItem.desc, applicationItem.ico)
} }
Spacer(Modifier.padding(vertical = 30.dp)) Spacer(Modifier.padding(vertical = 30.dp))
@@ -174,9 +171,8 @@ private fun Media() {
@Composable @Composable
private fun Other() { private fun Other() {
val context = LocalContext.current
Column(modifier = Modifier.fillMaxSize().verticalScroll(rememberScrollState())) { 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) UserRestrictionItem(otherItem.restriction, otherItem.name, otherItem.desc, otherItem.ico)
} }
Spacer(Modifier.padding(vertical = 30.dp)) 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) } if(VERSION.SDK_INT>=28) { list += Restriction(UserManager.DISALLOW_PRINTING, R.string.printing, "", R.drawable.print_fill0) }
return list return list
} }
fun application(context: Context): List<Restriction>{ fun application(): List<Restriction>{
val list:MutableList<Restriction> = mutableListOf() val list:MutableList<Restriction> = mutableListOf()
list += Restriction(UserManager.DISALLOW_INSTALL_APPS, R.string.install_app, "", R.drawable.android_fill0) 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) } 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 return list
} }
fun other(context: Context): List<Restriction>{ fun other(): List<Restriction>{
val list:MutableList<Restriction> = mutableListOf() val list:MutableList<Restriction> = mutableListOf()
if(VERSION.SDK_INT>=26) { list += Restriction(UserManager.DISALLOW_AUTOFILL, R.string.autofill, "", R.drawable.password_fill0) } 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) 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) list += Restriction(UserManager.DISALLOW_DEBUGGING_FEATURES, R.string.debug_features, "", R.drawable.adb_fill0)
return list return list
} }
fun getAllRestrictions(context: Context): List<String> { fun getAllRestrictions(): List<String> {
val result = mutableListOf<String>() val result = mutableListOf<String>()
internet().forEach { result.add(it.restriction) } internet().forEach { result.add(it.restriction) }
connectivity().forEach { result.add(it.restriction) } connectivity().forEach { result.add(it.restriction) }
media().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) } user().forEach { result.add(it.restriction) }
other(context).forEach { result.add(it.restriction) } other().forEach { result.add(it.restriction) }
return result return result
} }
} }

View File

@@ -17,8 +17,6 @@ serialization = "1.7.1"
androidx-activity-compose = { module = "androidx.activity:activity-compose", version.ref = "androidx-activity-compose" } androidx-activity-compose = { module = "androidx.activity:activity-compose", version.ref = "androidx-activity-compose" }
androidx-material3 = { module = "androidx.compose.material3:material3", version.ref = "material3" } androidx-material3 = { module = "androidx.compose.material3:material3", version.ref = "material3" }
androidx-navigation-compose = { module = "androidx.navigation:navigation-compose", version.ref = "navigation-compose" } 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" } accompanist-drawablepainter = { module = "com.google.accompanist:accompanist-drawablepainter", version.ref = "accompanist-drawablepainter" }
androidx-biometric = { group = "androidx.biometric", name = "biometric", version.ref = "biometric" } androidx-biometric = { group = "androidx.biometric", name = "biometric", version.ref = "biometric" }
@@ -34,4 +32,4 @@ serialization = { group = "org.jetbrains.kotlinx", name = "kotlinx-serialization
[plugins] [plugins]
android-application = { id = "com.android.application", version.ref = "agp" } android-application = { id = "com.android.application", version.ref = "agp" }
kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" } 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" }