diff --git a/app/src/main/java/com/bintianqi/owndroid/MainActivity.kt b/app/src/main/java/com/bintianqi/owndroid/MainActivity.kt index 3415c55..48fdc4e 100644 --- a/app/src/main/java/com/bintianqi/owndroid/MainActivity.kt +++ b/app/src/main/java/com/bintianqi/owndroid/MainActivity.kt @@ -1,6 +1,5 @@ package com.bintianqi.owndroid -import android.app.Activity import android.app.admin.DevicePolicyManager import android.content.ComponentName import android.content.Context @@ -10,7 +9,6 @@ import android.widget.Toast import androidx.activity.ComponentActivity import androidx.activity.compose.setContent import androidx.activity.enableEdgeToEdge -import androidx.activity.result.contract.ActivityResultContracts import androidx.compose.foundation.background import androidx.compose.foundation.clickable import androidx.compose.foundation.gestures.detectTapGestures @@ -49,28 +47,11 @@ import kotlinx.coroutines.delay var backToHome = false @ExperimentalMaterial3Api class MainActivity : ComponentActivity() { - private fun registerActivityResult(){ - getUserIcon = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { userIconUri = it.data?.data } - getApk = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { apkUri = it.data?.data } - getCaCert = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { - uriToStream(applicationContext,it.data?.data){stream-> - caCert = stream.readBytes() - if(caCert.size>5000){ Toast.makeText(applicationContext, R.string.file_too_large, Toast.LENGTH_SHORT).show(); caCert = byteArrayOf() } - } - } - createManagedProfile = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {} - addDeviceAdmin = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { - val myDpm = applicationContext.getSystemService(DEVICE_POLICY_SERVICE) as DevicePolicyManager - if(myDpm.isAdminActive(ComponentName(applicationContext, Receiver::class.java))){ - backToHome = true - } - } - } override fun onCreate(savedInstanceState: Bundle?) { enableEdgeToEdge() WindowCompat.setDecorFitsSystemWindows(window, false) super.onCreate(savedInstanceState) - registerActivityResult() + registerActivityResult(this) setContent { OwnDroidTheme { MyScaffold() diff --git a/app/src/main/java/com/bintianqi/owndroid/Receiver.kt b/app/src/main/java/com/bintianqi/owndroid/Receiver.kt index f3b7084..8e50434 100644 --- a/app/src/main/java/com/bintianqi/owndroid/Receiver.kt +++ b/app/src/main/java/com/bintianqi/owndroid/Receiver.kt @@ -51,6 +51,7 @@ class PackageInstallerReceiver:BroadcastReceiver(){ else->R.string.unknown } Log.e("OwnDroid", intent.getIntExtra(EXTRA_STATUS,999).toString()) - if(toastText!=999){Toast.makeText(context, toastText, Toast.LENGTH_SHORT).show()} + val text = context.getString(R.string.app_installer_status) + context.getString(toastText) + if(toastText!=999){Toast.makeText(context, text, Toast.LENGTH_SHORT).show()} } } diff --git a/app/src/main/java/com/bintianqi/owndroid/Utils.kt b/app/src/main/java/com/bintianqi/owndroid/Utils.kt index f3ce70d..702e895 100644 --- a/app/src/main/java/com/bintianqi/owndroid/Utils.kt +++ b/app/src/main/java/com/bintianqi/owndroid/Utils.kt @@ -1,14 +1,20 @@ package com.bintianqi.owndroid -import android.content.ClipData -import android.content.ClipboardManager -import android.content.Context +import android.app.admin.DevicePolicyManager +import android.content.* import android.net.Uri import android.widget.Toast +import androidx.activity.ComponentActivity +import androidx.activity.result.ActivityResultLauncher +import androidx.activity.result.contract.ActivityResultContracts +import com.bintianqi.owndroid.dpm.* import java.io.FileNotFoundException import java.io.IOException import java.io.InputStream +lateinit var getFile: ActivityResultLauncher +var fileUri: Uri? = null + fun uriToStream( context: Context, uri: Uri?, @@ -54,3 +60,23 @@ fun writeClipBoard(context: Context, string: String):Boolean{ } return true } + + +fun registerActivityResult(context: ComponentActivity){ + getFile = context.registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {activityResult -> + activityResult.data.let { + if(it==null){ + Toast.makeText(context.applicationContext, R.string.file_not_exist, Toast.LENGTH_SHORT).show() + }else{ + fileUri = it.data + } + } + } + createManagedProfile = context.registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {} + addDeviceAdmin = context.registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { + val myDpm = context.applicationContext.getSystemService(ComponentActivity.DEVICE_POLICY_SERVICE) as DevicePolicyManager + if(myDpm.isAdminActive(ComponentName(context.applicationContext, Receiver::class.java))){ + backToHome = true + } + } +} diff --git a/app/src/main/java/com/bintianqi/owndroid/dpm/ApplicationManage.kt b/app/src/main/java/com/bintianqi/owndroid/dpm/ApplicationManage.kt index 5307148..5795860 100644 --- a/app/src/main/java/com/bintianqi/owndroid/dpm/ApplicationManage.kt +++ b/app/src/main/java/com/bintianqi/owndroid/dpm/ApplicationManage.kt @@ -229,6 +229,9 @@ private fun Home(navCtrl:NavHostController, pkgName: String){ SubPageItem(R.string.set_default_dialer,"",R.drawable.call_fill0){navCtrl.navigate("DefaultDialer")} } Spacer(Modifier.padding(vertical = 30.dp)) + LaunchedEffect(Unit) { + fileUri = null + } } } @@ -810,19 +813,19 @@ private fun InstallApp(){ val installApkIntent = Intent(Intent.ACTION_GET_CONTENT) installApkIntent.setType("application/vnd.android.package-archive") installApkIntent.addCategory(Intent.CATEGORY_OPENABLE) - getApk.launch(installApkIntent) + getFile.launch(installApkIntent) }, modifier = Modifier.fillMaxWidth() ) { Text(stringResource(R.string.select_apk)) } var selected by remember{mutableStateOf(false)} - LaunchedEffect(selected){while(true){ delay(800); selected = apkUri!=null}} + LaunchedEffect(selected){while(true){ delay(800); selected = fileUri!=null}} AnimatedVisibility(selected) { Spacer(Modifier.padding(vertical = 3.dp)) Column(modifier = Modifier.fillMaxWidth()){ Button( - onClick = { uriToStream(myContext, apkUri){stream -> installPackage(myContext,stream)} }, + onClick = { uriToStream(myContext, fileUri){stream -> installPackage(myContext,stream)} }, modifier = Modifier.fillMaxWidth() ) { Text(stringResource(R.string.silent_install)) @@ -830,7 +833,7 @@ private fun InstallApp(){ Button( onClick = { val intent = Intent(Intent.ACTION_INSTALL_PACKAGE) - intent.setData(apkUri) + intent.setData(fileUri) intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) myContext.startActivity(intent) }, diff --git a/app/src/main/java/com/bintianqi/owndroid/dpm/DPM.kt b/app/src/main/java/com/bintianqi/owndroid/dpm/DPM.kt index 86228b6..01179a6 100644 --- a/app/src/main/java/com/bintianqi/owndroid/dpm/DPM.kt +++ b/app/src/main/java/com/bintianqi/owndroid/dpm/DPM.kt @@ -9,16 +9,9 @@ var selectedPackage = "" var applySelectedPackage = false var selectedPermission = "" var applySelectedPermission = false -lateinit var getCaCert: ActivityResultLauncher lateinit var createManagedProfile: ActivityResultLauncher -lateinit var getApk: ActivityResultLauncher -lateinit var getUserIcon: ActivityResultLauncher lateinit var addDeviceAdmin: ActivityResultLauncher -var userIconUri: Uri? = null -var apkUri: Uri? = null -var caCert = byteArrayOf() - fun isDeviceOwner(dpm: DevicePolicyManager): Boolean { return dpm.isDeviceOwnerApp("com.bintianqi.owndroid") } diff --git a/app/src/main/java/com/bintianqi/owndroid/dpm/Permissions.kt b/app/src/main/java/com/bintianqi/owndroid/dpm/Permissions.kt index ee9e97b..af2764b 100644 --- a/app/src/main/java/com/bintianqi/owndroid/dpm/Permissions.kt +++ b/app/src/main/java/com/bintianqi/owndroid/dpm/Permissions.kt @@ -321,8 +321,7 @@ fun DeviceInfo(){ val encryptionStatus = mutableMapOf( DevicePolicyManager.ENCRYPTION_STATUS_INACTIVE to stringResource(R.string.es_inactive), DevicePolicyManager.ENCRYPTION_STATUS_ACTIVE to stringResource(R.string.es_active), - DevicePolicyManager.ENCRYPTION_STATUS_UNSUPPORTED to stringResource(R.string.es_unsupported), - DevicePolicyManager.ENCRYPTION_STATUS_ACTIVATING to stringResource(R.string.unknown) + DevicePolicyManager.ENCRYPTION_STATUS_UNSUPPORTED to stringResource(R.string.es_unsupported) ) if(VERSION.SDK_INT>=23){ encryptionStatus[DevicePolicyManager.ENCRYPTION_STATUS_ACTIVE_DEFAULT_KEY] = stringResource(R.string.es_active_default_key) } if(VERSION.SDK_INT>=24){ encryptionStatus[DevicePolicyManager.ENCRYPTION_STATUS_ACTIVE_PER_USER] = stringResource(R.string.es_active_per_user) } @@ -428,6 +427,8 @@ private fun SupportMsg(){ focusMgr.clearFocus() myDpm.setShortSupportMessage(myComponent, shortMsg) myDpm.setLongSupportMessage(myComponent, longMsg) + shortMsg = myDpm.getShortSupportMessage(myComponent)?.toString() ?: "" + longMsg = myDpm.getLongSupportMessage(myComponent)?.toString() ?: "" Toast.makeText(myContext, R.string.success, Toast.LENGTH_SHORT).show() }, modifier = Modifier.fillMaxWidth() @@ -440,6 +441,8 @@ private fun SupportMsg(){ focusMgr.clearFocus() myDpm.setShortSupportMessage(myComponent, null) myDpm.setLongSupportMessage(myComponent, null) + shortMsg = myDpm.getShortSupportMessage(myComponent)?.toString() ?: "" + longMsg = myDpm.getLongSupportMessage(myComponent)?.toString() ?: "" Toast.makeText(myContext, R.string.success, Toast.LENGTH_SHORT).show() }, modifier = Modifier.fillMaxWidth() diff --git a/app/src/main/java/com/bintianqi/owndroid/dpm/SystemManager.kt b/app/src/main/java/com/bintianqi/owndroid/dpm/SystemManager.kt index d4c831e..3ebf4d5 100644 --- a/app/src/main/java/com/bintianqi/owndroid/dpm/SystemManager.kt +++ b/app/src/main/java/com/bintianqi/owndroid/dpm/SystemManager.kt @@ -41,9 +41,8 @@ import androidx.navigation.compose.NavHost import androidx.navigation.compose.composable import androidx.navigation.compose.currentBackStackEntryAsState import androidx.navigation.compose.rememberNavController +import com.bintianqi.owndroid.* import com.bintianqi.owndroid.R -import com.bintianqi.owndroid.Receiver -import com.bintianqi.owndroid.toText import com.bintianqi.owndroid.ui.* import com.bintianqi.owndroid.ui.theme.bgColor import kotlinx.coroutines.delay @@ -152,7 +151,7 @@ private fun Home(navCtrl: NavHostController,scrollState: ScrollState){ } SubPageItem(R.string.wipe_data,"",R.drawable.warning_fill0){navCtrl.navigate("WipeData")} Spacer(Modifier.padding(vertical = 30.dp)) - LaunchedEffect(Unit){caCert =byteArrayOf()} + LaunchedEffect(Unit){fileUri=null} } } @@ -596,34 +595,52 @@ private fun CaCert(){ val myDpm = myContext.getSystemService(ComponentActivity.DEVICE_POLICY_SERVICE) as DevicePolicyManager val myComponent = ComponentName(myContext,Receiver::class.java) var exist by remember{mutableStateOf(false)} - var isEmpty by remember{mutableStateOf(true)} + var uriPath by remember{mutableStateOf("")} + var caCertByteArray = byteArrayOf() val refresh = { - isEmpty = caCert.isEmpty() - exist = if(!isEmpty){ myDpm.hasCaCertInstalled(myComponent, caCert) }else{ false } + if(uriPath!=fileUri?.path){ + if(caCertByteArray.isEmpty()){ + uriToStream(myContext, fileUri){ + val array = it.readBytes() + caCertByteArray = if(array.size<10000){ + array + }else{ + byteArrayOf() + } + } + exist = myDpm.hasCaCertInstalled(myComponent, caCertByteArray) + } + } } - LaunchedEffect(exist){ while(true){ refresh();delay(600) } } + LaunchedEffect(exist){ while(true){ refresh();delay(500) } } Column(modifier = Modifier.fillMaxSize().padding(horizontal = 8.dp).verticalScroll(rememberScrollState())){ Spacer(Modifier.padding(vertical = 10.dp)) Text(text = stringResource(R.string.ca_cert), style = typography.headlineLarge) Spacer(Modifier.padding(vertical = 5.dp)) - Text(text = if(isEmpty){stringResource(R.string.please_select_ca_cert)}else{stringResource(R.string.cacert_installed, exist)}, modifier = Modifier.animateContentSize()) + AnimatedVisibility(uriPath!="") { + Text(text = uriPath) + } + Text( + text = if(uriPath==""){stringResource(R.string.please_select_ca_cert)}else{stringResource(R.string.cacert_installed, exist)}, + modifier = Modifier.animateContentSize() + ) Spacer(Modifier.padding(vertical = 5.dp)) Button( onClick = { val caCertIntent = Intent(Intent.ACTION_GET_CONTENT) caCertIntent.setType("*/*") caCertIntent.addCategory(Intent.CATEGORY_OPENABLE) - getCaCert.launch(caCertIntent) + getFile.launch(caCertIntent) }, modifier = Modifier.fillMaxWidth() ) { Text(stringResource(R.string.select_ca_cert)) } - AnimatedVisibility(!isEmpty) { + AnimatedVisibility(uriPath!="") { Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween){ Button( onClick = { - val result = myDpm.installCaCert(myComponent, caCert) + val result = myDpm.installCaCert(myComponent, caCertByteArray) Toast.makeText(myContext, if(result){R.string.success}else{R.string.fail}, Toast.LENGTH_SHORT).show() refresh() }, @@ -634,8 +651,8 @@ private fun CaCert(){ Button( onClick = { if(exist){ - myDpm.uninstallCaCert(myComponent, caCert) - exist = myDpm.hasCaCertInstalled(myComponent, caCert) + myDpm.uninstallCaCert(myComponent, caCertByteArray) + exist = myDpm.hasCaCertInstalled(myComponent, caCertByteArray) Toast.makeText(myContext, if(exist){R.string.fail}else{R.string.success}, Toast.LENGTH_SHORT).show() }else{ Toast.makeText(myContext, R.string.not_exist, Toast.LENGTH_SHORT).show() } }, diff --git a/app/src/main/java/com/bintianqi/owndroid/dpm/UserManager.kt b/app/src/main/java/com/bintianqi/owndroid/dpm/UserManager.kt index d793f57..78e731a 100644 --- a/app/src/main/java/com/bintianqi/owndroid/dpm/UserManager.kt +++ b/app/src/main/java/com/bintianqi/owndroid/dpm/UserManager.kt @@ -40,12 +40,10 @@ import androidx.navigation.compose.NavHost import androidx.navigation.compose.composable import androidx.navigation.compose.currentBackStackEntryAsState import androidx.navigation.compose.rememberNavController +import com.bintianqi.owndroid.* import com.bintianqi.owndroid.R -import com.bintianqi.owndroid.Receiver -import com.bintianqi.owndroid.toText import com.bintianqi.owndroid.ui.* import com.bintianqi.owndroid.ui.theme.bgColor -import com.bintianqi.owndroid.uriToStream import kotlinx.coroutines.delay var affiliationID = mutableSetOf() @@ -122,6 +120,9 @@ private fun Home(navCtrl: NavHostController,scrollState: ScrollState){ SubPageItem(R.string.affiliation_id,"",R.drawable.id_card_fill0){navCtrl.navigate("AffiliationID")} } Spacer(Modifier.padding(vertical = 30.dp)) + LaunchedEffect(Unit) { + fileUri = null + } } } @@ -509,17 +510,17 @@ private fun UserIcon(){ val intent = Intent(if(getContent){Intent.ACTION_GET_CONTENT}else{Intent.ACTION_PICK}) if(getContent){intent.addCategory(Intent.CATEGORY_OPENABLE)} intent.setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, "image/*") - getUserIcon.launch(intent) + getFile.launch(intent) }, modifier = Modifier.fillMaxWidth() ) { Text(stringResource(R.string.select_picture)) } - LaunchedEffect(Unit){ delay(600); canApply = userIconUri!=null } + LaunchedEffect(Unit){ delay(600); canApply = fileUri!=null } AnimatedVisibility(canApply) { Button( onClick = { - uriToStream(myContext, userIconUri){stream -> + uriToStream(myContext, fileUri){stream -> val bitmap = BitmapFactory.decodeStream(stream) myDpm.setUserIcon(myComponent,bitmap) Toast.makeText(myContext, R.string.success, Toast.LENGTH_SHORT).show() diff --git a/app/src/main/java/com/bintianqi/owndroid/ui/Animations.kt b/app/src/main/java/com/bintianqi/owndroid/ui/Animations.kt index d6fbe40..f7a9079 100644 --- a/app/src/main/java/com/bintianqi/owndroid/ui/Animations.kt +++ b/app/src/main/java/com/bintianqi/owndroid/ui/Animations.kt @@ -14,7 +14,7 @@ object Animations{ private val tween: FiniteAnimationSpec = tween(450, easing = bezier) val navHostEnterTransition: AnimatedContentTransitionScope.() -> EnterTransition = { - fadeIn(tween(83, easing = LinearEasing)) + + fadeIn(tween(150, easing = LinearEasing)) + slideIntoContainer( animationSpec = tween, towards = AnimatedContentTransitionScope.SlideDirection.End, diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index e4f0538..f2af943 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -43,7 +43,6 @@ 复制代码 未知状态 复制 - 文件太大了 文件不存在 IO异常 diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 9d6f5c3..86e0bb8 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -46,7 +46,6 @@ Not exist Unknown status Copy - File too large File not exist IO Exception