mirror of
https://github.com/awfixers-stuff/OwnDroid.git
synced 2026-03-23 11:05:59 +00:00
Fine-grained Dhizuku server permissions
Add app icon to fastlane metadate
This commit is contained in:
@@ -11,8 +11,14 @@ import androidx.activity.compose.setContent
|
|||||||
import androidx.activity.enableEdgeToEdge
|
import androidx.activity.enableEdgeToEdge
|
||||||
import androidx.activity.viewModels
|
import androidx.activity.viewModels
|
||||||
import androidx.compose.foundation.Image
|
import androidx.compose.foundation.Image
|
||||||
|
import androidx.compose.foundation.clickable
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.Row
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.layout.size
|
import androidx.compose.foundation.layout.size
|
||||||
import androidx.compose.material3.AlertDialog
|
import androidx.compose.material3.AlertDialog
|
||||||
|
import androidx.compose.material3.Checkbox
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.material3.TextButton
|
import androidx.compose.material3.TextButton
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
@@ -21,6 +27,7 @@ import androidx.compose.runtime.mutableIntStateOf
|
|||||||
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.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
@@ -60,8 +67,16 @@ class MyDhizukuService(context: Context, admin: ComponentName, client: IDhizukuC
|
|||||||
val file = mContext.filesDir.resolve(DHIZUKU_CLIENTS_FILE)
|
val file = mContext.filesDir.resolve(DHIZUKU_CLIENTS_FILE)
|
||||||
val clients = Json.decodeFromString<List<DhizukuClientInfo>>(file.readText())
|
val clients = Json.decodeFromString<List<DhizukuClientInfo>>(file.readText())
|
||||||
val signature = getPackageSignature(packageInfo)
|
val signature = getPackageSignature(packageInfo)
|
||||||
val hasPermission = DhizukuClientInfo(callingUid, signature, true) in clients
|
val requiredPermission = when (func) {
|
||||||
Log.d(TAG, "UID $callingUid, PID $callingPid, has permission: $hasPermission")
|
"remote_transact", "remote_process" -> func
|
||||||
|
"bind_user_service", "unbind_user_service" -> "user_service"
|
||||||
|
"get_delegated_scopes", "set_delegated_scopes" -> "delegated_scopes"
|
||||||
|
else -> "other"
|
||||||
|
}
|
||||||
|
val hasPermission = clients.find {
|
||||||
|
callingUid == it.uid && signature == it.signature && requiredPermission in it.permissions
|
||||||
|
} != null
|
||||||
|
Log.d(TAG, "UID $callingUid, PID $callingPid, required permission: $requiredPermission, has permission: $hasPermission")
|
||||||
return hasPermission
|
return hasPermission
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -91,9 +106,12 @@ class DhizukuActivity : ComponentActivity() {
|
|||||||
val label = appInfo.loadLabel(packageManager).toString()
|
val label = appInfo.loadLabel(packageManager).toString()
|
||||||
fun close(grantPermission: Boolean) {
|
fun close(grantPermission: Boolean) {
|
||||||
val file = filesDir.resolve(DHIZUKU_CLIENTS_FILE)
|
val file = filesDir.resolve(DHIZUKU_CLIENTS_FILE)
|
||||||
val clients = Json.decodeFromString<MutableList<DhizukuClientInfo>>(file.readText())
|
val json = Json { ignoreUnknownKeys = true }
|
||||||
|
val clients = json.decodeFromString<MutableList<DhizukuClientInfo>>(file.readText())
|
||||||
val index = clients.indexOfFirst { it.uid == uid }
|
val index = clients.indexOfFirst { it.uid == uid }
|
||||||
val clientInfo = DhizukuClientInfo(uid, getPackageSignature(packageInfo), grantPermission)
|
val clientInfo = DhizukuClientInfo(
|
||||||
|
uid, getPackageSignature(packageInfo), if (grantPermission) DhizukuPermissions else emptyList()
|
||||||
|
)
|
||||||
if (index == -1) clients += clientInfo
|
if (index == -1) clients += clientInfo
|
||||||
else clients[index] = clientInfo
|
else clients[index] = clientInfo
|
||||||
file.writeText(Json.encodeToString(clients))
|
file.writeText(Json.encodeToString(clients))
|
||||||
@@ -121,9 +139,9 @@ class DhizukuActivity : ComponentActivity() {
|
|||||||
confirmButton = {
|
confirmButton = {
|
||||||
var time by remember { mutableIntStateOf(3) }
|
var time by remember { mutableIntStateOf(3) }
|
||||||
LaunchedEffect(Unit) {
|
LaunchedEffect(Unit) {
|
||||||
(1..3).forEach {
|
for (i in 2 downTo 0) {
|
||||||
delay(1000)
|
delay(1000)
|
||||||
time -= 1
|
time = i
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
TextButton({
|
TextButton({
|
||||||
@@ -152,10 +170,11 @@ class DhizukuActivity : ComponentActivity() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val DhizukuPermissions = listOf("remote_transact", "remote_process", "user_service", "delegated_scopes", "other")
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
data class DhizukuClientInfo(
|
data class DhizukuClientInfo(
|
||||||
val uid: Int,
|
val uid: Int,
|
||||||
val signature: String?,
|
val signature: String?,
|
||||||
val allow: Boolean
|
val permissions: List<String> = emptyList()
|
||||||
)
|
)
|
||||||
@@ -10,6 +10,8 @@ import androidx.activity.compose.rememberLauncherForActivityResult
|
|||||||
import androidx.annotation.Keep
|
import androidx.annotation.Keep
|
||||||
import androidx.annotation.RequiresApi
|
import androidx.annotation.RequiresApi
|
||||||
import androidx.annotation.StringRes
|
import androidx.annotation.StringRes
|
||||||
|
import androidx.compose.animation.AnimatedVisibility
|
||||||
|
import androidx.compose.animation.core.animateFloatAsState
|
||||||
import androidx.compose.foundation.Image
|
import androidx.compose.foundation.Image
|
||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
import androidx.compose.foundation.clickable
|
import androidx.compose.foundation.clickable
|
||||||
@@ -35,6 +37,7 @@ import androidx.compose.foundation.verticalScroll
|
|||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.automirrored.filled.KeyboardArrowRight
|
import androidx.compose.material.icons.automirrored.filled.KeyboardArrowRight
|
||||||
import androidx.compose.material.icons.filled.Add
|
import androidx.compose.material.icons.filled.Add
|
||||||
|
import androidx.compose.material.icons.filled.ArrowDropDown
|
||||||
import androidx.compose.material.icons.filled.Check
|
import androidx.compose.material.icons.filled.Check
|
||||||
import androidx.compose.material.icons.filled.Close
|
import androidx.compose.material.icons.filled.Close
|
||||||
import androidx.compose.material.icons.filled.MoreVert
|
import androidx.compose.material.icons.filled.MoreVert
|
||||||
@@ -44,6 +47,7 @@ import androidx.compose.material.icons.outlined.Warning
|
|||||||
import androidx.compose.material3.AlertDialog
|
import androidx.compose.material3.AlertDialog
|
||||||
import androidx.compose.material3.Button
|
import androidx.compose.material3.Button
|
||||||
import androidx.compose.material3.ButtonDefaults
|
import androidx.compose.material3.ButtonDefaults
|
||||||
|
import androidx.compose.material3.Card
|
||||||
import androidx.compose.material3.Checkbox
|
import androidx.compose.material3.Checkbox
|
||||||
import androidx.compose.material3.DropdownMenu
|
import androidx.compose.material3.DropdownMenu
|
||||||
import androidx.compose.material3.DropdownMenuItem
|
import androidx.compose.material3.DropdownMenuItem
|
||||||
@@ -55,10 +59,10 @@ import androidx.compose.material3.MaterialTheme.colorScheme
|
|||||||
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
|
||||||
import androidx.compose.material3.Switch
|
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.material3.TextButton
|
import androidx.compose.material3.TextButton
|
||||||
import androidx.compose.material3.TopAppBar
|
import androidx.compose.material3.TopAppBar
|
||||||
|
import androidx.compose.material3.TriStateCheckbox
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
@@ -72,11 +76,13 @@ import androidx.compose.runtime.setValue
|
|||||||
import androidx.compose.ui.Alignment
|
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.rotate
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
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.painterResource
|
import androidx.compose.ui.res.painterResource
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
|
import androidx.compose.ui.state.ToggleableState
|
||||||
import androidx.compose.ui.text.input.ImeAction
|
import androidx.compose.ui.text.input.ImeAction
|
||||||
import androidx.compose.ui.text.input.KeyboardType
|
import androidx.compose.ui.text.input.KeyboardType
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
@@ -84,6 +90,7 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
|||||||
import com.bintianqi.owndroid.ChoosePackageContract
|
import com.bintianqi.owndroid.ChoosePackageContract
|
||||||
import com.bintianqi.owndroid.DHIZUKU_CLIENTS_FILE
|
import com.bintianqi.owndroid.DHIZUKU_CLIENTS_FILE
|
||||||
import com.bintianqi.owndroid.DhizukuClientInfo
|
import com.bintianqi.owndroid.DhizukuClientInfo
|
||||||
|
import com.bintianqi.owndroid.DhizukuPermissions
|
||||||
import com.bintianqi.owndroid.HorizontalPadding
|
import com.bintianqi.owndroid.HorizontalPadding
|
||||||
import com.bintianqi.owndroid.IUserService
|
import com.bintianqi.owndroid.IUserService
|
||||||
import com.bintianqi.owndroid.MyAdminComponent
|
import com.bintianqi.owndroid.MyAdminComponent
|
||||||
@@ -509,7 +516,8 @@ fun DhizukuServerSettingsScreen(onNavigateUp: () -> Unit) {
|
|||||||
LaunchedEffect(enabled) {
|
LaunchedEffect(enabled) {
|
||||||
if (enabled) {
|
if (enabled) {
|
||||||
clients.clear()
|
clients.clear()
|
||||||
clients.addAll(Json.decodeFromString<List<DhizukuClientInfo>>(file.readText()))
|
val json = Json { ignoreUnknownKeys = true }
|
||||||
|
clients.addAll(json.decodeFromString<List<DhizukuClientInfo>>(file.readText()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
MyLazyScaffold(R.string.dhizuku_server, onNavigateUp) {
|
MyLazyScaffold(R.string.dhizuku_server, onNavigateUp) {
|
||||||
@@ -524,10 +532,12 @@ fun DhizukuServerSettingsScreen(onNavigateUp: () -> Unit) {
|
|||||||
writeList()
|
writeList()
|
||||||
} else {
|
} else {
|
||||||
val info = pm.getApplicationInfo(name, 0)
|
val info = pm.getApplicationInfo(name, 0)
|
||||||
|
var expand by remember { mutableStateOf(false) }
|
||||||
|
Card(
|
||||||
|
Modifier.fillMaxWidth().padding(HorizontalPadding, 8.dp)
|
||||||
|
) {
|
||||||
Row(
|
Row(
|
||||||
Modifier
|
Modifier.fillMaxWidth().padding(8.dp, 8.dp, 0.dp, 8.dp),
|
||||||
.fillMaxWidth()
|
|
||||||
.padding(HorizontalPadding, 8.dp),
|
|
||||||
Arrangement.SpaceBetween, Alignment.CenterVertically
|
Arrangement.SpaceBetween, Alignment.CenterVertically
|
||||||
) {
|
) {
|
||||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||||
@@ -537,16 +547,51 @@ fun DhizukuServerSettingsScreen(onNavigateUp: () -> Unit) {
|
|||||||
.padding(end = 16.dp)
|
.padding(end = 16.dp)
|
||||||
.size(50.dp)
|
.size(50.dp)
|
||||||
)
|
)
|
||||||
|
Column {
|
||||||
Text(info.loadLabel(pm).toString(), style = typography.titleLarge)
|
Text(info.loadLabel(pm).toString(), style = typography.titleLarge)
|
||||||
|
Text(name, Modifier.alpha(0.7F), style = typography.bodyMedium)
|
||||||
}
|
}
|
||||||
Switch(client.allow, {
|
}
|
||||||
clients[index] = client.copy(allow = it)
|
val ts = when (DhizukuPermissions.filter { it !in client.permissions }.size) {
|
||||||
|
0 -> ToggleableState.On
|
||||||
|
DhizukuPermissions.size -> ToggleableState.Off
|
||||||
|
else -> ToggleableState.Indeterminate
|
||||||
|
}
|
||||||
|
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||||
|
TriStateCheckbox(ts, {
|
||||||
|
clients[index] = when (ts) {
|
||||||
|
ToggleableState.On, ToggleableState.Indeterminate -> client.copy(permissions = emptyList())
|
||||||
|
ToggleableState.Off -> client.copy(permissions = DhizukuPermissions)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
val degrees by animateFloatAsState(if(expand) 180F else 0F)
|
||||||
|
IconButton({ expand = !expand }) {
|
||||||
|
Icon(Icons.Default.ArrowDropDown, null, Modifier.rotate(degrees))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
AnimatedVisibility(expand, Modifier.padding(8.dp, 0.dp, 8.dp, 8.dp)) {
|
||||||
|
Column {
|
||||||
|
mapOf(
|
||||||
|
"remote_transact" to "Remote transact", "remote_process" to "Remote process",
|
||||||
|
"user_service" to "User service", "delegated_scopes" to "Delegated scopes",
|
||||||
|
"other" to context.getString(R.string.other)
|
||||||
|
).forEach { (k, v) ->
|
||||||
|
Row(Modifier.fillMaxWidth(), Arrangement.SpaceBetween, Alignment.CenterVertically) {
|
||||||
|
Text(v)
|
||||||
|
Checkbox(k in client.permissions, {
|
||||||
|
val newPermissions = if (it) client.permissions.plus(k) else client.permissions.minus(k)
|
||||||
|
clients[index] = client.copy(permissions = newPermissions)
|
||||||
writeList()
|
writeList()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Serializable object LockScreenInfo
|
@Serializable object LockScreenInfo
|
||||||
|
|||||||
BIN
fastlane/metadata/android/en-US/images/icon.png
Normal file
BIN
fastlane/metadata/android/en-US/images/icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.7 KiB |
Reference in New Issue
Block a user