Skip to content

Commit b1783b6

Browse files
committed
Implement configurable debug logging and improve log maintenance
- Add a toggle in Settings to enable/disable debug logging (disabled by default) - Refactor `LogUtils` to honor the logging preference and perform log purging asynchronously - Update log rotation to purge entries older than 7 days from both audit and app log files - Reduce log verbosity in `AppLockAccessibilityService` - Bump version to 2.2.2 (code 222) and update build tools to 37.0.0 rc1 - Update Kotlin compiler arguments to version 2.2
1 parent 20af7bd commit b1783b6

File tree

16 files changed

+126
-39
lines changed

16 files changed

+126
-39
lines changed

.idea/appInsightsSettings.xml

Lines changed: 14 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.idea/deploymentTargetSelector.xml

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.idea/kotlinc.xml

Lines changed: 4 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

app/build.gradle.kts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,17 @@ plugins {
88

99
android {
1010
namespace = "dev.pranav.applock"
11+
compileSdk = 36
1112
// Builds with Canary Preview won't work on non-Canary devices
1213
// compileSdkPreview = "CANARY"
13-
compileSdk = 36
1414

1515
defaultConfig {
1616
applicationId = "dev.pranav.applock"
1717
minSdk = 26
1818
targetSdk = 36
1919
// targetSdkPreview = "CANARY"
20-
versionCode = 221
21-
versionName = "2.2.1"
20+
versionCode = 222
21+
versionName = "2.2.2"
2222

2323
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
2424
}
@@ -50,10 +50,11 @@ android {
5050
includeInApk = false
5151
includeInBundle = false
5252
}
53+
buildToolsVersion = "37.0.0 rc1"
54+
compileSdkMinor = 1
5355
kotlin.compilerOptions {
5456
jvmTarget.set(JvmTarget.JVM_17)
5557
}
56-
ndkVersion = "29.0.13846066 rc3"
5758
}
5859

5960
dependencies {

app/release/app-release.apk

75 KB
Binary file not shown.

app/release/output-metadata.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@
1111
"type": "SINGLE",
1212
"filters": [],
1313
"attributes": [],
14-
"versionCode": 8,
15-
"versionName": "1.5.1",
14+
"versionCode": 221,
15+
"versionName": "2.2.1",
1616
"outputFile": "app-release.apk"
1717
}
1818
],

