From 2e955d8a3d37d3eef397a37068890b76d8483bb7 Mon Sep 17 00:00:00 2001 From: Huan Lin Date: Mon, 7 Oct 2024 15:09:29 -0700 Subject: [PATCH] [ios][platform_view]fix forwarding gesture recognizer state stuck at the ended state --- .../Source/FlutterPlatformViewsTest.mm | 68 +++++++++++++++++++ .../Source/FlutterPlatformViews_Internal.mm | 5 +- 2 files changed, 69 insertions(+), 4 deletions(-) diff --git a/shell/platform/darwin/ios/framework/Source/FlutterPlatformViewsTest.mm b/shell/platform/darwin/ios/framework/Source/FlutterPlatformViewsTest.mm index 904a3eace2564..186cfe9ea6a76 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterPlatformViewsTest.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterPlatformViewsTest.mm @@ -2782,6 +2782,74 @@ - (void)testFlutterPlatformViewTouchesCancelledEventAreForcedToBeCancelled { flutterPlatformViewsController->Reset(); } +- (void)testFlutterPlatformViewTouchesEndedOrTouchesCancelledEventDoesNotFailTheGestureRecognizer { + flutter::FlutterPlatformViewsTestMockPlatformViewDelegate mock_delegate; + + flutter::TaskRunners runners(/*label=*/self.name.UTF8String, + /*platform=*/GetDefaultTaskRunner(), + /*raster=*/GetDefaultTaskRunner(), + /*ui=*/GetDefaultTaskRunner(), + /*io=*/GetDefaultTaskRunner()); + auto flutterPlatformViewsController = std::make_shared(); + flutterPlatformViewsController->SetTaskRunner(GetDefaultTaskRunner()); + auto platform_view = std::make_unique( + /*delegate=*/mock_delegate, + /*rendering_api=*/mock_delegate.settings_.enable_impeller + ? flutter::IOSRenderingAPI::kMetal + : flutter::IOSRenderingAPI::kSoftware, + /*platform_views_controller=*/flutterPlatformViewsController, + /*task_runners=*/runners, + /*worker_task_runner=*/nil, + /*is_gpu_disabled_jsync_switch=*/std::make_shared()); + + FlutterPlatformViewsTestMockFlutterPlatformFactory* factory = + [[FlutterPlatformViewsTestMockFlutterPlatformFactory alloc] init]; + flutterPlatformViewsController->RegisterViewFactory( + factory, @"MockFlutterPlatformView", + FlutterPlatformViewGestureRecognizersBlockingPolicyEager); + FlutterResult result = ^(id result) { + }; + flutterPlatformViewsController->OnMethodCall( + [FlutterMethodCall + methodCallWithMethodName:@"create" + arguments:@{@"id" : @2, @"viewType" : @"MockFlutterPlatformView"}], + result); + + XCTAssertNotNil(gMockPlatformView); + + // Find touch inteceptor view + UIView* touchInteceptorView = gMockPlatformView; + while (touchInteceptorView != nil && + ![touchInteceptorView isKindOfClass:[FlutterTouchInterceptingView class]]) { + touchInteceptorView = touchInteceptorView.superview; + } + XCTAssertNotNil(touchInteceptorView); + + // Find ForwardGestureRecognizer + UIGestureRecognizer* forwardGestureRecognizer = nil; + for (UIGestureRecognizer* gestureRecognizer in touchInteceptorView.gestureRecognizers) { + if ([gestureRecognizer isKindOfClass:NSClassFromString(@"ForwardingGestureRecognizer")]) { + forwardGestureRecognizer = gestureRecognizer; + break; + } + } + id flutterViewContoller = OCMClassMock([FlutterViewController class]); + + flutterPlatformViewsController->SetFlutterViewController(flutterViewContoller); + + NSSet* touches1 = [NSSet setWithObject:@1]; + id event1 = OCMClassMock([UIEvent class]); + [forwardGestureRecognizer touchesBegan:touches1 withEvent:event1]; + [forwardGestureRecognizer touchesEnded:touches1 withEvent:event1]; + XCTAssert(forwardGestureRecognizer.state == UIGestureRecognizerStatePossible); + + [forwardGestureRecognizer touchesBegan:touches1 withEvent:event1]; + [forwardGestureRecognizer touchesCancelled:touches1 withEvent:event1]; + XCTAssert(forwardGestureRecognizer.state == UIGestureRecognizerStatePossible); + + flutterPlatformViewsController->Reset(); +} + - (void)testFlutterPlatformViewControllerSubmitFrameWithoutFlutterViewNotCrashing { flutter::FlutterPlatformViewsTestMockPlatformViewDelegate mock_delegate; diff --git a/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.mm b/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.mm index 5e76654bed179..a0c8c82ff5a51 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.mm @@ -736,10 +736,8 @@ - (void)touchesEnded:(NSSet*)touches withEvent:(UIEvent*)event { _currentTouchPointersCount -= touches.count; // Touches in one touch sequence are sent to the touchesEnded method separately if different // fingers stop touching the screen at different time. So one touchesEnded method triggering does - // not necessarially mean the touch sequence has ended. We Only set the state to - // UIGestureRecognizerStateFailed when all the touches in the current touch sequence is ended. + // not necessarially mean the touch sequence has ended. if (_currentTouchPointersCount == 0) { - self.state = UIGestureRecognizerStateFailed; _flutterViewController.reset(nil); } } @@ -753,7 +751,6 @@ - (void)touchesCancelled:(NSSet*)touches withEvent:(UIEvent*)event { [_flutterViewController.get() forceTouchesCancelled:touches]; _currentTouchPointersCount -= touches.count; if (_currentTouchPointersCount == 0) { - self.state = UIGestureRecognizerStateFailed; _flutterViewController.reset(nil); } }