diff --git a/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm b/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm index 64d53602adebd..f92830c71389b 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm @@ -1520,6 +1520,15 @@ - (void)handleKeyboardNotification:(NSNotification*)notification { BOOL keyboardAnimationIsCompounding = self.keyboardAnimationIsShowing == keyboardWillShow && _keyboardAnimationVSyncClient != nil; + // Avoid triggering startKeyBoardAnimation when keyboard notifications are triggered + // by the dismissal of password autofill prompt. When this happens, there is + // no keyboard on the screen and FlutterTextInputViewAccessibilityHider is nil. + FlutterTextInputPlugin* textInputPlugin = self.engine.textInputPlugin; + UIView* textInputHider = [[textInputPlugin textInputView] superview]; + if (keyboardWillShow && textInputHider == nil) { + return; + } + // Mark keyboard as showing or hiding. self.keyboardAnimationIsShowing = keyboardWillShow; diff --git a/shell/platform/darwin/ios/framework/Source/FlutterViewControllerTest.mm b/shell/platform/darwin/ios/framework/Source/FlutterViewControllerTest.mm index a68a55287fb42..afd89130afd60 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterViewControllerTest.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterViewControllerTest.mm @@ -305,6 +305,18 @@ - (void)testKeyboardAnimationIsShowingAndCompounding { FlutterViewController* viewController = [[FlutterViewController alloc] initWithEngine:engine nibName:nil bundle:nil]; + FlutterMethodCall* setClientCall = + [FlutterMethodCall methodCallWithMethodName:@"TextInput.setClient" + arguments:@[ @(123), @{@"autocorrect" : @YES} ]]; + [engine.textInputPlugin handleMethodCall:setClientCall + result:^(id _Nullable result){ + }]; + + // Check if FlutterTextInputViewAccessibilityHider exists. + FlutterTextInputPlugin* textInputPlugin = engine.textInputPlugin; + UIView* textInputHider = [[textInputPlugin textInputView] superview]; + XCTAssertNotNil(textInputHider); + FlutterViewController* viewControllerMock = OCMPartialMock(viewController); UIScreen* screen = [self setUpMockScreen]; CGRect viewFrame = screen.bounds; @@ -2188,4 +2200,46 @@ - (void)testFlutterViewControllerStartKeyboardAnimationWillCreateVsyncClientCorr XCTAssertNil(viewController.keyboardAnimationVSyncClient); } +- (void)testAvoidKeyboardAnimationWhenFlutterTextInputViewAccessibilityHiderIsNil { + FlutterEngine* engine = [[FlutterEngine alloc] init]; + [engine runWithEntrypoint:nil]; + FlutterViewController* viewController = [[FlutterViewController alloc] initWithEngine:engine + nibName:nil + bundle:nil]; + + FlutterViewController* viewControllerMock = OCMPartialMock(viewController); + UIScreen* screen = [self setUpMockScreen]; + CGRect viewFrame = screen.bounds; + [self setUpMockView:viewControllerMock + screen:screen + viewFrame:viewFrame + convertedFrame:viewFrame]; + + CGFloat screenHeight = screen.bounds.size.height; + CGFloat screenWidth = screen.bounds.size.height; + + // Check if FlutterTextInputViewAccessibilityHider is nil. + FlutterTextInputPlugin* textInputPlugin = engine.textInputPlugin; + UIView* textInputHider = [[textInputPlugin textInputView] superview]; + XCTAssertNil(textInputHider); + + // Start show keyboard animation. + CGRect showKeyboardBeginFrame = CGRectMake(0, screenHeight, screenWidth, 250); + CGRect showKeyboardEndFrame = CGRectMake(0, screenHeight - 250, screenWidth, 250); + NSNotification* fakeNotification = + [NSNotification notificationWithName:UIKeyboardWillChangeFrameNotification + object:nil + userInfo:@{ + @"UIKeyboardFrameBeginUserInfoKey" : @(showKeyboardBeginFrame), + @"UIKeyboardFrameEndUserInfoKey" : @(showKeyboardEndFrame), + @"UIKeyboardAnimationDurationUserInfoKey" : @(0.25), + @"UIKeyboardIsLocalUserInfoKey" : @(YES) + }]; + + viewControllerMock.targetViewInsetBottom = 0; + [viewControllerMock handleKeyboardNotification:fakeNotification]; + BOOL isShowingAnimation = viewControllerMock.keyboardAnimationIsShowing; + XCTAssertFalse(isShowingAnimation); +} + @end