app/src/main/java/dev/pranav/applock/AppLockApplication.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ class AppLockApplication : Application() {
2525
initializeComponents()
2626

2727
LogUtils.initialize(this)
28+
LogUtils.setLoggingEnabled(appLockRepository.isLoggingEnabled())
2829
// Purge logs older than 3 days on every app start (run in background to avoid ANR)
2930
thread(start = true, name = "LogPurge") {
3031
LogUtils.purgeOldLogs()

app/src/main/java/dev/pranav/applock/core/utils/LogUtils.kt

Lines changed: 61 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -9,19 +9,27 @@ import androidx.core.content.FileProvider
99
import java.io.File
1010
import java.time.Instant
1111
import java.time.temporal.ChronoUnit
12+
import kotlin.concurrent.thread
1213

1314
@SuppressLint("StaticFieldLeak")
1415
object LogUtils {
1516
private const val TAG = "LogUtils"
1617
private const val FILE_NAME = "app_logs.txt"
1718
private const val SECURITY_LOGS = "audit_log.txt"
1819
private lateinit var context: Context
20+
private var loggingEnabled = false
1921

2022
fun initialize(application: Context) {
2123
context = application
2224
}
2325

26+
fun setLoggingEnabled(enabled: Boolean) {
27+
loggingEnabled = enabled
28+
}
29+
2430
fun d(tag: String, message: String) {
31+
if (!loggingEnabled) return
32+
2533
val file = File(context.filesDir, SECURITY_LOGS)
2634

2735
if (!file.exists()) {
@@ -103,48 +111,73 @@ object LogUtils {
103111
}
104112

105113
/**
106-
* Purge log entries older than 3 days from the audit log file.
114+
* Purge log entries older than 3 days from both audit and app log files.
107115
* This prevents logs from growing indefinitely.
116+
* Runs asynchronously to avoid blocking the main thread.
108117
*/
109118
fun purgeOldLogs() {
119+
thread(name = "LogPurgeThread", isDaemon = true) {
120+
purgeOldLogsFromFile(File(context.filesDir, SECURITY_LOGS), "audit")
121+
purgeOldLogsFromFile(File(context.cacheDir, FILE_NAME), "app")
122+
}
123+
}
124+
125+
private fun purgeOldLogsFromFile(logFile: File, logType: String) {
110126
try {
111-
val securityLogFile = File(context.filesDir, SECURITY_LOGS)
112-
if (!securityLogFile.exists()) {
127+
if (!logFile.exists()) {
113128
return
114129
}
115130

116-
val threeDaysAgo = Instant.now().minus(3, ChronoUnit.DAYS)
117-
val lines = securityLogFile.readLines()
118-
val recentLines = mutableListOf<String>()
119-
120-
for (line in lines) {
121-
try {
122-
// Extract timestamp from log line format: "[ISO-8601 timestamp] D [TAG]: [message]"
123-
val timestampStr = line.substringBefore(" ")
124-
val timestamp = Instant.parse(timestampStr)
125-
126-
if (timestamp.isAfter(threeDaysAgo)) {
127-
recentLines.add(line)
131+
val tempDir = context.cacheDir
132+
val tempLogFile = File(tempDir, logFile.name + ".processing")
133+
val backupFile = File(tempDir, logFile.name + ".backup")
134+
135+
try {
136+
logFile.copyTo(backupFile, overwrite = true)
137+
138+
val threeDaysAgo = Instant.now().minus(7, ChronoUnit.DAYS)
139+
var purgedCount = 0
140+
var keptCount = 0
141+
142+
backupFile.bufferedReader().use { reader ->
143+
tempLogFile.bufferedWriter().use { writer ->
144+
reader.forEachLine { line ->
145+
try {
146+
val timestampStr = line.substringBefore(" ")
147+
val timestamp = Instant.parse(timestampStr)
148+
149+
if (timestamp.isAfter(threeDaysAgo)) {
150+
writer.write(line)
151+
writer.newLine()
152+
keptCount++
153+
} else {
154+
purgedCount++
155+
}
156+
} catch (_: Exception) {
157+
writer.write(line)
158+
writer.newLine()
159+
keptCount++
160+
}
161+
}
128162
}
129-
} catch (e: Exception) {
130-
// If we can't parse the timestamp, keep the line to avoid data loss
131-
recentLines.add(line)
132163
}
133-
}
134164

135-
// Rewrite the file with only recent logs
136-
if (recentLines.size < lines.size) {
137-
if (recentLines.isEmpty()) {
138-
// Delete the file if no recent logs remain
139-
securityLogFile.delete()
140-
Log.d(TAG, "Deleted log file - all entries were older than 3 days")
165+
if (keptCount == 0) {
166+
logFile.delete()
167+
tempLogFile.delete()
168+
Log.d(TAG, "Deleted $logType log file - all entries were older than 3 days")
169+
} else if (purgedCount > 0) {
170+
tempLogFile.copyTo(logFile, overwrite = true)
171+
tempLogFile.delete()
172+
Log.d(TAG, "Purged $purgedCount old $logType log entries")
141173
} else {
142-
securityLogFile.writeText(recentLines.joinToString("\n") + "\n")
143-
Log.d(TAG, "Purged ${lines.size - recentLines.size} old log entries")
174+
tempLogFile.delete()
144175
}
176+
} finally {
177+
backupFile.delete()
145178
}
146179
} catch (e: Exception) {
147-
Log.e(TAG, "Error purging old logs", e)
180+
Log.e(TAG, "Error purging old $logType logs", e)
148181
}
149182
}
150183
}

app/src/main/java/dev/pranav/applock/data/repository/AppLockRepository.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,9 @@ class AppLockRepository(private val context: Context) {
7676
fun isShowDonateLink(): Boolean = preferencesRepository.isShowDonateLink(context)
7777
fun setShowDonateLink(show: Boolean) = preferencesRepository.setShowDonateLink(context, show)
7878

79+
fun isLoggingEnabled(): Boolean = preferencesRepository.isLoggingEnabled()
80+
fun setLoggingEnabled(enabled: Boolean) = preferencesRepository.setLoggingEnabled(enabled)
81+
7982
fun setActiveBackend(backend: BackendImplementation) =
8083
backendServiceManager.setActiveBackend(backend)
8184

app/src/main/java/dev/pranav/applock/data/repository/PreferencesRepository.kt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,14 @@ class PreferencesRepository(context: Context) {
146146
settingsPrefs.edit { putBoolean(KEY_SHOW_DONATE_LINK, show) }
147147
}
148148

149+
fun isLoggingEnabled(): Boolean {
150+
return settingsPrefs.getBoolean(KEY_LOGGING_ENABLED, false)
151+
}
152+
153+
fun setLoggingEnabled(enabled: Boolean) {
154+
settingsPrefs.edit { putBoolean(KEY_LOGGING_ENABLED, enabled) }
155+
}
156+
149157
companion object {
150158
private const val PREFS_NAME_APP_LOCK = "app_lock_prefs"
151159
private const val PREFS_NAME_SETTINGS = "app_lock_settings"
@@ -160,6 +168,7 @@ class PreferencesRepository(context: Context) {
160168
private const val KEY_BACKEND_IMPLEMENTATION = "backend_implementation"
161169
private const val KEY_COMMUNITY_LINK_SHOWN = "community_link_shown"
162170
private const val KEY_SHOW_DONATE_LINK = "show_donate_link"
171+
private const val KEY_LOGGING_ENABLED = "logging_enabled"
163172
private const val LAST_VERSION_CODE = "last_version_code"
164173
private const val KEY_APPLOCK_ENABLED = "applock_enabled"
165174
private const val KEY_AUTO_UNLOCK = "auto_unlock"

0 commit comments

Comments
 (0)