mirror of
https://github.com/awfixers-stuff/OwnDroid.git
synced 2026-03-23 19:15:58 +00:00
Ca cert manage, update readme.md
This commit is contained in:
19
Readme.md
19
Readme.md
@@ -3,13 +3,20 @@
|
|||||||
### 简介
|
### 简介
|
||||||
|
|
||||||
使用安卓的Device Admin和Device Owner,全方位掌控你的设备。
|
使用安卓的Device Admin和Device Owner,全方位掌控你的设备。
|
||||||
这个应用使用Kotlin + Jetpack Compose,有不完全的质感设计3配色
|
|
||||||
|
|
||||||
记得给我个小星星,欢迎大家提交Issue
|
### 优点
|
||||||
|
|
||||||
|
- 开源。Device owner权限仅次于Root权限,十分危险,闭源软件的安全性没有保证
|
||||||
|
- UI友好。易于上手,使用Material design 3,支持系统主题色,适配手机和手表的屏幕尺寸
|
||||||
|
- 与时俱进。使用 Kotlin + Jetpack Compose,支持安卓14的新功能
|
||||||
|
- 维护中。这个项目正在不断更新。欢迎 Issue 和 Pull request
|
||||||
|
|
||||||
|
### 缺点
|
||||||
|
|
||||||
|
不支持一些 Device admin 和 Device owner 功能。如果追求功能齐全,谷歌官方的 [TestDPC](https://github.com/googlesamples/android-testdpc) 可能更适合你
|
||||||
|
|
||||||
### 功能
|
### 功能
|
||||||
|
|
||||||
已经适配手表,请在应用的设置里打开“Wear”
|
|
||||||
适配了一些预见式返回动画(需安卓13或14),可能不太稳定,如果有问题请向我反馈
|
适配了一些预见式返回动画(需安卓13或14),可能不太稳定,如果有问题请向我反馈
|
||||||
|
|
||||||
- 设备控制
|
- 设备控制
|
||||||
@@ -21,10 +28,11 @@
|
|||||||
- 设置时间
|
- 设置时间
|
||||||
- 管理系统更新策略
|
- 管理系统更新策略
|
||||||
- 清除数据
|
- 清除数据
|
||||||
- 管理应用
|
- 应用管理
|
||||||
- 隐藏应用
|
- 隐藏应用
|
||||||
- 停用应用
|
- 停用应用
|
||||||
- 禁止卸载应用
|
- 禁止卸载应用
|
||||||
|
- 应用权限管理
|
||||||
- 设置许可的输入法
|
- 设置许可的输入法
|
||||||
- 用户限制
|
- 用户限制
|
||||||
- 网络和互联网:禁止使用流量、WiFi、VPN、私人DNS
|
- 网络和互联网:禁止使用流量、WiFi、VPN、私人DNS
|
||||||
@@ -53,7 +61,8 @@
|
|||||||
- Managed Profile,工作资料和多用户相关
|
- Managed Profile,工作资料和多用户相关
|
||||||
- ~~应用管理:安装/卸载应用~~(暂不考虑)
|
- ~~应用管理:安装/卸载应用~~(暂不考虑)
|
||||||
- 应用管理:包选择器(目前只能手动输入包名)
|
- 应用管理:包选择器(目前只能手动输入包名)
|
||||||
- 用户管理:用户选择器(目前只能手动输入序列号)
|
- 应用管理:应用权限选择器
|
||||||
|
- 用户管理:用户选择器(目前只能手动输入用户序列号)
|
||||||
|
|
||||||
### 许可证
|
### 许可证
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,9 @@ import android.app.admin.DevicePolicyManager
|
|||||||
import android.app.admin.DevicePolicyManager.*
|
import android.app.admin.DevicePolicyManager.*
|
||||||
import android.content.ComponentName
|
import android.content.ComponentName
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
import android.os.Build.VERSION
|
import android.os.Build.VERSION
|
||||||
|
import android.util.Log
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import androidx.activity.ComponentActivity
|
import androidx.activity.ComponentActivity
|
||||||
import androidx.compose.animation.AnimatedVisibility
|
import androidx.compose.animation.AnimatedVisibility
|
||||||
@@ -29,6 +31,8 @@ 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.text.style.TextAlign
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
|
import kotlinx.coroutines.delay
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun DeviceControl(){
|
fun DeviceControl(){
|
||||||
@@ -144,13 +148,6 @@ fun DeviceControl(){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(isDeviceOwner(myDpm)||isProfileOwner(myDpm)){
|
|
||||||
Button(
|
|
||||||
onClick = {myDpm.uninstallAllUserCaCerts(myComponent);Toast.makeText(myContext, "成功", Toast.LENGTH_SHORT).show()},
|
|
||||||
modifier = Modifier.align(Alignment.CenterHorizontally)
|
|
||||||
) {
|
|
||||||
Text(text = "清除用户Ca证书")
|
|
||||||
}}
|
|
||||||
|
|
||||||
if(VERSION.SDK_INT>=28){
|
if(VERSION.SDK_INT>=28){
|
||||||
Column(modifier = sections()){
|
Column(modifier = sections()){
|
||||||
@@ -368,6 +365,64 @@ fun DeviceControl(){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(isDeviceOwner(myDpm)||isProfileOwner(myDpm)){
|
||||||
|
var exist by remember{mutableStateOf(false)}
|
||||||
|
var isEmpty by remember{mutableStateOf(false)}
|
||||||
|
val refresh = {
|
||||||
|
isEmpty = caCert.isEmpty()
|
||||||
|
exist = if(!isEmpty){ myDpm.hasCaCertInstalled(myComponent, caCert) }else{ false }
|
||||||
|
}
|
||||||
|
LaunchedEffect(exist){ launch{isCaCertSelected(600){refresh()}} }
|
||||||
|
Column(modifier = sections()){
|
||||||
|
Text(text = "Ca证书", style = typography.titleLarge)
|
||||||
|
if(isEmpty){ Text(text = "请选择Ca证书(.0)") }else{ Text(text = "证书已安装:$exist") }
|
||||||
|
Button(
|
||||||
|
onClick = {
|
||||||
|
val caCertIntent = Intent(Intent.ACTION_GET_CONTENT)
|
||||||
|
caCertIntent.setType("*/*")
|
||||||
|
caCertIntent.addCategory(Intent.CATEGORY_OPENABLE)
|
||||||
|
getCaCert.launch(caCertIntent)
|
||||||
|
},
|
||||||
|
modifier = Modifier.fillMaxWidth()
|
||||||
|
) {
|
||||||
|
Text("选择证书...")
|
||||||
|
}
|
||||||
|
Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween){
|
||||||
|
Button(
|
||||||
|
onClick = {
|
||||||
|
val result = myDpm.installCaCert(myComponent, caCert)
|
||||||
|
Toast.makeText(myContext, if(result){"成功"}else{"失败"}, Toast.LENGTH_SHORT).show()
|
||||||
|
refresh()
|
||||||
|
},
|
||||||
|
modifier = Modifier.fillMaxWidth(0.49F)
|
||||||
|
) {
|
||||||
|
Text("安装")
|
||||||
|
}
|
||||||
|
Button(
|
||||||
|
onClick = {
|
||||||
|
if(exist){
|
||||||
|
myDpm.uninstallCaCert(myComponent, caCert)
|
||||||
|
exist = myDpm.hasCaCertInstalled(myComponent, caCert)
|
||||||
|
Toast.makeText(myContext, if(exist){"失败"}else{"成功"}, Toast.LENGTH_SHORT).show()
|
||||||
|
}else{ Toast.makeText(myContext, "不存在", Toast.LENGTH_SHORT).show() }
|
||||||
|
},
|
||||||
|
modifier = Modifier.fillMaxWidth(0.96F)
|
||||||
|
) {
|
||||||
|
Text("卸载")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Button(
|
||||||
|
onClick = {
|
||||||
|
myDpm.uninstallAllUserCaCerts(myComponent)
|
||||||
|
Toast.makeText(myContext, "成功", Toast.LENGTH_SHORT).show()
|
||||||
|
},
|
||||||
|
modifier = Modifier.fillMaxWidth()
|
||||||
|
){
|
||||||
|
Text("清除用户Ca证书")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if(isDeviceOwner(myDpm)){
|
if(isDeviceOwner(myDpm)){
|
||||||
SysUpdatePolicy()
|
SysUpdatePolicy()
|
||||||
}
|
}
|
||||||
@@ -470,3 +525,10 @@ fun DeviceCtrlItem(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
suspend fun isCaCertSelected(delay:Long,operation:()->Unit){
|
||||||
|
while(true){
|
||||||
|
delay(delay)
|
||||||
|
operation()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -4,11 +4,14 @@ import android.annotation.SuppressLint
|
|||||||
import android.app.admin.DevicePolicyManager
|
import android.app.admin.DevicePolicyManager
|
||||||
import android.content.ComponentName
|
import android.content.ComponentName
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
import android.os.Build.VERSION
|
import android.os.Build.VERSION
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
import android.widget.Toast
|
||||||
import androidx.activity.ComponentActivity
|
import androidx.activity.ComponentActivity
|
||||||
import androidx.activity.compose.setContent
|
import androidx.activity.compose.setContent
|
||||||
import androidx.compose.animation.*
|
import androidx.activity.result.ActivityResultLauncher
|
||||||
|
import androidx.activity.result.contract.ActivityResultContracts
|
||||||
import androidx.compose.foundation.*
|
import androidx.compose.foundation.*
|
||||||
import androidx.compose.foundation.layout.*
|
import androidx.compose.foundation.layout.*
|
||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
@@ -17,7 +20,8 @@ import androidx.compose.material.icons.outlined.ArrowBack
|
|||||||
import androidx.compose.material.icons.outlined.Home
|
import androidx.compose.material.icons.outlined.Home
|
||||||
import androidx.compose.material3.*
|
import androidx.compose.material3.*
|
||||||
import androidx.compose.material3.MaterialTheme.typography
|
import androidx.compose.material3.MaterialTheme.typography
|
||||||
import androidx.compose.runtime.*
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
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.clip
|
import androidx.compose.ui.draw.clip
|
||||||
@@ -35,22 +39,32 @@ import androidx.navigation.compose.composable
|
|||||||
import androidx.navigation.compose.currentBackStackEntryAsState
|
import androidx.navigation.compose.currentBackStackEntryAsState
|
||||||
import androidx.navigation.compose.rememberNavController
|
import androidx.navigation.compose.rememberNavController
|
||||||
import com.binbin.androidowner.ui.theme.AndroidOwnerTheme
|
import com.binbin.androidowner.ui.theme.AndroidOwnerTheme
|
||||||
|
import java.io.FileNotFoundException
|
||||||
|
import java.io.IOException
|
||||||
|
|
||||||
/*lateinit var getOtaPackage: ActivityResultLauncher<Intent>
|
lateinit var getCaCert: ActivityResultLauncher<Intent>
|
||||||
var installOta = false
|
var caCert = byteArrayOf()
|
||||||
lateinit var otaUri:Uri*/
|
|
||||||
|
|
||||||
@ExperimentalMaterial3Api
|
@ExperimentalMaterial3Api
|
||||||
class MainActivity : ComponentActivity() {
|
class MainActivity : ComponentActivity() {
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
WindowCompat.setDecorFitsSystemWindows(window, false)
|
WindowCompat.setDecorFitsSystemWindows(window, false)
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
/*otaUri = Uri.EMPTY
|
getCaCert = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
|
||||||
getOtaPackage = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
|
val uri = it.data?.data
|
||||||
val data = it.data?.data
|
if(uri!=null){
|
||||||
installOta = true
|
try{
|
||||||
otaUri = data ?: Uri.EMPTY
|
val stream = contentResolver.openInputStream(uri)
|
||||||
}*/
|
if(stream!=null) {
|
||||||
|
caCert = stream.readBytes()
|
||||||
|
if(caCert.size>50000){ Toast.makeText(applicationContext, "太大了", Toast.LENGTH_SHORT).show(); caCert = byteArrayOf() }
|
||||||
|
}else{ Toast.makeText(applicationContext, "空的流", Toast.LENGTH_SHORT).show() }
|
||||||
|
stream?.close()
|
||||||
|
}
|
||||||
|
catch(e:FileNotFoundException){ Toast.makeText(applicationContext, "文件不存在", Toast.LENGTH_SHORT).show() }
|
||||||
|
catch(e:IOException){ Toast.makeText(applicationContext, "IO异常", Toast.LENGTH_SHORT).show() }
|
||||||
|
}else{ Toast.makeText(applicationContext, "空URI", Toast.LENGTH_SHORT).show() }
|
||||||
|
}
|
||||||
setContent {
|
setContent {
|
||||||
AndroidOwnerTheme {
|
AndroidOwnerTheme {
|
||||||
MyScaffold()
|
MyScaffold()
|
||||||
@@ -148,6 +162,7 @@ fun HomePage(navCtrl:NavHostController){
|
|||||||
val activateType = if(isDeviceOwner(myDpm)){"Device Owner"}else if(isProfileOwner(myDpm)){"Profile Owner"}else if(myDpm.isAdminActive(myComponent)){"Device Admin"}else{""}
|
val activateType = if(isDeviceOwner(myDpm)){"Device Owner"}else if(isProfileOwner(myDpm)){"Profile Owner"}else if(myDpm.isAdminActive(myComponent)){"Device Admin"}else{""}
|
||||||
val sharedPref = LocalContext.current.getSharedPreferences("data", Context.MODE_PRIVATE)
|
val sharedPref = LocalContext.current.getSharedPreferences("data", Context.MODE_PRIVATE)
|
||||||
val isWear = sharedPref.getBoolean("isWear",false)
|
val isWear = sharedPref.getBoolean("isWear",false)
|
||||||
|
caCert = byteArrayOf()
|
||||||
Column(modifier = Modifier.verticalScroll(rememberScrollState()), horizontalAlignment = Alignment.CenterHorizontally) {
|
Column(modifier = Modifier.verticalScroll(rememberScrollState()), horizontalAlignment = Alignment.CenterHorizontally) {
|
||||||
if(isWear){ Spacer(Modifier.padding(vertical = 3.dp)) }
|
if(isWear){ Spacer(Modifier.padding(vertical = 3.dp)) }
|
||||||
Row(
|
Row(
|
||||||
@@ -273,7 +288,7 @@ fun isProfileOwner(dpm:DevicePolicyManager): Boolean {
|
|||||||
return dpm.isProfileOwnerApp("com.binbin.androidowner")
|
return dpm.isProfileOwnerApp("com.binbin.androidowner")
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressLint("ModifierFactoryExtensionFunction")
|
@SuppressLint("ModifierFactoryExtensionFunction", "ComposableModifierFactory")
|
||||||
@Composable
|
@Composable
|
||||||
fun sections(bgColor:Color=MaterialTheme.colorScheme.primaryContainer):Modifier{
|
fun sections(bgColor:Color=MaterialTheme.colorScheme.primaryContainer):Modifier{
|
||||||
val backgroundColor = if(isSystemInDarkTheme()){bgColor.copy(0.4F)}else{bgColor.copy(0.6F)}
|
val backgroundColor = if(isSystemInDarkTheme()){bgColor.copy(0.4F)}else{bgColor.copy(0.6F)}
|
||||||
|
|||||||
Reference in New Issue
Block a user