diff --git a/Libraries/Components/AccessibilityInfo/AccessibilityInfo.android.js b/Libraries/Components/AccessibilityInfo/AccessibilityInfo.android.js index 75a37587d27725..fab85a0d5c1912 100644 --- a/Libraries/Components/AccessibilityInfo/AccessibilityInfo.android.js +++ b/Libraries/Components/AccessibilityInfo/AccessibilityInfo.android.js @@ -167,6 +167,29 @@ const AccessibilityInfo = { NativeAccessibilityInfo.announceForAccessibility(announcement); } }, + + /** + * Get the recommended timeout for changes to the UI needed by this user. + * + * See https://reactnative.dev/docs/accessibilityinfo.html#getRecommendedTimeoutMillis + */ + getRecommendedTimeoutMillis: function( + originalTimeout: number, + ): Promise { + return new Promise((resolve, reject) => { + if ( + NativeAccessibilityInfo && + NativeAccessibilityInfo.getRecommendedTimeoutMillis + ) { + NativeAccessibilityInfo.getRecommendedTimeoutMillis( + originalTimeout, + resolve, + ); + } else { + resolve(originalTimeout); + } + }); + }, }; module.exports = AccessibilityInfo; diff --git a/Libraries/Components/AccessibilityInfo/AccessibilityInfo.ios.js b/Libraries/Components/AccessibilityInfo/AccessibilityInfo.ios.js index 0730f808425547..9af89bf250af68 100644 --- a/Libraries/Components/AccessibilityInfo/AccessibilityInfo.ios.js +++ b/Libraries/Components/AccessibilityInfo/AccessibilityInfo.ios.js @@ -275,6 +275,15 @@ const AccessibilityInfo = { // $FlowFixMe[escaped-generic] _subscriptions.delete(handler); }, + + /** + * Android only + */ + getRecommendedTimeoutMillis: function( + originalTimeout: number, + ): Promise { + return Promise.resolve(originalTimeout); + }, }; module.exports = AccessibilityInfo; diff --git a/Libraries/Components/AccessibilityInfo/NativeAccessibilityInfo.js b/Libraries/Components/AccessibilityInfo/NativeAccessibilityInfo.js index 4810127fd7d48b..916667aa5c2c0a 100644 --- a/Libraries/Components/AccessibilityInfo/NativeAccessibilityInfo.js +++ b/Libraries/Components/AccessibilityInfo/NativeAccessibilityInfo.js @@ -20,6 +20,10 @@ export interface Spec extends TurboModule { ) => void; +setAccessibilityFocus: (reactTag: number) => void; +announceForAccessibility: (announcement: string) => void; + +getRecommendedTimeoutMillis?: ( + mSec: number, + onSuccess: (recommendedTimeoutMillis: number) => void, + ) => void; } export default (TurboModuleRegistry.get('AccessibilityInfo'): ?Spec); diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/accessibilityinfo/AccessibilityInfoModule.java b/ReactAndroid/src/main/java/com/facebook/react/modules/accessibilityinfo/AccessibilityInfoModule.java index bc923fed684d63..ad148228cd9bc0 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/modules/accessibilityinfo/AccessibilityInfoModule.java +++ b/ReactAndroid/src/main/java/com/facebook/react/modules/accessibilityinfo/AccessibilityInfoModule.java @@ -67,6 +67,7 @@ public void onChange(boolean selfChange, Uri uri) { private final ContentResolver mContentResolver; private boolean mReduceMotionEnabled = false; private boolean mTouchExplorationEnabled = false; + private int mRecommendedTimeout; private static final String REDUCE_MOTION_EVENT_NAME = "reduceMotionDidChange"; private static final String TOUCH_EXPLORATION_EVENT_NAME = "touchExplorationDidChange"; @@ -193,4 +194,16 @@ public void announceForAccessibility(String message) { public void setAccessibilityFocus(double reactTag) { // iOS only } + + @Override + public void getRecommendedTimeoutMillis(double originalTimeout, Callback successCallback) { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) { + successCallback.invoke((int) originalTimeout); + return; + } + mRecommendedTimeout = + mAccessibilityManager.getRecommendedTimeoutMillis( + (int) originalTimeout, AccessibilityManager.FLAG_CONTENT_CONTROLS); + successCallback.invoke(mRecommendedTimeout); + } } diff --git a/jest/setup.js b/jest/setup.js index 1bb9af5c51b1c9..6eaf71e5ee4cf2 100644 --- a/jest/setup.js +++ b/jest/setup.js @@ -128,6 +128,7 @@ jest removeEventListener: jest.fn(), setAccessibilityFocus: jest.fn(), sendAccessibilityEvent_unstable: jest.fn(), + getRecommendedTimeoutMillis: jest.fn(), })) .mock('../Libraries/Components/RefreshControl/RefreshControl', () => jest.requireActual(