Skip to content

Commit f11395a

Browse files
committed
Improve app details screen (#327)
Move delegated admins entry to upper level (#317) Fix permissions manager crash (#326)
1 parent 917a8ca commit f11395a

10 files changed

Lines changed: 113 additions & 56 deletions

File tree

.gitattributes

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
*.svg binary

app/src/main/java/com/bintianqi/owndroid/feature/applications/AppDetailsModel.kt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,8 @@ data class AppDetailsUiState(
88
val meteredDataDisabled: Boolean = false,
99
val keepUninstalled: Boolean = false
1010
)
11+
12+
class DetailedAppInfo(
13+
val version: String = "",
14+
val versionNumber: Int = 0
15+
)

app/src/main/java/com/bintianqi/owndroid/feature/applications/AppDetailsScreen.kt

Lines changed: 48 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,12 @@ import androidx.compose.foundation.layout.height
1111
import androidx.compose.foundation.layout.padding
1212
import androidx.compose.foundation.layout.size
1313
import androidx.compose.foundation.lazy.items
14+
import androidx.compose.foundation.text.selection.SelectionContainer
15+
import androidx.compose.material.icons.Icons
16+
import androidx.compose.material.icons.outlined.Info
17+
import androidx.compose.material3.FilledTonalButton
1418
import androidx.compose.material3.Icon
19+
import androidx.compose.material3.IconButton
1520
import androidx.compose.material3.MaterialTheme.typography
1621
import androidx.compose.material3.Text
1722
import androidx.compose.runtime.Composable
@@ -24,6 +29,7 @@ import androidx.compose.runtime.setValue
2429
import androidx.compose.ui.Alignment
2530
import androidx.compose.ui.Modifier
2631
import androidx.compose.ui.draw.alpha
32+
import androidx.compose.ui.platform.LocalContext
2733
import androidx.compose.ui.res.painterResource
2834
import androidx.compose.ui.res.stringResource
2935
import androidx.compose.ui.text.style.TextAlign
@@ -44,22 +50,38 @@ fun ApplicationDetailsScreen(
4450
) {
4551
val privilege by vm.privilegeState.collectAsStateWithLifecycle()
4652
var dialog by rememberSaveable { mutableIntStateOf(0) } // 1: clear storage, 2: uninstall
53+
val appInfo by vm.appInfo.collectAsState()
54+
val detailedAppInfo by vm.detailedAppInfo.collectAsState()
4755
val uiState by vm.uiState.collectAsStateWithLifecycle()
48-
MySmallTitleScaffold(R.string.place_holder, onNavigateUp, 0.dp) {
49-
Column(
56+
val context = LocalContext.current
57+
LaunchedEffect(Unit) {
58+
vm.getInfo()
59+
}
60+
MySmallTitleScaffold(R.string.place_holder, onNavigateUp, 0.dp, {
61+
IconButton({ vm.viewAppDetails(context) }) {
62+
Icon(Icons.Outlined.Info, null)
63+
}
64+
}) {
65+
if (appInfo != null) Column(
5066
Modifier
5167
.align(Alignment.CenterHorizontally)
52-
.padding(top = 16.dp), horizontalAlignment = Alignment.CenterHorizontally
68+
.padding(top = 16.dp, bottom = 8.dp), horizontalAlignment = Alignment.CenterHorizontally
5369
) {
54-
Image(rememberDrawablePainter(vm.appInfo.icon), null, Modifier.size(50.dp))
55-
Text(vm.appInfo.label, Modifier.padding(top = 4.dp))
56-
Text(
57-
vm.appInfo.name,
58-
Modifier
59-
.alpha(0.7F)
60-
.padding(bottom = 8.dp),
61-
style = typography.bodyMedium
62-
)
70+
Image(rememberDrawablePainter(appInfo!!.icon), null, Modifier.size(50.dp))
71+
SelectionContainer {
72+
Column(horizontalAlignment = Alignment.CenterHorizontally) {
73+
Text(appInfo!!.label, Modifier.padding(top = 4.dp))
74+
Text(
75+
appInfo!!.name, Modifier.alpha(0.7F),
76+
style = typography.bodyMedium
77+
)
78+
Text(
79+
detailedAppInfo.version + " (${detailedAppInfo.versionNumber})",
80+
Modifier.alpha(0.7F),
81+
style = typography.bodyMedium
82+
)
83+
}
84+
}
6385
}
6486
FunctionItem(R.string.permissions, icon = R.drawable.shield_fill0) {
6587
onNavigate(Destination.AppPermissionsManager)
@@ -89,10 +111,20 @@ fun ApplicationDetailsScreen(
89111
FunctionItem(R.string.managed_configuration, icon = R.drawable.description_fill0) {
90112
onNavigate(Destination.ManagedConfiguration(vm.packageName))
91113
}
92-
if (VERSION.SDK_INT >= 28) FunctionItem(
93-
R.string.clear_app_storage, icon = R.drawable.mop_fill0
94-
) { dialog = 1 }
95-
FunctionItem(R.string.uninstall, icon = R.drawable.delete_fill0) { dialog = 2 }
114+
Row(Modifier.fillMaxWidth().padding(8.dp)) {
115+
FilledTonalButton(
116+
{ dialog = 1 },
117+
Modifier.padding(horizontal = 4.dp).weight(1F)
118+
) {
119+
Text(stringResource(R.string.clear_storage))
120+
}
121+
FilledTonalButton(
122+
{ dialog = 2 },
123+
Modifier.padding(horizontal = 4.dp).weight(1F)
124+
) {
125+
Text(stringResource(R.string.uninstall))
126+
}
127+
}
96128
Spacer(Modifier.height(BottomPadding))
97129
}
98130
if (dialog == 1 && VERSION.SDK_INT >= 28)

app/src/main/java/com/bintianqi/owndroid/feature/applications/AppDetailsViewModel.kt

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,22 @@
11
package com.bintianqi.owndroid.feature.applications
22

3+
import android.content.Context
4+
import android.content.Intent
35
import android.content.pm.PackageManager
46
import android.content.pm.PermissionInfo
7+
import android.net.Uri
58
import android.os.Build.VERSION
9+
import android.provider.Settings
610
import androidx.annotation.RequiresApi
711
import androidx.lifecycle.ViewModel
812
import androidx.lifecycle.viewModelScope
913
import com.bintianqi.owndroid.MyApplication
1014
import com.bintianqi.owndroid.PrivilegeHelper
15+
import com.bintianqi.owndroid.utils.AppInfo
1116
import com.bintianqi.owndroid.utils.PrivilegeStatus
1217
import com.bintianqi.owndroid.utils.ToastChannel
1318
import com.bintianqi.owndroid.utils.getAppInfo
19+
import com.bintianqi.owndroid.utils.getInstalledAppsFlags
1420
import com.bintianqi.owndroid.utils.plusOrMinus
1521
import com.bintianqi.owndroid.utils.uninstallPackage
1622
import kotlinx.coroutines.Dispatchers
@@ -23,14 +29,31 @@ class AppDetailsViewModel(
2329
val packageName: String, val application: MyApplication, val ph: PrivilegeHelper,
2430
val privilegeState: StateFlow<PrivilegeStatus>, val toastChannel: ToastChannel
2531
) : ViewModel() {
26-
val appInfo = getAppInfo(application.packageManager, packageName)
32+
val appInfo = MutableStateFlow<AppInfo?>(null)
33+
val detailedAppInfo = MutableStateFlow(DetailedAppInfo())
2734
val uiState = MutableStateFlow(AppDetailsUiState())
2835

29-
init {
30-
getStatus()
36+
fun getInfo() {
37+
viewModelScope.launch(Dispatchers.IO) {
38+
val pkgInfo = application.packageManager.getPackageInfo(
39+
packageName, getInstalledAppsFlags
40+
)
41+
appInfo.value = getAppInfo(application.packageManager, packageName)
42+
detailedAppInfo.value = DetailedAppInfo(pkgInfo.versionName ?: "", pkgInfo.versionCode)
43+
getStatus()
44+
}
45+
}
46+
47+
fun viewAppDetails(context: Context) {
48+
val intent = Intent()
49+
intent.action = Settings.ACTION_APPLICATION_DETAILS_SETTINGS
50+
intent.data = Uri.fromParts("package", packageName, null)
51+
try {
52+
context.startActivity(intent)
53+
} catch (_: Exception) {}
3154
}
3255

33-
fun getStatus() = ph.safeDpmCall {
56+
private fun getStatus() = ph.safeDpmCall {
3457
uiState.value = AppDetailsUiState(
3558
if (VERSION.SDK_INT >= 24) dpm.isPackageSuspended(dar, packageName) else false,
3659
dpm.isApplicationHidden(dar, packageName),
@@ -114,7 +137,7 @@ class AppDetailsViewModel(
114137
allPermissions += pm.queryPermissionsByGroup(it.name, 0)
115138
}
116139
val requestedPermissions = application.packageManager.getPackageInfo(
117-
packageName, PackageManager.GET_PERMISSIONS
140+
packageName, PackageManager.GET_PERMISSIONS or getInstalledAppsFlags
118141
).requestedPermissions ?: emptyArray()
119142
val actualPermissions = allPermissions.filter {
120143
it.protectionLevel and PermissionInfo.PROTECTION_DANGEROUS != 0 &&

app/src/main/java/com/bintianqi/owndroid/feature/applications/AppFeaturesViewModel.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ class AppFeaturesViewModel(
102102
allPermissions += pm.queryPermissionsByGroup(it.name, 0)
103103
}
104104
var allRequestedPermissions = mutableListOf<String>()
105-
pm.getInstalledPackages(PackageManager.GET_PERMISSIONS).forEach {
105+
pm.getInstalledPackages(PackageManager.GET_PERMISSIONS or getInstalledAppsFlags).forEach {
106106
allRequestedPermissions += it.requestedPermissions ?: emptyArray()
107107
}
108108
allRequestedPermissions = allRequestedPermissions.distinct().toMutableList()

app/src/main/java/com/bintianqi/owndroid/feature/applications/Common.kt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ import com.bintianqi.owndroid.PrivilegeHelper
3434
import com.bintianqi.owndroid.R
3535
import com.bintianqi.owndroid.utils.AppInfo
3636
import com.bintianqi.owndroid.utils.getAppInfo
37+
import com.bintianqi.owndroid.utils.getInstalledAppsFlags
3738
import com.bintianqi.owndroid.utils.searchInString
3839
import com.bintianqi.owndroid.utils.transformAppRestrictionEntryList
3940
import kotlinx.serialization.Serializable
@@ -277,7 +278,9 @@ fun getAppStatus(
277278
}
278279
}
279280
} catch (_: Exception) {}
280-
val pkgInfo = context.packageManager.getPackageInfo(packageName, PackageManager.GET_PERMISSIONS)
281+
val pkgInfo = context.packageManager.getPackageInfo(
282+
packageName, PackageManager.GET_PERMISSIONS or getInstalledAppsFlags
283+
)
281284
return AppChooserEntry(
282285
appInfo, hasMc, mcModified, suspended, hidden, ub, ucd, mdd,
283286
Manifest.permission.INTERNET in (pkgInfo.requestedPermissions ?: emptyArray())

app/src/main/java/com/bintianqi/owndroid/feature/privilege/WorkingModesScreen.kt

Lines changed: 16 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ import androidx.compose.foundation.layout.Row
1212
import androidx.compose.foundation.layout.fillMaxSize
1313
import androidx.compose.foundation.layout.fillMaxWidth
1414
import androidx.compose.foundation.layout.padding
15-
import androidx.compose.foundation.layout.size
1615
import androidx.compose.foundation.rememberScrollState
1716
import androidx.compose.foundation.text.selection.SelectionContainer
1817
import androidx.compose.foundation.verticalScroll
@@ -120,18 +119,6 @@ fun WorkModesScreen(
120119
},
121120
leadingIcon = { Icon(Icons.Default.Close, null) }
122121
)
123-
if (VERSION.SDK_INT >= 26) DropdownMenuItem(
124-
{ Text(stringResource(R.string.delegated_admins)) },
125-
{
126-
expanded = false
127-
onNavigate(Destination.DelegatedAdmins)
128-
},
129-
leadingIcon = {
130-
Icon(
131-
painterResource(R.drawable.admin_panel_settings_fill0), null
132-
)
133-
}
134-
)
135122
if (!privilege.dhizuku && VERSION.SDK_INT >= 28) DropdownMenuItem(
136123
{ Text(stringResource(R.string.transfer_ownership)) },
137124
{
@@ -197,18 +184,28 @@ fun WorkModesScreen(
197184
.padding(top = 20.dp)
198185
.fillMaxWidth()
199186
.clickable { onNavigate(Destination.DhizukuServerSettings) }
200-
.padding(vertical = 4.dp),
187+
.padding(vertical = 12.dp),
201188
verticalAlignment = Alignment.CenterVertically
202189
) {
203190
Icon(
204-
painterResource(R.drawable.dhizuku_icon), null,
205-
Modifier
206-
.padding(8.dp)
207-
.size(28.dp)
191+
painterResource(R.drawable.m3_dhizuku_icon), null,
192+
Modifier.padding(start = 12.dp, end = 8.dp)
208193
)
209194
Text(stringResource(R.string.dhizuku_server), style = typography.titleLarge)
210195
}
211-
196+
Row(
197+
Modifier
198+
.fillMaxWidth()
199+
.clickable { onNavigate(Destination.DelegatedAdmins) }
200+
.padding(vertical = 12.dp),
201+
verticalAlignment = Alignment.CenterVertically
202+
) {
203+
Icon(
204+
painterResource(R.drawable.admin_panel_settings_fill0), null,
205+
Modifier.padding(start = 12.dp, end = 8.dp)
206+
)
207+
Text(stringResource(R.string.delegated_admins), style = typography.titleLarge)
208+
}
212209
Column(Modifier.padding(HorizontalPadding, 20.dp)) {
213210
Row(
214211
Modifier.padding(bottom = 4.dp), verticalAlignment = Alignment.CenterVertically

app/src/main/res/drawable/dhizuku_icon.xml

Lines changed: 0 additions & 13 deletions
This file was deleted.
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<vector xmlns:android="http://schemas.android.com/apk/res/android"
2+
android:width="24dp"
3+
android:height="24dp"
4+
android:viewportWidth="24"
5+
android:viewportHeight="24">
6+
<path
7+
android:fillColor="#FF000000"
8+
android:pathData="m16.541,1.01c-0.869,0 -1.602,0.731 -1.602,1.6v2.799c0,0.081 0.007,0.16 0.02,0.238l-5.488,5.488h-3.195v-1.244c1.754,-0.423 3.07,-2.013 3.07,-3.891 0,-2.197 -1.803,-4 -4,-4 -2.197,0 -4,1.803 -4,4 0,1.827 1.246,3.382 2.93,3.854v6.402h-2.131a1,1 0,0 0,-1 1,1 1,0 0,0 1,1h2.131v0.703h-2.18a1,1 0,0 0,-1 1,1 1,0 0,0 1,1h2.18v0.625a1,1 0,0 0,1 1,1 1,0 0,0 1,-1v-8.449h3.373l5.344,5.207c-0.01,0.071 -0.016,0.142 -0.016,0.215v2.801c0,0.869 0.731,1.6 1.6,1.6h2.799c0.869,0 1.602,-0.731 1.602,-1.6v-2.801c0,-0.869 -0.732,-1.6 -1.602,-1.6h-2.799c-0.045,0 -0.09,0.002 -0.135,0.006l-3.93,-3.828h4.432v0.49c0,0.869 0.731,1.6 1.6,1.6h2.801c0.869,0 1.6,-0.731 1.6,-1.6v-2.801c0,-0.869 -0.731,-1.6 -1.6,-1.6h-2.801c-0.869,0 -1.6,0.731 -1.6,1.6v0.311h-4.645l4.129,-4.129c0.037,0.003 0.075,0.004 0.113,0.004h2.799c0.869,0 1.6,-0.732 1.6,-1.602v-2.799c0,-0.869 -0.731,-1.6 -1.6,-1.6zM16.939,3.01h2v2h-2zM5.346,4c1.116,0 2,0.884 2,2 0,1.116 -0.884,2 -2,2 -1.116,0 -2,-0.884 -2,-2 0,-1.116 0.884,-2 2,-2zM18.943,11.225h2v2h-2zM16.977,18.957h2v2h-2z"/>
9+
</vector>

app/src/main/res/values-zh-rCN/strings.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -615,7 +615,7 @@
615615
<string name="lock_when_leaving">离开时锁定</string>
616616
<string name="unlock">解锁</string>
617617
<string name="security">安全性</string>
618-
<string name="clear_storage">清除存储空间</string>
618+
<string name="clear_storage">清除存储</string>
619619

620620
<string name="api_key">API密钥</string>
621621
<string name="api_key_exist">API密钥已存在,设置新的密钥将会覆盖当前密钥</string>

0 commit comments

Comments
 (0)