simplify code of getting file

optimize animation
This commit is contained in:
BinTianqi
2024-05-11 15:34:10 +08:00
parent 8224211f3c
commit a8de0ed986
11 changed files with 82 additions and 59 deletions

View File

@@ -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()

View File

@@ -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()}
}
}

View File

@@ -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<Intent>
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
}
}
}

View File

@@ -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)
},

View File

@@ -9,16 +9,9 @@ var selectedPackage = ""
var applySelectedPackage = false
var selectedPermission = ""
var applySelectedPermission = false
lateinit var getCaCert: ActivityResultLauncher<Intent>
lateinit var createManagedProfile: ActivityResultLauncher<Intent>
lateinit var getApk: ActivityResultLauncher<Intent>
lateinit var getUserIcon: ActivityResultLauncher<Intent>
lateinit var addDeviceAdmin: ActivityResultLauncher<Intent>
var userIconUri: Uri? = null
var apkUri: Uri? = null
var caCert = byteArrayOf()
fun isDeviceOwner(dpm: DevicePolicyManager): Boolean {
return dpm.isDeviceOwnerApp("com.bintianqi.owndroid")
}

View File

@@ -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()

View File

@@ -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() }
},

View File

@@ -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<String>()
@@ -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()

View File

@@ -14,7 +14,7 @@ object Animations{
private val tween: FiniteAnimationSpec<IntOffset> = tween(450, easing = bezier)
val navHostEnterTransition: AnimatedContentTransitionScope<NavBackStackEntry>.() -> EnterTransition = {
fadeIn(tween(83, easing = LinearEasing)) +
fadeIn(tween(150, easing = LinearEasing)) +
slideIntoContainer(
animationSpec = tween,
towards = AnimatedContentTransitionScope.SlideDirection.End,

View File

@@ -43,7 +43,6 @@
<string name="copy_command">复制代码</string>
<string name="unknown_status">未知状态</string>
<string name="copy">复制</string>
<string name="file_too_large">文件太大了</string>
<string name="file_not_exist">文件不存在</string>
<string name="io_exception">IO异常</string>

View File

@@ -46,7 +46,6 @@
<string name="not_exist">Not exist</string>
<string name="unknown_status">Unknown status</string>
<string name="copy">Copy</string>
<string name="file_too_large">File too large</string>
<string name="file_not_exist">File not exist</string>
<string name="io_exception">IO Exception</string>