Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit f19f14d

Browse files
committed
refactored the accessibility bridge to have a view controller instead of a view
1 parent f1d3739 commit f19f14d

File tree

4 files changed

+38
-42
lines changed

4 files changed

+38
-42
lines changed

shell/platform/darwin/ios/framework/Source/accessibility_bridge.h

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include "flutter/lib/ui/semantics/custom_accessibility_action.h"
1919
#include "flutter/lib/ui/semantics/semantics_node.h"
2020
#include "flutter/shell/platform/darwin/common/framework/Headers/FlutterChannels.h"
21+
#include "flutter/shell/platform/darwin/ios/framework/Headers/FlutterViewController.h"
2122
#include "flutter/shell/platform/darwin/ios/framework/Source/FlutterTextInputPlugin.h"
2223
#include "flutter/shell/platform/darwin/ios/framework/Source/FlutterView.h"
2324
#include "flutter/shell/platform/darwin/ios/framework/Source/SemanticsObject.h"
@@ -42,12 +43,13 @@ class AccessibilityBridge final : public AccessibilityBridgeIos {
4243
virtual ~IosDelegate() = default;
4344
/// Returns true when the FlutterViewController associated with the `view`
4445
/// is presenting a modal view controller.
45-
virtual bool IsFlutterViewControllerPresentingModalViewController(UIView* view) = 0;
46+
virtual bool IsFlutterViewControllerPresentingModalViewController(
47+
FlutterViewController* view_controller) = 0;
4648
virtual void PostAccessibilityNotification(UIAccessibilityNotifications notification,
4749
id argument) = 0;
4850
};
4951

