Repository navigation
Return a longer recommended timeout on iOS while Switch Control is running - #59453
Open
camilopires wants to merge 5 commits into
Open
camilopires wants to merge 5 commits into
camilopires wants to merge 5 commits into
Conversation
getRecommendedTimeoutMillis(originalTimeout) read Android's "Time to take action" setting and resolved originalTimeout unchanged on iOS. It now asks NativeAccessibilityManagerIOS too, so iOS can allow a longer timeout while Switch Control is running. The native side follows. This changes an existing API, so new JS on an older binary keeps the old behaviour: when the native method or the whole module is missing, it still resolves originalTimeout rather than rejecting. The docs now say that Android follows the setting from Android 10 (API 29), and that iOS allows three times originalTimeout while Switch Control is running. Adds Jest tests for the native value and for both fallbacks, and a type test. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Add a row to Accessibility's display options that shows getRecommendedTimeoutMillis(4000). AccessibilityInfo has no event for the recommended timeout, so the row reads it again whenever RNTester becomes active. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…nning RCTAccessibilityManager implements getRecommendedTimeoutMillis: it returns three times the original timeout while Switch Control is running (UIAccessibilityIsSwitchControlRunning), and the original timeout otherwise. iOS has no recommended timeout setting, and moving between elements one switch press at a time is slow. Tests can replace how one module instance reads Switch Control with RCTAccessibilityManagerSetSwitchControlReader, in +Internal.h. Pass nil to read the system again. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Add RCTAccessibilityManagerTimeoutTests to RNTesterUnitTests, in its own file. With a per-instance Switch Control reader, the tests check three times the timeout while Switch Control is running, the original timeout when it isn't, that 0 stays 0, that the reader is read on every call, that two instances keep their own readers, and that with no reader the system is read. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The iOS NativeAccessibilityManager spec gains getRecommendedTimeoutMillis, so the generated spec method appears in the Apple snapshots. Generated with Doxygen 1.16.1 and Python 3.12, as in validate-cxx-api-snapshots.yml. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This was referenced Oct 24, 2026
Open
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary:
Following the discussion in react-native-community/discussions-and-proposals#1026, this makes the existing
AccessibilityInfo.getRecommendedTimeoutMillis(originalTimeout)useful on iOS. It was split out of #59318 (the accessibility preferences snapshot) so that the change to an existing API can be reviewed on its own.Until now,
getRecommendedTimeoutMillisread Android's "Time to take action" setting and resolvedoriginalTimeoutunchanged on iOS. iOS has no such setting, but it does have people who need more time: Switch Control users move between elements one switch press at a time, so a 4-second toast or an auto-dismissing banner is often gone before they reach it.On iOS,
getRecommendedTimeoutMillisnow asksRCTAccessibilityManager, which returns three timesoriginalTimeoutwhile Switch Control is running (UIAccessibilityIsSwitchControlRunning()), andoriginalTimeoutotherwise. This uses the method apps already call for timeouts, rather than a newisSwitchControlEnabled()flag that every app would have to turn into a timeout itself. It also replaces the separategetRecommendedTimeoutI suggested on #1026.Why 3×: Apple publishes no recommended figure, and Switch Control's own scanning speed is user-configurable, so there's no value to read. 3× is a judgement call: it turns a typical 3–5 second toast into 9–15 seconds, which gives a switch user time to scan to it without leaving the UI on screen indefinitely. I'm happy to change the multiplier, or to make it configurable, if reviewers prefer.
Effect on existing callers (
[IOS] [CHANGED]): iOS code that already callsgetRecommendedTimeoutMillisgets a longer value while Switch Control is running. Nothing changes when it isn't running,0stays0, and Android is unchanged.Older binaries: because this changes an existing API, new JS on a binary without the native method keeps the old behaviour. When
NativeAccessibilityManagerIOS.getRecommendedTimeoutMillis, or the whole module, is missing, it still resolvesoriginalTimeoutrather than rejecting. (New APIs such asgetPreferences()in #59318 reject instead, likeisShowBordersEnabled.)The docs now also say that Android follows "Time to take action" only from Android 10 (API 29); earlier versions resolve
originalTimeout.Overlaps: this edits several of the same files as #59318, so whichever lands second needs a small rebase. Five files conflict, each in a few lines: the iOS native-module mock in
__tests__/AccessibilityInfo-test.js,RCTAccessibilityManager+Internal.h, the@implementationivar block inRCTAccessibilityManager.mm,__typetests__/index.tsxand RNTester's Accessibility example. The C++ API snapshots andproject.pbxprojmerge cleanly, because the XCTests are in their own file,RCTAccessibilityManagerTimeoutTests.m.Changelog:
[IOS] [CHANGED] -
AccessibilityInfo.getRecommendedTimeoutMillis()returns three timesoriginalTimeoutwhile Switch Control is runningTest Plan:
yarn jest packages/react-native/Libraries/Components/AccessibilityInfo: 45 tests pass. New ones cover the iOS native value, and that iOS resolvesoriginalTimeoutwhen the native method is missing and when the whole native module is missing.yarn flow-check: 0 errorsyarn lint: passesyarn build-types --validate: API snapshot up to date (the public signature doesn't change)yarn test-generated-typescriptandyarn test-typescript-legacy: passyarn format-check-cpp, and Prettier on the changed JS and TS: passgetRecommendedTimeoutMillis:onSuccess:.RCTAccessibilityManagerTimeoutTestsin RNTesterUnitTests: 5 tests pass on an iPhone 18 Pro simulator (iOS 27.0, Xcode 27.1). Each module instance gets its own Switch Control reader (RCTAccessibilityManagerSetSwitchControlReader, in+Internal.h). They check 3× while Switch Control is running, the original value when it isn't, that0stays0, that the reader is read on every call, that two instances keep their own readers, and that with no reader (or after resetting it tonil) the system value is used. Removing the* 3makes 4 of them fail.I haven't run the new RNTester row on a simulator or emulator yet. With Switch Control off it would show the original 4000 ms, which the unit tests already cover; I'll add screenshots once I've run it.
Not verified: the timeout with Switch Control running on a real device. The iOS simulator has no Switch Control, so that path is covered by the unit tests only. I'll add the device result here once I've run it.