mirror of
https://github.com/wgtunnel/android.git
synced 2026-07-03 14:07:49 +02:00
Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 0008573b4d | |||
| 47b2deaf3d | |||
| 99f6b438ab | |||
| f047a1e1b8 |
@@ -8,7 +8,6 @@ import com.zaneschepke.wireguardautotunnel.data.repository.AppStateRepository
|
||||
import com.zaneschepke.wireguardautotunnel.data.repository.SettingsRepository
|
||||
import com.zaneschepke.wireguardautotunnel.module.ApplicationScope
|
||||
import com.zaneschepke.wireguardautotunnel.module.IoDispatcher
|
||||
import com.zaneschepke.wireguardautotunnel.module.MainDispatcher
|
||||
import com.zaneschepke.wireguardautotunnel.service.tunnel.BackendState
|
||||
import com.zaneschepke.wireguardautotunnel.service.tunnel.TunnelService
|
||||
import com.zaneschepke.wireguardautotunnel.util.LocaleUtil
|
||||
@@ -18,7 +17,6 @@ import dagger.hilt.android.HiltAndroidApp
|
||||
import kotlinx.coroutines.CoroutineDispatcher
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
|
||||
@@ -45,10 +43,6 @@ class WireGuardAutoTunnel : Application() {
|
||||
@IoDispatcher
|
||||
lateinit var ioDispatcher: CoroutineDispatcher
|
||||
|
||||
@Inject
|
||||
@MainDispatcher
|
||||
lateinit var mainDispatcher: CoroutineDispatcher
|
||||
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
instance = this
|
||||
@@ -65,19 +59,22 @@ class WireGuardAutoTunnel : Application() {
|
||||
} else {
|
||||
Timber.plant(ReleaseTree())
|
||||
}
|
||||
|
||||
applicationScope.launch {
|
||||
withContext(mainDispatcher) {
|
||||
if (appStateRepository.isLocalLogsEnabled() && !isRunningOnTv()) logReader.initialize()
|
||||
}
|
||||
if (!settingsRepository.getSettings().isKernelEnabled) {
|
||||
tunnelService.setBackendState(BackendState.SERVICE_ACTIVE, emptyList())
|
||||
}
|
||||
|
||||
appStateRepository.getLocale()?.let {
|
||||
LocaleUtil.changeLocale(it)
|
||||
}
|
||||
}
|
||||
if (!isRunningOnTv()) {
|
||||
applicationScope.launch(ioDispatcher) {
|
||||
if (appStateRepository.isLocalLogsEnabled()) {
|
||||
Timber.d("Starting logger")
|
||||
logReader.start()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onTerminate() {
|
||||
|
||||
@@ -2,9 +2,9 @@ package com.zaneschepke.wireguardautotunnel.module
|
||||
|
||||
import android.content.Context
|
||||
import com.zaneschepke.logcatter.LogReader
|
||||
import com.zaneschepke.logcatter.LogcatCollector
|
||||
import com.zaneschepke.wireguardautotunnel.service.notification.NotificationService
|
||||
import com.zaneschepke.wireguardautotunnel.service.notification.WireGuardNotification
|
||||
import com.zaneschepke.logcatter.LogcatReader
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.hilt.InstallIn
|
||||
@@ -27,7 +27,7 @@ class AppModule {
|
||||
@Singleton
|
||||
@Provides
|
||||
fun provideLogCollect(@ApplicationContext context: Context): LogReader {
|
||||
return LogcatReader.init(storageDir = context.filesDir.absolutePath)
|
||||
return LogcatCollector.init(context = context)
|
||||
}
|
||||
|
||||
@Singleton
|
||||
|
||||
+2
-2
@@ -86,13 +86,13 @@ constructor(
|
||||
|
||||
fun NotificationChannels.asBuilder(): NotificationCompat.Builder {
|
||||
return when (this) {
|
||||
NotificationChannels.AUTO_TUNNEL -> {
|
||||
NotificationChannels.VPN -> {
|
||||
NotificationCompat.Builder(
|
||||
context,
|
||||
context.getString(R.string.auto_tunnel_channel_id),
|
||||
)
|
||||
}
|
||||
NotificationChannels.VPN -> {
|
||||
NotificationChannels.AUTO_TUNNEL -> {
|
||||
NotificationCompat.Builder(
|
||||
context,
|
||||
context.getString(R.string.vpn_channel_id),
|
||||
|
||||
-2
@@ -85,7 +85,6 @@ constructor(
|
||||
|
||||
private suspend fun setState(tunnelConfig: TunnelConfig, tunnelState: TunnelState): Result<TunnelState> {
|
||||
return runCatching {
|
||||
updateTunnelConfig(tunnelConfig) //need so kernel can get tunnel name or it breaks kernel
|
||||
when (val backend = backend()) {
|
||||
is Backend -> backend.setState(this, tunnelState.toWgState(), TunnelConfig.configFromWgQuick(tunnelConfig.wgQuick)).let { TunnelState.from(it) }
|
||||
is org.amnezia.awg.backend.Backend -> {
|
||||
@@ -103,7 +102,6 @@ constructor(
|
||||
else -> throw NotImplementedError()
|
||||
}
|
||||
}.onFailure {
|
||||
//TODO add better error message and comms to user
|
||||
Timber.e(it)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -141,6 +141,7 @@ constructor(
|
||||
}
|
||||
|
||||
private suspend fun onLoggerStop() {
|
||||
logReader.stop()
|
||||
logReader.deleteAndClearLogs()
|
||||
}
|
||||
|
||||
@@ -237,7 +238,6 @@ constructor(
|
||||
if (!isKernelEnabled) {
|
||||
requestRoot().onSuccess {
|
||||
if (!isKernelSupported()) return@onSuccess SnackbarController.showMessage(StringValue.StringResource(R.string.kernel_not_supported))
|
||||
tunnelService.get().setBackendState(BackendState.INACTIVE, emptyList())
|
||||
appDataRepository.settings.save(
|
||||
copy(
|
||||
isKernelEnabled = true,
|
||||
|
||||
+41
-42
@@ -151,51 +151,50 @@ fun SettingsScreen(viewModel: SettingsViewModel = hiltViewModel(), appViewModel:
|
||||
),
|
||||
)
|
||||
if (!isRunningOnTv) {
|
||||
add(
|
||||
SelectionItem(
|
||||
Icons.Outlined.VpnLock,
|
||||
{
|
||||
ScaledSwitch(
|
||||
enabled = !(
|
||||
(
|
||||
uiState.settings.isTunnelOnWifiEnabled ||
|
||||
uiState.settings.isTunnelOnEthernetEnabled ||
|
||||
uiState.settings.isTunnelOnMobileDataEnabled
|
||||
) &&
|
||||
uiState.settings.isAutoTunnelEnabled
|
||||
),
|
||||
onClick = { appViewModel.onToggleAlwaysOnVPN() },
|
||||
checked = uiState.settings.isAlwaysOnVpnEnabled,
|
||||
)
|
||||
},
|
||||
title = {
|
||||
Text(
|
||||
stringResource(R.string.always_on_vpn_support),
|
||||
style = MaterialTheme.typography.bodyMedium.copy(MaterialTheme.colorScheme.onSurface),
|
||||
)
|
||||
},
|
||||
onClick = { appViewModel.onToggleAlwaysOnVPN() },
|
||||
addAll(
|
||||
listOf(
|
||||
SelectionItem(
|
||||
Icons.Outlined.VpnLock,
|
||||
{
|
||||
ScaledSwitch(
|
||||
enabled = !(
|
||||
(
|
||||
uiState.settings.isTunnelOnWifiEnabled ||
|
||||
uiState.settings.isTunnelOnEthernetEnabled ||
|
||||
uiState.settings.isTunnelOnMobileDataEnabled
|
||||
) &&
|
||||
uiState.settings.isAutoTunnelEnabled
|
||||
),
|
||||
onClick = { appViewModel.onToggleAlwaysOnVPN() },
|
||||
checked = uiState.settings.isAlwaysOnVpnEnabled,
|
||||
)
|
||||
},
|
||||
title = {
|
||||
Text(
|
||||
stringResource(R.string.always_on_vpn_support),
|
||||
style = MaterialTheme.typography.bodyMedium.copy(MaterialTheme.colorScheme.onSurface),
|
||||
)
|
||||
},
|
||||
onClick = { appViewModel.onToggleAlwaysOnVPN() },
|
||||
),
|
||||
SelectionItem(
|
||||
Icons.Outlined.VpnKeyOff,
|
||||
title = {
|
||||
Text(
|
||||
stringResource(R.string.kill_switch_options),
|
||||
style = MaterialTheme.typography.bodyMedium.copy(MaterialTheme.colorScheme.onSurface),
|
||||
)
|
||||
},
|
||||
onClick = {
|
||||
navController.navigate(Route.KillSwitch)
|
||||
},
|
||||
trailing = {
|
||||
ForwardButton { navController.navigate(Route.KillSwitch) }
|
||||
},
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
add(
|
||||
SelectionItem(
|
||||
Icons.Outlined.VpnKeyOff,
|
||||
title = {
|
||||
Text(
|
||||
stringResource(R.string.kill_switch_options),
|
||||
style = MaterialTheme.typography.bodyMedium.copy(MaterialTheme.colorScheme.onSurface),
|
||||
)
|
||||
},
|
||||
onClick = {
|
||||
navController.navigate(Route.KillSwitch)
|
||||
},
|
||||
trailing = {
|
||||
ForwardButton { navController.navigate(Route.KillSwitch) }
|
||||
},
|
||||
),
|
||||
)
|
||||
|
||||
add(
|
||||
SelectionItem(
|
||||
Icons.Outlined.Restore,
|
||||
|
||||
+16
-23
@@ -25,10 +25,7 @@ import com.zaneschepke.wireguardautotunnel.ui.common.button.surface.SelectionIte
|
||||
import com.zaneschepke.wireguardautotunnel.ui.common.button.surface.SurfaceSelectionGroupButton
|
||||
import com.zaneschepke.wireguardautotunnel.ui.common.navigation.TopNavBar
|
||||
import com.zaneschepke.wireguardautotunnel.ui.common.permission.vpn.withVpnPermission
|
||||
import com.zaneschepke.wireguardautotunnel.ui.common.snackbar.SnackbarController
|
||||
import com.zaneschepke.wireguardautotunnel.ui.screens.settings.components.ForwardButton
|
||||
import com.zaneschepke.wireguardautotunnel.util.StringValue
|
||||
import com.zaneschepke.wireguardautotunnel.util.extensions.isRunningOnTv
|
||||
import com.zaneschepke.wireguardautotunnel.util.extensions.launchVpnSettings
|
||||
import com.zaneschepke.wireguardautotunnel.util.extensions.scaledHeight
|
||||
import com.zaneschepke.wireguardautotunnel.util.extensions.scaledWidth
|
||||
@@ -41,8 +38,6 @@ fun KillSwitchScreen(uiState: AppUiState, appViewModel: AppViewModel) {
|
||||
|
||||
fun toggleVpnKillSwitch() {
|
||||
with(uiState.settings) {
|
||||
//TODO improve this error message
|
||||
if(isKernelEnabled) return SnackbarController.showMessage(StringValue.StringResource(R.string.kernel_not_supported))
|
||||
if (isVpnKillSwitchEnabled) {
|
||||
appViewModel.onToggleVpnKillSwitch(false)
|
||||
} else {
|
||||
@@ -71,25 +66,23 @@ fun KillSwitchScreen(uiState: AppUiState, appViewModel: AppViewModel) {
|
||||
.padding(top = 24.dp.scaledHeight())
|
||||
.padding(horizontal = 24.dp.scaledWidth()),
|
||||
) {
|
||||
if (!context.isRunningOnTv()) {
|
||||
SurfaceSelectionGroupButton(
|
||||
listOf(
|
||||
SelectionItem(
|
||||
Icons.Outlined.AdminPanelSettings,
|
||||
title = {
|
||||
Text(
|
||||
stringResource(R.string.native_kill_switch),
|
||||
style = MaterialTheme.typography.bodyMedium.copy(MaterialTheme.colorScheme.onSurface),
|
||||
)
|
||||
},
|
||||
onClick = { context.launchVpnSettings() },
|
||||
trailing = {
|
||||
ForwardButton { context.launchVpnSettings() }
|
||||
},
|
||||
),
|
||||
SurfaceSelectionGroupButton(
|
||||
listOf(
|
||||
SelectionItem(
|
||||
Icons.Outlined.AdminPanelSettings,
|
||||
title = {
|
||||
Text(
|
||||
stringResource(R.string.native_kill_switch),
|
||||
style = MaterialTheme.typography.bodyMedium.copy(MaterialTheme.colorScheme.onSurface),
|
||||
)
|
||||
},
|
||||
onClick = { context.launchVpnSettings() },
|
||||
trailing = {
|
||||
ForwardButton { context.launchVpnSettings() }
|
||||
},
|
||||
),
|
||||
)
|
||||
}
|
||||
),
|
||||
)
|
||||
SurfaceSelectionGroupButton(
|
||||
buildList {
|
||||
add(
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
object Constants {
|
||||
const val VERSION_NAME = "3.6.4"
|
||||
const val VERSION_NAME = "3.6.1"
|
||||
const val JVM_TARGET = "17"
|
||||
const val VERSION_CODE = 36400
|
||||
const val VERSION_CODE = 36100
|
||||
const val TARGET_SDK = 35
|
||||
const val MIN_SDK = 26
|
||||
const val APP_ID = "com.zaneschepke.wireguardautotunnel"
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
What's new:
|
||||
- Added VPN kill switch w/LAN bypass
|
||||
- Improved auto tunnel speed and reliability
|
||||
- Improved tile sync
|
||||
- Various bug fixes and improvements
|
||||
@@ -1,3 +0,0 @@
|
||||
What's new:
|
||||
- Fixed kernel mode toggle bug
|
||||
- Fixed notification crash bug
|
||||
@@ -49,7 +49,6 @@ dependencies {
|
||||
androidTestImplementation(libs.androidx.junit)
|
||||
androidTestImplementation(libs.androidx.espresso.core)
|
||||
|
||||
implementation(libs.androidx.lifecycle.process)
|
||||
// logging
|
||||
implementation(libs.timber)
|
||||
}
|
||||
|
||||
@@ -4,7 +4,8 @@ import com.zaneschepke.logcatter.model.LogMessage
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
interface LogReader {
|
||||
fun initialize(onLogMessage: ((message: LogMessage) -> Unit)? = null)
|
||||
suspend fun start(onLogMessage: ((message: LogMessage) -> Unit)? = null)
|
||||
fun stop()
|
||||
fun zipLogFiles(path: String)
|
||||
suspend fun deleteAndClearLogs()
|
||||
val bufferedLogs: Flow<LogMessage>
|
||||
|
||||
+85
-62
@@ -1,30 +1,26 @@
|
||||
package com.zaneschepke.logcatter
|
||||
|
||||
import androidx.lifecycle.DefaultLifecycleObserver
|
||||
import androidx.lifecycle.LifecycleOwner
|
||||
import androidx.lifecycle.ProcessLifecycleOwner
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import android.content.Context
|
||||
import com.zaneschepke.logcatter.model.LogMessage
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.channels.BufferOverflow
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
import kotlinx.coroutines.flow.asSharedFlow
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import timber.log.Timber
|
||||
import java.io.BufferedOutputStream
|
||||
import java.io.BufferedReader
|
||||
import java.io.File
|
||||
import java.io.FileNotFoundException
|
||||
import java.io.FileOutputStream
|
||||
import java.io.IOException
|
||||
import java.io.InputStreamReader
|
||||
import java.util.zip.ZipEntry
|
||||
import java.util.zip.ZipOutputStream
|
||||
|
||||
object LogcatReader {
|
||||
object LogcatCollector {
|
||||
|
||||
private const val MAX_FILE_SIZE = 2097152L // 2MB
|
||||
private const val MAX_FOLDER_SIZE = 10485760L // 10MB
|
||||
@@ -44,7 +40,7 @@ object LogcatReader {
|
||||
var logcatPath = ""
|
||||
}
|
||||
|
||||
fun init(maxFileSize: Long = MAX_FILE_SIZE, maxFolderSize: Long = MAX_FOLDER_SIZE, storageDir: String): LogReader {
|
||||
fun init(maxFileSize: Long = MAX_FILE_SIZE, maxFolderSize: Long = MAX_FOLDER_SIZE, context: Context): LogReader {
|
||||
if (maxFileSize > maxFolderSize) {
|
||||
throw IllegalStateException("maxFileSize must be less than maxFolderSize")
|
||||
}
|
||||
@@ -52,11 +48,13 @@ object LogcatReader {
|
||||
LogcatHelperInit.maxFileSize = maxFileSize
|
||||
LogcatHelperInit.maxFolderSize = maxFolderSize
|
||||
LogcatHelperInit.pID = android.os.Process.myPid()
|
||||
LogcatHelperInit.publicAppDirectory = storageDir
|
||||
LogcatHelperInit.logcatPath = LogcatHelperInit.publicAppDirectory + File.separator + "logs"
|
||||
val logDirectory = File(LogcatHelperInit.logcatPath)
|
||||
if (!logDirectory.exists()) {
|
||||
logDirectory.mkdir()
|
||||
context.getExternalFilesDir(null)?.let {
|
||||
LogcatHelperInit.publicAppDirectory = it.absolutePath
|
||||
LogcatHelperInit.logcatPath = LogcatHelperInit.publicAppDirectory + File.separator + "logs"
|
||||
val logDirectory = File(LogcatHelperInit.logcatPath)
|
||||
if (!logDirectory.exists()) {
|
||||
logDirectory.mkdir()
|
||||
}
|
||||
}
|
||||
return Logcat
|
||||
}
|
||||
@@ -64,12 +62,7 @@ object LogcatReader {
|
||||
|
||||
internal object Logcat : LogReader {
|
||||
|
||||
private lateinit var logcatReader: LogcatReader
|
||||
|
||||
override fun initialize(onLogMessage: ((message: LogMessage) -> Unit)?) {
|
||||
logcatReader = LogcatReader(LogcatHelperInit.pID.toString(), LogcatHelperInit.logcatPath, onLogMessage)
|
||||
ProcessLifecycleOwner.get().lifecycle.addObserver(logcatReader)
|
||||
}
|
||||
private var logcatReader: LogcatReader? = null
|
||||
|
||||
private fun obfuscator(log: String): String {
|
||||
return findKeyRegex.replace(log, "<crypto-key>").let { first ->
|
||||
@@ -79,10 +72,22 @@ object LogcatReader {
|
||||
}.let { last -> findIpv4AddressRegex.replace(last, "<ipv4-address>") }
|
||||
}
|
||||
|
||||
override suspend fun start(onLogMessage: ((message: LogMessage) -> Unit)?) {
|
||||
logcatReader ?: run {
|
||||
logcatReader = LogcatReader(LogcatHelperInit.pID.toString(), LogcatHelperInit.logcatPath, onLogMessage)
|
||||
}
|
||||
logcatReader?.run()
|
||||
}
|
||||
|
||||
override fun stop() {
|
||||
logcatReader?.stop()
|
||||
logcatReader = null
|
||||
}
|
||||
|
||||
override fun zipLogFiles(path: String) {
|
||||
logcatReader.cancel()
|
||||
logcatReader?.pause()
|
||||
zipAll(path)
|
||||
logcatReader.onCreate(ProcessLifecycleOwner.get())
|
||||
logcatReader?.resume()
|
||||
}
|
||||
|
||||
private fun zipAll(zipFilePath: String) {
|
||||
@@ -105,10 +110,10 @@ object LogcatReader {
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
override suspend fun deleteAndClearLogs() {
|
||||
withContext(ioDispatcher) {
|
||||
logcatReader.cancel()
|
||||
logcatReader?.pause()
|
||||
_bufferedLogs.resetReplayCache()
|
||||
logcatReader.deleteAllFiles()
|
||||
logcatReader.onCreate(ProcessLifecycleOwner.get())
|
||||
logcatReader?.deleteAllFiles()
|
||||
logcatReader?.resume()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -129,25 +134,57 @@ object LogcatReader {
|
||||
pID: String,
|
||||
private val logcatPath: String,
|
||||
private val callback: ((input: LogMessage) -> Unit)?,
|
||||
) : DefaultLifecycleObserver {
|
||||
) {
|
||||
private var logcatProc: Process? = null
|
||||
private var reader: BufferedReader? = null
|
||||
|
||||
private val command = "logcat -v epoch | grep \"($pID)\""
|
||||
private val clearLogCommand = "logcat -c"
|
||||
private var logJob: Job? = null
|
||||
@get:Synchronized @set:Synchronized
|
||||
private var paused = false
|
||||
|
||||
@get:Synchronized @set:Synchronized
|
||||
private var stopped = false
|
||||
private var command = ""
|
||||
private var clearLogCommand = ""
|
||||
private var outputStream: FileOutputStream? = null
|
||||
|
||||
override fun onCreate(owner: LifecycleOwner) {
|
||||
super.onCreate(owner)
|
||||
logJob = owner.lifecycleScope.launch(ioDispatcher) {
|
||||
init {
|
||||
try {
|
||||
outputStream = FileOutputStream(createLogFile(logcatPath))
|
||||
} catch (e: FileNotFoundException) {
|
||||
Timber.e(e)
|
||||
}
|
||||
|
||||
command = "logcat -v epoch | grep \"($pID)\""
|
||||
clearLogCommand = "logcat -c"
|
||||
}
|
||||
|
||||
fun pause() {
|
||||
paused = true
|
||||
}
|
||||
fun stop() {
|
||||
stopped = true
|
||||
}
|
||||
|
||||
fun resume() {
|
||||
paused = false
|
||||
}
|
||||
|
||||
fun clear() {
|
||||
Runtime.getRuntime().exec(clearLogCommand)
|
||||
}
|
||||
|
||||
suspend fun run() {
|
||||
withContext(ioDispatcher) {
|
||||
paused = false
|
||||
stopped = false
|
||||
if (outputStream == null) return@withContext
|
||||
try {
|
||||
if (outputStream == null) outputStream = createNewLogFileStream()
|
||||
clear()
|
||||
logcatProc = Runtime.getRuntime().exec(command)
|
||||
reader = BufferedReader(InputStreamReader(logcatProc!!.inputStream), 1024)
|
||||
var line: String? = null
|
||||
while (true) {
|
||||
var line: String?
|
||||
while (!stopped) {
|
||||
if (paused) continue
|
||||
line = reader?.readLine()
|
||||
if (line.isNullOrEmpty()) continue
|
||||
outputStream?.let {
|
||||
@@ -159,8 +196,8 @@ object LogcatReader {
|
||||
deleteOldestFile()
|
||||
}
|
||||
line.let { text ->
|
||||
val sanitized = obfuscator(text)
|
||||
it.write((sanitized + System.lineSeparator()).toByteArray())
|
||||
val obfuscated = obfuscator(text)
|
||||
it.write((obfuscated + System.lineSeparator()).toByteArray())
|
||||
try {
|
||||
val logMessage = LogMessage.from(text)
|
||||
_bufferedLogs.tryEmit(logMessage)
|
||||
@@ -177,34 +214,19 @@ object LogcatReader {
|
||||
} catch (e: IOException) {
|
||||
Timber.e(e)
|
||||
} finally {
|
||||
reset()
|
||||
logcatProc?.destroy()
|
||||
logcatProc = null
|
||||
|
||||
try {
|
||||
reader?.close()
|
||||
outputStream?.close()
|
||||
reader = null
|
||||
outputStream = null
|
||||
} catch (e: IOException) {
|
||||
Timber.e(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
logJob?.invokeOnCompletion {
|
||||
reset()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDestroy(owner: LifecycleOwner) {
|
||||
super.onDestroy(owner)
|
||||
logJob?.cancel()
|
||||
}
|
||||
|
||||
fun cancel() {
|
||||
logJob?.cancel()
|
||||
}
|
||||
|
||||
private fun reset() {
|
||||
logcatProc?.destroy()
|
||||
logcatProc = null
|
||||
reader?.close()
|
||||
outputStream?.close()
|
||||
reader = null
|
||||
outputStream = null
|
||||
}
|
||||
|
||||
fun clear() {
|
||||
Runtime.getRuntime().exec(clearLogCommand)
|
||||
}
|
||||
|
||||
private fun getFolderSize(path: String): Long {
|
||||
@@ -244,6 +266,7 @@ object LogcatReader {
|
||||
directory.listFiles()?.toMutableList()?.run {
|
||||
this.forEach { it.delete() }
|
||||
}
|
||||
outputStream = createNewLogFileStream()
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -1 +1 @@
|
||||
13
|
||||
12
|
||||
Reference in New Issue
Block a user