Skip to content

Commit 958a09c

Browse files
authored
Audit codebase and implement comprehensive improvements (#22)
Fixes bounding box calculations, process execution, thread management, shell scripts, and build configurations; adds unit tests for core logic. Review feedback on ADB timeout handling and CLI subshell logic addressed in bbdbd10.
2 parents 74a7977 + bbdbd10 commit 958a09c

15 files changed

Lines changed: 443 additions & 491 deletions

File tree

BUILD.md

Lines changed: 14 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -6,22 +6,22 @@ InputBlocker is a monorepo. It contains the Android Engine (Xposed/LSPosed hook)
66

77
| Dependency | Version | Notes |
88
|---|---|---|
9-
| **JDK** | 17 | Required. Use Eclipse Temurin or a similar distribution. |
10-
| **Android SDK** | API 34 (compile/target), API 23 (min) | Set this through `ANDROID_HOME` or `local.properties`. |
11-
| **Gradle** | 8.x | The wrapper is included, so you don't need a manual install. |
9+
| **JDK** | 17+ | Required (JDK 17, 21+ supported). |
10+
| **Android SDK** | API 34+ (compile/target), API 23 (min) | Set this through `ANDROID_HOME` or `local.properties`. |
11+
| **Gradle** | 9.x | The wrapper is included, so you don't need a manual install. |
1212
| **Kotlin Compose Plugin** | 2.4.0 | Supported alongside the Kotlin plugin version matching your Gradle setup. |
1313

1414
### Environment Setup
1515

1616
**Linux / macOS:**
1717
```bash
18-
export JAVA_HOME=/path/to/jdk17
18+
export JAVA_HOME=/path/to/jdk
1919
export ANDROID_HOME=/path/to/android-sdk
2020
```
2121

2222
**Windows (PowerShell):**
2323
```powershell
24-
$env:JAVA_HOME = "C:\path\to\jdk17"
24+
$env:JAVA_HOME = "C:\path\to\jdk"
2525
$env:ANDROID_HOME = "C:\path\to\Android\Sdk"
2626
```
2727

@@ -71,14 +71,14 @@ docker run --rm -v $(pwd):/home/gradle/project -w /home/gradle/project inputbloc
7171

7272
## Version Parameters
7373

74-
Both version flags are required. The build will fail if you don't include them.
74+
Version flags can be passed via `-PVERSION_NAME` and `-PVERSION_CODE`. Defaults (`0.1.0` / `1`) are configured in `gradle.properties` if omitted.
7575

76-
| Flag | Type | Example | Purpose |
77-
|---|---|---|---|
78-
| `-PVERSION_NAME` | String | `"0.1.0"` | The version string users see. |
79-
| `-PVERSION_CODE` | Int | `1` | Internal integer for tracking updates. |
76+
| Flag | Type | Default | Example | Purpose |
77+
|---|---|---|---|---|
78+
| `-PVERSION_NAME` | String | `"0.1.0"` | `"0.1.0"` | The version string users see. |
79+
| `-PVERSION_CODE` | Int | `1` | `1` | Internal integer for tracking updates. |
8080

81-
During the testing phase, `VERSION_NAME` stays at `0.1.0` regardless of changes. This keeps distribution consistent until we validate core features. Our CI/CD workflow handles automatic version assignment for official releases.
81+
Our CI/CD workflow handles automatic version assignment for official releases.
8282

8383
## Verifying Your Build
8484

@@ -96,16 +96,16 @@ Once the build finishes, you should verify the artifacts before deployment.
9696
| **PC Tool (EXE)** | `pc-tool-kotlin/build/compose/binaries/main/exe/InputBlockerSetup-<version>.exe` |
9797
| **PC Tool (DEB)** | `pc-tool-kotlin/build/compose/binaries/main/deb/inputblockersetup_<version>_amd64.deb` |
9898
| **PC Tool (DMG)** | `pc-tool-kotlin/build/compose/binaries/main/dmg/InputBlockerSetup-<version>.dmg` |
99-
| **Module ZIP** | `build/distributions/inputblocker.zip` |
99+
| **Module ZIP** | `build/distributions/InputBlockerModule.zip` |
100100

101101
## Troubleshooting
102102

103103
### Java Version Mismatch
104104

105105
```
106-
Unsupported class file major version 67
106+
Unsupported class file major version
107107
```
108-
This means your environment isn't using JDK 17. Check your version with `java -version` and make sure `JAVA_HOME` points to the right path.
108+
Make sure `JAVA_HOME` points to a compatible JDK 17+ distribution. Check your version with `java -version`.
109109

110110
### SDK Not Found
111111

@@ -119,10 +119,6 @@ If the build hangs or behaves strangely, try stopping the daemon:
119119
```
120120
Then run your build command again.
121121

122-
### Version Flags Missing
123-
124-
If you see "Version flags are required," you forgot to pass `-PVERSION_NAME` and `-PVERSION_CODE`. These are mandatory for every build task.
125-
126122
## CI/CD Pipeline
127123

128124
We use GitHub Actions for automated builds. The release workflow handles:
@@ -134,14 +130,10 @@ We use GitHub Actions for automated builds. The release workflow handles:
134130
- GitHub Release creation.
135131
- Deployment of `update.json` for the in-app updater.
136132

137-
For CI builds without access to release signing secrets, `assembleDebug` is used instead of `assembleRelease`. Debug APKs are suitable for testing but should not be distributed to end users.
138-
139133
## Project Structure
140134

141135
```
142136
├── android-app/ # Android app and LSPosed/Vector hook module
143-
│ ├── app/
144-
│ └── module/
145137
├── shared/ # KMP shared core
146138
├── pc-tool-kotlin/ # Compose Desktop PC Designer
147139
├── module/ # Root module shell scripts

android-app/app/src/main/java/com/inputblocker/app/ConfigFileObserver.kt

Lines changed: 15 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,7 @@ import java.util.concurrent.atomic.AtomicBoolean
1010

1111
/**
1212
* Monitors config file changes via FileObserver (inotify) with a
13-
* polling fallback for filesystems that don't support inotify
14-
* (e.g., some Magisk overlay setups).
15-
*
16-
* Usage:
17-
* val watcher = ConfigFileObserver(configPath) { /* reload */ }
18-
* watcher.start()
19-
* watcher.stop()
13+
* polling fallback for filesystems that don't support inotify.
2014
*/
2115
class ConfigFileObserver(
2216
private val configPath: String,
@@ -26,7 +20,6 @@ class ConfigFileObserver(
2620
) {
2721
companion object {
2822
private const val TAG = "ConfigFileObserver"
29-
/** Fallback polling interval (ms) if FileObserver fails */
3023
private const val FALLBACK_POLL_MS = 5000L
3124
}
3225

@@ -35,11 +28,14 @@ class ConfigFileObserver(
3528
@Volatile private var lastModified = 0L
3629
private val running = AtomicBoolean(false)
3730

31+
private val reloadRunnable = Runnable {
32+
if (running.get()) {
33+
onConfigChanged()
34+
}
35+
}
3836

39-
/** @see #start() */
4037
fun startWatching() = start()
4138

42-
/** @see #stop() */
4339
fun stopWatching() = stop()
4440

4541
fun start() {
@@ -54,38 +50,31 @@ class ConfigFileObserver(
5450
return
5551
}
5652

57-
// Initial timestamp
5853
lastModified = configFile.lastModified()
5954

6055
try {
6156
fileObserver = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
62-
// API 29+ supports mask-based FileObserver on the parent directory
6357
object : FileObserver(parentDir, FileObserver.CLOSE_WRITE or FileObserver.MOVED_TO) {
6458
override fun onEvent(event: Int, path: String?) {
6559
if (path == null) return
6660
if (path == configFile.name || path.endsWith(".conf")) {
6761
val now = configFile.lastModified()
6862
if (now > lastModified) {
6963
lastModified = now
70-
handler.removeCallbacksAndMessages(null)
71-
handler.postDelayed({
72-
if (running.get()) onConfigChanged()
73-
}, 300L)
64+
handler.removeCallbacks(reloadRunnable)
65+
handler.postDelayed(reloadRunnable, 300L)
7466
}
7567
}
7668
}
7769
}
7870
} else {
79-
// Pre-API 29: observe the config file directly (no mask support)
8071
object : FileObserver(configFile.absolutePath) {
8172
override fun onEvent(event: Int, path: String?) {
8273
val now = configFile.lastModified()
8374
if (now > lastModified) {
8475
lastModified = now
85-
handler.removeCallbacksAndMessages(null)
86-
handler.postDelayed({
87-
if (running.get()) onConfigChanged()
88-
}, 300L)
76+
handler.removeCallbacks(reloadRunnable)
77+
handler.postDelayed(reloadRunnable, 300L)
8978
}
9079
}
9180
}
@@ -105,15 +94,13 @@ class ConfigFileObserver(
10594
fileObserver = null
10695
fallbackThread?.interrupt()
10796
fallbackThread = null
108-
handler.removeCallbacksAndMessages(null)
97+
handler.removeCallbacks(reloadRunnable)
10998
}
11099

111-
/** Force an immediate config reload (called when app saves config directly) */
100+
/** Force an immediate config reload */
112101
fun notifyChanged() {
113-
handler.removeCallbacksAndMessages(null)
114-
handler.post {
115-
if (running.get()) onConfigChanged()
116-
}
102+
handler.removeCallbacks(reloadRunnable)
103+
handler.post(reloadRunnable)
117104
}
118105

119106
private fun startFallback() {
@@ -126,9 +113,7 @@ class ConfigFileObserver(
126113
val modified = configFile.lastModified()
127114
if (modified > lastModified) {
128115
lastModified = modified
129-
handler.post {
130-
if (running.get()) onConfigChanged()
131-
}
116+
handler.post(reloadRunnable)
132117
}
133118
} catch (_: InterruptedException) {
134119
break

0 commit comments

Comments
 (0)