Added a feature to save logs to local storage (#1741)

- Added export logs to local storage
[1664](https://github.com/tiann/KernelSU/issues/1664)

---------

Co-authored-by: weishu <twsxtd@gmail.com>
This commit is contained in:
Alex
2024-05-23 08:16:44 +05:30
committed by GitHub
parent 4e3f03ae96
commit d6860160e8
46 changed files with 203 additions and 28 deletions

View File

@@ -1,11 +1,17 @@
package me.weishu.kernelsu.ui.screen
import android.content.ContentResolver
import android.content.Context
import android.content.Intent
import android.database.Cursor
import android.net.Uri
import android.provider.OpenableColumns
import android.util.Log
import android.widget.Toast
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
@@ -20,25 +26,34 @@ import androidx.compose.material.icons.filled.DeleteForever
import androidx.compose.material.icons.filled.DeveloperMode
import androidx.compose.material.icons.filled.Fence
import androidx.compose.material.icons.filled.RemoveModerator
import androidx.compose.material.icons.filled.Save
import androidx.compose.material.icons.filled.Share
import androidx.compose.material.icons.filled.Update
import androidx.compose.material3.BottomSheetScaffold
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.ListItem
import androidx.compose.material3.ModalBottomSheet
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.LineHeightStyle
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.core.content.FileProvider
import com.maxkeppeker.sheets.core.models.base.Header
import com.maxkeppeker.sheets.core.models.base.IconSource
@@ -65,12 +80,16 @@ import me.weishu.kernelsu.ui.component.rememberLoadingDialog
import me.weishu.kernelsu.ui.screen.destinations.AppProfileTemplateScreenDestination
import me.weishu.kernelsu.ui.screen.destinations.FlashScreenDestination
import me.weishu.kernelsu.ui.util.getBugreportFile
import me.weishu.kernelsu.ui.util.getFileNameFromUri
import me.weishu.kernelsu.ui.util.shrinkModules
import java.time.LocalDateTime
import java.time.format.DateTimeFormatter
/**
* @author weishu
* @date 2023/1/1.
*/
@OptIn(ExperimentalMaterial3Api::class)
@Destination
@Composable
fun SettingScreen(navigator: DestinationsNavigator) {
@@ -151,6 +170,7 @@ fun SettingScreen(navigator: DestinationsNavigator) {
enableWebDebugging = it
}
var showBottomsheet by remember { mutableStateOf(false) }
ListItem(
leadingContent = {
@@ -161,34 +181,127 @@ fun SettingScreen(navigator: DestinationsNavigator) {
},
headlineContent = { Text(stringResource(id = R.string.send_log)) },
modifier = Modifier.clickable {
scope.launch {
val bugreport = loadingDialog.withLoading {
withContext(Dispatchers.IO) {
getBugreportFile(context)
}
}
val uri: Uri =
FileProvider.getUriForFile(
context,
"${BuildConfig.APPLICATION_ID}.fileprovider",
bugreport
)
val shareIntent = Intent(Intent.ACTION_SEND)
shareIntent.putExtra(Intent.EXTRA_STREAM, uri)
shareIntent.setDataAndType(uri, "application/zip")
shareIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
context.startActivity(
Intent.createChooser(
shareIntent,
context.getString(R.string.send_log)
)
)
}
showBottomsheet = true
}
)
if (showBottomsheet){
ModalBottomSheet(
onDismissRequest = { showBottomsheet = false },
content = {
Row(modifier = Modifier.padding(10.dp)
.align(Alignment.CenterHorizontally)
) {
Box{
Column(
modifier = Modifier.padding(16.dp)
.clickable {
scope.launch {
val bugreport = loadingDialog.withLoading {
withContext(Dispatchers.IO) {
getBugreportFile(context)
}
}
val uri: Uri =
FileProvider.getUriForFile(
context,
"${BuildConfig.APPLICATION_ID}.fileprovider",
bugreport
)
val filename = getFileNameFromUri(context , uri)
val savefile = Intent(Intent.ACTION_CREATE_DOCUMENT).apply {
addCategory(Intent.CATEGORY_OPENABLE)
type = "application/zip"
putExtra(Intent.EXTRA_STREAM, uri)
putExtra(Intent.EXTRA_TITLE, filename)
flags = Intent.FLAG_GRANT_READ_URI_PERMISSION
}
context.startActivity(
Intent.createChooser(
savefile,
context.getString(R.string.save_log)
)
)
}
}
) {
Icon(
Icons.Filled.Save,
contentDescription = null,
modifier = Modifier.align(Alignment.CenterHorizontally)
)
Text(
text = stringResource(id = R.string.save_log),
modifier = Modifier.padding(top = 16.dp),
textAlign = TextAlign.Center.also {
LineHeightStyle(
alignment = LineHeightStyle.Alignment.Center,
trim = LineHeightStyle.Trim.None
)
}
)
}
}
Box{
Column(
modifier = Modifier.padding(16.dp)
.clickable {
scope.launch {
val bugreport = loadingDialog.withLoading {
withContext(Dispatchers.IO) {
getBugreportFile(context)
}
}
val uri: Uri =
FileProvider.getUriForFile(
context,
"${BuildConfig.APPLICATION_ID}.fileprovider",
bugreport
)
val shareIntent = Intent(Intent.ACTION_SEND)
shareIntent.putExtra(Intent.EXTRA_STREAM, uri)
shareIntent.setDataAndType(uri, "application/zip")
shareIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
context.startActivity(
Intent.createChooser(
shareIntent,
context.getString(R.string.send_log)
)
)
}
}
) {
Icon(
Icons.Filled.Share,
contentDescription = null,
modifier = Modifier.align(Alignment.CenterHorizontally)
)
Text(
text = stringResource(id = R.string.send_log),
modifier = Modifier.padding(top = 16.dp),
textAlign = TextAlign.Center.also {
LineHeightStyle(
alignment = LineHeightStyle.Alignment.Center,
trim = LineHeightStyle.Trim.None
)
}
)
}
}
}
}
)
}
val shrink = stringResource(id = R.string.shrink_sparse_image)
val shrinkMessage = stringResource(id = R.string.shrink_sparse_image_message)
@@ -237,7 +350,6 @@ fun SettingScreen(navigator: DestinationsNavigator) {
}
}
}
@Composable
fun UninstallItem(
navigator: DestinationsNavigator,

View File

@@ -1,10 +1,14 @@
package me.weishu.kernelsu.ui.util
import android.content.ContentResolver
import android.content.Context
import android.database.Cursor
import android.net.Uri
import android.os.Build
import android.os.Environment
import android.os.Parcelable
import android.os.SystemClock
import android.provider.OpenableColumns
import android.util.Log
import com.topjohnwu.superuser.CallbackList
import com.topjohnwu.superuser.Shell
@@ -48,6 +52,18 @@ inline fun <T> withNewRootShell(
return createRootShell(globalMnt).use(block)
}
fun getFileNameFromUri(context: Context, uri: Uri): String? {
var fileName: String? = null
val contentResolver: ContentResolver = context.contentResolver
val cursor: Cursor? = contentResolver.query(uri, null, null, null, null)
cursor?.use {
if (it.moveToFirst()) {
fileName = it.getString(it.getColumnIndexOrThrow(OpenableColumns.DISPLAY_NAME))
}
}
return fileName
}
fun createRootShell(globalMnt: Boolean = false): Shell {
Shell.enableVerboseLogging = BuildConfig.DEBUG
val builder = Shell.Builder.create()

View File

@@ -1,12 +1,16 @@
package me.weishu.kernelsu.ui.util
import android.content.ContentResolver
import android.content.Context
import android.net.Uri
import android.os.Build
import android.os.ParcelFileDescriptor
import android.system.Os
import com.topjohnwu.superuser.ShellUtils
import me.weishu.kernelsu.Natives
import me.weishu.kernelsu.ui.screen.getManagerVersion
import java.io.File
import java.io.FileOutputStream
import java.io.FileWriter
import java.io.PrintWriter
import java.time.LocalDateTime
@@ -108,3 +112,4 @@ fun getBugreportFile(context: Context): File {
return targetFile
}