Keyboard
- Only jump to the app when the voice surface is shown (tab tap / opened
there); typing tabs no longer leave the host on keyboard open.
- Wait up to 0.4 s for the arbiter to report the host app before leaving,
and late-bind an id that arrives within 6 s of the jump.
- Empty arbiter callbacks no longer wipe an already captured host id;
install the capture handler in every build configuration.
App
- Return to the previous app with up to four retries using iOS's real
open result, and honor the skip-app-switch preference.
- Keep the pending host id across cold-start zombie reconciliation, and
expire it after two minutes (legacy values without a timestamp stay valid).
- Show a light tip pointing at the system back control when we cannot
return automatically ("点击返回,立即使用").
Tests: TTL behaviour and return retry policy.
88 lines
3.7 KiB
Swift
88 lines
3.7 KiB
Swift
// FlowSessionPolicyTests.swift
|
|
// OSGKeyboardTests
|
|
|
|
@testable import OSGKeyboardShared
|
|
import XCTest
|
|
|
|
final class FlowSessionPolicyTests: XCTestCase {
|
|
private func makeDefaults() -> UserDefaults {
|
|
let suite = "group.com.osgkeyboard.shared.tests.policy.\(UUID().uuidString)"
|
|
let defaults = UserDefaults(suiteName: suite)!
|
|
defaults.removePersistentDomain(forName: suite)
|
|
return defaults
|
|
}
|
|
|
|
func testSkipAppSwitchDefaultsToTrue() {
|
|
let defaults = makeDefaults()
|
|
XCTAssertTrue(FlowSessionPolicy.skipAppSwitch(defaults: defaults))
|
|
}
|
|
|
|
func testInactivityDurationDefaultsToFiveMinutes() {
|
|
let defaults = makeDefaults()
|
|
XCTAssertEqual(FlowSessionPolicy.inactivityDuration(defaults: defaults), .fiveMinutes)
|
|
XCTAssertEqual(FlowSessionPolicy.sessionDuration(defaults: defaults), 5 * 60)
|
|
}
|
|
|
|
func testShortInactivityDurations() {
|
|
XCTAssertEqual(FlowInactivityDuration.oneMinute.timeInterval, 60)
|
|
XCTAssertEqual(FlowInactivityDuration.fiveMinutes.timeInterval, 5 * 60)
|
|
XCTAssertEqual(FlowInactivityDuration.tenMinutes.timeInterval, 10 * 60)
|
|
}
|
|
|
|
func testPiPSessionHasNoInactivityExpiry() {
|
|
let defaults = makeDefaults()
|
|
FlowSessionBridge.markSessionActivePersistent(sessionId: UUID(), defaults: defaults)
|
|
|
|
XCTAssertTrue(FlowSessionBridge.isSessionActive(defaults: defaults))
|
|
XCTAssertNil(defaults.object(forKey: FlowSessionKeys.flowSessionExpires))
|
|
}
|
|
|
|
func testLegacyExpiryDoesNotInvalidatePersistentSession() {
|
|
let defaults = makeDefaults()
|
|
FlowSessionBridge.markSessionActivePersistent(defaults: defaults)
|
|
defaults.set(Date().timeIntervalSince1970 - 30, forKey: FlowSessionKeys.flowSessionExpires)
|
|
|
|
XCTAssertTrue(FlowSessionBridge.isSessionActive(defaults: defaults))
|
|
}
|
|
|
|
func testPendingHostBundleIdRoundTrip() {
|
|
let defaults = makeDefaults()
|
|
FlowSessionBridge.setPendingHostBundleId("com.tencent.xin", defaults: defaults)
|
|
XCTAssertEqual(FlowSessionBridge.pendingHostBundleId(defaults: defaults), "com.tencent.xin")
|
|
FlowSessionBridge.clearPendingHostBundleId(defaults: defaults)
|
|
XCTAssertNil(FlowSessionBridge.pendingHostBundleId(defaults: defaults))
|
|
}
|
|
|
|
func testPendingHostBundleIdExpiresAfterTTL() {
|
|
let defaults = makeDefaults()
|
|
FlowSessionBridge.setPendingHostBundleId("com.tencent.xin", defaults: defaults)
|
|
|
|
let justInside = Date().addingTimeInterval(FlowSessionKeys.pendingHostBundleIdTTL - 5)
|
|
XCTAssertEqual(
|
|
FlowSessionBridge.pendingHostBundleId(defaults: defaults, now: justInside),
|
|
"com.tencent.xin"
|
|
)
|
|
let pastTTL = Date().addingTimeInterval(FlowSessionKeys.pendingHostBundleIdTTL + 5)
|
|
XCTAssertNil(FlowSessionBridge.pendingHostBundleId(defaults: defaults, now: pastTTL))
|
|
}
|
|
|
|
func testPendingHostBundleIdWithoutTimestampStaysValid() {
|
|
// Written by an older build: no timestamp key. Must keep working.
|
|
let defaults = makeDefaults()
|
|
defaults.set("com.tencent.xin", forKey: FlowSessionKeys.pendingHostBundleId)
|
|
|
|
let farFuture = Date().addingTimeInterval(FlowSessionKeys.pendingHostBundleIdTTL * 10)
|
|
XCTAssertEqual(
|
|
FlowSessionBridge.pendingHostBundleId(defaults: defaults, now: farFuture),
|
|
"com.tencent.xin"
|
|
)
|
|
}
|
|
|
|
func testClearingPendingHostBundleIdAlsoClearsTimestamp() {
|
|
let defaults = makeDefaults()
|
|
FlowSessionBridge.setPendingHostBundleId("com.tencent.xin", defaults: defaults)
|
|
FlowSessionBridge.clearPendingHostBundleId(defaults: defaults)
|
|
XCTAssertNil(defaults.object(forKey: FlowSessionKeys.pendingHostBundleIdAt))
|
|
}
|
|
}
|