From aa5fbd0b33eb11d7424268a48bd57d65b813dbc9 Mon Sep 17 00:00:00 2001
From: BinTianqi <1220958406@qq.com>
Date: Thu, 4 Apr 2024 23:42:02 +0800
Subject: [PATCH] package selector in AppManage
---
Readme.md | 13 +-
app/build.gradle.kts | 5 +-
app/src/main/AndroidManifest.xml | 2 +-
.../com/binbin/androidowner/MainActivity.kt | 1 +
.../com/binbin/androidowner/PkgSelector.kt | 190 ++++++++++++++++++
.../androidowner/dpm/ApplicationManage.kt | 19 +-
.../java/com/binbin/androidowner/dpm/DPM.kt | 3 +-
app/src/main/res/drawable/checklist_fill0.xml | 9 +
app/src/main/res/drawable/refresh_fill0.xml | 9 +
app/src/main/res/values/strings.xml | 6 +
10 files changed, 244 insertions(+), 13 deletions(-)
create mode 100644 app/src/main/java/com/binbin/androidowner/PkgSelector.kt
create mode 100644 app/src/main/res/drawable/checklist_fill0.xml
create mode 100644 app/src/main/res/drawable/refresh_fill0.xml
diff --git a/Readme.md b/Readme.md
index 317aad0..5b0857c 100644
--- a/Readme.md
+++ b/Readme.md
@@ -6,9 +6,7 @@
使用安卓的Device Admin和Device Owner特权,完全掌控你的设备。
-**从v4.2开始,重写代码,重新设计,界面会发生很大改变。**
-
-我正在为这个App取一个新的名字......
+_我正在为这个App取一个新的名字......_
### 优点
@@ -19,7 +17,7 @@
### 缺点
-功能没有谷歌官方的 [TestDPC](https://github.com/googlesamples/android-testdpc) 那么多
+功能没有谷歌官方的 [TestDPC](https://github.com/googlesamples/android-testdpc) 那么全
### 功能
@@ -33,14 +31,13 @@
### 正在开发的功能
-- 应用管理:包选择器(目前只能手动输入包名)
-- 应用管理:应用权限选择器
-- 用户管理:用户选择器(目前只能手动输入用户序列号)
+- 应用管理:应用权限选择器(现在只能手动输入权限名称)
+- 用户管理:用户选择器(现在只能手动输入用户序列号)
- 安全日志和网络日志
### 许可证
-[License.md](License.md)
+[License.md](LICENSE.md)
> Copyright (C) 2024 BinTianqi
>
diff --git a/app/build.gradle.kts b/app/build.gradle.kts
index e3e90ca..0694f43 100644
--- a/app/build.gradle.kts
+++ b/app/build.gradle.kts
@@ -11,8 +11,8 @@ android {
applicationId = "com.binbin.androidowner"
minSdk = 21
targetSdk = 34
- versionCode = 21
- versionName = "4.4"
+ versionCode = 22
+ versionName = "4.5"
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
vectorDrawables {
@@ -60,6 +60,7 @@ dependencies {
implementation(platform("androidx.compose:compose-bom:2024.02.01"))
implementation("androidx.compose.ui:ui")
implementation("androidx.compose.ui:ui-graphics")
+ implementation("com.google.accompanist:accompanist-drawablepainter:0.35.0-alpha")
debugImplementation("androidx.compose.ui:ui-tooling-preview")
implementation("androidx.compose.material3:material3:1.2.0")
implementation("androidx.navigation:navigation-compose:2.7.7")
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 1a68182..31f2c8f 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -18,7 +18,7 @@
-
+
()
+
+@OptIn(ExperimentalMaterial3Api::class, ExperimentalFoundationApi::class)
+@Composable
+fun PackageSelector(navCtrl:NavHostController){
+ val context = LocalContext.current
+ val pm = context.packageManager
+ val apps = pm.getInstalledApplications(0)
+ var progress by remember{mutableIntStateOf(0)}
+ var show by remember{mutableStateOf(true)}
+ var hideProgress by remember{mutableStateOf(true)}
+ var filter by remember{mutableStateOf("data")}
+ val scrollState = rememberLazyListState()
+ val co = rememberCoroutineScope()
+ val getPkgList:suspend ()->Unit = {
+ show = false
+ progress = 0
+ hideProgress = false
+ pkgs.clear()
+ for(pkg in apps){
+ val srcDir = pkg.sourceDir
+ pkgs+=PkgInfo(
+ pkg.packageName, pkg.loadLabel(pm).toString(), pkg.loadIcon(pm),
+ if(srcDir.contains("/data/")){ "data" }
+ else if(
+ srcDir.contains("system/priv-app")||srcDir.contains("product/priv-app")||
+ srcDir.contains("ext/priv-app")||srcDir.contains("vendor/priv-app")
+ ){"priv"}
+ else if(srcDir.contains("apex")){"apex"}
+ else{"system"}
+ )
+ progress+=1
+ delay(1)
+ }
+ show = true
+ delay(300)
+ hideProgress = true
+ }
+ Scaffold(
+ topBar = {
+ TopAppBar(
+ title = {
+ Row(
+ horizontalArrangement = Arrangement.SpaceBetween, modifier = Modifier.fillMaxWidth().padding(bottom = 2.dp),
+ verticalAlignment = Alignment.CenterVertically
+ ){
+ Text(text = stringResource(R.string.pkg_selector))
+ Row {
+ Icon(
+ painter = painterResource(R.drawable.filter_alt_fill0),
+ contentDescription = "filter",
+ modifier = Modifier
+ .padding(horizontal = 6.dp)
+ .clip(RoundedCornerShape(50))
+ .combinedClickable(
+ onClick = {
+ when(filter){
+ "data"-> {
+ filter = "system"; co.launch {scrollState.scrollToItem(0)}
+ Toast.makeText(context, context.getString(R.string.show_system_app), Toast.LENGTH_SHORT).show()
+ }
+ "system"-> {
+ filter = "priv"; co.launch {scrollState.scrollToItem(0)}
+ Toast.makeText(context, context.getString(R.string.show_priv_app), Toast.LENGTH_SHORT).show()
+ }
+ else-> {
+ filter = "data"; co.launch {scrollState.scrollToItem(0)}
+ Toast.makeText(context, context.getString(R.string.show_user_app), Toast.LENGTH_SHORT).show()
+ }
+ }
+ },
+ onLongClick = {
+ filter = "apex"
+ Toast.makeText(context, context.getString(R.string.show_apex_app), Toast.LENGTH_SHORT).show()
+ }
+ )
+ .padding(5.dp)
+ )
+ Icon(
+ painter = painterResource(R.drawable.refresh_fill0),
+ contentDescription = "refresh",
+ modifier = Modifier
+ .padding(horizontal = 6.dp)
+ .clip(RoundedCornerShape(50))
+ .clickable{
+ co.launch{
+ delay(100)
+ getPkgList()
+ }
+ }
+ .padding(5.dp)
+ )
+ }
+ }
+ },
+ navigationIcon = {NavIcon{navCtrl.navigateUp()}},
+ colors = TopAppBarDefaults.topAppBarColors(containerColor = bgColor)
+ )
+ }
+ ){paddingValues->
+ LazyColumn(
+ horizontalAlignment = Alignment.CenterHorizontally,
+ modifier = Modifier.fillMaxSize().background(bgColor).padding(top = paddingValues.calculateTopPadding()),
+ state = scrollState
+ ){
+ items(1){
+ AnimatedVisibility(!hideProgress) {
+ LinearProgressIndicator(progress = {progress.toFloat()/apps.size}, modifier = Modifier.fillMaxWidth())
+ }
+ }
+ if(show) {
+ items(pkgs) {
+ if(filter==it.type){
+ PackageItem(it, navCtrl)
+ }
+ }
+ }else{
+ items(1){
+ Spacer(Modifier.padding(top = 5.dp))
+ Text(text = stringResource(R.string.loading), modifier = Modifier.alpha(0.8F))
+ }
+ }
+ }
+ LaunchedEffect(Unit){
+ delay(250)
+ if(pkgs.size==0){getPkgList()}
+ }
+ }
+}
+
+@Composable
+private fun PackageItem(pkg:PkgInfo, navCtrl: NavHostController){
+ Row(
+ verticalAlignment = Alignment.CenterVertically,
+ modifier = Modifier
+ .fillMaxWidth()
+ .clickable{selectedPackage=pkg.pkgName;applySelectedPackage=true;navCtrl.navigateUp()}
+ .padding(vertical = 3.dp)
+ ){
+ Spacer(Modifier.padding(start = 15.dp))
+ Image(
+ painter = rememberDrawablePainter(pkg.icon), contentDescription = "App icon",
+ modifier = Modifier.size(50.dp)
+ )
+ Spacer(Modifier.padding(start = 15.dp))
+ Column {
+ Text(text = pkg.label, style = typography.titleLarge)
+ Text(text = pkg.pkgName, modifier = Modifier.alpha(0.8F))
+ Spacer(Modifier.padding(top = 3.dp))
+ }
+ }
+}
diff --git a/app/src/main/java/com/binbin/androidowner/dpm/ApplicationManage.kt b/app/src/main/java/com/binbin/androidowner/dpm/ApplicationManage.kt
index 9252ed9..f1ce02d 100644
--- a/app/src/main/java/com/binbin/androidowner/dpm/ApplicationManage.kt
+++ b/app/src/main/java/com/binbin/androidowner/dpm/ApplicationManage.kt
@@ -25,6 +25,7 @@ import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.animateContentSize
import androidx.compose.foundation.*
import androidx.compose.foundation.layout.*
+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
@@ -33,8 +34,10 @@ import androidx.compose.material3.MaterialTheme.typography
import androidx.compose.runtime.*
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.clip
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalFocusManager
+import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.input.KeyboardType
@@ -93,6 +96,12 @@ fun ApplicationManage(navCtrl:NavHostController){
}
){ paddingValues->
Column(modifier = Modifier.fillMaxSize().padding(top = paddingValues.calculateTopPadding())){
+ LaunchedEffect(Unit) {
+ while(true){
+ if(applySelectedPackage){pkgName = selectedPackage; applySelectedPackage = false}
+ delay(200)
+ }
+ }
if(backStackEntry?.destination?.route!="InstallApp"){
TextField(
value = pkgName,
@@ -100,7 +109,15 @@ fun ApplicationManage(navCtrl:NavHostController){
label = { Text(stringResource(R.string.package_name)) },
modifier = Modifier.fillMaxWidth(),
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Ascii, imeAction = ImeAction.Done),
- keyboardActions = KeyboardActions(onDone = {focusMgr.clearFocus()})
+ keyboardActions = KeyboardActions(onDone = {focusMgr.clearFocus()}),
+ trailingIcon = {
+ Icon(painter = painterResource(R.drawable.checklist_fill0), contentDescription = null,
+ modifier = Modifier
+ .clip(RoundedCornerShape(50))
+ .clickable(onClick = {navCtrl.navigate("PackageSelector")})
+ .padding(3.dp))
+ },
+ singleLine = true
)
}
NavHost(
diff --git a/app/src/main/java/com/binbin/androidowner/dpm/DPM.kt b/app/src/main/java/com/binbin/androidowner/dpm/DPM.kt
index a789480..3ad10a6 100644
--- a/app/src/main/java/com/binbin/androidowner/dpm/DPM.kt
+++ b/app/src/main/java/com/binbin/androidowner/dpm/DPM.kt
@@ -5,7 +5,8 @@ import android.content.Intent
import android.net.Uri
import androidx.activity.result.ActivityResultLauncher
-
+var selectedPackage = ""
+var applySelectedPackage = false
lateinit var getCaCert: ActivityResultLauncher
lateinit var createManagedProfile: ActivityResultLauncher
lateinit var getApk: ActivityResultLauncher
diff --git a/app/src/main/res/drawable/checklist_fill0.xml b/app/src/main/res/drawable/checklist_fill0.xml
new file mode 100644
index 0000000..811a0e2
--- /dev/null
+++ b/app/src/main/res/drawable/checklist_fill0.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/refresh_fill0.xml b/app/src/main/res/drawable/refresh_fill0.xml
new file mode 100644
index 0000000..0703668
--- /dev/null
+++ b/app/src/main/res/drawable/refresh_fill0.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index e35d66b..01f53d7 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -238,6 +238,12 @@
应用管理
+ 应用选择器
+ 加载中
+ 显示用户应用
+ 显示系统应用
+ 显示priv-app
+ 显示apex应用
挂起
隐藏
如果隐藏,有可能是没安装