diff --git a/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm b/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm index ca76e8832734bdb2de53446e05e0b5c46a425f21..3fb1f2ea5a3795bbdc56a81daa0b04e2d3f2e17d 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm @@ -127,8 +127,8 @@ class PlatformMessageResponseDarwin : public blink::PlatformMessageResponse { _orientationPreferences = UIInterfaceOrientationMaskAll; _statusBarStyle = UIStatusBarStyleDefault; - _platformView = - std::make_shared(reinterpret_cast(self.view.layer)); + _platformView = std::make_shared( + reinterpret_cast(self.view.layer), self); _platformView->Attach( // First frame callback. diff --git a/shell/platform/darwin/ios/framework/Source/accessibility_bridge.h b/shell/platform/darwin/ios/framework/Source/accessibility_bridge.h index 574662d5f488115ee1ac266b4f11ab778478eca3..43a695a826f03a91f0128c6d3fa3b02a011b126f 100644 --- a/shell/platform/darwin/ios/framework/Source/accessibility_bridge.h +++ b/shell/platform/darwin/ios/framework/Source/accessibility_bridge.h @@ -12,6 +12,7 @@ #include "flutter/fml/platform/darwin/scoped_nsobject.h" #include "flutter/lib/ui/semantics/semantics_node.h" +#include "flutter/shell/platform/darwin/ios/framework/Headers/FlutterChannels.h" #include "flutter/shell/platform/darwin/ios/framework/Source/FlutterView.h" #include "lib/fxl/macros.h" #include "third_party/skia/include/core/SkMatrix44.h" @@ -58,10 +59,12 @@ class AccessibilityBridge final { void VisitObjectsRecursivelyAndRemove(SemanticsObject* object, NSMutableArray* doomed_uids); void ReleaseObjects(std::unordered_map& objects); + void HandleEvent(NSDictionary* annotatedEvent); UIView* view_; PlatformViewIOS* platform_view_; fml::scoped_nsobject> objects_; + fml::scoped_nsprotocol accessibility_channel_; FXL_DISALLOW_COPY_AND_ASSIGN(AccessibilityBridge); }; diff --git a/shell/platform/darwin/ios/framework/Source/accessibility_bridge.mm b/shell/platform/darwin/ios/framework/Source/accessibility_bridge.mm index 28518f8a9ffe60640e46455d56197e3f16fb1dca..06135d426c8f39fe9857874ff0e416e2fa2c61e1 100644 --- a/shell/platform/darwin/ios/framework/Source/accessibility_bridge.mm +++ b/shell/platform/darwin/ios/framework/Source/accessibility_bridge.mm @@ -240,8 +240,6 @@ bool GeometryComparator(SemanticsObject* a, SemanticsObject* b) { if (!_node.HasAction(action)) return NO; _bridge->DispatchSemanticsAction(_uid, action); - // TODO(tvolkert): provide meaningful string (e.g. "page 2 of 5") - UIAccessibilityPostNotification(UIAccessibilityPageScrolledNotification, nil); return YES; } @@ -320,6 +318,12 @@ bool GeometryComparator(SemanticsObject* a, SemanticsObject* b) { : [[_semanticsObject parent] accessibilityContainer]; } +#pragma mark - UIAccessibilityAction overrides + +- (BOOL)accessibilityScroll:(UIAccessibilityScrollDirection)direction { + return [_semanticsObject accessibilityScroll:direction]; +} + @end #pragma mark - AccessibilityBridge impl @@ -327,10 +331,19 @@ bool GeometryComparator(SemanticsObject* a, SemanticsObject* b) { namespace shell { AccessibilityBridge::AccessibilityBridge(UIView* view, PlatformViewIOS* platform_view) - : view_(view), platform_view_(platform_view), objects_([[NSMutableDictionary alloc] init]) {} + : view_(view), platform_view_(platform_view), objects_([[NSMutableDictionary alloc] init]) { + accessibility_channel_.reset([[FlutterBasicMessageChannel alloc] + initWithName:@"flutter/accessibility" + binaryMessenger:platform_view->binary_messenger() + codec:[FlutterStandardMessageCodec sharedInstance]]); + [accessibility_channel_.get() setMessageHandler:^(id message, FlutterReply reply) { + HandleEvent((NSDictionary*)message); + }]; +} AccessibilityBridge::~AccessibilityBridge() { view_.accessibilityElements = nil; + [accessibility_channel_.get() setMessageHandler:nil]; } void AccessibilityBridge::UpdateSemantics(std::vector nodes) { @@ -375,28 +388,10 @@ void AccessibilityBridge::UpdateSemantics(std::vector node NSMutableArray* doomed_uids = [NSMutableArray arrayWithArray:[objects_.get() allKeys]]; if (root) VisitObjectsRecursivelyAndRemove(root, doomed_uids); - - bool focused_object_doomed = false; - for (NSNumber* uid in doomed_uids) { - SemanticsObject* object = objects_.get()[uid]; - if ([object accessibilityElementIsFocused]) { - focused_object_doomed = true; - break; - } - } - [objects_ removeObjectsForKeys:doomed_uids]; - if (focused_object_doomed) { - // Previously focused element is no longer in the tree. - // Passing `nil` as argument to let iOS figure out what to focus next. - // TODO(goderbauer): Figure out which element should be focused next and post - // UIAccessibilityLayoutChangedNotification with that element instead. - UIAccessibilityPostNotification(UIAccessibilityScreenChangedNotification, nil); - } else { - // Passing `nil` as argument to keep focus where it is. - UIAccessibilityPostNotification(UIAccessibilityLayoutChangedNotification, nil); - } + // TODO(goderbauer): figure out which node to focus next. + UIAccessibilityPostNotification(UIAccessibilityLayoutChangedNotification, nil); } void AccessibilityBridge::DispatchSemanticsAction(int32_t uid, blink::SemanticsAction action) { @@ -419,4 +414,14 @@ void AccessibilityBridge::VisitObjectsRecursivelyAndRemove(SemanticsObject* obje VisitObjectsRecursivelyAndRemove(child, doomed_uids); } +void AccessibilityBridge::HandleEvent(NSDictionary* annotatedEvent) { + NSString* type = annotatedEvent[@"type"]; + if ([type isEqualToString:@"scroll"]) { + // TODO(tvolkert): provide meaningful string (e.g. "page 2 of 5") + UIAccessibilityPostNotification(UIAccessibilityPageScrolledNotification, @""); + } else { + NSCAssert(NO, @"Invalid event type %@", type); + } +} + } // namespace shell diff --git a/shell/platform/darwin/ios/platform_view_ios.h b/shell/platform/darwin/ios/platform_view_ios.h index 0c2da60faff4634099fe8baf3c55d4d9fd71f95a..0b4bc9d9ecad71d85cd26bb1b6b7c84322f2cb99 100644 --- a/shell/platform/darwin/ios/platform_view_ios.h +++ b/shell/platform/darwin/ios/platform_view_ios.h @@ -22,7 +22,8 @@ namespace shell { class PlatformViewIOS : public PlatformView { public: - explicit PlatformViewIOS(CALayer* layer); + explicit PlatformViewIOS(CALayer* layer, + NSObject* binaryMessenger); ~PlatformViewIOS() override; @@ -55,12 +56,17 @@ class PlatformViewIOS : public PlatformView { const std::string& main, const std::string& packages) override; + NSObject* binary_messenger() const { + return binary_messenger_; + } + private: std::unique_ptr ios_surface_; PlatformMessageRouter platform_message_router_; std::unique_ptr accessibility_bridge_; fxl::Closure firstFrameCallback_; fxl::WeakPtrFactory weak_factory_; + NSObject* binary_messenger_; void SetupAndLoadFromSource(const std::string& assets_directory, const std::string& main, diff --git a/shell/platform/darwin/ios/platform_view_ios.mm b/shell/platform/darwin/ios/platform_view_ios.mm index 56c22b5ce3f390b40ae352af5f12bd216b5095de..8e0e7c4fc2cdb94c4470d608812feff2c8dcab21 100644 --- a/shell/platform/darwin/ios/platform_view_ios.mm +++ b/shell/platform/darwin/ios/platform_view_ios.mm @@ -17,10 +17,11 @@ namespace shell { -PlatformViewIOS::PlatformViewIOS(CALayer* layer) +PlatformViewIOS::PlatformViewIOS(CALayer* layer, NSObject* binaryMessenger) : PlatformView(std::make_unique(std::make_unique())), ios_surface_(IOSSurface::Create(surface_config_, layer)), - weak_factory_(this) {} + weak_factory_(this), + binary_messenger_(binaryMessenger) {} PlatformViewIOS::~PlatformViewIOS() = default;