| Flutter iOS Embedder |

SemanticsObjectTest.mm
Go to the documentation of this file.
1 // Copyright 2013 The Flutter Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #import <OCMock/OCMock.h>
6 #import <XCTest/XCTest.h>
7
8 #import "flutter/shell/platform/darwin/common/framework/Headers/FlutterMacros.h"
9 #import "flutter/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.h"
10 #import "flutter/shell/platform/darwin/ios/framework/Source/FlutterSemanticsScrollView.h"
11 #import "flutter/shell/platform/darwin/ios/framework/Source/FlutterTouchInterceptingView_Test.h"
12 #import "flutter/shell/platform/darwin/ios/framework/Source/SemanticsObject.h"
13 #import "flutter/shell/platform/darwin/ios/framework/Source/SemanticsObjectTestMocks.h"
14 #import "flutter/shell/platform/darwin/ios/framework/Source/TextInputSemanticsObject.h"
15
16 FLUTTER_ASSERT_ARC
17
18 const float kFloatCompareEpsilon = 0.001;
19
20 @interface SemanticsObject (UIFocusSystem) <UIFocusItem, UIFocusItemContainer>
21 @end
22
23 @interface FlutterScrollableSemanticsObject (UIFocusItemScrollableContainer) <
24 UIFocusItemScrollableContainer>
25 @end
26
27 @interface TextInputSemanticsObject (Test)
28 - (UIView<UITextInput>*)textInputSurrogate;
29 @end
30
31 @interface SemanticsObjectTest : XCTestCase
32 @end
33
34 @implementation SemanticsObjectTest
35
36 - (void)testCreate {
37 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
38 new flutter::testing::MockAccessibilityBridge());
39 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
40 SemanticsObject* object = [[SemanticsObject alloc] initWithBridge:bridge uid:0];
41 XCTAssertNotNil(object);
42 }
43
44 - (void)testSetChildren {
45 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
46 new flutter::testing::MockAccessibilityBridge());
47 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
48 SemanticsObject* parent = [[SemanticsObject alloc] initWithBridge:bridge uid:0];
49 SemanticsObject* child = [[SemanticsObject alloc] initWithBridge:bridge uid:1];
50 parent.children = @[ child ];
51 XCTAssertEqual(parent, child.parent);
52 parent.children = @[];
53 XCTAssertNil(child.parent);
54 }
55
56 - (void)testAccessibilityHitTestFocusAtLeaf {
57 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
58 new flutter::testing::MockAccessibilityBridge());
59 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
60 SemanticsObject* object0 = [[SemanticsObject alloc] initWithBridge:bridge uid:0];
61 SemanticsObject* object1 = [[SemanticsObject alloc] initWithBridge:bridge uid:1];
62 SemanticsObject* object2 = [[SemanticsObject alloc] initWithBridge:bridge uid:2];
63 SemanticsObject* object3 = [[SemanticsObject alloc] initWithBridge:bridge uid:3];
64 object0.children = @[ object1 ];
65 object0.childrenInHitTestOrder = @[ object1 ];
66 object1.children = @[ object2, object3 ];
67 object1.childrenInHitTestOrder = @[ object2, object3 ];
68
69 flutter::SemanticsNode node0;
70 node0.id = 0;
71 node0.rect = SkRect::MakeXYWH(0, 0, 200, 200);
72 node0.label = "0";
73 [object0 setSemanticsNode:&node0];
74
75 flutter::SemanticsNode node1;
76 node1.id = 1;
77 node1.rect = SkRect::MakeXYWH(0, 0, 200, 200);
78 node1.label = "1";
79 [object1 setSemanticsNode:&node1];
80
81 flutter::SemanticsNode node2;
82 node2.id = 2;
83 node2.rect = SkRect::MakeXYWH(0, 0, 100, 100);
84 node2.label = "2";
85 [object2 setSemanticsNode:&node2];
86
87 flutter::SemanticsNode node3;
88 node3.id = 3;
89 node3.rect = SkRect::MakeXYWH(0, 0, 200, 200);
90 node3.label = "3";
91 [object3 setSemanticsNode:&node3];
92
93 CGPoint point = CGPointMake(10, 10);
94 id hitTestResult = [object0 _accessibilityHitTest:point withEvent:nil];
95
96 // Focus to object2 because it's the first object in hit test order
97 XCTAssertEqual(hitTestResult, object2);
98 }
99
100 - (void)testAccessibilityHitTestNoFocusableItem {
101 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
102 new flutter::testing::MockAccessibilityBridge());
103 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
104 SemanticsObject* object0 = [[SemanticsObject alloc] initWithBridge:bridge uid:0];
105 SemanticsObject* object1 = [[SemanticsObject alloc] initWithBridge:bridge uid:1];
106 SemanticsObject* object2 = [[SemanticsObject alloc] initWithBridge:bridge uid:2];
107 SemanticsObject* object3 = [[SemanticsObject alloc] initWithBridge:bridge uid:3];
108 object0.children = @[ object1 ];
109 object0.childrenInHitTestOrder = @[ object1 ];
110 object1.children = @[ object2, object3 ];
111 object1.childrenInHitTestOrder = @[ object2, object3 ];
112
113 flutter::SemanticsNode node0;
114 node0.id = 0;
115 node0.rect = SkRect::MakeXYWH(0, 0, 200, 200);
116 [object0 setSemanticsNode:&node0];
117
118 flutter::SemanticsNode node1;
119 node1.id = 1;
120 node1.rect = SkRect::MakeXYWH(0, 0, 200, 200);
121 [object1 setSemanticsNode:&node1];
122
123 flutter::SemanticsNode node2;
124 node2.id = 2;
125 node2.rect = SkRect::MakeXYWH(0, 0, 100, 100);
126 [object2 setSemanticsNode:&node2];
127
128 flutter::SemanticsNode node3;
129 node3.id = 3;
130 node3.rect = SkRect::MakeXYWH(0, 0, 200, 200);
131 [object3 setSemanticsNode:&node3];
132
133 CGPoint point = CGPointMake(10, 10);
134 id hitTestResult = [object0 _accessibilityHitTest:point withEvent:nil];
135
136 XCTAssertNil(hitTestResult);
137 }
138
139 - (void)testAccessibilityScrollToVisible {
140 fml::WeakPtrFactory<flutter::testing::MockAccessibilityBridge> factory(
141 new flutter::testing::MockAccessibilityBridge());
142 fml::WeakPtr<flutter::testing::MockAccessibilityBridge> bridge = factory.GetWeakPtr();
143 SemanticsObject* object3 = [[SemanticsObject alloc] initWithBridge:bridge uid:3];
144
145 flutter::SemanticsNode node3;
146 node3.id = 3;
147 node3.rect = SkRect::MakeXYWH(0, 0, 200, 200);
148 [object3 setSemanticsNode:&node3];
149
150 [object3 accessibilityScrollToVisible];
151
152 XCTAssertTrue(bridge->observations.size() == 1);
153 XCTAssertTrue(bridge->observations[0].id == 3);
154 XCTAssertTrue(bridge->observations[0].action == flutter::SemanticsAction::kShowOnScreen);
155 }
156
157 - (void)testAccessibilityScrollToVisibleWithChild {
158 fml::WeakPtrFactory<flutter::testing::MockAccessibilityBridge> factory(
159 new flutter::testing::MockAccessibilityBridge());
160 fml::WeakPtr<flutter::testing::MockAccessibilityBridge> bridge = factory.GetWeakPtr();
161 SemanticsObject* object3 = [[SemanticsObject alloc] initWithBridge:bridge uid:3];
162
163 flutter::SemanticsNode node3;
164 node3.id = 3;
165 node3.rect = SkRect::MakeXYWH(0, 0, 200, 200);
166 [object3 setSemanticsNode:&node3];
167
168 [object3 accessibilityScrollToVisibleWithChild:object3];
169
170 XCTAssertTrue(bridge->observations.size() == 1);
171 XCTAssertTrue(bridge->observations[0].id == 3);
172 XCTAssertTrue(bridge->observations[0].action == flutter::SemanticsAction::kShowOnScreen);
173 }
174
175 - (void)testAccessibilityHitTestOutOfRect {
176 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
177 new flutter::testing::MockAccessibilityBridge());
178 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
179 SemanticsObject* object0 = [[SemanticsObject alloc] initWithBridge:bridge uid:0];
180 SemanticsObject* object1 = [[SemanticsObject alloc] initWithBridge:bridge uid:1];
181 SemanticsObject* object2 = [[SemanticsObject alloc] initWithBridge:bridge uid:2];
182 SemanticsObject* object3 = [[SemanticsObject alloc] initWithBridge:bridge uid:3];
183 object0.children = @[ object1 ];
184 object0.childrenInHitTestOrder = @[ object1 ];
185 object1.children = @[ object2, object3 ];
186 object1.childrenInHitTestOrder = @[ object2, object3 ];
187
188 flutter::SemanticsNode node0;
189 node0.id = 0;
190 node0.rect = SkRect::MakeXYWH(0, 0, 200, 200);
191 node0.label = "0";
192 [object0 setSemanticsNode:&node0];
193
194 flutter::SemanticsNode node1;
195 node1.id = 1;
196 node1.rect = SkRect::MakeXYWH(0, 0, 200, 200);
197 node1.label = "1";
198 [object1 setSemanticsNode:&node1];
199
200 flutter::SemanticsNode node2;
201 node2.id = 2;
202 node2.rect = SkRect::MakeXYWH(0, 0, 100, 100);
203 node2.label = "2";
204 [object2 setSemanticsNode:&node2];
205
206 flutter::SemanticsNode node3;
207 node3.id = 3;
208 node3.rect = SkRect::MakeXYWH(0, 0, 200, 200);
209 node3.label = "3";
210 [object3 setSemanticsNode:&node3];
211
212 CGPoint point = CGPointMake(300, 300);
213 id hitTestResult = [object0 _accessibilityHitTest:point withEvent:nil];
214
215 XCTAssertNil(hitTestResult);
216 }
217
218 - (void)testReplaceChildAtIndex {
219 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
220 new flutter::testing::MockAccessibilityBridge());
221 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
222 SemanticsObject* parent = [[SemanticsObject alloc] initWithBridge:bridge uid:0];
223 SemanticsObject* child1 = [[SemanticsObject alloc] initWithBridge:bridge uid:1];
224 SemanticsObject* child2 = [[SemanticsObject alloc] initWithBridge:bridge uid:2];
225 parent.children = @[ child1 ];
226 [parent replaceChildAtIndex:0 withChild:child2];
227 XCTAssertNil(child1.parent);
228 XCTAssertEqual(parent, child2.parent);
229 XCTAssertEqualObjects(parent.children, @[ child2 ]);
230 }
231
232 - (void)testPlainSemanticsObjectWithLabelHasStaticTextTrait {
233 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
234 new flutter::testing::MockAccessibilityBridge());
235 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
236 flutter::SemanticsNode node;
237 node.label = "foo";
238 FlutterSemanticsObject* object = [[FlutterSemanticsObject alloc] initWithBridge:bridge uid:0];
239 [object setSemanticsNode:&node];
240 XCTAssertEqual([object accessibilityTraits], UIAccessibilityTraitStaticText);
241 }
242
243 - (void)testNodeWithImplicitScrollIsAnAccessibilityElementWhenItisHidden {
244 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
245 new flutter::testing::MockAccessibilityBridge());
246 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
247 flutter::SemanticsNode node;
248 node.flags = static_cast<int32_t>(flutter::SemanticsFlags::kHasImplicitScrolling) |
249 static_cast<int32_t>(flutter::SemanticsFlags::kIsHidden);
250 FlutterSemanticsObject* object = [[FlutterSemanticsObject alloc] initWithBridge:bridge uid:0];
251 [object setSemanticsNode:&node];
252 XCTAssertEqual(object.isAccessibilityElement, YES);
253 }
254
255 - (void)testNodeWithImplicitScrollIsNotAnAccessibilityElementWhenItisNotHidden {
256 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
257 new flutter::testing::MockAccessibilityBridge());
258 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
259 flutter::SemanticsNode node;
260 node.flags = static_cast<int32_t>(flutter::SemanticsFlags::kHasImplicitScrolling);
261 FlutterSemanticsObject* object = [[FlutterSemanticsObject alloc] initWithBridge:bridge uid:0];
262 [object setSemanticsNode:&node];
263 XCTAssertEqual(object.isAccessibilityElement, NO);
264 }
265
266 - (void)testIntresetingSemanticsObjectWithLabelHasStaticTextTrait {
267 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
268 new flutter::testing::MockAccessibilityBridge());
269 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
270 flutter::SemanticsNode node;
271 node.label = "foo";
272 FlutterSemanticsObject* object = [[FlutterSemanticsObject alloc] initWithBridge:bridge uid:0];
273 SemanticsObject* child1 = [[SemanticsObject alloc] initWithBridge:bridge uid:1];
274 object.children = @[ child1 ];
275 [object setSemanticsNode:&node];
276 XCTAssertEqual([object accessibilityTraits], UIAccessibilityTraitNone);
277 }
278
279 - (void)testIntresetingSemanticsObjectWithLabelHasStaticTextTrait1 {
280 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
281 new flutter::testing::MockAccessibilityBridge());
282 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
283 flutter::SemanticsNode node;
284 node.label = "foo";
285 node.flags = static_cast<int32_t>(flutter::SemanticsFlags::kIsTextField);
286 FlutterSemanticsObject* object = [[FlutterSemanticsObject alloc] initWithBridge:bridge uid:0];
287 [object setSemanticsNode:&node];
288 XCTAssertEqual([object accessibilityTraits], UIAccessibilityTraitNone);
289 }
290
291 - (void)testIntresetingSemanticsObjectWithLabelHasStaticTextTrait2 {
292 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
293 new flutter::testing::MockAccessibilityBridge());
294 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
295 flutter::SemanticsNode node;
296 node.label = "foo";
297 node.flags = static_cast<int32_t>(flutter::SemanticsFlags::kIsButton);
298 FlutterSemanticsObject* object = [[FlutterSemanticsObject alloc] initWithBridge:bridge uid:0];
299 [object setSemanticsNode:&node];
300 XCTAssertEqual([object accessibilityTraits], UIAccessibilityTraitButton);
301 }
302
303 - (void)testVerticalFlutterScrollableSemanticsObject {
304 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
305 new flutter::testing::MockAccessibilityBridge());
306 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
307
308 float transformScale = 0.5f;
309 float screenScale = [[bridge->view() window] screen].scale;
310 float effectivelyScale = transformScale / screenScale;
311 float x = 10;
312 float y = 10;
313 float w = 100;
314 float h = 200;
315 float scrollExtentMax = 500.0;
316 float scrollPosition = 150.0;
317
318 flutter::SemanticsNode node;
319 node.flags = static_cast<int32_t>(flutter::SemanticsFlags::kHasImplicitScrolling);
320 node.actions = flutter::kVerticalScrollSemanticsActions;
321 node.rect = SkRect::MakeXYWH(x, y, w, h);
322 node.scrollExtentMax = scrollExtentMax;
323 node.scrollPosition = scrollPosition;
324 node.transform = {
325 transformScale, 0, 0, 0, 0, transformScale, 0, 0, 0, 0, transformScale, 0, 0, 0, 0, 1.0};
326 FlutterScrollableSemanticsObject* scrollable =
327 [[FlutterScrollableSemanticsObject alloc] initWithBridge:bridge uid:0];
328 [scrollable setSemanticsNode:&node];
329 [scrollable accessibilityBridgeDidFinishUpdate];
330 UIScrollView* scrollView = [scrollable nativeAccessibility];
331
332 XCTAssertEqualWithAccuracy(scrollView.frame.origin.x, x * effectivelyScale, kFloatCompareEpsilon);
333 XCTAssertEqualWithAccuracy(scrollView.frame.origin.y, y * effectivelyScale, kFloatCompareEpsilon);
334 XCTAssertEqualWithAccuracy(scrollView.frame.size.width, w * effectivelyScale,
335 kFloatCompareEpsilon);
336 XCTAssertEqualWithAccuracy(scrollView.frame.size.height, h * effectivelyScale,
337 kFloatCompareEpsilon);
338
339 XCTAssertEqualWithAccuracy(scrollView.contentSize.width, w * effectivelyScale,
340 kFloatCompareEpsilon);
341 XCTAssertEqualWithAccuracy(scrollView.contentSize.height,
342 (h + scrollExtentMax) * effectivelyScale, kFloatCompareEpsilon);
343
344 XCTAssertEqual(scrollView.contentOffset.x, 0);
345 XCTAssertEqualWithAccuracy(scrollView.contentOffset.y, scrollPosition * effectivelyScale,
346 kFloatCompareEpsilon);
347 }
348
349 - (void)testVerticalFlutterScrollableSemanticsObjectNoWindowDoesNotCrash {
350 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
351 new flutter::testing::MockAccessibilityBridgeNoWindow());
352 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
353
354 float transformScale = 0.5f;
355 float x = 10;
356 float y = 10;
357 float w = 100;
358 float h = 200;
359 float scrollExtentMax = 500.0;
360 float scrollPosition = 150.0;
361
362 flutter::SemanticsNode node;
363 node.flags = static_cast<int32_t>(flutter::SemanticsFlags::kHasImplicitScrolling);
364 node.actions = flutter::kVerticalScrollSemanticsActions;
365 node.rect = SkRect::MakeXYWH(x, y, w, h);
366 node.scrollExtentMax = scrollExtentMax;
367 node.scrollPosition = scrollPosition;
368 node.transform = {
369 transformScale, 0, 0, 0, 0, transformScale, 0, 0, 0, 0, transformScale, 0, 0, 0, 0, 1.0};
370 FlutterScrollableSemanticsObject* scrollable =
371 [[FlutterScrollableSemanticsObject alloc] initWithBridge:bridge uid:0];
372 [scrollable setSemanticsNode:&node];
373 [scrollable accessibilityBridgeDidFinishUpdate];
374 XCTAssertNoThrow([scrollable accessibilityBridgeDidFinishUpdate]);
375 }
376
377 - (void)testHorizontalFlutterScrollableSemanticsObject {
378 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
379 new flutter::testing::MockAccessibilityBridge());
380 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
381
382 float transformScale = 0.5f;
383 float screenScale = [[bridge->view() window] screen].scale;
384 float effectivelyScale = transformScale / screenScale;
385 float x = 10;
386 float y = 10;
387 float w = 100;
388 float h = 200;
389 float scrollExtentMax = 500.0;
390 float scrollPosition = 150.0;
391
392 flutter::SemanticsNode node;
393 node.flags = static_cast<int32_t>(flutter::SemanticsFlags::kHasImplicitScrolling);
394 node.actions = flutter::kHorizontalScrollSemanticsActions;
395 node.rect = SkRect::MakeXYWH(x, y, w, h);
396 node.scrollExtentMax = scrollExtentMax;
397 node.scrollPosition = scrollPosition;
398 node.transform = {
399 transformScale, 0, 0, 0, 0, transformScale, 0, 0, 0, 0, transformScale, 0, 0, 0, 0, 1.0};
400 FlutterScrollableSemanticsObject* scrollable =
401 [[FlutterScrollableSemanticsObject alloc] initWithBridge:bridge uid:0];
402 [scrollable setSemanticsNode:&node];
403 [scrollable accessibilityBridgeDidFinishUpdate];
404 UIScrollView* scrollView = [scrollable nativeAccessibility];
405
406 XCTAssertEqualWithAccuracy(scrollView.frame.origin.x, x * effectivelyScale, kFloatCompareEpsilon);
407 XCTAssertEqualWithAccuracy(scrollView.frame.origin.y, y * effectivelyScale, kFloatCompareEpsilon);
408 XCTAssertEqualWithAccuracy(scrollView.frame.size.width, w * effectivelyScale,
409 kFloatCompareEpsilon);
410 XCTAssertEqualWithAccuracy(scrollView.frame.size.height, h * effectivelyScale,
411 kFloatCompareEpsilon);
412
413 XCTAssertEqualWithAccuracy(scrollView.contentSize.width, (w + scrollExtentMax) * effectivelyScale,
414 kFloatCompareEpsilon);
415 XCTAssertEqualWithAccuracy(scrollView.contentSize.height, h * effectivelyScale,
416 kFloatCompareEpsilon);
417
418 XCTAssertEqualWithAccuracy(scrollView.contentOffset.x, scrollPosition * effectivelyScale,
419 kFloatCompareEpsilon);
420 XCTAssertEqual(scrollView.contentOffset.y, 0);
421 }
422
423 - (void)testCanHandleInfiniteScrollExtent {
424 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
425 new flutter::testing::MockAccessibilityBridge());
426 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
427
428 float transformScale = 0.5f;
429 float screenScale = [[bridge->view() window] screen].scale;
430 float effectivelyScale = transformScale / screenScale;
431 float x = 10;
432 float y = 10;
433 float w = 100;
434 float h = 200;
435 float scrollExtentMax = INFINITY;
436 float scrollPosition = 150.0;
437
438 flutter::SemanticsNode node;
439 node.flags = static_cast<int32_t>(flutter::SemanticsFlags::kHasImplicitScrolling);
440 node.actions = flutter::kVerticalScrollSemanticsActions;
441 node.rect = SkRect::MakeXYWH(x, y, w, h);
442 node.scrollExtentMax = scrollExtentMax;
443 node.scrollPosition = scrollPosition;
444 node.transform = {
445 transformScale, 0, 0, 0, 0, transformScale, 0, 0, 0, 0, transformScale, 0, 0, 0, 0, 1.0};
446 FlutterScrollableSemanticsObject* scrollable =
447 [[FlutterScrollableSemanticsObject alloc] initWithBridge:bridge uid:0];
448 [scrollable setSemanticsNode:&node];
449 [scrollable accessibilityBridgeDidFinishUpdate];
450 UIScrollView* scrollView = [scrollable nativeAccessibility];
451 XCTAssertEqualWithAccuracy(scrollView.frame.origin.x, x * effectivelyScale, kFloatCompareEpsilon);
452 XCTAssertEqualWithAccuracy(scrollView.frame.origin.y, y * effectivelyScale, kFloatCompareEpsilon);
453 XCTAssertEqualWithAccuracy(scrollView.frame.size.width, w * effectivelyScale,
454 kFloatCompareEpsilon);
455 XCTAssertEqualWithAccuracy(scrollView.frame.size.height, h * effectivelyScale,
456 kFloatCompareEpsilon);
457
458 XCTAssertEqualWithAccuracy(scrollView.contentSize.width, w * effectivelyScale,
459 kFloatCompareEpsilon);
460 XCTAssertEqualWithAccuracy(scrollView.contentSize.height,
461 (h + kScrollExtentMaxForInf + scrollPosition) * effectivelyScale,
462 kFloatCompareEpsilon);
463
464 XCTAssertEqual(scrollView.contentOffset.x, 0);
465 XCTAssertEqualWithAccuracy(scrollView.contentOffset.y, scrollPosition * effectivelyScale,
466 kFloatCompareEpsilon);
467 }
468
469 - (void)testCanHandleNaNScrollExtentAndScrollPoisition {
470 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
471 new flutter::testing::MockAccessibilityBridge());
472 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
473
474 float transformScale = 0.5f;
475 float screenScale = [[bridge->view() window] screen].scale;
476 float effectivelyScale = transformScale / screenScale;
477 float x = 10;
478 float y = 10;
479 float w = 100;
480 float h = 200;
481 float scrollExtentMax = std::nan("");
482 float scrollPosition = std::nan("");
483
484 flutter::SemanticsNode node;
485 node.flags = static_cast<int32_t>(flutter::SemanticsFlags::kHasImplicitScrolling);
486 node.actions = flutter::kVerticalScrollSemanticsActions;
487 node.rect = SkRect::MakeXYWH(x, y, w, h);
488 node.scrollExtentMax = scrollExtentMax;
489 node.scrollPosition = scrollPosition;
490 node.transform = {
491 transformScale, 0, 0, 0, 0, transformScale, 0, 0, 0, 0, transformScale, 0, 0, 0, 0, 1.0};
492 FlutterScrollableSemanticsObject* scrollable =
493 [[FlutterScrollableSemanticsObject alloc] initWithBridge:bridge uid:0];
494 [scrollable setSemanticsNode:&node];
495 [scrollable accessibilityBridgeDidFinishUpdate];
496 UIScrollView* scrollView = [scrollable nativeAccessibility];
497
498 XCTAssertEqualWithAccuracy(scrollView.frame.origin.x, x * effectivelyScale, kFloatCompareEpsilon);
499 XCTAssertEqualWithAccuracy(scrollView.frame.origin.y, y * effectivelyScale, kFloatCompareEpsilon);
500 XCTAssertEqualWithAccuracy(scrollView.frame.size.width, w * effectivelyScale,
501 kFloatCompareEpsilon);
502 XCTAssertEqualWithAccuracy(scrollView.frame.size.height, h * effectivelyScale,
503 kFloatCompareEpsilon);
504
505 // Content size equal to the scrollable size.
506 XCTAssertEqualWithAccuracy(scrollView.contentSize.width, w * effectivelyScale,
507 kFloatCompareEpsilon);
508 XCTAssertEqualWithAccuracy(scrollView.contentSize.height, h * effectivelyScale,
509 kFloatCompareEpsilon);
510
511 XCTAssertEqual(scrollView.contentOffset.x, 0);
512 XCTAssertEqual(scrollView.contentOffset.y, 0);
513 }
514
515 - (void)testFlutterScrollableSemanticsObjectIsNotHittestable {
516 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
517 new flutter::testing::MockAccessibilityBridge());
518 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
519
520 flutter::SemanticsNode node;
521 node.flags = static_cast<int32_t>(flutter::SemanticsFlags::kHasImplicitScrolling);
522 node.actions = flutter::kHorizontalScrollSemanticsActions;
523 node.rect = SkRect::MakeXYWH(0, 0, 100, 200);
524 node.scrollExtentMax = 100.0;
525 node.scrollPosition = 0.0;
526
527 FlutterScrollableSemanticsObject* scrollable =
528 [[FlutterScrollableSemanticsObject alloc] initWithBridge:bridge uid:0];
529 [scrollable setSemanticsNode:&node];
530 [scrollable accessibilityBridgeDidFinishUpdate];
531 UIScrollView* scrollView = [scrollable nativeAccessibility];
532 XCTAssertEqual([scrollView hitTest:CGPointMake(10, 10) withEvent:nil], nil);
533 }
534
535 - (void)testFlutterScrollableSemanticsObjectIsHiddenWhenVoiceOverIsRunning {
536 flutter::testing::MockAccessibilityBridge* mock = new flutter::testing::MockAccessibilityBridge();
537 mock->isVoiceOverRunningValue = false;
538 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(mock);
539 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
540
541 flutter::SemanticsNode node;
542 node.flags = static_cast<int32_t>(flutter::SemanticsFlags::kHasImplicitScrolling);
543 node.actions = flutter::kHorizontalScrollSemanticsActions;
544 node.rect = SkRect::MakeXYWH(0, 0, 100, 200);
545 node.scrollExtentMax = 100.0;
546 node.scrollPosition = 0.0;
547
548 FlutterScrollableSemanticsObject* scrollable =
549 [[FlutterScrollableSemanticsObject alloc] initWithBridge:bridge uid:0];
550 [scrollable setSemanticsNode:&node];
551 [scrollable accessibilityBridgeDidFinishUpdate];
552 UIScrollView* scrollView = [scrollable nativeAccessibility];
553 XCTAssertTrue(scrollView.isAccessibilityElement);
554 mock->isVoiceOverRunningValue = true;
555 XCTAssertFalse(scrollView.isAccessibilityElement);
556 }
557
558 - (void)testFlutterSemanticsObjectHasIdentifier {
559 flutter::testing::MockAccessibilityBridge* mock = new flutter::testing::MockAccessibilityBridge();
560 mock->isVoiceOverRunningValue = true;
561 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(mock);
562 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
563
564 flutter::SemanticsNode node;
565 node.identifier = "identifier";
566
567 FlutterSemanticsObject* object = [[FlutterSemanticsObject alloc] initWithBridge:bridge uid:0];
568 [object setSemanticsNode:&node];
569 XCTAssertTrue([object.accessibilityIdentifier isEqualToString:@"identifier"]);
570 }
571
572 - (void)testFlutterScrollableSemanticsObjectWithLabelValueHintIsNotHiddenWhenVoiceOverIsRunning {
573 flutter::testing::MockAccessibilityBridge* mock = new flutter::testing::MockAccessibilityBridge();
574 mock->isVoiceOverRunningValue = true;
575 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(mock);
576 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
577
578 flutter::SemanticsNode node;
579 node.flags = static_cast<int32_t>(flutter::SemanticsFlags::kHasImplicitScrolling);
580 node.actions = flutter::kHorizontalScrollSemanticsActions;
581 node.rect = SkRect::MakeXYWH(0, 0, 100, 200);
582 node.label = "label";
583 node.value = "value";
584 node.hint = "hint";
585 node.scrollExtentMax = 100.0;
586 node.scrollPosition = 0.0;
587
588 FlutterScrollableSemanticsObject* scrollable =
589 [[FlutterScrollableSemanticsObject alloc] initWithBridge:bridge uid:0];
590 [scrollable setSemanticsNode:&node];
591 [scrollable accessibilityBridgeDidFinishUpdate];
592 UIScrollView* scrollView = [scrollable nativeAccessibility];
593 XCTAssertTrue(scrollView.isAccessibilityElement);
594 XCTAssertTrue(
595 [scrollView.accessibilityLabel isEqualToString:NSLocalizedString(@"label", @"test")]);
596 XCTAssertTrue(
597 [scrollView.accessibilityValue isEqualToString:NSLocalizedString(@"value", @"test")]);
598 XCTAssertTrue([scrollView.accessibilityHint isEqualToString:NSLocalizedString(@"hint", @"test")]);
599 }
600
601 - (void)testFlutterSemanticsObjectMergeTooltipToLabel {
602 flutter::testing::MockAccessibilityBridge* mock = new flutter::testing::MockAccessibilityBridge();
603 mock->isVoiceOverRunningValue = true;
604 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(mock);
605 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
606
607 flutter::SemanticsNode node;
608 node.rect = SkRect::MakeXYWH(0, 0, 100, 200);
609 node.label = "label";
610 node.tooltip = "tooltip";
611 FlutterSemanticsObject* object = [[FlutterSemanticsObject alloc] initWithBridge:bridge uid:0];
612 [object setSemanticsNode:&node];
613 XCTAssertTrue(object.isAccessibilityElement);
614 XCTAssertTrue([object.accessibilityLabel isEqualToString:@"label\ntooltip"]);
615 }
616
617 - (void)testSemanticsObjectContainerAccessibilityFrameCoversEntireScreen {
618 flutter::testing::MockAccessibilityBridge* mock = new flutter::testing::MockAccessibilityBridge();
619 mock->isVoiceOverRunningValue = true;
620 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(mock);
621 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
622
623 flutter::SemanticsNode parent;
624 parent.id = 0;
625 parent.actions = static_cast<int32_t>(flutter::SemanticsAction::kTap);
626
627 flutter::SemanticsNode child;
628 child.id = 1;
629 child.actions = static_cast<int32_t>(flutter::SemanticsAction::kTap);
630 child.rect = SkRect::MakeXYWH(0, 0, 100, 100);
631 parent.childrenInTraversalOrder.push_back(1);
632
633 FlutterSemanticsObject* parentObject = [[FlutterSemanticsObject alloc] initWithBridge:bridge
634 uid:0];
635 [parentObject setSemanticsNode:&parent];
636
637 FlutterSemanticsObject* childObject = [[FlutterSemanticsObject alloc] initWithBridge:bridge
638 uid:1];
639 [childObject setSemanticsNode:&child];
640
641 parentObject.children = @[ childObject ];
642 [parentObject accessibilityBridgeDidFinishUpdate];
643 [childObject accessibilityBridgeDidFinishUpdate];
644
645 SemanticsObjectContainer* container =
646 static_cast<SemanticsObjectContainer*>(parentObject.accessibilityContainer);
647
648 XCTAssertTrue(childObject.accessibilityRespondsToUserInteraction);
649 XCTAssertTrue(CGRectEqualToRect(container.accessibilityFrame, UIScreen.mainScreen.bounds));
650 }
651
652 - (void)testFlutterSemanticsObjectAttributedStringsDoNotCrashWhenEmpty {
653 flutter::testing::MockAccessibilityBridge* mock = new flutter::testing::MockAccessibilityBridge();
654 mock->isVoiceOverRunningValue = true;
655 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(mock);
656 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
657
658 flutter::SemanticsNode node;
659 node.rect = SkRect::MakeXYWH(0, 0, 100, 200);
660 FlutterSemanticsObject* object = [[FlutterSemanticsObject alloc] initWithBridge:bridge uid:0];
661 [object setSemanticsNode:&node];
662 XCTAssertTrue(object.accessibilityAttributedLabel == nil);
663 }
664
665 - (void)testFlutterScrollableSemanticsObjectReturnsParentContainerIfNoChildren {
666 flutter::testing::MockAccessibilityBridge* mock = new flutter::testing::MockAccessibilityBridge();
667 mock->isVoiceOverRunningValue = true;
668 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(mock);
669 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
670
671 flutter::SemanticsNode parent;
672 parent.id = 0;
673 parent.rect = SkRect::MakeXYWH(0, 0, 100, 200);
674 parent.label = "label";
675 parent.value = "value";
676 parent.hint = "hint";
677
678 flutter::SemanticsNode node;
679 node.id = 1;
680 node.flags = static_cast<int32_t>(flutter::SemanticsFlags::kHasImplicitScrolling);
681 node.actions = flutter::kHorizontalScrollSemanticsActions;
682 node.rect = SkRect::MakeXYWH(0, 0, 100, 200);
683 node.label = "label";
684 node.value = "value";
685 node.hint = "hint";
686 node.scrollExtentMax = 100.0;
687 node.scrollPosition = 0.0;
688 parent.childrenInTraversalOrder.push_back(1);
689
690 FlutterSemanticsObject* parentObject = [[FlutterSemanticsObject alloc] initWithBridge:bridge
691 uid:0];
692 [parentObject setSemanticsNode:&parent];
693
694 FlutterScrollableSemanticsObject* scrollable =
695 [[FlutterScrollableSemanticsObject alloc] initWithBridge:bridge uid:1];
696 [scrollable setSemanticsNode:&node];
697 UIScrollView* scrollView = [scrollable nativeAccessibility];
698
699 parentObject.children = @[ scrollable ];
700 [parentObject accessibilityBridgeDidFinishUpdate];
701 [scrollable accessibilityBridgeDidFinishUpdate];
702 XCTAssertTrue(scrollView.isAccessibilityElement);
703 SemanticsObjectContainer* container =
704 static_cast<SemanticsObjectContainer*>(scrollable.accessibilityContainer);
705 XCTAssertEqual(container.semanticsObject, parentObject);
706 }
707
708 - (void)testFlutterScrollableSemanticsObjectNoScrollBarOrContentInsets {
709 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
710 new flutter::testing::MockAccessibilityBridge());
711 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
712
713 flutter::SemanticsNode node;
714 node.flags = static_cast<int32_t>(flutter::SemanticsFlags::kHasImplicitScrolling);
715 node.actions = flutter::kHorizontalScrollSemanticsActions;
716 node.rect = SkRect::MakeXYWH(0, 0, 100, 200);
717 node.scrollExtentMax = 100.0;
718 node.scrollPosition = 0.0;
719
720 FlutterScrollableSemanticsObject* scrollable =
721 [[FlutterScrollableSemanticsObject alloc] initWithBridge:bridge uid:0];
722 [scrollable setSemanticsNode:&node];
723 [scrollable accessibilityBridgeDidFinishUpdate];
724 UIScrollView* scrollView = [scrollable nativeAccessibility];
725
726 XCTAssertFalse(scrollView.showsHorizontalScrollIndicator);
727 XCTAssertFalse(scrollView.showsVerticalScrollIndicator);
728 XCTAssertEqual(scrollView.contentInsetAdjustmentBehavior,
729 UIScrollViewContentInsetAdjustmentNever);
730 XCTAssertTrue(UIEdgeInsetsEqualToEdgeInsets(scrollView.contentInset, UIEdgeInsetsZero));
731 }
732
733 - (void)testSemanticsObjectBuildsAttributedString {
734 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
735 new flutter::testing::MockAccessibilityBridge());
736 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
737 flutter::SemanticsNode node;
738 node.label = "label";
739 std::shared_ptr<flutter::SpellOutStringAttribute> attribute =
740 std::make_shared<flutter::SpellOutStringAttribute>();
741 attribute->start = 1;
742 attribute->end = 2;
743 attribute->type = flutter::StringAttributeType::kSpellOut;
744 node.labelAttributes.push_back(attribute);
745 node.value = "value";
746 attribute = std::make_shared<flutter::SpellOutStringAttribute>();
747 attribute->start = 2;
748 attribute->end = 3;
749 attribute->type = flutter::StringAttributeType::kSpellOut;
750 node.valueAttributes.push_back(attribute);
751 node.hint = "hint";
752 std::shared_ptr<flutter::LocaleStringAttribute> local_attribute =
753 std::make_shared<flutter::LocaleStringAttribute>();
754 local_attribute->start = 3;
755 local_attribute->end = 4;
756 local_attribute->type = flutter::StringAttributeType::kLocale;
757 local_attribute->locale = "en-MX";
758 node.hintAttributes.push_back(local_attribute);
759 FlutterSemanticsObject* object = [[FlutterSemanticsObject alloc] initWithBridge:bridge uid:0];
760 [object setSemanticsNode:&node];
761 NSMutableAttributedString* expectedAttributedLabel =
762 [[NSMutableAttributedString alloc] initWithString:NSLocalizedString(@"label", @"test")];
763 NSDictionary* attributeDict = @{
764 UIAccessibilitySpeechAttributeSpellOut : @YES,
765 };
766 [expectedAttributedLabel setAttributes:attributeDict range:NSMakeRange(1, 1)];
767 XCTAssertTrue(
768 [object.accessibilityAttributedLabel isEqualToAttributedString:expectedAttributedLabel]);
769
770 NSMutableAttributedString* expectedAttributedValue =
771 [[NSMutableAttributedString alloc] initWithString:NSLocalizedString(@"value", @"test")];
772 attributeDict = @{
773 UIAccessibilitySpeechAttributeSpellOut : @YES,
774 };
775 [expectedAttributedValue setAttributes:attributeDict range:NSMakeRange(2, 1)];
776 XCTAssertTrue(
777 [object.accessibilityAttributedValue isEqualToAttributedString:expectedAttributedValue]);
778
779 NSMutableAttributedString* expectedAttributedHint =
780 [[NSMutableAttributedString alloc] initWithString:NSLocalizedString(@"hint", @"test")];
781 attributeDict = @{
782 UIAccessibilitySpeechAttributeLanguage : @"en-MX",
783 };
784 [expectedAttributedHint setAttributes:attributeDict range:NSMakeRange(3, 1)];
785 XCTAssertTrue(
786 [object.accessibilityAttributedHint isEqualToAttributedString:expectedAttributedHint]);
787 }
788
789 - (void)testShouldTriggerAnnouncement {
790 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
791 new flutter::testing::MockAccessibilityBridge());
792 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
793 SemanticsObject* object = [[SemanticsObject alloc] initWithBridge:bridge uid:0];
794
795 // Handle nil with no node set.
796 XCTAssertFalse([object nodeShouldTriggerAnnouncement:nil]);
797
798 // Handle initial setting of node with liveRegion
799 flutter::SemanticsNode node;
800 node.flags = static_cast<int32_t>(flutter::SemanticsFlags::kIsLiveRegion);
801 node.label = "foo";
802 XCTAssertTrue([object nodeShouldTriggerAnnouncement:&node]);
803
804 // Handle nil with node set.
805 [object setSemanticsNode:&node];
806 XCTAssertFalse([object nodeShouldTriggerAnnouncement:nil]);
807
808 // Handle new node, still has live region, same label.
809 XCTAssertFalse([object nodeShouldTriggerAnnouncement:&node]);
810
811 // Handle update node with new label, still has live region.
812 flutter::SemanticsNode updatedNode;
813 updatedNode.flags = static_cast<int32_t>(flutter::SemanticsFlags::kIsLiveRegion);
814 updatedNode.label = "bar";
815 XCTAssertTrue([object nodeShouldTriggerAnnouncement:&updatedNode]);
816
817 // Handle dropping the live region flag.
818 updatedNode.flags = 0;
819 XCTAssertFalse([object nodeShouldTriggerAnnouncement:&updatedNode]);
820
821 // Handle adding the flag when the label has not changed.
822 updatedNode.label = "foo";
823 [object setSemanticsNode:&updatedNode];
824 XCTAssertTrue([object nodeShouldTriggerAnnouncement:&node]);
825 }
826
827 - (void)testShouldDispatchShowOnScreenActionForHeader {
828 fml::WeakPtrFactory<flutter::testing::MockAccessibilityBridge> factory(
829 new flutter::testing::MockAccessibilityBridge());
830 fml::WeakPtr<flutter::testing::MockAccessibilityBridge> bridge = factory.GetWeakPtr();
831 SemanticsObject* object = [[SemanticsObject alloc] initWithBridge:bridge uid:1];
832
833 // Handle initial setting of node with header.
834 flutter::SemanticsNode node;
835 node.flags = static_cast<int32_t>(flutter::SemanticsFlags::kIsHeader);
836 node.label = "foo";
837
838 [object setSemanticsNode:&node];
839
840 // Simulate accessibility focus.
841 [object accessibilityElementDidBecomeFocused];
842
843 XCTAssertTrue(bridge->observations.size() == 1);
844 XCTAssertTrue(bridge->observations[0].id == 1);
845 XCTAssertTrue(bridge->observations[0].action == flutter::SemanticsAction::kShowOnScreen);
846 }
847
848 - (void)testShouldDispatchShowOnScreenActionForHidden {
849 fml::WeakPtrFactory<flutter::testing::MockAccessibilityBridge> factory(
850 new flutter::testing::MockAccessibilityBridge());
851 fml::WeakPtr<flutter::testing::MockAccessibilityBridge> bridge = factory.GetWeakPtr();
852 SemanticsObject* object = [[SemanticsObject alloc] initWithBridge:bridge uid:1];
853
854 // Handle initial setting of node with hidden.
855 flutter::SemanticsNode node;
856 node.flags = static_cast<int32_t>(flutter::SemanticsFlags::kIsHidden);
857 node.label = "foo";
858
859 [object setSemanticsNode:&node];
860
861 // Simulate accessibility focus.
862 [object accessibilityElementDidBecomeFocused];
863
864 XCTAssertTrue(bridge->observations.size() == 1);
865 XCTAssertTrue(bridge->observations[0].id == 1);
866 XCTAssertTrue(bridge->observations[0].action == flutter::SemanticsAction::kShowOnScreen);
867 }
868
869 - (void)testFlutterSwitchSemanticsObjectMatchesUISwitch {
870 fml::WeakPtrFactory<flutter::testing::MockAccessibilityBridge> factory(
871 new flutter::testing::MockAccessibilityBridge());
872 fml::WeakPtr<flutter::testing::MockAccessibilityBridge> bridge = factory.GetWeakPtr();
873 FlutterSwitchSemanticsObject* object = [[FlutterSwitchSemanticsObject alloc] initWithBridge:bridge
874 uid:1];
875
876 // Handle initial setting of node with header.
877 flutter::SemanticsNode node;
878 node.flags = static_cast<int32_t>(flutter::SemanticsFlags::kHasToggledState) |
879 static_cast<int32_t>(flutter::SemanticsFlags::kIsToggled) |
880 static_cast<int32_t>(flutter::SemanticsFlags::kIsEnabled);
881 node.label = "foo";
882 [object setSemanticsNode:&node];
883 // Create ab real UISwitch to compare the FlutterSwitchSemanticsObject with.
884 UISwitch* nativeSwitch = [[UISwitch alloc] init];
885 nativeSwitch.on = YES;
886
887 XCTAssertEqual(object.accessibilityTraits, nativeSwitch.accessibilityTraits);
888 XCTAssertEqualObjects(object.accessibilityValue, nativeSwitch.accessibilityValue);
889
890 // Set the toggled to false;
891 flutter::SemanticsNode update;
892 update.flags = static_cast<int32_t>(flutter::SemanticsFlags::kHasToggledState) |
893 static_cast<int32_t>(flutter::SemanticsFlags::kIsEnabled);
894 update.label = "foo";
895 [object setSemanticsNode:&update];
896
897 nativeSwitch.on = NO;
898
899 XCTAssertEqual(object.accessibilityTraits, nativeSwitch.accessibilityTraits);
900 XCTAssertEqualObjects(object.accessibilityValue, nativeSwitch.accessibilityValue);
901 }
902
903 - (void)testFlutterSemanticsObjectOfRadioButton {
904 fml::WeakPtrFactory<flutter::testing::MockAccessibilityBridge> factory(
905 new flutter::testing::MockAccessibilityBridge());
906 fml::WeakPtr<flutter::testing::MockAccessibilityBridge> bridge = factory.GetWeakPtr();
907 FlutterSemanticsObject* object = [[FlutterSemanticsObject alloc] initWithBridge:bridge uid:0];
908
909 // Handle initial setting of node with header.
910 flutter::SemanticsNode node;
911 node.flags = static_cast<int32_t>(flutter::SemanticsFlags::kIsInMutuallyExclusiveGroup) |
912 static_cast<int32_t>(flutter::SemanticsFlags::kHasCheckedState) |
913 static_cast<int32_t>(flutter::SemanticsFlags::kHasEnabledState) |
914 static_cast<int32_t>(flutter::SemanticsFlags::kIsEnabled);
915 node.label = "foo";
916 [object setSemanticsNode:&node];
917 XCTAssertTrue((object.accessibilityTraits & UIAccessibilityTraitButton) > 0);
918 XCTAssertNil(object.accessibilityValue);
919 }
920
921 - (void)testFlutterSwitchSemanticsObjectMatchesUISwitchDisabled {
922 fml::WeakPtrFactory<flutter::testing::MockAccessibilityBridge> factory(
923 new flutter::testing::MockAccessibilityBridge());
924 fml::WeakPtr<flutter::testing::MockAccessibilityBridge> bridge = factory.GetWeakPtr();
925 FlutterSwitchSemanticsObject* object = [[FlutterSwitchSemanticsObject alloc] initWithBridge:bridge
926 uid:1];
927
928 // Handle initial setting of node with header.
929 flutter::SemanticsNode node;
930 node.flags = static_cast<int32_t>(flutter::SemanticsFlags::kHasToggledState) |
931 static_cast<int32_t>(flutter::SemanticsFlags::kIsToggled);
932 node.label = "foo";
933 [object setSemanticsNode:&node];
934 // Create ab real UISwitch to compare the FlutterSwitchSemanticsObject with.
935 UISwitch* nativeSwitch = [[UISwitch alloc] init];
936 nativeSwitch.on = YES;
937 nativeSwitch.enabled = NO;
938
939 XCTAssertEqual(object.accessibilityTraits, nativeSwitch.accessibilityTraits);
940 XCTAssertEqualObjects(object.accessibilityValue, nativeSwitch.accessibilityValue);
941 }
942
943 - (void)testSemanticsObjectDeallocated {
944 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
945 new flutter::testing::MockAccessibilityBridge());
946 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
947 SemanticsObject* parent = [[SemanticsObject alloc] initWithBridge:bridge uid:0];
948 SemanticsObject* child = [[SemanticsObject alloc] initWithBridge:bridge uid:1];
949 parent.children = @[ child ];
950 // Validate SemanticsObject deallocation does not crash.
951 // https://github.com/flutter/flutter/issues/66032
952 __weak SemanticsObject* weakObject = parent;
953 parent = nil;
954 XCTAssertNil(weakObject);
955 }
956
957 - (void)testFlutterSemanticsObjectReturnsNilContainerWhenBridgeIsNotAlive {
958 FlutterSemanticsObject* parentObject;
959 FlutterScrollableSemanticsObject* scrollable;
960 FlutterSemanticsObject* object2;
961
962 flutter::SemanticsNode parent;
963 parent.id = 0;
964 parent.rect = SkRect::MakeXYWH(0, 0, 100, 200);
965 parent.label = "label";
966 parent.value = "value";
967 parent.hint = "hint";
968
969 flutter::SemanticsNode node;
970 node.id = 1;
971 node.flags = static_cast<int32_t>(flutter::SemanticsFlags::kHasImplicitScrolling);
972 node.actions = flutter::kHorizontalScrollSemanticsActions;
973 node.rect = SkRect::MakeXYWH(0, 0, 100, 200);
974 node.label = "label";
975 node.value = "value";
976 node.hint = "hint";
977 node.scrollExtentMax = 100.0;
978 node.scrollPosition = 0.0;
979 parent.childrenInTraversalOrder.push_back(1);
980
981 flutter::SemanticsNode node2;
982 node2.id = 2;
983 node2.rect = SkRect::MakeXYWH(0, 0, 100, 200);
984 node2.label = "label";
985 node2.value = "value";
986 node2.hint = "hint";
987 node2.scrollExtentMax = 100.0;
988 node2.scrollPosition = 0.0;
989 parent.childrenInTraversalOrder.push_back(2);
990
991 {
992 flutter::testing::MockAccessibilityBridge* mock =
993 new flutter::testing::MockAccessibilityBridge();
994 mock->isVoiceOverRunningValue = true;
995 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(mock);
996 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
997
998 parentObject = [[FlutterSemanticsObject alloc] initWithBridge:bridge uid:0];
999 [parentObject setSemanticsNode:&parent];
1000
1001 scrollable = [[FlutterScrollableSemanticsObject alloc] initWithBridge:bridge uid:1];
1002 [scrollable setSemanticsNode:&node];
1003 [scrollable accessibilityBridgeDidFinishUpdate];
1004
1005 object2 = [[FlutterSemanticsObject alloc] initWithBridge:bridge uid:2];
1006 [object2 setSemanticsNode:&node2];
1007
1008 parentObject.children = @[ scrollable, object2 ];
1009 [parentObject accessibilityBridgeDidFinishUpdate];
1010 [scrollable accessibilityBridgeDidFinishUpdate];
1011 [object2 accessibilityBridgeDidFinishUpdate];
1012
1013 // Returns the correct container if the bridge is alive.
1014 SemanticsObjectContainer* container =
1015 static_cast<SemanticsObjectContainer*>(scrollable.accessibilityContainer);
1016 XCTAssertEqual(container.semanticsObject, parentObject);
1017 SemanticsObjectContainer* container2 =
1018 static_cast<SemanticsObjectContainer*>(object2.accessibilityContainer);
1019 XCTAssertEqual(container2.semanticsObject, parentObject);
1020 }
1021 // The bridge pointer went out of scope and was deallocated.
1022
1023 XCTAssertNil(scrollable.accessibilityContainer);
1024 XCTAssertNil(object2.accessibilityContainer);
1025 }
1026
1027 - (void)testAccessibilityHitTestSearchCanReturnPlatformView {
1028 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
1029 new flutter::testing::MockAccessibilityBridge());
1030 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
1031 SemanticsObject* object0 = [[SemanticsObject alloc] initWithBridge:bridge uid:0];
1032 SemanticsObject* object1 = [[SemanticsObject alloc] initWithBridge:bridge uid:1];
1033 SemanticsObject* object3 = [[SemanticsObject alloc] initWithBridge:bridge uid:3];
1034 FlutterTouchInterceptingView* platformView =
1035 [[FlutterTouchInterceptingView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];
1036 FlutterPlatformViewSemanticsContainer* platformViewSemanticsContainer =
1037 [[FlutterPlatformViewSemanticsContainer alloc] initWithBridge:bridge
1038 uid:1
1039 platformView:platformView];
1040
1041 object0.children = @[ object1 ];
1042 object0.childrenInHitTestOrder = @[ object1 ];
1043 object1.children = @[ platformViewSemanticsContainer, object3 ];
1044 object1.childrenInHitTestOrder = @[ platformViewSemanticsContainer, object3 ];
1045
1046 flutter::SemanticsNode node0;
1047 node0.id = 0;
1048 node0.rect = SkRect::MakeXYWH(0, 0, 200, 200);
1049 node0.label = "0";
1050 [object0 setSemanticsNode:&node0];
1051
1052 flutter::SemanticsNode node1;
1053 node1.id = 1;
1054 node1.rect = SkRect::MakeXYWH(0, 0, 200, 200);
1055 node1.label = "1";
1056 [object1 setSemanticsNode:&node1];
1057
1058 flutter::SemanticsNode node2;
1059 node2.id = 2;
1060 node2.rect = SkRect::MakeXYWH(0, 0, 100, 100);
1061 node2.label = "2";
1062 [platformViewSemanticsContainer setSemanticsNode:&node2];
1063
1064 flutter::SemanticsNode node3;
1065 node3.id = 3;
1066 node3.rect = SkRect::MakeXYWH(0, 0, 200, 200);
1067 node3.label = "3";
1068 [object3 setSemanticsNode:&node3];
1069
1070 CGPoint point = CGPointMake(10, 10);
1071 id hitTestResult = [object0 _accessibilityHitTest:point withEvent:nil];
1072
1073 XCTAssertEqual(hitTestResult, platformView);
1074 }
1075
1076 - (void)testFlutterPlatformViewSemanticsContainer {
1077 fml::WeakPtrFactory<flutter::testing::MockAccessibilityBridge> factory(
1078 new flutter::testing::MockAccessibilityBridge());
1079 fml::WeakPtr<flutter::testing::MockAccessibilityBridge> bridge = factory.GetWeakPtr();
1080 __weak FlutterTouchInterceptingView* weakPlatformView;
1081 __weak FlutterPlatformViewSemanticsContainer* weakContainer;
1082 @autoreleasepool {
1083 FlutterTouchInterceptingView* platformView = [[FlutterTouchInterceptingView alloc] init];
1084 weakPlatformView = platformView;
1085
1086 @autoreleasepool {
1087 FlutterPlatformViewSemanticsContainer* container =
1088 [[FlutterPlatformViewSemanticsContainer alloc] initWithBridge:bridge
1089 uid:1
1090 platformView:platformView];
1091 weakContainer = container;
1092 XCTAssertEqualObjects(platformView.accessibilityContainer, container);
1093 XCTAssertNotNil(weakPlatformView);
1094 XCTAssertNotNil(weakContainer);
1095 }
1096 // Check the variables are still lived.
1097 // `container` is `retain` in `platformView`, so it will not be nil here.
1098 XCTAssertNotNil(weakPlatformView);
1099 XCTAssertNotNil(weakContainer);
1100 }
1101 // Check if there's no more strong references to `platformView` after container and platformView
1102 // are released.
1103 XCTAssertNil(weakPlatformView);
1104 XCTAssertNil(weakContainer);
1105 }
1106
1107 - (void)testTextInputSemanticsObject {
1108 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
1109 new flutter::testing::MockAccessibilityBridge());
1110 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
1111
1112 flutter::SemanticsNode node;
1113 node.label = "foo";
1114 node.flags = static_cast<int32_t>(flutter::SemanticsFlags::kIsTextField) |
1115 static_cast<int32_t>(flutter::SemanticsFlags::kIsReadOnly);
1116 TextInputSemanticsObject* object = [[TextInputSemanticsObject alloc] initWithBridge:bridge uid:0];
1117 [object setSemanticsNode:&node];
1118 [object accessibilityBridgeDidFinishUpdate];
1119 XCTAssertEqual([object accessibilityTraits], UIAccessibilityTraitNone);
1120 }
1121
1122 - (void)testTextInputSemanticsObject_canPerformAction {
1123 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
1124 new flutter::testing::MockAccessibilityBridge());
1125 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
1126
1127 flutter::SemanticsNode node;
1128 node.label = "foo";
1129 node.flags = static_cast<int32_t>(flutter::SemanticsFlags::kIsTextField) |
1130 static_cast<int32_t>(flutter::SemanticsFlags::kIsReadOnly);
1131 TextInputSemanticsObject* object = [[TextInputSemanticsObject alloc] initWithBridge:bridge uid:0];
1132 [object setSemanticsNode:&node];
1133 [object accessibilityBridgeDidFinishUpdate];
1134
1135 id textInputSurrogate = OCMClassMock([UIResponder class]);
1136 id partialSemanticsObject = OCMPartialMock(object);
1137 OCMStub([partialSemanticsObject textInputSurrogate]).andReturn(textInputSurrogate);
1138
1139 OCMExpect([textInputSurrogate canPerformAction:[OCMArg anySelector] withSender:OCMOCK_ANY])
1140 .andReturn(YES);
1141 XCTAssertTrue([partialSemanticsObject canPerformAction:@selector(copy:) withSender:nil]);
1142
1143 OCMExpect([textInputSurrogate canPerformAction:[OCMArg anySelector] withSender:OCMOCK_ANY])
1144 .andReturn(NO);
1145 XCTAssertFalse([partialSemanticsObject canPerformAction:@selector(copy:) withSender:nil]);
1146 }
1147
1148 - (void)testTextInputSemanticsObject_editActions {
1149 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
1150 new flutter::testing::MockAccessibilityBridge());
1151 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
1152
1153 flutter::SemanticsNode node;
1154 node.label = "foo";
1155 node.flags = static_cast<int32_t>(flutter::SemanticsFlags::kIsTextField) |
1156 static_cast<int32_t>(flutter::SemanticsFlags::kIsReadOnly);
1157 TextInputSemanticsObject* object = [[TextInputSemanticsObject alloc] initWithBridge:bridge uid:0];
1158 [object setSemanticsNode:&node];
1159 [object accessibilityBridgeDidFinishUpdate];
1160
1161 id textInputSurrogate = OCMClassMock([UIResponder class]);
1162 id partialSemanticsObject = OCMPartialMock(object);
1163 OCMStub([partialSemanticsObject textInputSurrogate]).andReturn(textInputSurrogate);
1164
1165 XCTestExpectation* copyExpectation =
1166 [self expectationWithDescription:@"Surrogate's copy method is called."];
1167 XCTestExpectation* cutExpectation =
1168 [self expectationWithDescription:@"Surrogate's cut method is called."];
1169 XCTestExpectation* pasteExpectation =
1170 [self expectationWithDescription:@"Surrogate's paste method is called."];
1171 XCTestExpectation* selectAllExpectation =
1172 [self expectationWithDescription:@"Surrogate's selectAll method is called."];
1173 XCTestExpectation* deleteExpectation =
1174 [self expectationWithDescription:@"Surrogate's delete method is called."];
1175
1176 OCMStub([textInputSurrogate copy:OCMOCK_ANY]).andDo(^(NSInvocation* invocation) {
1177 [copyExpectation fulfill];
1178 });
1179 OCMStub([textInputSurrogate cut:OCMOCK_ANY]).andDo(^(NSInvocation* invocation) {
1180 [cutExpectation fulfill];
1181 });
1182 OCMStub([textInputSurrogate paste:OCMOCK_ANY]).andDo(^(NSInvocation* invocation) {
1183 [pasteExpectation fulfill];
1184 });
1185 OCMStub([textInputSurrogate selectAll:OCMOCK_ANY]).andDo(^(NSInvocation* invocation) {
1186 [selectAllExpectation fulfill];
1187 });
1188 OCMStub([textInputSurrogate delete:OCMOCK_ANY]).andDo(^(NSInvocation* invocation) {
1189 [deleteExpectation fulfill];
1190 });
1191
1192 [partialSemanticsObject copy:nil];
1193 [partialSemanticsObject cut:nil];
1194 [partialSemanticsObject paste:nil];
1195 [partialSemanticsObject selectAll:nil];
1196 [partialSemanticsObject delete:nil];
1197
1198 [self waitForExpectationsWithTimeout:1 handler:nil];
1199 }
1200
1201 - (void)testSliderSemanticsObject {
1202 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
1203 new flutter::testing::MockAccessibilityBridge());
1204 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
1205
1206 flutter::SemanticsNode node;
1207 node.flags = static_cast<int32_t>(flutter::SemanticsFlags::kIsSlider);
1208 SemanticsObject* object = [[SemanticsObject alloc] initWithBridge:bridge uid:0];
1209 [object setSemanticsNode:&node];
1210 [object accessibilityBridgeDidFinishUpdate];
1211 XCTAssertEqual([object accessibilityActivate], YES);
1212 }
1213
1214 - (void)testUIFocusItemConformance {
1215 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
1216 new flutter::testing::MockAccessibilityBridge());
1217 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
1218 SemanticsObject* parent = [[SemanticsObject alloc] initWithBridge:bridge uid:0];
1219 SemanticsObject* child = [[SemanticsObject alloc] initWithBridge:bridge uid:1];
1220 parent.children = @[ child ];
1221
1222 // parentFocusEnvironment
1223 XCTAssertTrue([parent.parentFocusEnvironment isKindOfClass:[UIView class]]);
1224 XCTAssertEqual(child.parentFocusEnvironment, child.parent);
1225
1226 // canBecomeFocused
1227 flutter::SemanticsNode childNode;
1228 childNode.flags = static_cast<int32_t>(flutter::SemanticsFlags::kIsHidden);
1229 childNode.actions = static_cast<int32_t>(flutter::SemanticsAction::kTap);
1230 [child setSemanticsNode:&childNode];
1231 XCTAssertFalse(child.canBecomeFocused);
1232 childNode.flags = 0;
1233 [child setSemanticsNode:&childNode];
1234 XCTAssertTrue(child.canBecomeFocused);
1235 childNode.actions = 0;
1236 [child setSemanticsNode:&childNode];
1237 XCTAssertFalse(child.canBecomeFocused);
1238
1239 CGFloat scale = ((bridge->view().window.screen ?: UIScreen.mainScreen)).scale;
1240
1241 childNode.rect = SkRect::MakeXYWH(0, 0, 100 * scale, 100 * scale);
1242 [child setSemanticsNode:&childNode];
1243 flutter::SemanticsNode parentNode;
1244 parentNode.rect = SkRect::MakeXYWH(0, 0, 200, 200);
1245 [parent setSemanticsNode:&parentNode];
1246
1247 XCTAssertTrue(CGRectEqualToRect(child.frame, CGRectMake(0, 0, 100, 100)));
1248 }
1249
1250 - (void)testUIFocusItemContainerConformance {
1251 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
1252 new flutter::testing::MockAccessibilityBridge());
1253 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
1254 SemanticsObject* parent = [[SemanticsObject alloc] initWithBridge:bridge uid:0];
1255 SemanticsObject* child1 = [[SemanticsObject alloc] initWithBridge:bridge uid:1];
1256 SemanticsObject* child2 = [[SemanticsObject alloc] initWithBridge:bridge uid:2];
1257 parent.childrenInHitTestOrder = @[ child1, child2 ];
1258
1259 // focusItemsInRect
1260 NSArray<id<UIFocusItem>>* itemsInRect = [parent focusItemsInRect:CGRectMake(0, 0, 100, 100)];
1261 XCTAssertEqual(itemsInRect.count, (unsigned long)2);
1262 XCTAssertTrue([itemsInRect containsObject:child1]);
1263 XCTAssertTrue([itemsInRect containsObject:child2]);
1264 }
1265
1266 - (void)testUIFocusItemScrollableContainerConformance {
1267 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
1268 new flutter::testing::MockAccessibilityBridge());
1269 fml::WeakPtr<flutter::testing::MockAccessibilityBridge> bridge = factory.GetWeakPtr();
1270 FlutterScrollableSemanticsObject* scrollable =
1271 [[FlutterScrollableSemanticsObject alloc] initWithBridge:bridge uid:5];
1272
1273 // setContentOffset
1274 CGPoint p = CGPointMake(123.0, 456.0);
1275 [scrollable.scrollView scrollViewWillEndDragging:scrollable.scrollView
1276 withVelocity:CGPointZero
1277 targetContentOffset:&p];
1278 scrollable.scrollView.contentOffset = p;
1279 [scrollable.scrollView scrollViewDidEndDecelerating:scrollable.scrollView];
1280 XCTAssertEqual(bridge->observations.size(), (size_t)1);
1281 XCTAssertEqual(bridge->observations[0].id, 5);
1282 XCTAssertEqual(bridge->observations[0].action, flutter::SemanticsAction::kScrollToOffset);
1283
1284 std::vector<uint8_t> args = bridge->observations[0].args;
1285 XCTAssertEqual(args.size(), 3 * sizeof(CGFloat));
1286
1287 NSData* encoded = [NSData dataWithBytes:args.data() length:args.size()];
1288 FlutterStandardTypedData* decoded = [[FlutterStandardMessageCodec sharedInstance] decode:encoded];
1289 CGPoint point = CGPointZero;
1290 memcpy(&point, decoded.data.bytes, decoded.data.length);
1291 XCTAssertTrue(CGPointEqualToPoint(point, p));
1292 }
1293
1294 - (void)testUIFocusItemScrollableContainerNoFeedbackLoops {
1295 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
1296 new flutter::testing::MockAccessibilityBridge());
1297 fml::WeakPtr<flutter::testing::MockAccessibilityBridge> bridge = factory.GetWeakPtr();
1298 FlutterScrollableSemanticsObject* scrollable =
1299 [[FlutterScrollableSemanticsObject alloc] initWithBridge:bridge uid:5];
1300
1301 // setContentOffset
1302 const CGPoint p = CGPointMake(0.0, 456.0);
1303 scrollable.scrollView.contentOffset = p;
1304 bridge->observations.clear();
1305
1306 const SkScalar scrollPosition = p.y + 0.0000000000000001;
1307 flutter::SemanticsNode node;
1308 node.flags = static_cast<int32_t>(flutter::SemanticsFlags::kHasImplicitScrolling);
1309 node.actions = flutter::kVerticalScrollSemanticsActions;
1310 node.rect = SkRect::MakeXYWH(0, 0, 100, 200);
1311 node.scrollExtentMax = 10000;
1312 node.scrollPosition = scrollPosition;
1313 node.transform = {1.0, 0, 0, 0, 0, 1.0, 0, 0, 0, 0, 1.0, 0, 0, scrollPosition, 0, 1.0};
1314 [scrollable setSemanticsNode:&node];
1315 [scrollable accessibilityBridgeDidFinishUpdate];
1316
1317 XCTAssertEqual(bridge->observations.size(), (size_t)0);
1318 }
1319 @end
FlutterMacros.h
FlutterPlatformViews_Internal.h
FlutterSemanticsScrollView.h
FlutterTouchInterceptingView_Test.h
SemanticsObject.h
kScrollExtentMaxForInf
constexpr float kScrollExtentMaxForInf
Definition: SemanticsObject.h:18
kFloatCompareEpsilon
FLUTTER_ASSERT_ARC const float kFloatCompareEpsilon
Definition: SemanticsObjectTest.mm:18
SemanticsObjectTestMocks.h
TextInputSemanticsObject.h
FlutterScrollableSemanticsObject(UIFocusItemScrollableContainer)
Definition: SemanticsObjectTest.mm:24
SemanticsObject(UIFocusSystem)
Definition: SemanticsObject+UIFocusSystem.mm:32
TextInputSemanticsObject(Test)
Definition: SemanticsObjectTest.mm:27
-[TextInputSemanticsObject(Test) textInputSurrogate]
UIView< UITextInput > * textInputSurrogate()
FlutterTouchInterceptingView
Definition: FlutterPlatformViews.mm:515
-[FlutterTouchInterceptingView accessibilityContainer]
id accessibilityContainer()
flutter::testing::MockAccessibilityBridge
Definition: SemanticsObjectTestMocks.h:32
flutter::testing::MockAccessibilityBridge::isVoiceOverRunningValue
bool isVoiceOverRunningValue
Definition: SemanticsObjectTestMocks.h:56
flutter::testing::MockAccessibilityBridgeNoWindow
Definition: SemanticsObjectTestMocks.h:63
FlutterPlatformViewSemanticsContainer
Definition: SemanticsObject.h:170
FlutterScrollableSemanticsObject
Definition: SemanticsObject.h:190
FlutterScrollableSemanticsObject::scrollView
FlutterSemanticsScrollView * scrollView
Definition: SemanticsObject.h:190
FlutterSemanticsObject
Definition: SemanticsObject.h:156
FlutterStandardMessageCodec
Definition: FlutterCodecs.h:209
FlutterStandardTypedData
Definition: FlutterCodecs.h:301
FlutterStandardTypedData::data
NSData * data
Definition: FlutterCodecs.h:344
FlutterSwitchSemanticsObject
Definition: SemanticsObject.h:184
SemanticsObjectContainer
Definition: SemanticsObject.h:228
SemanticsObjectContainer::semanticsObject
SemanticsObject * semanticsObject
Definition: SemanticsObject.h:235
SemanticsObject
Definition: SemanticsObject.h:32
-[SemanticsObject _accessibilityHitTest:withEvent:]
id _accessibilityHitTest:withEvent:(CGPoint point,[withEvent] UIEvent *event)
SemanticsObject::parent
SemanticsObject * parent
Definition: SemanticsObject.h:42
SemanticsObject::childrenInHitTestOrder
NSArray< SemanticsObject * > * childrenInHitTestOrder
Definition: SemanticsObject.h:74
SemanticsObject::nativeAccessibility
id nativeAccessibility
Definition: SemanticsObject.h:83
-[SemanticsObject accessibilityScrollToVisibleWithChild:]
BOOL accessibilityScrollToVisibleWithChild:(id child)
-[SemanticsObject accessibilityBridgeDidFinishUpdate]
void accessibilityBridgeDidFinishUpdate()
Definition: SemanticsObject.mm:337
-[SemanticsObject accessibilityScrollToVisible]
BOOL accessibilityScrollToVisible()
SemanticsObject::children
NSArray< SemanticsObject * > * children
Definition: SemanticsObject.h:68
-[SemanticsObject replaceChildAtIndex:withChild:]
void replaceChildAtIndex:withChild:(NSInteger index,[withChild] SemanticsObject *child)
Definition: SemanticsObject.mm:374
-[SemanticsObject setSemanticsNode:]
void setSemanticsNode:(const flutter::SemanticsNode *NS_REQUIRES_SUPER)
Definition: SemanticsObject.mm:333
SemanticsObjectTest
Definition: SemanticsObjectTest.mm:32
TextInputSemanticsObject
Definition: TextInputSemanticsObject.h:20
FLUTTER_ASSERT_ARC
Definition: FlutterChannelKeyResponder.mm:13
+[FlutterMessageCodec-p sharedInstance]
instancetype sharedInstance()