Files
TRIPandHKLHaoBin 6f9af89583 release: OpenLess 2.0.0-Beta.4+build.20260930 (#1126)
Integrate ASR/Omni fixes, API Route, Android IME and confirmation-based vocabulary learning. Complete settings transitions and macOS single-item credential storage. Synchronize all application versions to 2.0.0-Beta.4+build.20260930.

Integrated PRs: #1116, #1120, #1121, #1123, #1124, #1067 and #1128. Linux #1117 remains independent and is excluded from automatic release.

Validated: full cross-platform CI, 18 UI motion cases, 112 frontend test files, 1245 Core tests (1 ignored) and 572 macOS native tests.

Co-authored-by: HKLHaoBin <we3q@qq.com>
2026-09-30 20:32:53 +08:00

132 lines
6.7 KiB
Kotlin

package com.openless.app
/** JNI bridge from Kotlin overlay / lifecycle code into Rust Coordinator. */
object OpenLessNative {
private const val BACKEND_CONTRACT_VERSION = "2.0.0"
init {
try {
System.loadLibrary("openless_lib")
} catch (error: UnsatisfiedLinkError) {
android.util.Log.e("OpenLessNative", "failed to load openless_lib", error)
}
}
@JvmStatic external fun nativeStartDictation()
@JvmStatic external fun nativeStartDictationWithTranslation(translation: Boolean)
@JvmStatic external fun nativeStopDictation()
@JvmStatic external fun nativeStopDictationWithTranslation(translation: Boolean)
@JvmStatic external fun nativeStopDictationAsQuickNote()
@JvmStatic external fun nativeCancelDictation()
@JvmStatic external fun nativeObserveVocabularyText(generation: Long, text: String): Boolean
@JvmStatic external fun nativeVocabularyObservationActive(generation: Long): Boolean
@JvmStatic external fun nativeVocabularyObservationRemainingMs(generation: Long): Long
@JvmStatic external fun nativeCurrentVocabularyObservation(): Long
@JvmStatic external fun nativeStopVocabularyObservation(generation: Long)
@JvmStatic external fun nativePendingVocabularySuggestions(): String
@JvmStatic external fun nativeResolveVocabularySuggestion(id: String, accept: Boolean): Boolean
@JvmStatic external fun nativeAddLearnedVocabulary(phrase: String): Boolean
// Adds a word/phrase straight to the global Dictionary (same store
// add_vocab exposes to the desktop UI) instead of a CorrectionRule —
// see native_bridge.rs's spawn_add_vocabulary_word() doc comment for
// why the IME's own edit/correction flows moved to this. The older
// CorrectionRule bindings below are kept too — upstream/beta's own
// code paths still use them; this file just adds an alternative for
// this branch's own IME flows, not a replacement.
@JvmStatic external fun nativeAddVocabularyWord(phrase: String)
/** Records a hand-corrected span from the IME's "edit result" flow into the shared correction dictionary. */
@JvmStatic external fun nativeAddCorrectionRule(pattern: String, replacement: String)
/** JSON array of every existing correction rule's pattern — lets the clipboard swipe-left gesture show "add" vs. "remove" before the drag finishes. */
@JvmStatic external fun nativeCorrectionRulePatterns(): String
/** Removes every correction rule whose pattern exactly matches — the clipboard swipe-left "remove" action. */
@JvmStatic external fun nativeRemoveCorrectionRule(pattern: String)
/** JSON array of every existing Dictionary entry's phrase — same purpose as nativeCorrectionRulePatterns(), for the clipboard swipe-left zone now that adding writes to the Dictionary instead. */
@JvmStatic external fun nativeVocabularyPhrases(): String
/** Removes every Dictionary entry whose phrase exactly matches — the clipboard swipe-left "remove" action's counterpart to nativeAddVocabularyWord(). */
@JvmStatic external fun nativeRemoveVocabularyWord(phrase: String)
/**
* Registers this Context as the one with_android_env() (every
* Rust->Kotlin JNI call, including dictation/waveform capsule updates)
* routes through — replaces whatever was registered before, since a
* GlobalRef stays valid for the registrant's whole lifecycle. Despite
* the name, this was never actually Activity-specific on the Rust side
* (register_active_activity() in jni.rs just stores a generic JObject),
* and no longer requires one here either: OpenLessRuntimeService now
* registers itself, not OpenLessBackendWarmupActivity — a foreground
* Service that starts/stops in lockstep with the IME being active is a
* far more stable registrant than an Activity that spends nearly its
* entire life backgrounded via moveTaskToBack() and can be reclaimed by
* the OS at any point during that (see OpenLessRuntimeService.onCreate()
* for the current registrant, and OpenLessProcessRestartStats' "actkill"
* history for what depending on the Activity instead used to cost).
* Call from onCreate(); pair with nativeUnregisterActivityContext() in
* onDestroy().
*/
@JvmStatic external fun nativeRegisterActivityContext(context: android.content.Context)
/** Clears the registration from nativeRegisterActivityContext() — only takes effect if `context` is still the currently-registered one. */
@JvmStatic external fun nativeUnregisterActivityContext(context: android.content.Context)
/**
* True once some registrant (see nativeRegisterActivityContext()) has
* called it and nothing has unregistered since. The Rust backend can
* stay perfectly healthy for a long time after its last registered
* Context is gone (that's the whole point of Phase 1/2's recovery
* design) — requireBackendContract() alone can't see that gap, since it
* only checks whether the backend itself is running, not whether
* there's still something around for it to notify.
*/
@JvmStatic external fun nativeHasRegisteredActivityContext(): Boolean
@JvmStatic external fun nativeBackendSnapshot(): String
@JvmStatic external fun nativeImeCommand(json: String): String
@JvmStatic
fun requireBackendContract() {
val response = org.json.JSONObject(nativeBackendSnapshot())
val version = response.optString("contractVersion")
check(version == BACKEND_CONTRACT_VERSION) {
"unsupported backend contract version: $version"
}
check(response.optBoolean("ok")) {
response.optString("error", "backend unavailable")
}
}
@JvmStatic external fun nativeSwitchStylePack()
@JvmStatic external fun nativeFinalizeQaFromOverlay()
@JvmStatic external fun nativeNotifyOverlayDestroyed()
/**
* Idempotent — safe to call from every OpenLessBackendWarmupActivity.onCreate().
* No-ops when the "main" WebviewWindow already exists; otherwise rebuilds it,
* attaching to whichever Activity instance most recently registered with Tao
* (this one). See android/native_bridge.rs's ensure_main_webview_window() doc
* comment for why a fresh Activity instance never gets onWebViewCreate()
* without this — the settings-reopen black screen fix.
*/
@JvmStatic external fun nativeEnsureMainWebviewWindow(): Boolean
/** Explicit, user-selected plaintext transfer; result envelopes carry failures. */
@JvmStatic external fun nativeExportProviderSettings(includeCredentials: Boolean): String
@JvmStatic external fun nativeImportProviderSettings(json: String, selection: Boolean, credentials: Boolean): String
}