diff --git a/shell/platform/darwin/ios/framework/Source/FlutterPlatformViewsTest.mm b/shell/platform/darwin/ios/framework/Source/FlutterPlatformViewsTest.mm index 877320c4f6e3e..f8b5e4ebc3e7b 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterPlatformViewsTest.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterPlatformViewsTest.mm @@ -621,15 +621,15 @@ - (void)testSetFlutterViewControllerAfterCreateCanStillDispatchTouchEvents { } // Before setting flutter view controller, events are not dispatched. - NSSet* touches1 = OCMClassMock([NSSet class]); - UIEvent* event1 = OCMClassMock([UIEvent class]); - UIViewController* mockFlutterViewContoller = OCMClassMock([UIViewController class]); + NSSet* touches1 = [[[NSSet alloc] init] autorelease]; + id event1 = OCMClassMock([UIEvent class]); + id mockFlutterViewContoller = OCMClassMock([UIViewController class]); [forwardGectureRecognizer touchesBegan:touches1 withEvent:event1]; OCMReject([mockFlutterViewContoller touchesBegan:touches1 withEvent:event1]); // Set flutter view controller allows events to be dispatched. - NSSet* touches2 = OCMClassMock([NSSet class]); - UIEvent* event2 = OCMClassMock([UIEvent class]); + NSSet* touches2 = [[[NSSet alloc] init] autorelease]; + id event2 = OCMClassMock([UIEvent class]); flutterPlatformViewsController->SetFlutterViewController(mockFlutterViewContoller); [forwardGectureRecognizer touchesBegan:touches2 withEvent:event2]; OCMVerify([mockFlutterViewContoller touchesBegan:touches2 withEvent:event2]); @@ -681,39 +681,37 @@ - (void)testSetFlutterViewControllerInTheMiddleOfTouchEventShouldStillAllowGestu break; } } - UIViewController* mockFlutterViewContoller = OCMClassMock([UIViewController class]); + id mockFlutterViewContoller = OCMClassMock([UIViewController class]); { // ***** Sequence 1, finishing touch event with touchEnded ***** // - flutterPlatformViewsController->SetFlutterViewController(mockFlutterViewContoller); - NSSet* touches1 = OCMClassMock([NSSet class]); - UIEvent* event1 = OCMClassMock([UIEvent class]); + NSSet* touches1 = [[[NSSet alloc] init] autorelease]; + id event1 = OCMClassMock([UIEvent class]); [forwardGectureRecognizer touchesBegan:touches1 withEvent:event1]; OCMVerify([mockFlutterViewContoller touchesBegan:touches1 withEvent:event1]); flutterPlatformViewsController->SetFlutterViewController(nil); // Allow the touch events to finish - NSSet* touches2 = OCMClassMock([NSSet class]); - UIEvent* event2 = OCMClassMock([UIEvent class]); + NSSet* touches2 = [[[NSSet alloc] init] autorelease]; + id event2 = OCMClassMock([UIEvent class]); [forwardGectureRecognizer touchesMoved:touches2 withEvent:event2]; OCMVerify([mockFlutterViewContoller touchesMoved:touches2 withEvent:event2]); - NSSet* touches3 = OCMClassMock([NSSet class]); - UIEvent* event3 = OCMClassMock([UIEvent class]); + NSSet* touches3 = [[[NSSet alloc] init] autorelease]; + id event3 = OCMClassMock([UIEvent class]); [forwardGectureRecognizer touchesEnded:touches3 withEvent:event3]; OCMVerify([mockFlutterViewContoller touchesEnded:touches3 withEvent:event3]); // Now the 2nd touch sequence should not be allowed. - NSSet* touches4 = OCMClassMock([NSSet class]); - UIEvent* event4 = OCMClassMock([UIEvent class]); - mockFlutterViewContoller = OCMClassMock([UIViewController class]); + NSSet* touches4 = [[[NSSet alloc] init] autorelease]; + id event4 = OCMClassMock([UIEvent class]); [forwardGectureRecognizer touchesBegan:touches4 withEvent:event4]; OCMReject([mockFlutterViewContoller touchesBegan:touches4 withEvent:event4]); - NSSet* touches5 = OCMClassMock([NSSet class]); - UIEvent* event5 = OCMClassMock([UIEvent class]); + NSSet* touches5 = [[[NSSet alloc] init] autorelease]; + id event5 = OCMClassMock([UIEvent class]); [forwardGectureRecognizer touchesEnded:touches5 withEvent:event5]; OCMReject([mockFlutterViewContoller touchesEnded:touches5 withEvent:event5]); } @@ -722,105 +720,145 @@ - (void)testSetFlutterViewControllerInTheMiddleOfTouchEventShouldStillAllowGestu // ***** Sequence 2, finishing touch event with touchCancelled ***** // flutterPlatformViewsController->SetFlutterViewController(mockFlutterViewContoller); - NSSet* touches1 = OCMClassMock([NSSet class]); - UIEvent* event1 = OCMClassMock([UIEvent class]); + NSSet* touches1 = [[[NSSet alloc] init] autorelease]; + id event1 = OCMClassMock([UIEvent class]); [forwardGectureRecognizer touchesBegan:touches1 withEvent:event1]; OCMVerify([mockFlutterViewContoller touchesBegan:touches1 withEvent:event1]); flutterPlatformViewsController->SetFlutterViewController(nil); // Allow the touch events to finish - NSSet* touches2 = OCMClassMock([NSSet class]); - UIEvent* event2 = OCMClassMock([UIEvent class]); + NSSet* touches2 = [[[NSSet alloc] init] autorelease]; + id event2 = OCMClassMock([UIEvent class]); [forwardGectureRecognizer touchesMoved:touches2 withEvent:event2]; OCMVerify([mockFlutterViewContoller touchesMoved:touches2 withEvent:event2]); - NSSet* touches3 = OCMClassMock([NSSet class]); - UIEvent* event3 = OCMClassMock([UIEvent class]); + NSSet* touches3 = [[[NSSet alloc] init] autorelease]; + id event3 = OCMClassMock([UIEvent class]); [forwardGectureRecognizer touchesCancelled:touches3 withEvent:event3]; OCMVerify([mockFlutterViewContoller touchesCancelled:touches3 withEvent:event3]); // Now the 2nd touch sequence should not be allowed. - NSSet* touches4 = OCMClassMock([NSSet class]); - UIEvent* event4 = OCMClassMock([UIEvent class]); - mockFlutterViewContoller = OCMClassMock([UIViewController class]); + NSSet* touches4 = [[[NSSet alloc] init] autorelease]; + id event4 = OCMClassMock([UIEvent class]); [forwardGectureRecognizer touchesBegan:touches4 withEvent:event4]; OCMReject([mockFlutterViewContoller touchesBegan:touches4 withEvent:event4]); - NSSet* touches5 = OCMClassMock([NSSet class]); - UIEvent* event5 = OCMClassMock([UIEvent class]); + NSSet* touches5 = [[[NSSet alloc] init] autorelease]; + id event5 = OCMClassMock([UIEvent class]); [forwardGectureRecognizer touchesEnded:touches5 withEvent:event5]; OCMReject([mockFlutterViewContoller touchesEnded:touches5 withEvent:event5]); } - { - // ***** Sequence 3, multile touches in one sequence with setting flutter view controllers in - // between ***** // - flutterPlatformViewsController->SetFlutterViewController(mockFlutterViewContoller); + flutterPlatformViewsController->Reset(); +} - NSSet* touches1 = OCMClassMock([NSSet class]); - OCMStub([touches1 count]).andReturn(1); - UIEvent* event1 = OCMClassMock([UIEvent class]); - [forwardGectureRecognizer touchesBegan:touches1 withEvent:event1]; - OCMVerify([mockFlutterViewContoller touchesBegan:touches1 withEvent:event1]); +- (void) + testSetFlutterViewControllerInTheMiddleOfTouchEventAllowsTheNewControllerToHandleSecondTouchSequence { + flutter::FlutterPlatformViewsTestMockPlatformViewDelegate mock_delegate; + auto thread_task_runner = CreateNewThread("FlutterPlatformViewsTest"); + flutter::TaskRunners runners(/*label=*/self.name.UTF8String, + /*platform=*/thread_task_runner, + /*raster=*/thread_task_runner, + /*ui=*/thread_task_runner, + /*io=*/thread_task_runner); + auto flutterPlatformViewsController = std::make_shared(); + auto platform_view = std::make_unique( + /*delegate=*/mock_delegate, + /*rendering_api=*/flutter::IOSRenderingAPI::kSoftware, + /*platform_views_controller=*/flutterPlatformViewsController, + /*task_runners=*/runners); - UIViewController* mockFlutterViewContoller2 = OCMClassMock([UIViewController class]); - flutterPlatformViewsController->SetFlutterViewController(mockFlutterViewContoller2); - - // Touch events should still send to the old FlutterViewController if FlutterViewController - // is updated in between. - NSSet* touches2 = OCMClassMock([NSSet class]); - OCMStub([touches2 count]).andReturn(1); - UIEvent* event2 = OCMClassMock([UIEvent class]); - [forwardGectureRecognizer touchesBegan:touches2 withEvent:event2]; - OCMVerify([mockFlutterViewContoller touchesBegan:touches2 withEvent:event2]); - OCMReject([mockFlutterViewContoller2 touchesBegan:touches2 withEvent:event2]); - - NSSet* touches3 = OCMClassMock([NSSet class]); - OCMStub([touches3 count]).andReturn(1); - UIEvent* event3 = OCMClassMock([UIEvent class]); - [forwardGectureRecognizer touchesMoved:touches3 withEvent:event3]; - OCMVerify([mockFlutterViewContoller touchesMoved:touches3 withEvent:event3]); - OCMReject([mockFlutterViewContoller2 touchesMoved:touches3 withEvent:event3]); - - NSSet* touches4 = OCMClassMock([NSSet class]); - OCMStub([touches4 count]).andReturn(1); - UIEvent* event4 = OCMClassMock([UIEvent class]); - [forwardGectureRecognizer touchesEnded:touches4 withEvent:event4]; - OCMVerify([mockFlutterViewContoller touchesEnded:touches4 withEvent:event4]); - OCMReject([mockFlutterViewContoller2 touchesEnded:touches4 withEvent:event4]); - - NSSet* touches5 = OCMClassMock([NSSet class]); - OCMStub([touches5 count]).andReturn(1); - UIEvent* event5 = OCMClassMock([UIEvent class]); - [forwardGectureRecognizer touchesEnded:touches5 withEvent:event5]; - OCMVerify([mockFlutterViewContoller touchesEnded:touches5 withEvent:event5]); - OCMReject([mockFlutterViewContoller2 touchesEnded:touches5 withEvent:event5]); + FlutterPlatformViewsTestMockFlutterPlatformFactory* factory = + [[FlutterPlatformViewsTestMockFlutterPlatformFactory new] autorelease]; + flutterPlatformViewsController->RegisterViewFactory( + factory, @"MockFlutterPlatformView", + FlutterPlatformViewGestureRecognizersBlockingPolicyEager); + FlutterResult result = ^(id result) { + }; + flutterPlatformViewsController->OnMethodCall( + [FlutterMethodCall + methodCallWithMethodName:@"create" + arguments:@{@"id" : @2, @"viewType" : @"MockFlutterPlatformView"}], + result); - // Now the 2nd touch sequence should go to the new FlutterViewController + XCTAssertNotNil(gMockPlatformView); - NSSet* touches6 = OCMClassMock([NSSet class]); - OCMStub([touches6 count]).andReturn(1); - UIEvent* event6 = OCMClassMock([UIEvent class]); - [forwardGectureRecognizer touchesBegan:touches6 withEvent:event6]; - OCMVerify([mockFlutterViewContoller2 touchesBegan:touches6 withEvent:event6]); - OCMReject([mockFlutterViewContoller touchesBegan:touches6 withEvent:event6]); + // Find touch inteceptor view + UIView* touchInteceptorView = gMockPlatformView; + while (touchInteceptorView != nil && + ![touchInteceptorView isKindOfClass:[FlutterTouchInterceptingView class]]) { + touchInteceptorView = touchInteceptorView.superview; + } + XCTAssertNotNil(touchInteceptorView); - // Allow the touch events to finish - NSSet* touches7 = OCMClassMock([NSSet class]); - OCMStub([touches7 count]).andReturn(1); - UIEvent* event7 = OCMClassMock([UIEvent class]); - [forwardGectureRecognizer touchesMoved:touches7 withEvent:event7]; - OCMVerify([mockFlutterViewContoller2 touchesMoved:touches7 withEvent:event7]); - OCMReject([mockFlutterViewContoller touchesMoved:touches7 withEvent:event7]); - - NSSet* touches8 = OCMClassMock([NSSet class]); - OCMStub([touches8 count]).andReturn(1); - UIEvent* event8 = OCMClassMock([UIEvent class]); - [forwardGectureRecognizer touchesEnded:touches8 withEvent:event8]; - OCMVerify([mockFlutterViewContoller2 touchesEnded:touches8 withEvent:event8]); - OCMReject([mockFlutterViewContoller touchesEnded:touches8 withEvent:event8]); + // Find ForwardGestureRecognizer + UIGestureRecognizer* forwardGectureRecognizer = nil; + for (UIGestureRecognizer* gestureRecognizer in touchInteceptorView.gestureRecognizers) { + if ([gestureRecognizer isKindOfClass:NSClassFromString(@"ForwardingGestureRecognizer")]) { + forwardGectureRecognizer = gestureRecognizer; + break; + } } + id mockFlutterViewContoller = OCMClassMock([UIViewController class]); + + flutterPlatformViewsController->SetFlutterViewController(mockFlutterViewContoller); + + // The touches in this sequence requires 1 touch object, we always create the NSSet with one item. + NSSet* touches1 = [NSSet setWithObject:@1]; + id event1 = OCMClassMock([UIEvent class]); + [forwardGectureRecognizer touchesBegan:touches1 withEvent:event1]; + OCMVerify([mockFlutterViewContoller touchesBegan:touches1 withEvent:event1]); + + UIViewController* mockFlutterViewContoller2 = OCMClassMock([UIViewController class]); + flutterPlatformViewsController->SetFlutterViewController(mockFlutterViewContoller2); + + // Touch events should still send to the old FlutterViewController if FlutterViewController + // is updated in between. + NSSet* touches2 = [NSSet setWithObject:@1]; + id event2 = OCMClassMock([UIEvent class]); + [forwardGectureRecognizer touchesBegan:touches2 withEvent:event2]; + OCMVerify([mockFlutterViewContoller touchesBegan:touches2 withEvent:event2]); + OCMReject([mockFlutterViewContoller2 touchesBegan:touches2 withEvent:event2]); + + NSSet* touches3 = [NSSet setWithObject:@1]; + id event3 = OCMClassMock([UIEvent class]); + [forwardGectureRecognizer touchesMoved:touches3 withEvent:event3]; + OCMVerify([mockFlutterViewContoller touchesMoved:touches3 withEvent:event3]); + OCMReject([mockFlutterViewContoller2 touchesMoved:touches3 withEvent:event3]); + + NSSet* touches4 = [NSSet setWithObject:@1]; + id event4 = OCMClassMock([UIEvent class]); + [forwardGectureRecognizer touchesEnded:touches4 withEvent:event4]; + OCMVerify([mockFlutterViewContoller touchesEnded:touches4 withEvent:event4]); + OCMReject([mockFlutterViewContoller2 touchesEnded:touches4 withEvent:event4]); + + NSSet* touches5 = [NSSet setWithObject:@1]; + id event5 = OCMClassMock([UIEvent class]); + [forwardGectureRecognizer touchesEnded:touches5 withEvent:event5]; + OCMVerify([mockFlutterViewContoller touchesEnded:touches5 withEvent:event5]); + OCMReject([mockFlutterViewContoller2 touchesEnded:touches5 withEvent:event5]); + + // Now the 2nd touch sequence should go to the new FlutterViewController + + NSSet* touches6 = [NSSet setWithObject:@1]; + id event6 = OCMClassMock([UIEvent class]); + [forwardGectureRecognizer touchesBegan:touches6 withEvent:event6]; + OCMVerify([mockFlutterViewContoller2 touchesBegan:touches6 withEvent:event6]); + OCMReject([mockFlutterViewContoller touchesBegan:touches6 withEvent:event6]); + + // Allow the touch events to finish + NSSet* touches7 = [NSSet setWithObject:@1]; + id event7 = OCMClassMock([UIEvent class]); + [forwardGectureRecognizer touchesMoved:touches7 withEvent:event7]; + OCMVerify([mockFlutterViewContoller2 touchesMoved:touches7 withEvent:event7]); + OCMReject([mockFlutterViewContoller touchesMoved:touches7 withEvent:event7]); + + NSSet* touches8 = [NSSet setWithObject:@1]; + id event8 = OCMClassMock([UIEvent class]); + [forwardGectureRecognizer touchesEnded:touches8 withEvent:event8]; + OCMVerify([mockFlutterViewContoller2 touchesEnded:touches8 withEvent:event8]); + OCMReject([mockFlutterViewContoller touchesEnded:touches8 withEvent:event8]); flutterPlatformViewsController->Reset(); }