From f2570d2476df5532abcaf4beb6128c427ac21d3e Mon Sep 17 00:00:00 2001 From: Aaron Clarke Date: Wed, 3 Jun 2020 14:41:42 -0700 Subject: [PATCH] refactored the accessibility bridge to have a view controller instead of a view --- .../framework/Source/accessibility_bridge.h | 10 +++-- .../framework/Source/accessibility_bridge.mm | 37 ++++++------------- .../Source/accessibility_bridge_test.mm | 23 +++++++++--- .../platform/darwin/ios/platform_view_ios.mm | 10 ++--- 4 files changed, 38 insertions(+), 42 deletions(-) diff --git a/shell/platform/darwin/ios/framework/Source/accessibility_bridge.h b/shell/platform/darwin/ios/framework/Source/accessibility_bridge.h index 77e5813792ad1..a1e3c2d7fb18f 100644 --- a/shell/platform/darwin/ios/framework/Source/accessibility_bridge.h +++ b/shell/platform/darwin/ios/framework/Source/accessibility_bridge.h @@ -18,6 +18,7 @@ #include "flutter/lib/ui/semantics/custom_accessibility_action.h" #include "flutter/lib/ui/semantics/semantics_node.h" #include "flutter/shell/platform/darwin/common/framework/Headers/FlutterChannels.h" +#include "flutter/shell/platform/darwin/ios/framework/Headers/FlutterViewController.h" #include "flutter/shell/platform/darwin/ios/framework/Source/FlutterTextInputPlugin.h" #include "flutter/shell/platform/darwin/ios/framework/Source/FlutterView.h" #include "flutter/shell/platform/darwin/ios/framework/Source/SemanticsObject.h" @@ -42,12 +43,13 @@ class AccessibilityBridge final : public AccessibilityBridgeIos { virtual ~IosDelegate() = default; /// Returns true when the FlutterViewController associated with the `view` /// is presenting a modal view controller. - virtual bool IsFlutterViewControllerPresentingModalViewController(UIView* view) = 0; + virtual bool IsFlutterViewControllerPresentingModalViewController( + FlutterViewController* view_controller) = 0; virtual void PostAccessibilityNotification(UIAccessibilityNotifications notification, id argument) = 0; }; - AccessibilityBridge(UIView* view, + AccessibilityBridge(FlutterViewController* view_controller, PlatformViewIOS* platform_view, FlutterPlatformViewsController* platform_views_controller, std::unique_ptr ios_delegate = nullptr); @@ -62,7 +64,7 @@ class AccessibilityBridge final : public AccessibilityBridgeIos { UIView* textInputView() override; - UIView* view() const override { return view_; } + UIView* view() const override { return view_controller_.view; } fml::WeakPtr GetWeakPtr(); @@ -78,7 +80,7 @@ class AccessibilityBridge final : public AccessibilityBridgeIos { NSMutableArray* doomed_uids); void HandleEvent(NSDictionary* annotatedEvent); - UIView* view_; + FlutterViewController* view_controller_; PlatformViewIOS* platform_view_; FlutterPlatformViewsController* platform_views_controller_; fml::scoped_nsobject> objects_; diff --git a/shell/platform/darwin/ios/framework/Source/accessibility_bridge.mm b/shell/platform/darwin/ios/framework/Source/accessibility_bridge.mm index 6fd197e69ceb2..0d42cce730a9b 100644 --- a/shell/platform/darwin/ios/framework/Source/accessibility_bridge.mm +++ b/shell/platform/darwin/ios/framework/Source/accessibility_bridge.mm @@ -16,27 +16,12 @@ namespace flutter { namespace { -FlutterViewController* _Nullable GetFlutterViewControllerForView(UIView* view) { - // There is no way to get a view's view controller in UIKit directly, this is - // somewhat of a hacky solution to get that. This could be eliminated if the - // bridge actually kept a reference to a FlutterViewController instead of a - // UIView. - id nextResponder = [view nextResponder]; - if ([nextResponder isKindOfClass:[FlutterViewController class]]) { - return nextResponder; - } else if ([nextResponder isKindOfClass:[UIView class]]) { - return GetFlutterViewControllerForView(nextResponder); - } else { - return nil; - } -} - class DefaultIosDelegate : public AccessibilityBridge::IosDelegate { public: - bool IsFlutterViewControllerPresentingModalViewController(UIView* view) override { - FlutterViewController* viewController = GetFlutterViewControllerForView(view); - if (viewController) { - return viewController.isPresentingViewController; + bool IsFlutterViewControllerPresentingModalViewController( + FlutterViewController* view_controller) override { + if (view_controller) { + return view_controller.isPresentingViewController; } else { return false; } @@ -49,11 +34,11 @@ void PostAccessibilityNotification(UIAccessibilityNotifications notification, }; } // namespace -AccessibilityBridge::AccessibilityBridge(UIView* view, +AccessibilityBridge::AccessibilityBridge(FlutterViewController* view_controller, PlatformViewIOS* platform_view, FlutterPlatformViewsController* platform_views_controller, std::unique_ptr ios_delegate) - : view_(view), + : view_controller_(view_controller), platform_view_(platform_view), platform_views_controller_(platform_views_controller), objects_([[NSMutableDictionary alloc] init]), @@ -74,7 +59,7 @@ void PostAccessibilityNotification(UIAccessibilityNotifications notification, AccessibilityBridge::~AccessibilityBridge() { [accessibility_channel_.get() setMessageHandler:nil]; clearState(); - view_.accessibilityElements = nil; + view_controller_.view.accessibilityElements = nil; } UIView* AccessibilityBridge::textInputView() { @@ -164,8 +149,8 @@ void PostAccessibilityNotification(UIAccessibilityNotifications notification, SemanticsObject* lastAdded = nil; if (root) { - if (!view_.accessibilityElements) { - view_.accessibilityElements = @[ [root accessibilityContainer] ]; + if (!view_controller_.view.accessibilityElements) { + view_controller_.view.accessibilityElements = @[ [root accessibilityContainer] ]; } NSMutableArray* newRoutes = [[[NSMutableArray alloc] init] autorelease]; [root collectRoutes:newRoutes]; @@ -188,7 +173,7 @@ void PostAccessibilityNotification(UIAccessibilityNotifications notification, previous_routes_.push_back([route uid]); } } else { - view_.accessibilityElements = nil; + view_controller_.view.accessibilityElements = nil; } NSMutableArray* doomed_uids = [NSMutableArray arrayWithArray:[objects_.get() allKeys]]; @@ -198,7 +183,7 @@ void PostAccessibilityNotification(UIAccessibilityNotifications notification, layoutChanged = layoutChanged || [doomed_uids count] > 0; if (routeChanged) { - if (!ios_delegate_->IsFlutterViewControllerPresentingModalViewController(view_)) { + if (!ios_delegate_->IsFlutterViewControllerPresentingModalViewController(view_controller_)) { ios_delegate_->PostAccessibilityNotification(UIAccessibilityScreenChangedNotification, [lastAdded routeFocusObject]); } diff --git a/shell/platform/darwin/ios/framework/Source/accessibility_bridge_test.mm b/shell/platform/darwin/ios/framework/Source/accessibility_bridge_test.mm index b6e07133672e1..300c30b47bfe6 100644 --- a/shell/platform/darwin/ios/framework/Source/accessibility_bridge_test.mm +++ b/shell/platform/darwin/ios/framework/Source/accessibility_bridge_test.mm @@ -96,7 +96,8 @@ void OnPlatformViewMarkTextureFrameAvailable(int64_t texture_id) override {} class MockIosDelegate : public AccessibilityBridge::IosDelegate { public: - bool IsFlutterViewControllerPresentingModalViewController(UIView* view) override { + bool IsFlutterViewControllerPresentingModalViewController( + FlutterViewController* view_controller) override { return result_IsFlutterViewControllerPresentingModalViewController_; }; @@ -157,9 +158,11 @@ - (void)testUpdateSemanticsEmpty { /*rendering_api=*/flutter::IOSRenderingAPI::kSoftware, /*task_runners=*/runners); id mockFlutterView = OCMClassMock([FlutterView class]); + id mockFlutterViewController = OCMClassMock([FlutterViewController class]); + OCMStub([mockFlutterViewController view]).andReturn(mockFlutterView); OCMExpect([mockFlutterView setAccessibilityElements:[OCMArg isNil]]); auto bridge = - std::make_unique(/*view=*/mockFlutterView, + std::make_unique(/*view_controller=*/mockFlutterViewController, /*platform_view=*/platform_view.get(), /*platform_views_controller=*/nil); flutter::SemanticsNodeUpdates nodes; @@ -181,10 +184,12 @@ - (void)testUpdateSemanticsOneNode { /*rendering_api=*/flutter::IOSRenderingAPI::kSoftware, /*task_runners=*/runners); id mockFlutterView = OCMClassMock([FlutterView class]); + id mockFlutterViewController = OCMClassMock([FlutterViewController class]); + OCMStub([mockFlutterViewController view]).andReturn(mockFlutterView); std::string label = "some label"; __block auto bridge = - std::make_unique(/*view=*/mockFlutterView, + std::make_unique(/*view_controller=*/mockFlutterViewController, /*platform_view=*/platform_view.get(), /*platform_views_controller=*/nil); @@ -224,6 +229,8 @@ - (void)testSemanticsDeallocated { /*rendering_api=*/flutter::IOSRenderingAPI::kSoftware, /*task_runners=*/runners); id mockFlutterView = OCMClassMock([FlutterView class]); + id mockFlutterViewController = OCMClassMock([FlutterViewController class]); + OCMStub([mockFlutterViewController view]).andReturn(mockFlutterView); std::string label = "some label"; auto flutterPlatformViewsController = @@ -243,7 +250,7 @@ - (void)testSemanticsDeallocated { result); auto bridge = std::make_unique( - /*view=*/mockFlutterView, + /*view_controller=*/mockFlutterViewController, /*platform_view=*/platform_view.get(), /*platform_views_controller=*/flutterPlatformViewsController.get()); @@ -274,6 +281,8 @@ - (void)testAnnouncesRouteChanges { /*rendering_api=*/flutter::IOSRenderingAPI::kSoftware, /*task_runners=*/runners); id mockFlutterView = OCMClassMock([FlutterView class]); + id mockFlutterViewController = OCMClassMock([FlutterViewController class]); + OCMStub([mockFlutterViewController view]).andReturn(mockFlutterView); std::string label = "some label"; NSMutableArray*>* accessibility_notifications = @@ -287,7 +296,7 @@ - (void)testAnnouncesRouteChanges { }]; }; __block auto bridge = - std::make_unique(/*view=*/mockFlutterView, + std::make_unique(/*view_controller=*/mockFlutterViewController, /*platform_view=*/platform_view.get(), /*platform_views_controller=*/nil, /*ios_delegate=*/std::move(ios_delegate)); @@ -331,6 +340,8 @@ - (void)testAnnouncesIgnoresRouteChangesWhenModal { /*rendering_api=*/flutter::IOSRenderingAPI::kSoftware, /*task_runners=*/runners); id mockFlutterView = OCMClassMock([FlutterView class]); + id mockFlutterViewController = OCMClassMock([FlutterViewController class]); + OCMStub([mockFlutterViewController view]).andReturn(mockFlutterView); std::string label = "some label"; NSMutableArray*>* accessibility_notifications = @@ -345,7 +356,7 @@ - (void)testAnnouncesIgnoresRouteChangesWhenModal { }; ios_delegate->result_IsFlutterViewControllerPresentingModalViewController_ = true; __block auto bridge = - std::make_unique(/*view=*/mockFlutterView, + std::make_unique(/*view_controller=*/mockFlutterViewController, /*platform_view=*/platform_view.get(), /*platform_views_controller=*/nil, /*ios_delegate=*/std::move(ios_delegate)); diff --git a/shell/platform/darwin/ios/platform_view_ios.mm b/shell/platform/darwin/ios/platform_view_ios.mm index 14fcc2141c478..773eadf8979b9 100644 --- a/shell/platform/darwin/ios/platform_view_ios.mm +++ b/shell/platform/darwin/ios/platform_view_ios.mm @@ -107,9 +107,8 @@ FML_DCHECK(ios_surface_ != nullptr); if (accessibility_bridge_) { - accessibility_bridge_.reset( - new AccessibilityBridge(static_cast(owner_controller_.get().view), this, - [owner_controller_.get() platformViewsController])); + accessibility_bridge_.reset(new AccessibilityBridge( + owner_controller_.get(), this, [owner_controller_.get() platformViewsController])); } } @@ -150,9 +149,8 @@ new AccessibilityBridge(static_cast(owner_controller_.get().view), return; } if (enabled && !accessibility_bridge_) { - accessibility_bridge_.reset( - new AccessibilityBridge(static_cast(owner_controller_.get().view), this, - [owner_controller_.get() platformViewsController])); + accessibility_bridge_.reset(new AccessibilityBridge( + owner_controller_.get(), this, [owner_controller_.get() platformViewsController])); } else if (!enabled && accessibility_bridge_) { accessibility_bridge_.reset(); } else {