fix: keyboard stability, host-only analytics, and auto-reply dedupe
- record analytics/usage only in the host app; the extension no longer opens the SQLite queues, so hiding the keyboard cannot hold WAL locks (0xdead10cc) - sync clipboard history writes across processes so deletes made on one side are not reverted by the other - guard memory-relief reentrancy on controller and telemetry sides to break the recursive crash loop - resolve credentials off the main thread and migrate legacy keys once per install, so Keychain reads cannot be caught in the suspend window - gate Volcengine ASR ping completion to once (SIGTRAP on double resume) - treat same-text captures as the same logical copy and dedupe auto actions by content fingerprint within 30s, stopping Universal Clipboard storms - realign version line to 2.1.0 (build 110)
This commit is contained in:
@@ -81,4 +81,75 @@ final class EnglishKeyboardDeviceUITests: XCTestCase {
|
||||
"OSGKeyboard extension window should be on screen"
|
||||
)
|
||||
}
|
||||
|
||||
/// Chinese → English used to take the whole extension down. Memory relief
|
||||
/// fired while the typing surface was being torn down, and every teardown
|
||||
/// step recorded a milestone that asked for relief again — the nesting
|
||||
/// overflowed the main thread's stack.
|
||||
func testSwitchingToEnglishAfterChineseKeepsTheKeyboardAlive() throws {
|
||||
let app = XCUIApplication()
|
||||
app.launchArguments = [
|
||||
"--whats-new-host",
|
||||
"--whats-new-lang=en",
|
||||
"--whats-new-scenario=edit"
|
||||
]
|
||||
app.launch()
|
||||
|
||||
let textView = app.textViews["notes.host.textView"]
|
||||
XCTAssertTrue(
|
||||
textView.waitForExistence(timeout: 12),
|
||||
"Notes host text view should appear"
|
||||
)
|
||||
if !textView.exists {
|
||||
return
|
||||
}
|
||||
textView.tap()
|
||||
|
||||
let keyboard = XCUIApplication(bundleIdentifier: "com.osgkeyboard.ios.keyboard")
|
||||
guard let chineseTab = inputTab("chinese", host: app, keyboard: keyboard) else {
|
||||
throw XCTSkip(
|
||||
"OSGKeyboard extension is not the active keyboard on this device. Enable it in Settings ▸ Keyboard, then re-run."
|
||||
)
|
||||
}
|
||||
chineseTab.tap()
|
||||
|
||||
// Loading Rime pushes the footprint past our relief thresholds, which is
|
||||
// what arms the shed that runs on the way back out to English.
|
||||
XCTAssertTrue(
|
||||
keyboard.buttons["n"].waitForExistence(timeout: 12),
|
||||
"Chinese typing surface should come up"
|
||||
)
|
||||
|
||||
guard let englishTab = inputTab("english", host: app, keyboard: keyboard) else {
|
||||
XCTFail("English tab should be reachable from the Chinese surface")
|
||||
return
|
||||
}
|
||||
englishTab.tap()
|
||||
|
||||
XCTAssertTrue(
|
||||
keyboard.buttons["n"].waitForExistence(timeout: 12),
|
||||
"English surface should be usable instead of the extension being killed"
|
||||
)
|
||||
XCTAssertTrue(
|
||||
keyboard.windows.firstMatch.exists,
|
||||
"OSGKeyboard extension should survive the switch to English"
|
||||
)
|
||||
}
|
||||
|
||||
/// The top-bar tabs show up in the host's accessibility hierarchy on some OS
|
||||
/// versions and in the extension's on others; try both before concluding
|
||||
/// that OSGKeyboard is not the active keyboard.
|
||||
private func inputTab(
|
||||
_ name: String,
|
||||
host: XCUIApplication,
|
||||
keyboard: XCUIApplication,
|
||||
timeout: TimeInterval = 10
|
||||
) -> XCUIElement? {
|
||||
let identifier = "assistant.tab.\(name)"
|
||||
let inHost = host.descendants(matching: .any)[identifier]
|
||||
if inHost.waitForExistence(timeout: timeout) { return inHost }
|
||||
let inExtension = keyboard.descendants(matching: .any)[identifier]
|
||||
if inExtension.waitForExistence(timeout: timeout) { return inExtension }
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user