feat(android): native Android client — full app parity build (A1–A36 + S1)
Some checks failed
relay-tripwire / cross-tenant-tripwire (push) Has been cancelled
ios / package-tests (APIClient) (push) Has been cancelled
ios / package-tests (HostRegistry) (push) Has been cancelled
ios / package-tests (SessionCore) (push) Has been cancelled
ios / package-tests (WireProtocol) (push) Has been cancelled
ios / testsupport-tests (push) Has been cancelled
ios / app-tests (push) Has been cancelled
ios / ipad-tests (push) Has been cancelled
ios / integration-tests (push) Has been cancelled
ios / ui-test (push) Has been cancelled
ios / ios17-floor-tests (push) Has been cancelled
Some checks failed
relay-tripwire / cross-tenant-tripwire (push) Has been cancelled
ios / package-tests (APIClient) (push) Has been cancelled
ios / package-tests (HostRegistry) (push) Has been cancelled
ios / package-tests (SessionCore) (push) Has been cancelled
ios / package-tests (WireProtocol) (push) Has been cancelled
ios / testsupport-tests (push) Has been cancelled
ios / app-tests (push) Has been cancelled
ios / ipad-tests (push) Has been cancelled
ios / integration-tests (push) Has been cancelled
ios / ui-test (push) Has been cancelled
ios / ios17-floor-tests (push) Has been cancelled
Mirror the iOS P0+P1 client as a Gradle multi-module app. Pure-JVM (Kover ≥80% gated): :wire-protocol (frozen contract + HostEndpoint CSWSH origin + byte-exact codec), :session-core (SessionEngine + reconnect/ping/gate/digest reducers), :api-client, :client-tls (pure PKCS12/keymanager), :transport-okhttp (OkHttp WS+REST). Framework: :app (Compose M3 Adaptive, Hilt, FCM, 11 screens + NavGraph), :terminal-view (Termux terminal-emulator/-view via JitPack, Apache-2.0 — the renderer seam proven headless), :host-registry (DataStore), :client-tls-android (AndroidKeyStore + Tink). Highlights: single-key-home mTLS (non-exportable AndroidKeyStore key + re-reading X509KeyManager + connectionPool.evictAll on rotation, ping-pong single-commit so a failed rotation never clobbers the prior identity); FCM Allow/Deny trust split (Deny=BroadcastReceiver, Allow=trampoline Activity hosting BiometricPrompt); per-consumer-Channel EventBus (R10); config-surviving RetainedSessionHolder; byte-exact KeyByteMap; §5.4 pairing warning tiers. Verified: ~484 JVM tests + Kover ≥80% on the pure modules + :app assembles to an APK; all framework modules assemble. Device behaviors (rendering/IME/FCM/biometric/camera, E2E A34/A35, S2 real-handset FCM spike) deferred to android/DEVICE_QA_CHECKLIST.md per plan §7 (no emulator/Firebase here). Built via multi-agent orchestration (TDD builders → adversarial cross-review → fix → re-verify → independent gate); progress in android/PROGRESS_ANDROID.md.
This commit is contained in:
@@ -1,31 +1,80 @@
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
// :terminal-view — Android-framework-bound Termux `terminal-emulator` +
|
||||
// `terminal-view` wrap (RemoteTerminalSession: no local process, WS-driven).
|
||||
// Mirrors the iOS SwiftTerm host view. Depends ONLY on :wire-protocol.
|
||||
// :terminal-view (A16) — the XL terminal-render module.
|
||||
//
|
||||
// SCAFFOLD STUB ONLY — COMMENTED OUT in settings.gradle.kts (no Android SDK here).
|
||||
// TODO(android-sdk): enable when an Android SDK is available.
|
||||
// Wraps Termux `terminal-emulator` (VT100/xterm parser + `TerminalBuffer` scrollback
|
||||
// ring) + `terminal-view` (`TerminalView`/`TerminalRenderer` glyph painter). These two
|
||||
// libraries are Apache-2.0 (plan §9 R2 — they descend from jackpal's Apache-2.0 emulator;
|
||||
// only `termux-shared`/app are GPLv3, and we depend on NEITHER). Consumed from JitPack.
|
||||
//
|
||||
// `RemoteTerminalSession` is the FORK (plan §6.1): it holds a `TerminalEmulator` with NO
|
||||
// local subprocess / NO JNI, feeds remote WS bytes into it off the main thread, and routes
|
||||
// emulator-originated bytes back out through `engineSend`. Depends ONLY on :wire-protocol
|
||||
// (boundary note §3 — the SessionEvent→ByteArray decode is A21's, not here).
|
||||
//
|
||||
// AGP 9 has built-in Kotlin → apply ONLY com.android.library (adding
|
||||
// org.jetbrains.kotlin.android errors). No serialization/compose plugins needed.
|
||||
//
|
||||
// The pure logic (RemoteTerminalSession seam, TerminalGridMath resize formula,
|
||||
// pendingOutput ordering, DECCKM key form) is a LOCAL JVM unit test: `TerminalEmulator`
|
||||
// is pure Java whose exercised path touches no runtime android API, so it drives headless
|
||||
// on `testDebugUnitTest` (android.jar stubs on the classpath, isReturnDefaultValues=true).
|
||||
// Rendering / IME / selection / rotation-rebind are device QA (plan §7).
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
/*
|
||||
plugins {
|
||||
id("com.android.library")
|
||||
alias(libs.plugins.kotlin.android)
|
||||
}
|
||||
|
||||
android {
|
||||
namespace = "wang.yaojia.webterm.terminalview"
|
||||
compileSdk = 35
|
||||
defaultConfig { minSdk = 29 }
|
||||
compileSdk = 36
|
||||
|
||||
defaultConfig {
|
||||
minSdk = 29
|
||||
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
||||
}
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility = JavaVersion.VERSION_17
|
||||
targetCompatibility = JavaVersion.VERSION_17
|
||||
}
|
||||
|
||||
testOptions {
|
||||
unitTests {
|
||||
// The Termux emulator references a couple of android.* APIs (e.g. Base64 in the
|
||||
// OSC-52 path we never exercise); default-return keeps any incidental android
|
||||
// call from throwing "not mocked" in the headless JVM seam tests.
|
||||
isReturnDefaultValues = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
kotlin { jvmToolchain(17) }
|
||||
kotlin {
|
||||
jvmToolchain(17)
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation(project(":wire-protocol"))
|
||||
// Termux VT100/xterm emulator (Apache-2.0) — scope to these two libs ONLY,
|
||||
// never `termux-shared`/app module (GPLv3). Consumable via JitPack.
|
||||
// implementation("com.termux:terminal-view:0.118.0")
|
||||
// implementation("com.termux:terminal-emulator:0.118.0")
|
||||
// Boundary note (plan §3): :terminal-view depends ONLY on :wire-protocol.
|
||||
api(project(":wire-protocol"))
|
||||
implementation(libs.kotlinx.coroutines.core)
|
||||
// Provides the `Main` dispatcher on Android — without it `Dispatchers.Main.immediate`
|
||||
// throws "Module with the Main dispatcher is missing" at runtime on-device.
|
||||
implementation(libs.kotlinx.coroutines.android)
|
||||
|
||||
// Termux VT100/xterm emulator + view (Apache-2.0). Scope is these TWO libs ONLY —
|
||||
// never `termux-shared`/app (GPLv3). JitPack builds them from the termux-app repo.
|
||||
implementation(libs.termux.terminal.view)
|
||||
implementation(libs.termux.terminal.emulator)
|
||||
|
||||
testImplementation(libs.bundles.unit.test)
|
||||
testRuntimeOnly(libs.junit.platform.launcher)
|
||||
|
||||
androidTestImplementation(libs.androidx.test.ext.junit)
|
||||
androidTestImplementation(libs.androidx.test.core)
|
||||
androidTestImplementation(libs.androidx.test.runner)
|
||||
}
|
||||
|
||||
// Local (JVM) unit tests run on the JUnit 5 platform, matching the pure modules.
|
||||
tasks.withType<Test>().configureEach {
|
||||
useJUnitPlatform()
|
||||
}
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user