From e3a05c9e3e3fbec231cfcf98d986cd4befc5ce1f Mon Sep 17 00:00:00 2001 From: Joshua Gross Date: Fri, 8 Jan 2021 18:08:30 -0800 Subject: [PATCH] iOS implementation of sendAccessibilityEvent Summary: This is the iOS native implementation of sendAccessibilityEvent for Fabric. Changelog: [Internal] Reviewed By: shergin Differential Revision: D25857401 fbshipit-source-id: e57d2e7fd45052bcf05cee7d0cb6c55ee974f358 --- React/Fabric/Mounting/RCTMountingManager.h | 6 ++++++ React/Fabric/Mounting/RCTMountingManager.mm | 24 +++++++++++++++++++++ React/Fabric/RCTScheduler.h | 3 +++ React/Fabric/RCTScheduler.mm | 6 ++++++ React/Fabric/RCTSurfacePresenter.mm | 9 ++++++++ 5 files changed, 48 insertions(+) diff --git a/React/Fabric/Mounting/RCTMountingManager.h b/React/Fabric/Mounting/RCTMountingManager.h index 0166914bed2..986d47c040b 100644 --- a/React/Fabric/Mounting/RCTMountingManager.h +++ b/React/Fabric/Mounting/RCTMountingManager.h @@ -38,6 +38,12 @@ NS_ASSUME_NONNULL_BEGIN */ - (void)dispatchCommand:(ReactTag)reactTag commandName:(NSString *)commandName args:(NSArray *)args; +/** + * Dispatch an accessibility event to be performed on the main thread. + * Can be called from any thread. + */ +- (void)sendAccessibilityEvent:(ReactTag)reactTag eventType:(NSString *)eventType; + - (void)synchronouslyUpdateViewOnUIThread:(ReactTag)reactTag changedProps:(NSDictionary *)props componentDescriptor:(const facebook::react::ComponentDescriptor &)componentDescriptor; diff --git a/React/Fabric/Mounting/RCTMountingManager.mm b/React/Fabric/Mounting/RCTMountingManager.mm index 2d737a7fe62..4edc91d4e6d 100644 --- a/React/Fabric/Mounting/RCTMountingManager.mm +++ b/React/Fabric/Mounting/RCTMountingManager.mm @@ -180,6 +180,22 @@ static void RCTPerformMountInstructions( }); } +- (void)sendAccessibilityEvent:(ReactTag)reactTag eventType:(NSString *)eventType +{ + if (RCTIsMainQueue()) { + // Already on the proper thread, so: + // * No need to do a thread jump; + // * No need to allocate a block. + [self synchronouslyDispatchAccessbilityEventOnUIThread:reactTag eventType:eventType]; + return; + } + + RCTExecuteOnMainQueue(^{ + RCTAssertMainQueue(); + [self synchronouslyDispatchAccessbilityEventOnUIThread:reactTag eventType:eventType]; + }); +} + - (void)initiateTransaction:(MountingCoordinator::Shared const &)mountingCoordinator { SystraceSection s("-[RCTMountingManager initiateTransaction:]"); @@ -257,4 +273,12 @@ static void RCTPerformMountInstructions( [componentView handleCommand:commandName args:args]; } +- (void)synchronouslyDispatchAccessbilityEventOnUIThread:(ReactTag)reactTag eventType:(NSString *)eventType +{ + if ([@"focus" isEqualToString:eventType]) { + UIView *componentView = [_componentViewRegistry findComponentViewWithTag:reactTag]; + UIAccessibilityPostNotification(UIAccessibilityLayoutChangedNotification, componentView); + } +} + @end diff --git a/React/Fabric/RCTScheduler.h b/React/Fabric/RCTScheduler.h index 20536137226..d68a01e47c0 100644 --- a/React/Fabric/RCTScheduler.h +++ b/React/Fabric/RCTScheduler.h @@ -31,6 +31,9 @@ NS_ASSUME_NONNULL_BEGIN commandName:(std::string const &)commandName args:(folly::dynamic const)args; +- (void)schedulerDidSendAccessibilityEvent:(facebook::react::ShadowView const &)shadowView + eventType:(std::string const &)eventType; + @end /** diff --git a/React/Fabric/RCTScheduler.mm b/React/Fabric/RCTScheduler.mm index 31190002461..bd0d347efc4 100644 --- a/React/Fabric/RCTScheduler.mm +++ b/React/Fabric/RCTScheduler.mm @@ -59,6 +59,12 @@ class SchedulerDelegateProxy : public SchedulerDelegate { // Does nothing for now. } + void schedulerDidSendAccessibilityEvent(const ShadowView &shadowView, std::string const &eventType) override + { + RCTScheduler *scheduler = (__bridge RCTScheduler *)scheduler_; + [scheduler.delegate schedulerDidSendAccessibilityEvent:shadowView eventType:eventType]; + } + private: void *scheduler_; }; diff --git a/React/Fabric/RCTSurfacePresenter.mm b/React/Fabric/RCTSurfacePresenter.mm index e7fe8cf0350..70ff82ded2b 100644 --- a/React/Fabric/RCTSurfacePresenter.mm +++ b/React/Fabric/RCTSurfacePresenter.mm @@ -465,6 +465,15 @@ static BackgroundExecutor RCTGetBackgroundExecutor() [self->_mountingManager dispatchCommand:tag commandName:commandStr args:argsArray]; } +- (void)schedulerDidSendAccessibilityEvent:(const facebook::react::ShadowView &)shadowView + eventType:(const std::string &)eventType +{ + ReactTag tag = shadowView.tag; + NSString *eventTypeStr = [[NSString alloc] initWithUTF8String:eventType.c_str()]; + + [self->_mountingManager sendAccessibilityEvent:tag eventType:eventTypeStr]; +} + - (void)addObserver:(id)observer { std::unique_lock lock(_observerListMutex);