@@ -450,7 +450,7 @@ - (void)testAnnouncesLayoutChangeWithNilIfLastFocusIsRemoved {
450
450
451
451
XCTAssertEqual ([accessibility_notifications count ], 0ul );
452
452
// Simulates the focusing on the node 1.
453
- bridge->AccessibilityFocusDidChange (1 );
453
+ bridge->AccessibilityObjectDidBecomeFocused (1 );
454
454
455
455
flutter::SemanticsNodeUpdates second_update;
456
456
// Simulates the removal of the node 1
@@ -520,7 +520,7 @@ - (void)testAnnouncesLayoutChangeWithLastFocused {
520
520
521
521
XCTAssertEqual ([accessibility_notifications count ], 0ul );
522
522
// Simulates the focusing on the node 1.
523
- bridge->AccessibilityFocusDidChange (1 );
523
+ bridge->AccessibilityObjectDidBecomeFocused (1 );
524
524
525
525
flutter::SemanticsNodeUpdates second_update;
526
526
// Simulates the removal of the node 2.
@@ -539,6 +539,80 @@ - (void)testAnnouncesLayoutChangeWithLastFocused {
539
539
UIAccessibilityLayoutChangedNotification);
540
540
}
541
541
542
+ - (void )testAnnouncesLayoutChangeWhenFocusMovedOutside {
543
+ flutter::MockDelegate mock_delegate;
544
+ auto thread_task_runner = CreateNewThread (" AccessibilityBridgeTest" );
545
+ flutter::TaskRunners runners (/* label=*/ self.name .UTF8String ,
546
+ /* platform=*/ thread_task_runner,
547
+ /* raster=*/ thread_task_runner,
548
+ /* ui=*/ thread_task_runner,
549
+ /* io=*/ thread_task_runner);
550
+ auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
551
+ /* delegate=*/ mock_delegate,
552
+ /* rendering_api=*/ flutter::IOSRenderingAPI::kSoftware ,
553
+ /* task_runners=*/ runners);
554
+ id mockFlutterViewController = OCMClassMock ([FlutterViewController class ]);
555
+ id mockFlutterView = OCMClassMock ([FlutterView class ]);
556
+ OCMStub ([mockFlutterViewController view ]).andReturn (mockFlutterView);
557
+
558
+ NSMutableArray <NSDictionary <NSString *, id >*>* accessibility_notifications =
559
+ [[[NSMutableArray alloc ] init ] autorelease ];
560
+ auto ios_delegate = std::make_unique<flutter::MockIosDelegate>();
561
+ ios_delegate->on_PostAccessibilityNotification_ =
562
+ [accessibility_notifications](UIAccessibilityNotifications notification, id argument) {
563
+ [accessibility_notifications addObject: @{
564
+ @" notification" : @(notification),
565
+ @" argument" : argument ? argument : [NSNull null ],
566
+ }];
567
+ };
568
+ __block auto bridge =
569
+ std::make_unique<flutter::AccessibilityBridge>(/* view_controller=*/ mockFlutterViewController,
570
+ /* platform_view=*/ platform_view.get (),
571
+ /* platform_views_controller=*/ nil ,
572
+ /* ios_delegate=*/ std::move (ios_delegate));
573
+
574
+ flutter::CustomAccessibilityActionUpdates actions;
575
+ flutter::SemanticsNodeUpdates first_update;
576
+
577
+ flutter::SemanticsNode node_one;
578
+ node_one.id = 1 ;
579
+ node_one.label = " route1" ;
580
+ first_update[node_one.id ] = node_one;
581
+ flutter::SemanticsNode node_two;
582
+ node_two.id = 2 ;
583
+ node_two.label = " route2" ;
584
+ first_update[node_two.id ] = node_two;
585
+ flutter::SemanticsNode root_node;
586
+ root_node.id = kRootNodeId ;
587
+ root_node.label = " root" ;
588
+ root_node.childrenInTraversalOrder = {1 , 2 };
589
+ root_node.childrenInHitTestOrder = {1 , 2 };
590
+ first_update[root_node.id ] = root_node;
591
+ bridge->UpdateSemantics (/* nodes=*/ first_update, /* actions=*/ actions);
592
+
593
+ XCTAssertEqual ([accessibility_notifications count ], 0ul );
594
+ // Simulates the focusing on the node 1.
595
+ bridge->AccessibilityObjectDidBecomeFocused (1 );
596
+ // Simulates that the focus move outside of flutter.
597
+ bridge->AccessibilityObjectDidLoseFocus (1 );
598
+
599
+ flutter::SemanticsNodeUpdates second_update;
600
+ // Simulates the removal of the node 2.
601
+ flutter::SemanticsNode new_root_node;
602
+ new_root_node.id = kRootNodeId ;
603
+ new_root_node.label = " root" ;
604
+ new_root_node.childrenInTraversalOrder = {1 };
605
+ new_root_node.childrenInHitTestOrder = {1 };
606
+ second_update[root_node.id ] = new_root_node;
607
+ bridge->UpdateSemantics (/* nodes=*/ second_update, /* actions=*/ actions);
608
+ NSNull * focusObject = accessibility_notifications[0 ][@" argument" ];
609
+ // Since the focus is moved outside of the app right before the layout
610
+ // changed, the bridge should not try to refocus anything .
611
+ XCTAssertEqual (focusObject, [NSNull null ]);
612
+ XCTAssertEqual ([accessibility_notifications[0 ][@" notification" ] unsignedIntValue ],
613
+ UIAccessibilityLayoutChangedNotification);
614
+ }
615
+
542
616
- (void )testAnnouncesScrollChangeWithLastFocused {
543
617
flutter::MockDelegate mock_delegate;
544
618
auto thread_task_runner = CreateNewThread (" AccessibilityBridgeTest" );
@@ -591,7 +665,7 @@ - (void)testAnnouncesScrollChangeWithLastFocused {
591
665
[accessibility_notifications removeAllObjects ];
592
666
593
667
// Simulates the focusing on the node 1.
594
- bridge->AccessibilityFocusDidChange (1 );
668
+ bridge->AccessibilityObjectDidBecomeFocused (1 );
595
669
596
670
flutter::SemanticsNodeUpdates second_update;
597
671
// Simulates the scrolling on the node 1.
0 commit comments