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应用 挂起 隐藏 如果隐藏,有可能是没安装