Files
react-native/Libraries/Components/AccessibilityInfo/AccessibilityInfo.android.js
T
grgr-dkrkandFacebook GitHub Bot d29a7e7a89 add getRecommendedTimeoutMillis to AccessibilityInfo (#31063)
Summary:
resolve https://github.com/facebook/react-native/issues/30866

This PR is for using `getRecommendedTimeoutMillis` with React Native, which is available on Android 10 and above.
This allows the Android "Time to take action (Accessibility timeout)" setting to be reflected in the app.

## Changelog

<!-- Help reviewers and the release process by writing your own changelog entry. For an example, see:
https://github.com/facebook/react-native/wiki/Changelog
-->

[Android] [Added] - Add `getRecommendedTimeoutMillis` to AccessibilityInfo

Pull Request resolved: https://github.com/facebook/react-native/pull/31063

Test Plan:
I couldn't find any tests at the code level, so I tested them on my Android device.

 ---

### Android 10 (Pixel4a)
#### Settings
<img src="https://user-images.githubusercontent.com/40130327/109322854-210f2400-7896-11eb-9f3b-b88afa27abfb.png" width="400" alt="Set the timeout to 1 minute on the settings screen." />

#### App
<img src="https://user-images.githubusercontent.com/40130327/109322895-32583080-7896-11eb-9c48-c4aa9afb94d9.png" width="400" alt="The baseline timeout is 3000 ms, but the result of `getRecommendedTimeoutMillis` returns 60000 ms." />

 ---

### Android 7, iOS(Simulator)
Return the original timeout.
<img src="https://user-images.githubusercontent.com/40130327/109323217-911daa00-7896-11eb-9eba-659bc623f2ac.png" width="400" alt="Return the original timeout on Android 7." />

<img src="https://user-images.githubusercontent.com/40130327/109323357-b7dbe080-7896-11eb-89e9-305eea8b801b.png" width="400" alt="Return the original timeout on iOS simulator." />

Reviewed By: lunaleaps

Differential Revision: D27475370

Pulled By: nadiia

fbshipit-source-id: 4cdd9eb5ddb20d89c1d870e640b4b7e3c3c1b14d
2021-04-06 13:48:24 -07:00

196 lines
5.4 KiB
JavaScript

/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
* @flow strict-local
*/
import RCTDeviceEventEmitter from '../../EventEmitter/RCTDeviceEventEmitter';
import NativeAccessibilityInfo from './NativeAccessibilityInfo';
import type {EventSubscription} from 'react-native/Libraries/vendor/emitter/EventEmitter';
import type {HostComponent} from '../../Renderer/shims/ReactNativeTypes';
import {sendAccessibilityEvent} from '../../Renderer/shims/ReactNative';
import legacySendAccessibilityEvent from './legacySendAccessibilityEvent';
import {type ElementRef} from 'react';
const REDUCE_MOTION_EVENT = 'reduceMotionDidChange';
const TOUCH_EXPLORATION_EVENT = 'touchExplorationDidChange';
type AccessibilityEventDefinitions = {
reduceMotionChanged: [boolean],
screenReaderChanged: [boolean],
// alias for screenReaderChanged
change: [boolean],
};
type AccessibilityEventTypes = 'focus' | 'click';
const _subscriptions = new Map();
/**
* Sometimes it's useful to know whether or not the device has a screen reader
* that is currently active. The `AccessibilityInfo` API is designed for this
* purpose. You can use it to query the current state of the screen reader as
* well as to register to be notified when the state of the screen reader
* changes.
*
* See https://reactnative.dev/docs/accessibilityinfo.html
*/
const AccessibilityInfo = {
/**
* iOS only
*/
isBoldTextEnabled: function(): Promise<boolean> {
return Promise.resolve(false);
},
/**
* iOS only
*/
isGrayscaleEnabled: function(): Promise<boolean> {
return Promise.resolve(false);
},
/**
* iOS only
*/
isInvertColorsEnabled: function(): Promise<boolean> {
return Promise.resolve(false);
},
isReduceMotionEnabled: function(): Promise<boolean> {
return new Promise((resolve, reject) => {
if (NativeAccessibilityInfo) {
NativeAccessibilityInfo.isReduceMotionEnabled(resolve);
} else {
reject(false);
}
});
},
/**
* iOS only
*/
isReduceTransparencyEnabled: function(): Promise<boolean> {
return Promise.resolve(false);
},
isScreenReaderEnabled: function(): Promise<boolean> {
return new Promise((resolve, reject) => {
if (NativeAccessibilityInfo) {
NativeAccessibilityInfo.isTouchExplorationEnabled(resolve);
} else {
reject(false);
}
});
},
addEventListener: function<K: $Keys<AccessibilityEventDefinitions>>(
eventName: K,
handler: (...$ElementType<AccessibilityEventDefinitions, K>) => void,
): EventSubscription {
let listener;
if (eventName === 'change' || eventName === 'screenReaderChanged') {
listener = RCTDeviceEventEmitter.addListener(
TOUCH_EXPLORATION_EVENT,
handler,
);
} else if (eventName === 'reduceMotionChanged') {
listener = RCTDeviceEventEmitter.addListener(
REDUCE_MOTION_EVENT,
handler,
);
}
// $FlowFixMe[escaped-generic]
_subscriptions.set(handler, listener);
return {
remove: () => {
// $FlowIssue flow does not recognize handler properly
AccessibilityInfo.removeEventListener<K>(eventName, handler);
},
};
},
removeEventListener: function<K: $Keys<AccessibilityEventDefinitions>>(
eventName: K,
handler: (...$ElementType<AccessibilityEventDefinitions, K>) => void,
): void {
// $FlowFixMe[escaped-generic]
const listener = _subscriptions.get(handler);
if (!listener) {
return;
}
listener.remove();
// $FlowFixMe[escaped-generic]
_subscriptions.delete(handler);
},
/**
* Set accessibility focus to a react component.
*
* See https://reactnative.dev/docs/accessibilityinfo.html#setaccessibilityfocus
*/
setAccessibilityFocus: function(reactTag: number): void {
legacySendAccessibilityEvent(reactTag, 'focus');
},
/**
* Send a named accessibility event to a HostComponent.
*/
sendAccessibilityEvent_unstable: function(
handle: ElementRef<HostComponent<mixed>>,
eventType: AccessibilityEventTypes,
) {
// route through React renderer to distinguish between Fabric and non-Fabric handles
// iOS only supports 'focus' event types
if (eventType === 'focus') {
sendAccessibilityEvent(handle, eventType);
} else if (eventType === 'click') {
// Do nothing!
}
},
/**
* Post a string to be announced by the screen reader.
*
* See https://reactnative.dev/docs/accessibilityinfo.html#announceforaccessibility
*/
announceForAccessibility: function(announcement: string): void {
if (NativeAccessibilityInfo) {
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<number> {
return new Promise((resolve, reject) => {
if (
NativeAccessibilityInfo &&
NativeAccessibilityInfo.getRecommendedTimeoutMillis
) {
NativeAccessibilityInfo.getRecommendedTimeoutMillis(
originalTimeout,
resolve,
);
} else {
resolve(originalTimeout);
}
});
},
};
module.exports = AccessibilityInfo;