50-
AccessibilityBridge(UIView* view,
52+
AccessibilityBridge(FlutterViewController* view_controller,
5153
PlatformViewIOS* platform_view,
5254
FlutterPlatformViewsController* platform_views_controller,
5355
std::unique_ptr<IosDelegate> ios_delegate = nullptr);
@@ -62,7 +64,7 @@ class AccessibilityBridge final : public AccessibilityBridgeIos {
6264

6365
UIView<UITextInput>* textInputView() override;
6466

65-
UIView* view() const override { return view_; }
67+
UIView* view() const override { return view_controller_.view; }
6668

6769
fml::WeakPtr<AccessibilityBridge> GetWeakPtr();
6870

@@ -78,7 +80,7 @@ class AccessibilityBridge final : public AccessibilityBridgeIos {
7880
NSMutableArray<NSNumber*>* doomed_uids);
7981
void HandleEvent(NSDictionary<NSString*, id>* annotatedEvent);
8082

81-
UIView* view_;
83+
FlutterViewController* view_controller_;
8284
PlatformViewIOS* platform_view_;
8385
FlutterPlatformViewsController* platform_views_controller_;
8486
fml::scoped_nsobject<NSMutableDictionary<NSNumber*, SemanticsObject*>> objects_;

shell/platform/darwin/ios/framework/Source/accessibility_bridge.mm

Lines changed: 11 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -16,27 +16,12 @@
1616
namespace flutter {
1717
namespace {
1818

19-
FlutterViewController* _Nullable GetFlutterViewControllerForView(UIView* view) {
20-
// There is no way to get a view's view controller in UIKit directly, this is
21-
// somewhat of a hacky solution to get that. This could be eliminated if the
22-
// bridge actually kept a reference to a FlutterViewController instead of a
23-
// UIView.
24-
id nextResponder = [view nextResponder];
25-
if ([nextResponder isKindOfClass:[FlutterViewController class]]) {
26-
return nextResponder;
27-
} else if ([nextResponder isKindOfClass:[UIView class]]) {
28-
return GetFlutterViewControllerForView(nextResponder);
29-
} else {
30-
return nil;
31-
}
32-
}
33-
3419
class DefaultIosDelegate : public AccessibilityBridge::IosDelegate {
3520
public:
36-
bool IsFlutterViewControllerPresentingModalViewController(UIView* view) override {
37-
FlutterViewController* viewController = GetFlutterViewControllerForView(view);
38-
if (viewController) {
39-
return viewController.isPresentingViewController;
21+
bool IsFlutterViewControllerPresentingModalViewController(
22+
FlutterViewController* view_controller) override {
23+
if (view_controller) {
24+
return view_controller.isPresentingViewController;
4025
} else {
4126
return false;
4227
}
@@ -49,11 +34,11 @@ void PostAccessibilityNotification(UIAccessibilityNotifications notification,
4934
};
5035
} // namespace
5136

52-
AccessibilityBridge::AccessibilityBridge(UIView* view,
37+
AccessibilityBridge::AccessibilityBridge(FlutterViewController* view_controller,
5338
PlatformViewIOS* platform_view,
5439
FlutterPlatformViewsController* platform_views_controller,
5540
std::unique_ptr<IosDelegate> ios_delegate)
56-
: view_(view),
41+
: view_controller_(view_controller),
5742
platform_view_(platform_view),
5843
platform_views_controller_(platform_views_controller),
5944
objects_([[NSMutableDictionary alloc] init]),
@@ -73,7 +58,7 @@ void PostAccessibilityNotification(UIAccessibilityNotifications notification,
7358

7459
AccessibilityBridge::~AccessibilityBridge() {
7560
clearState();
76-
view_.accessibilityElements = nil;
61+
view_controller_.view.accessibilityElements = nil;
7762
}
7863

7964
UIView<UITextInput>* AccessibilityBridge::textInputView() {
@@ -141,8 +126,8 @@ void PostAccessibilityNotification(UIAccessibilityNotifications notification,
141126
SemanticsObject* lastAdded = nil;
142127

143128
if (root) {
144-
if (!view_.accessibilityElements) {
145-
view_.accessibilityElements = @[ [root accessibilityContainer] ];
129+
if (!view_controller_.view.accessibilityElements) {
130+
view_controller_.view.accessibilityElements = @[ [root accessibilityContainer] ];
146131
}
147132
NSMutableArray<SemanticsObject*>* newRoutes = [[[NSMutableArray alloc] init] autorelease];
148133
[root collectRoutes:newRoutes];
@@ -165,7 +150,7 @@ void PostAccessibilityNotification(UIAccessibilityNotifications notification,
165150
previous_routes_.push_back([route uid]);
166151
}
167152
} else {
168-
view_.accessibilityElements = nil;
153+
view_controller_.view.accessibilityElements = nil;
169154
}
170155

171156
NSMutableArray<NSNumber*>* doomed_uids = [NSMutableArray arrayWithArray:[objects_.get() allKeys]];
@@ -175,7 +160,7 @@ void PostAccessibilityNotification(UIAccessibilityNotifications notification,
175160

176161
layoutChanged = layoutChanged || [doomed_uids count] > 0;
177162
if (routeChanged) {
178-
if (!ios_delegate_->IsFlutterViewControllerPresentingModalViewController(view_)) {
163+
if (!ios_delegate_->IsFlutterViewControllerPresentingModalViewController(view_controller_)) {
179164
NSString* routeName = [lastAdded routeName];
180165
ios_delegate_->PostAccessibilityNotification(UIAccessibilityScreenChangedNotification,
181166
routeName);

shell/platform/darwin/ios/framework/Source/accessibility_bridge_test.mm

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,8 @@ void OnPlatformViewMarkTextureFrameAvailable(int64_t texture_id) override {}
8989

9090
class MockIosDelegate : public AccessibilityBridge::IosDelegate {
9191
public:
92-
bool IsFlutterViewControllerPresentingModalViewController(UIView* view) override {
92+
bool IsFlutterViewControllerPresentingModalViewController(
93+
FlutterViewController* view_controller) override {
9394
return result_IsFlutterViewControllerPresentingModalViewController_;
9495
};
9596

@@ -150,9 +151,11 @@ - (void)testUpdateSemanticsEmpty {
150151
/*rendering_api=*/flutter::IOSRenderingAPI::kSoftware,
151152
/*task_runners=*/runners);
152153
id mockFlutterView = OCMClassMock([FlutterView class]);
154+
id mockFlutterViewController = OCMClassMock([FlutterViewController class]);
155+
OCMStub([mockFlutterViewController view]).andReturn(mockFlutterView);
153156
OCMExpect([mockFlutterView setAccessibilityElements:[OCMArg isNil]]);
154157
auto bridge =
155-
std::make_unique<flutter::AccessibilityBridge>(/*view=*/mockFlutterView,
158+
std::make_unique<flutter::AccessibilityBridge>(/*view_controller=*/mockFlutterViewController,
156159
/*platform_view=*/platform_view.get(),
157160
/*platform_views_controller=*/nil);
158161
flutter::SemanticsNodeUpdates nodes;
@@ -174,10 +177,12 @@ - (void)testUpdateSemanticsOneNode {
174177
/*rendering_api=*/flutter::IOSRenderingAPI::kSoftware,
175178
/*task_runners=*/runners);
176179
id mockFlutterView = OCMClassMock([FlutterView class]);
180+
id mockFlutterViewController = OCMClassMock([FlutterViewController class]);
181+
OCMStub([mockFlutterViewController view]).andReturn(mockFlutterView);
177182
std::string label = "some label";
178183

179184
__block auto bridge =
180-
std::make_unique<flutter::AccessibilityBridge>(/*view=*/mockFlutterView,
185+
std::make_unique<flutter::AccessibilityBridge>(/*view_controller=*/mockFlutterViewController,
181186
/*platform_view=*/platform_view.get(),
182187
/*platform_views_controller=*/nil);
183188

@@ -217,6 +222,8 @@ - (void)testSemanticsDeallocated {
217222
/*rendering_api=*/flutter::IOSRenderingAPI::kSoftware,
218223
/*task_runners=*/runners);
219224
id mockFlutterView = OCMClassMock([FlutterView class]);
225+
id mockFlutterViewController = OCMClassMock([FlutterViewController class]);
226+
OCMStub([mockFlutterViewController view]).andReturn(mockFlutterView);
220227
std::string label = "some label";
221228

222229
auto flutterPlatformViewsController =
@@ -236,7 +243,7 @@ - (void)testSemanticsDeallocated {
236243
result);
237244

238245
auto bridge = std::make_unique<flutter::AccessibilityBridge>(
239-
/*view=*/mockFlutterView,
246+
/*view_controller=*/mockFlutterViewController,
240247
/*platform_view=*/platform_view.get(),
241248
/*platform_views_controller=*/flutterPlatformViewsController.get());
242249

@@ -267,6 +274,8 @@ - (void)testAnnouncesRouteChanges {
267274
/*rendering_api=*/flutter::IOSRenderingAPI::kSoftware,
268275
/*task_runners=*/runners);
269276
id mockFlutterView = OCMClassMock([FlutterView class]);
277+
id mockFlutterViewController = OCMClassMock([FlutterViewController class]);
278+
OCMStub([mockFlutterViewController view]).andReturn(mockFlutterView);
270279
std::string label = "some label";
271280

272281
NSMutableArray<NSDictionary<NSString*, id>*>* accessibility_notifications =
@@ -280,7 +289,7 @@ - (void)testAnnouncesRouteChanges {
280289
}];
281290
};
282291
__block auto bridge =
283-
std::make_unique<flutter::AccessibilityBridge>(/*view=*/mockFlutterView,
292+
std::make_unique<flutter::AccessibilityBridge>(/*view_controller=*/mockFlutterViewController,
284293
/*platform_view=*/platform_view.get(),
285294
/*platform_views_controller=*/nil,
286295
/*ios_delegate=*/std::move(ios_delegate));
@@ -322,6 +331,8 @@ - (void)testAnnouncesIgnoresRouteChangesWhenModal {
322331
/*rendering_api=*/flutter::IOSRenderingAPI::kSoftware,
323332
/*task_runners=*/runners);
324333
id mockFlutterView = OCMClassMock([FlutterView class]);
334+
id mockFlutterViewController = OCMClassMock([FlutterViewController class]);
335+
OCMStub([mockFlutterViewController view]).andReturn(mockFlutterView);
325336
std::string label = "some label";
326337

327338
NSMutableArray<NSDictionary<NSString*, id>*>* accessibility_notifications =
@@ -336,7 +347,7 @@ - (void)testAnnouncesIgnoresRouteChangesWhenModal {
336347
};
337348
ios_delegate->result_IsFlutterViewControllerPresentingModalViewController_ = true;
338349
__block auto bridge =
339-
std::make_unique<flutter::AccessibilityBridge>(/*view=*/mockFlutterView,
350+
std::make_unique<flutter::AccessibilityBridge>(/*view_controller=*/mockFlutterViewController,
340351
/*platform_view=*/platform_view.get(),
341352
/*platform_views_controller=*/nil,
342353
/*ios_delegate=*/std::move(ios_delegate));

shell/platform/darwin/ios/platform_view_ios.mm

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -107,9 +107,8 @@
107107
FML_DCHECK(ios_surface_ != nullptr);
108108

109109
if (accessibility_bridge_) {
110-
accessibility_bridge_.reset(
111-
new AccessibilityBridge(static_cast<FlutterView*>(owner_controller_.get().view), this,
112-
[owner_controller_.get() platformViewsController]));
110+
accessibility_bridge_.reset(new AccessibilityBridge(
111+
owner_controller_.get(), this, [owner_controller_.get() platformViewsController]));
113112
}
114113
}
115114

@@ -150,9 +149,8 @@ new AccessibilityBridge(static_cast<FlutterView*>(owner_controller_.get().view),
150149
return;
151150
}
152151
if (enabled && !accessibility_bridge_) {
153-
accessibility_bridge_.reset(
154-
new AccessibilityBridge(static_cast<FlutterView*>(owner_controller_.get().view), this,
155-
[owner_controller_.get() platformViewsController]));
152+
accessibility_bridge_.reset(new AccessibilityBridge(
153+
owner_controller_.get(), this, [owner_controller_.get() platformViewsController]));
156154
} else if (!enabled && accessibility_bridge_) {
157155
accessibility_bridge_.reset();
158156
} else {

0 commit comments

Comments
 (0)