react-native-macos/React/CoreModules/RCTAccessibilityManager.mm

383 строки
15 KiB
Plaintext
Исходник Обычный вид История

/*
* 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.
*/
#import "RCTAccessibilityManager.h"
#import "RCTAccessibilityManager+Internal.h"
#import <FBReactNativeSpec/FBReactNativeSpec.h>
#import <React/RCTBridge.h>
#import <React/RCTConvert.h>
#import <React/RCTEventDispatcherProtocol.h>
#import <React/RCTLog.h>
#import <React/RCTUIManager.h>
#import "CoreModulesPlugins.h"
NSString *const RCTAccessibilityManagerDidUpdateMultiplierNotification =
@"RCTAccessibilityManagerDidUpdateMultiplierNotification";
@interface RCTAccessibilityManager () <NativeAccessibilityManagerSpec>
@property (nonatomic, copy) NSString *contentSizeCategory;
@property (nonatomic, assign) CGFloat multiplier;
@end
@implementation RCTAccessibilityManager
@synthesize viewRegistry_DEPRECATED = _viewRegistry_DEPRECATED;
@synthesize moduleRegistry = _moduleRegistry;
@synthesize multipliers = _multipliers;
RCT_EXPORT_MODULE()
+ (BOOL)requiresMainQueueSetup
{
return YES;
}
- (instancetype)init
{
if (self = [super init]) {
_multiplier = 1.0;
Refactored module access to allow for lazy loading Summary: public The `bridge.modules` dictionary provides access to all native modules, but this API requires that every module is initialized in advance so that any module can be accessed. This diff introduces a better API that will allow modules to be initialized lazily as they are needed, and deprecates `bridge.modules` (modules that use it will still work, but should be rewritten to use `bridge.moduleClasses` or `-[bridge moduleForName/Class:` instead. The rules are now as follows: * Any module that overrides `init` or `setBridge:` will be initialized on the main thread when the bridge is created * Any module that implements `constantsToExport:` will be initialized later when the config is exported (the module itself will be initialized on a background queue, but `constantsToExport:` will still be called on the main thread. * All other modules will be initialized lazily when a method is first called on them. These rules may seem slightly arcane, but they have the advantage of not violating any assumptions that may have been made by existing code - any module written under the original assumption that it would be initialized synchronously on the main thread when the bridge is created should still function exactly the same, but modules that avoid overriding `init` or `setBridge:` will now be loaded lazily. I've rewritten most of the standard modules to take advantage of this new lazy loading, with the following results: Out of the 65 modules included in UIExplorer: * 16 are initialized on the main thread when the bridge is created * A further 8 are initialized when the config is exported to JS * The remaining 41 will be initialized lazily on-demand Reviewed By: jspahrsummers Differential Revision: D2677695 fb-gh-sync-id: 507ae7e9fd6b563e89292c7371767c978e928f33
2015-11-25 14:09:00 +03:00
// TODO: can this be moved out of the startup path?
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(didReceiveNewContentSizeCategory:)
name:UIContentSizeCategoryDidChangeNotification
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(accessibilityAnnouncementDidFinish:)
name:UIAccessibilityAnnouncementDidFinishNotification
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(boldTextStatusDidChange:)
name:UIAccessibilityBoldTextStatusDidChangeNotification
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(grayscaleStatusDidChange:)
name:UIAccessibilityGrayscaleStatusDidChangeNotification
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(invertColorsStatusDidChange:)
name:UIAccessibilityInvertColorsStatusDidChangeNotification
object:nil];
- Add support for "reduce motion" into AccessibilityInfo (#23839) Summary: This PR adds `isReduceMotionEnabled()` to `AccessibilityInfo` in other to add support for "reduce motion", exposing the Operational System's settings option. Additionally, it adds a new event, `reduceMotionChanged`, in order to listen for this flag's update. With this feature, developers will be able to disable or reduce animations, _**something that will be required as soon as WCAG 2.1 draft got approved**._ See [WCAG 2.1 — 2.3.3 Animations from Interaction criteria](https://knowbility.org/blog/2018/WCAG21-233Animations/) It's exposed by [`UIAccessibility`' isReduceMotionEnabled ](https://developer.apple.com/documentation/uikit/uiaccessibility/1615133-isreducemotionenabled ) on iOS and [Settings.Global.TRANSITION_ANIMATION_SCALE](https://developer.android.com/reference/android/provider/Settings.Global#TRANSITION_ANIMATION_SCALE) on Android. Up until now, `AccessibilityInfo` only exposes screen reader flag. By adding this second accessibility option, it's a good opportunity to rename `fetch` method to an appropriate name, `isScreenReaderEnabled`, as well as rename `change` event to `screenReaderChanged`, which will make it clearer and more specific. (In case it's approved, a follow-up PR could exposes [more iOS acessibility flags](https://developer.apple.com/documentation/uikit/uiaccessibility), such as `isShakeToUndoEnabled`, `isReduceTransparencyEnabled`, `isGrayscaleEnabled`, `isInvertColorsEnabled`) (iOS code inspired by [phonegap-mobile-accessibility](https://github.com/phonegap/phonegap-mobile-accessibility). And Android by [Flutter](https://github.com/flutter/engine/blob/master/shell/platform/android/io/flutter/view/AccessibilityBridge.java )) Pull Request resolved: https://github.com/facebook/react-native/pull/23839 Differential Revision: D14406227 Pulled By: hramos fbshipit-source-id: adf43be84c488522bf1e29d862681220ad193883
2019-03-13 06:23:54 +03:00
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(reduceMotionStatusDidChange:)
name:UIAccessibilityReduceMotionStatusDidChangeNotification
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(reduceTransparencyStatusDidChange:)
name:UIAccessibilityReduceTransparencyStatusDidChangeNotification
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(voiceVoiceOverStatusDidChange:)
name:UIAccessibilityVoiceOverStatusDidChangeNotification
object:nil];
self.contentSizeCategory = RCTSharedApplication().preferredContentSizeCategory;
_isBoldTextEnabled = UIAccessibilityIsBoldTextEnabled();
_isGrayscaleEnabled = UIAccessibilityIsGrayscaleEnabled();
_isInvertColorsEnabled = UIAccessibilityIsInvertColorsEnabled();
- Add support for "reduce motion" into AccessibilityInfo (#23839) Summary: This PR adds `isReduceMotionEnabled()` to `AccessibilityInfo` in other to add support for "reduce motion", exposing the Operational System's settings option. Additionally, it adds a new event, `reduceMotionChanged`, in order to listen for this flag's update. With this feature, developers will be able to disable or reduce animations, _**something that will be required as soon as WCAG 2.1 draft got approved**._ See [WCAG 2.1 — 2.3.3 Animations from Interaction criteria](https://knowbility.org/blog/2018/WCAG21-233Animations/) It's exposed by [`UIAccessibility`' isReduceMotionEnabled ](https://developer.apple.com/documentation/uikit/uiaccessibility/1615133-isreducemotionenabled ) on iOS and [Settings.Global.TRANSITION_ANIMATION_SCALE](https://developer.android.com/reference/android/provider/Settings.Global#TRANSITION_ANIMATION_SCALE) on Android. Up until now, `AccessibilityInfo` only exposes screen reader flag. By adding this second accessibility option, it's a good opportunity to rename `fetch` method to an appropriate name, `isScreenReaderEnabled`, as well as rename `change` event to `screenReaderChanged`, which will make it clearer and more specific. (In case it's approved, a follow-up PR could exposes [more iOS acessibility flags](https://developer.apple.com/documentation/uikit/uiaccessibility), such as `isShakeToUndoEnabled`, `isReduceTransparencyEnabled`, `isGrayscaleEnabled`, `isInvertColorsEnabled`) (iOS code inspired by [phonegap-mobile-accessibility](https://github.com/phonegap/phonegap-mobile-accessibility). And Android by [Flutter](https://github.com/flutter/engine/blob/master/shell/platform/android/io/flutter/view/AccessibilityBridge.java )) Pull Request resolved: https://github.com/facebook/react-native/pull/23839 Differential Revision: D14406227 Pulled By: hramos fbshipit-source-id: adf43be84c488522bf1e29d862681220ad193883
2019-03-13 06:23:54 +03:00
_isReduceMotionEnabled = UIAccessibilityIsReduceMotionEnabled();
_isReduceTransparencyEnabled = UIAccessibilityIsReduceTransparencyEnabled();
_isVoiceOverEnabled = UIAccessibilityIsVoiceOverRunning();
}
return self;
}
- (void)didReceiveNewContentSizeCategory:(NSNotification *)note
{
self.contentSizeCategory = note.userInfo[UIContentSizeCategoryNewValueKey];
}
- (void)accessibilityAnnouncementDidFinish:(__unused NSNotification *)notification
{
NSDictionary *userInfo = notification.userInfo;
// Response dictionary to populate the event with.
NSDictionary *response = @{
@"announcement" : userInfo[UIAccessibilityAnnouncementKeyStringValue],
@"success" : userInfo[UIAccessibilityAnnouncementKeyWasSuccessful]
};
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
[[_moduleRegistry moduleForName:"EventDispatcher"] sendDeviceEventWithName:@"announcementFinished" body:response];
#pragma clang diagnostic pop
}
- (void)boldTextStatusDidChange:(__unused NSNotification *)notification
{
BOOL newBoldTextEnabled = UIAccessibilityIsBoldTextEnabled();
if (_isBoldTextEnabled != newBoldTextEnabled) {
_isBoldTextEnabled = newBoldTextEnabled;
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
[[_moduleRegistry moduleForName:"EventDispatcher"] sendDeviceEventWithName:@"boldTextChanged"
body:@(_isBoldTextEnabled)];
#pragma clang diagnostic pop
}
}
- (void)grayscaleStatusDidChange:(__unused NSNotification *)notification
{
BOOL newGrayscaleEnabled = UIAccessibilityIsGrayscaleEnabled();
if (_isGrayscaleEnabled != newGrayscaleEnabled) {
_isGrayscaleEnabled = newGrayscaleEnabled;
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
[[_moduleRegistry moduleForName:"EventDispatcher"] sendDeviceEventWithName:@"grayscaleChanged"
body:@(_isGrayscaleEnabled)];
#pragma clang diagnostic pop
}
}
- (void)invertColorsStatusDidChange:(__unused NSNotification *)notification
{
BOOL newInvertColorsEnabled = UIAccessibilityIsInvertColorsEnabled();
if (_isInvertColorsEnabled != newInvertColorsEnabled) {
_isInvertColorsEnabled = newInvertColorsEnabled;
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
[[_moduleRegistry moduleForName:"EventDispatcher"] sendDeviceEventWithName:@"invertColorsChanged"
body:@(_isInvertColorsEnabled)];
#pragma clang diagnostic pop
}
}
- Add support for "reduce motion" into AccessibilityInfo (#23839) Summary: This PR adds `isReduceMotionEnabled()` to `AccessibilityInfo` in other to add support for "reduce motion", exposing the Operational System's settings option. Additionally, it adds a new event, `reduceMotionChanged`, in order to listen for this flag's update. With this feature, developers will be able to disable or reduce animations, _**something that will be required as soon as WCAG 2.1 draft got approved**._ See [WCAG 2.1 — 2.3.3 Animations from Interaction criteria](https://knowbility.org/blog/2018/WCAG21-233Animations/) It's exposed by [`UIAccessibility`' isReduceMotionEnabled ](https://developer.apple.com/documentation/uikit/uiaccessibility/1615133-isreducemotionenabled ) on iOS and [Settings.Global.TRANSITION_ANIMATION_SCALE](https://developer.android.com/reference/android/provider/Settings.Global#TRANSITION_ANIMATION_SCALE) on Android. Up until now, `AccessibilityInfo` only exposes screen reader flag. By adding this second accessibility option, it's a good opportunity to rename `fetch` method to an appropriate name, `isScreenReaderEnabled`, as well as rename `change` event to `screenReaderChanged`, which will make it clearer and more specific. (In case it's approved, a follow-up PR could exposes [more iOS acessibility flags](https://developer.apple.com/documentation/uikit/uiaccessibility), such as `isShakeToUndoEnabled`, `isReduceTransparencyEnabled`, `isGrayscaleEnabled`, `isInvertColorsEnabled`) (iOS code inspired by [phonegap-mobile-accessibility](https://github.com/phonegap/phonegap-mobile-accessibility). And Android by [Flutter](https://github.com/flutter/engine/blob/master/shell/platform/android/io/flutter/view/AccessibilityBridge.java )) Pull Request resolved: https://github.com/facebook/react-native/pull/23839 Differential Revision: D14406227 Pulled By: hramos fbshipit-source-id: adf43be84c488522bf1e29d862681220ad193883
2019-03-13 06:23:54 +03:00
- (void)reduceMotionStatusDidChange:(__unused NSNotification *)notification
{
BOOL newReduceMotionEnabled = UIAccessibilityIsReduceMotionEnabled();
if (_isReduceMotionEnabled != newReduceMotionEnabled) {
_isReduceMotionEnabled = newReduceMotionEnabled;
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
[[_moduleRegistry moduleForName:"EventDispatcher"] sendDeviceEventWithName:@"reduceMotionChanged"
body:@(_isReduceMotionEnabled)];
- Add support for "reduce motion" into AccessibilityInfo (#23839) Summary: This PR adds `isReduceMotionEnabled()` to `AccessibilityInfo` in other to add support for "reduce motion", exposing the Operational System's settings option. Additionally, it adds a new event, `reduceMotionChanged`, in order to listen for this flag's update. With this feature, developers will be able to disable or reduce animations, _**something that will be required as soon as WCAG 2.1 draft got approved**._ See [WCAG 2.1 — 2.3.3 Animations from Interaction criteria](https://knowbility.org/blog/2018/WCAG21-233Animations/) It's exposed by [`UIAccessibility`' isReduceMotionEnabled ](https://developer.apple.com/documentation/uikit/uiaccessibility/1615133-isreducemotionenabled ) on iOS and [Settings.Global.TRANSITION_ANIMATION_SCALE](https://developer.android.com/reference/android/provider/Settings.Global#TRANSITION_ANIMATION_SCALE) on Android. Up until now, `AccessibilityInfo` only exposes screen reader flag. By adding this second accessibility option, it's a good opportunity to rename `fetch` method to an appropriate name, `isScreenReaderEnabled`, as well as rename `change` event to `screenReaderChanged`, which will make it clearer and more specific. (In case it's approved, a follow-up PR could exposes [more iOS acessibility flags](https://developer.apple.com/documentation/uikit/uiaccessibility), such as `isShakeToUndoEnabled`, `isReduceTransparencyEnabled`, `isGrayscaleEnabled`, `isInvertColorsEnabled`) (iOS code inspired by [phonegap-mobile-accessibility](https://github.com/phonegap/phonegap-mobile-accessibility). And Android by [Flutter](https://github.com/flutter/engine/blob/master/shell/platform/android/io/flutter/view/AccessibilityBridge.java )) Pull Request resolved: https://github.com/facebook/react-native/pull/23839 Differential Revision: D14406227 Pulled By: hramos fbshipit-source-id: adf43be84c488522bf1e29d862681220ad193883
2019-03-13 06:23:54 +03:00
#pragma clang diagnostic pop
}
}
- (void)reduceTransparencyStatusDidChange:(__unused NSNotification *)notification
{
BOOL newReduceTransparencyEnabled = UIAccessibilityIsReduceTransparencyEnabled();
if (_isReduceTransparencyEnabled != newReduceTransparencyEnabled) {
_isReduceTransparencyEnabled = newReduceTransparencyEnabled;
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
[[_moduleRegistry moduleForName:"EventDispatcher"] sendDeviceEventWithName:@"reduceTransparencyChanged"
body:@(_isReduceTransparencyEnabled)];
#pragma clang diagnostic pop
}
}
- (void)voiceVoiceOverStatusDidChange:(__unused NSNotification *)notification
{
BOOL isVoiceOverEnabled = UIAccessibilityIsVoiceOverRunning();
[self _setIsVoiceOverEnabled:isVoiceOverEnabled];
}
- (void)_setIsVoiceOverEnabled:(BOOL)isVoiceOverEnabled
{
if (_isVoiceOverEnabled != isVoiceOverEnabled) {
_isVoiceOverEnabled = isVoiceOverEnabled;
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
[[_moduleRegistry moduleForName:"EventDispatcher"] sendDeviceEventWithName:@"screenReaderChanged"
body:@(_isVoiceOverEnabled)];
#pragma clang diagnostic pop
}
}
- (void)setContentSizeCategory:(NSString *)contentSizeCategory
{
if (_contentSizeCategory != contentSizeCategory) {
_contentSizeCategory = [contentSizeCategory copy];
[self invalidateMultiplier];
}
}
- (void)invalidateMultiplier
{
self.multiplier = [self multiplierForContentSizeCategory:_contentSizeCategory];
[[NSNotificationCenter defaultCenter] postNotificationName:RCTAccessibilityManagerDidUpdateMultiplierNotification
object:self];
}
- (CGFloat)multiplierForContentSizeCategory:(NSString *)category
{
NSNumber *m = self.multipliers[category];
if (m.doubleValue <= 0.0) {
RCTLogError(@"Can't determine multiplier for category %@. Using 1.0.", category);
m = @1.0;
}
return m.doubleValue;
}
- (void)setMultipliers:(NSDictionary<NSString *, NSNumber *> *)multipliers
{
if (_multipliers != multipliers) {
_multipliers = [multipliers copy];
[self invalidateMultiplier];
}
}
- (NSDictionary<NSString *, NSNumber *> *)multipliers
{
if (_multipliers == nil) {
_multipliers = @{
UIContentSizeCategoryExtraSmall : @0.823,
UIContentSizeCategorySmall : @0.882,
UIContentSizeCategoryMedium : @0.941,
UIContentSizeCategoryLarge : @1.0,
UIContentSizeCategoryExtraLarge : @1.118,
UIContentSizeCategoryExtraExtraLarge : @1.235,
UIContentSizeCategoryExtraExtraExtraLarge : @1.353,
UIContentSizeCategoryAccessibilityMedium : @1.786,
UIContentSizeCategoryAccessibilityLarge : @2.143,
UIContentSizeCategoryAccessibilityExtraLarge : @2.643,
UIContentSizeCategoryAccessibilityExtraExtraLarge : @3.143,
UIContentSizeCategoryAccessibilityExtraExtraExtraLarge : @3.571
};
}
return _multipliers;
}
RCT_EXPORT_METHOD(setAccessibilityContentSizeMultipliers
: (JS::NativeAccessibilityManager::SpecSetAccessibilityContentSizeMultipliersJSMultipliers &)
JSMultipliers)
{
NSMutableDictionary<NSString *, NSNumber *> *multipliers = [NSMutableDictionary new];
setMultipliers(multipliers, UIContentSizeCategoryExtraSmall, JSMultipliers.extraSmall());
setMultipliers(multipliers, UIContentSizeCategorySmall, JSMultipliers.small());
setMultipliers(multipliers, UIContentSizeCategoryMedium, JSMultipliers.medium());
setMultipliers(multipliers, UIContentSizeCategoryLarge, JSMultipliers.large());
setMultipliers(multipliers, UIContentSizeCategoryExtraLarge, JSMultipliers.extraLarge());
setMultipliers(multipliers, UIContentSizeCategoryExtraExtraLarge, JSMultipliers.extraExtraLarge());
setMultipliers(multipliers, UIContentSizeCategoryExtraExtraExtraLarge, JSMultipliers.extraExtraExtraLarge());
setMultipliers(multipliers, UIContentSizeCategoryAccessibilityMedium, JSMultipliers.accessibilityMedium());
setMultipliers(multipliers, UIContentSizeCategoryAccessibilityLarge, JSMultipliers.accessibilityLarge());
setMultipliers(multipliers, UIContentSizeCategoryAccessibilityExtraLarge, JSMultipliers.accessibilityExtraLarge());
setMultipliers(
multipliers, UIContentSizeCategoryAccessibilityExtraExtraLarge, JSMultipliers.accessibilityExtraExtraLarge());
setMultipliers(
multipliers,
UIContentSizeCategoryAccessibilityExtraExtraExtraLarge,
JSMultipliers.accessibilityExtraExtraExtraLarge());
self.multipliers = multipliers;
}
static void setMultipliers(
NSMutableDictionary<NSString *, NSNumber *> *multipliers,
NSString *key,
folly::Optional<double> optionalDouble)
{
if (optionalDouble.hasValue()) {
multipliers[key] = @(optionalDouble.value());
}
}
RCT_EXPORT_METHOD(setAccessibilityFocus : (double)reactTag)
{
dispatch_async(dispatch_get_main_queue(), ^{
UIView *view = [self.viewRegistry_DEPRECATED viewForReactTag:@(reactTag)];
UIAccessibilityPostNotification(UIAccessibilityLayoutChangedNotification, view);
});
}
RCT_EXPORT_METHOD(announceForAccessibility : (NSString *)announcement)
{
UIAccessibilityPostNotification(UIAccessibilityAnnouncementNotification, announcement);
}
RCT_EXPORT_METHOD(getMultiplier : (RCTResponseSenderBlock)callback)
{
if (callback) {
callback(@[ @(self.multiplier) ]);
}
}
RCT_EXPORT_METHOD(getCurrentBoldTextState
: (RCTResponseSenderBlock)onSuccess onError
: (__unused RCTResponseSenderBlock)onError)
{
onSuccess(@[ @(_isBoldTextEnabled) ]);
}
RCT_EXPORT_METHOD(getCurrentGrayscaleState
: (RCTResponseSenderBlock)onSuccess onError
: (__unused RCTResponseSenderBlock)onError)
{
onSuccess(@[ @(_isGrayscaleEnabled) ]);
}
RCT_EXPORT_METHOD(getCurrentInvertColorsState
: (RCTResponseSenderBlock)onSuccess onError
: (__unused RCTResponseSenderBlock)onError)
{
onSuccess(@[ @(_isInvertColorsEnabled) ]);
}
RCT_EXPORT_METHOD(getCurrentReduceMotionState
: (RCTResponseSenderBlock)onSuccess onError
: (__unused RCTResponseSenderBlock)onError)
{
onSuccess(@[ @(_isReduceMotionEnabled) ]);
}
RCT_EXPORT_METHOD(getCurrentReduceTransparencyState
: (RCTResponseSenderBlock)onSuccess onError
: (__unused RCTResponseSenderBlock)onError)
- Add support for "reduce motion" into AccessibilityInfo (#23839) Summary: This PR adds `isReduceMotionEnabled()` to `AccessibilityInfo` in other to add support for "reduce motion", exposing the Operational System's settings option. Additionally, it adds a new event, `reduceMotionChanged`, in order to listen for this flag's update. With this feature, developers will be able to disable or reduce animations, _**something that will be required as soon as WCAG 2.1 draft got approved**._ See [WCAG 2.1 — 2.3.3 Animations from Interaction criteria](https://knowbility.org/blog/2018/WCAG21-233Animations/) It's exposed by [`UIAccessibility`' isReduceMotionEnabled ](https://developer.apple.com/documentation/uikit/uiaccessibility/1615133-isreducemotionenabled ) on iOS and [Settings.Global.TRANSITION_ANIMATION_SCALE](https://developer.android.com/reference/android/provider/Settings.Global#TRANSITION_ANIMATION_SCALE) on Android. Up until now, `AccessibilityInfo` only exposes screen reader flag. By adding this second accessibility option, it's a good opportunity to rename `fetch` method to an appropriate name, `isScreenReaderEnabled`, as well as rename `change` event to `screenReaderChanged`, which will make it clearer and more specific. (In case it's approved, a follow-up PR could exposes [more iOS acessibility flags](https://developer.apple.com/documentation/uikit/uiaccessibility), such as `isShakeToUndoEnabled`, `isReduceTransparencyEnabled`, `isGrayscaleEnabled`, `isInvertColorsEnabled`) (iOS code inspired by [phonegap-mobile-accessibility](https://github.com/phonegap/phonegap-mobile-accessibility). And Android by [Flutter](https://github.com/flutter/engine/blob/master/shell/platform/android/io/flutter/view/AccessibilityBridge.java )) Pull Request resolved: https://github.com/facebook/react-native/pull/23839 Differential Revision: D14406227 Pulled By: hramos fbshipit-source-id: adf43be84c488522bf1e29d862681220ad193883
2019-03-13 06:23:54 +03:00
{
onSuccess(@[ @(_isReduceTransparencyEnabled) ]);
- Add support for "reduce motion" into AccessibilityInfo (#23839) Summary: This PR adds `isReduceMotionEnabled()` to `AccessibilityInfo` in other to add support for "reduce motion", exposing the Operational System's settings option. Additionally, it adds a new event, `reduceMotionChanged`, in order to listen for this flag's update. With this feature, developers will be able to disable or reduce animations, _**something that will be required as soon as WCAG 2.1 draft got approved**._ See [WCAG 2.1 — 2.3.3 Animations from Interaction criteria](https://knowbility.org/blog/2018/WCAG21-233Animations/) It's exposed by [`UIAccessibility`' isReduceMotionEnabled ](https://developer.apple.com/documentation/uikit/uiaccessibility/1615133-isreducemotionenabled ) on iOS and [Settings.Global.TRANSITION_ANIMATION_SCALE](https://developer.android.com/reference/android/provider/Settings.Global#TRANSITION_ANIMATION_SCALE) on Android. Up until now, `AccessibilityInfo` only exposes screen reader flag. By adding this second accessibility option, it's a good opportunity to rename `fetch` method to an appropriate name, `isScreenReaderEnabled`, as well as rename `change` event to `screenReaderChanged`, which will make it clearer and more specific. (In case it's approved, a follow-up PR could exposes [more iOS acessibility flags](https://developer.apple.com/documentation/uikit/uiaccessibility), such as `isShakeToUndoEnabled`, `isReduceTransparencyEnabled`, `isGrayscaleEnabled`, `isInvertColorsEnabled`) (iOS code inspired by [phonegap-mobile-accessibility](https://github.com/phonegap/phonegap-mobile-accessibility). And Android by [Flutter](https://github.com/flutter/engine/blob/master/shell/platform/android/io/flutter/view/AccessibilityBridge.java )) Pull Request resolved: https://github.com/facebook/react-native/pull/23839 Differential Revision: D14406227 Pulled By: hramos fbshipit-source-id: adf43be84c488522bf1e29d862681220ad193883
2019-03-13 06:23:54 +03:00
}
RCT_EXPORT_METHOD(getCurrentVoiceOverState
: (RCTResponseSenderBlock)onSuccess onError
: (__unused RCTResponseSenderBlock)onError)
{
onSuccess(@[ @(_isVoiceOverEnabled) ]);
}
Part 2: Update ObjC++ codegen classes to use ObjCTurboModule::InitParams Summary: ## Summary Please check out D21035209. ## Changes - Codemod all ObjC NativeModule `getTurboModuleWithJsInvoker:nativeInvoker:perfLogger` methods to `getTurboModule:(const ObjCTurboModule::Args)` ## Script ``` var withSpaces = (...args) => args.join('\s*') var regexString = withSpaces( '-', '\(', 'std::shared_ptr', '<', '(?<turboModuleClass>(facebook::react::|react::|::|)TurboModule)', '>', '\)', 'getTurboModuleWithJsInvoker', ':', '\(', 'std::shared_ptr', '<', '(?<fbNamespace>(facebook::react::|react::|::|))CallInvoker', '>', '\)', '(?<jsInvokerInstance>[A-Za-z0-9]+)', 'nativeInvoker', ':', '\(', 'std::shared_ptr', '<', '(facebook::react::|react::|::|)CallInvoker', '>', '\)', '(?<nativeInvokerInstance>[A-Za-z0-9]+)', 'perfLogger', ':', '\(', 'id', '<', 'RCTTurboModulePerformanceLogger', '>', '\)', '(?<perfLoggerInstance>[A-Za-z0-9]+)', '{', 'return', 'std::make_shared', '<', '(?<specName>(facebook::react::|react::|::|)Native[%A-Za-z0-9]+SpecJSI)', '>', '\(', 'self', ',', '\k<jsInvokerInstance>', ',', '\k<nativeInvokerInstance>', ',', '\k<perfLoggerInstance>', '\)', ';', '}', ) var replaceString = `- (std::shared_ptr<$<turboModuleClass>>) getTurboModule:(const $<fbNamespace>ObjCTurboModule::InitParams &)params { return std::make_shared<$<specName>>(params); }` const exec = require('../lib/exec'); const abspath = require('../lib/abspath'); const relpath = require('../lib/relpath'); const readFile = (filename) => require('fs').readFileSync(filename, 'utf8'); const writeFile = (filename, content) => require('fs').writeFileSync(filename, content); function main() { const tmFiles = exec('cd ~/fbsource && xbgs -n 10000 -l getTurboModuleWithJsInvoker:').split('\n').filter(Boolean); tmFiles .filter((filename) => !filename.includes('microsoft-fork-of-react-native')) .map(abspath) .forEach((filename) => { const source = readFile(filename); const newSource = source.replace(new RegExp(regexString, 'g'), replaceString); if (source == newSource) { console.log(relpath(filename)); } writeFile(filename, newSource); }); } if (!module.parent) { main(); } ``` ## Re-generating diff ``` > hg revert -r .^ --all > node index.js # run script ``` Changelog: [iOS][Changed] - Make all ObjC NativeModules create TurboModules using ObjCTurboModule::Args Reviewed By: PeteTheHeat Differential Revision: D21036265 fbshipit-source-id: 404bcc548d1775ef23d793527606d02fe384a0a2
2020-04-17 03:23:39 +03:00
- (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:
(const facebook::react::ObjCTurboModule::InitParams &)params
{
Part 2: Update ObjC++ codegen classes to use ObjCTurboModule::InitParams Summary: ## Summary Please check out D21035209. ## Changes - Codemod all ObjC NativeModule `getTurboModuleWithJsInvoker:nativeInvoker:perfLogger` methods to `getTurboModule:(const ObjCTurboModule::Args)` ## Script ``` var withSpaces = (...args) => args.join('\s*') var regexString = withSpaces( '-', '\(', 'std::shared_ptr', '<', '(?<turboModuleClass>(facebook::react::|react::|::|)TurboModule)', '>', '\)', 'getTurboModuleWithJsInvoker', ':', '\(', 'std::shared_ptr', '<', '(?<fbNamespace>(facebook::react::|react::|::|))CallInvoker', '>', '\)', '(?<jsInvokerInstance>[A-Za-z0-9]+)', 'nativeInvoker', ':', '\(', 'std::shared_ptr', '<', '(facebook::react::|react::|::|)CallInvoker', '>', '\)', '(?<nativeInvokerInstance>[A-Za-z0-9]+)', 'perfLogger', ':', '\(', 'id', '<', 'RCTTurboModulePerformanceLogger', '>', '\)', '(?<perfLoggerInstance>[A-Za-z0-9]+)', '{', 'return', 'std::make_shared', '<', '(?<specName>(facebook::react::|react::|::|)Native[%A-Za-z0-9]+SpecJSI)', '>', '\(', 'self', ',', '\k<jsInvokerInstance>', ',', '\k<nativeInvokerInstance>', ',', '\k<perfLoggerInstance>', '\)', ';', '}', ) var replaceString = `- (std::shared_ptr<$<turboModuleClass>>) getTurboModule:(const $<fbNamespace>ObjCTurboModule::InitParams &)params { return std::make_shared<$<specName>>(params); }` const exec = require('../lib/exec'); const abspath = require('../lib/abspath'); const relpath = require('../lib/relpath'); const readFile = (filename) => require('fs').readFileSync(filename, 'utf8'); const writeFile = (filename, content) => require('fs').writeFileSync(filename, content); function main() { const tmFiles = exec('cd ~/fbsource && xbgs -n 10000 -l getTurboModuleWithJsInvoker:').split('\n').filter(Boolean); tmFiles .filter((filename) => !filename.includes('microsoft-fork-of-react-native')) .map(abspath) .forEach((filename) => { const source = readFile(filename); const newSource = source.replace(new RegExp(regexString, 'g'), replaceString); if (source == newSource) { console.log(relpath(filename)); } writeFile(filename, newSource); }); } if (!module.parent) { main(); } ``` ## Re-generating diff ``` > hg revert -r .^ --all > node index.js # run script ``` Changelog: [iOS][Changed] - Make all ObjC NativeModules create TurboModules using ObjCTurboModule::Args Reviewed By: PeteTheHeat Differential Revision: D21036265 fbshipit-source-id: 404bcc548d1775ef23d793527606d02fe384a0a2
2020-04-17 03:23:39 +03:00
return std::make_shared<facebook::react::NativeAccessibilityManagerSpecJSI>(params);
}
#pragma mark - Internal
void RCTAccessibilityManagerSetIsVoiceOverEnabled(
RCTAccessibilityManager *accessibilityManager,
BOOL isVoiceOverEnabled)
{
[accessibilityManager _setIsVoiceOverEnabled:isVoiceOverEnabled];
}
@end
@implementation RCTBridge (RCTAccessibilityManager)
- (RCTAccessibilityManager *)accessibilityManager
{
Refactored module access to allow for lazy loading Summary: public The `bridge.modules` dictionary provides access to all native modules, but this API requires that every module is initialized in advance so that any module can be accessed. This diff introduces a better API that will allow modules to be initialized lazily as they are needed, and deprecates `bridge.modules` (modules that use it will still work, but should be rewritten to use `bridge.moduleClasses` or `-[bridge moduleForName/Class:` instead. The rules are now as follows: * Any module that overrides `init` or `setBridge:` will be initialized on the main thread when the bridge is created * Any module that implements `constantsToExport:` will be initialized later when the config is exported (the module itself will be initialized on a background queue, but `constantsToExport:` will still be called on the main thread. * All other modules will be initialized lazily when a method is first called on them. These rules may seem slightly arcane, but they have the advantage of not violating any assumptions that may have been made by existing code - any module written under the original assumption that it would be initialized synchronously on the main thread when the bridge is created should still function exactly the same, but modules that avoid overriding `init` or `setBridge:` will now be loaded lazily. I've rewritten most of the standard modules to take advantage of this new lazy loading, with the following results: Out of the 65 modules included in UIExplorer: * 16 are initialized on the main thread when the bridge is created * A further 8 are initialized when the config is exported to JS * The remaining 41 will be initialized lazily on-demand Reviewed By: jspahrsummers Differential Revision: D2677695 fb-gh-sync-id: 507ae7e9fd6b563e89292c7371767c978e928f33
2015-11-25 14:09:00 +03:00
return [self moduleForClass:[RCTAccessibilityManager class]];
}
@end
Class RCTAccessibilityManagerCls(void)
{
return RCTAccessibilityManager.class;
}