diff --git a/shell/platform/darwin/ios/framework/Source/FlutterTextInputPlugin.mm b/shell/platform/darwin/ios/framework/Source/FlutterTextInputPlugin.mm index 11cae1f4c308c..67be8a2d85fac 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterTextInputPlugin.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterTextInputPlugin.mm @@ -52,6 +52,7 @@ static NSString* const kKeyboardAppearance = @"keyboardAppearance"; static NSString* const kInputAction = @"inputAction"; static NSString* const kEnableDeltaModel = @"enableDeltaModel"; +static NSString* const kEnableInteractiveSelection = @"enableInteractiveSelection"; static NSString* const kSmartDashesType = @"smartDashesType"; static NSString* const kSmartQuotesType = @"smartQuotesType"; @@ -732,6 +733,7 @@ @implementation FlutterTextInputView { // The view has reached end of life, and is no longer // allowed to access its textInputDelegate. BOOL _decommissioned; + bool _enableInteractiveSelection; } @synthesize tokenizer = _tokenizer; @@ -765,6 +767,7 @@ - (instancetype)initWithOwner:(FlutterTextInputPlugin*)textInputPlugin { _returnKeyType = UIReturnKeyDone; _secureTextEntry = NO; _enableDeltaModel = NO; + _enableInteractiveSelection = YES; _accessibilityEnabled = NO; _decommissioned = NO; if (@available(iOS 11.0, *)) { @@ -796,7 +799,7 @@ - (void)configureWithDictionary:(NSDictionary*)configuration { self.keyboardType = ToUIKeyboardType(inputType); self.returnKeyType = ToUIReturnKeyType(configuration[kInputAction]); self.autocapitalizationType = ToUITextAutoCapitalizationType(configuration); - + _enableInteractiveSelection = [configuration[kEnableInteractiveSelection] boolValue]; if (@available(iOS 11.0, *)) { NSString* smartDashesType = configuration[kSmartDashesType]; // This index comes from the SmartDashesType enum in the framework. @@ -1115,6 +1118,10 @@ - (void)setSelectedTextRangeLocal:(UITextRange*)selectedTextRange { } - (void)setSelectedTextRange:(UITextRange*)selectedTextRange { + if (!_enableInteractiveSelection) { + return; + } + [self setSelectedTextRangeLocal:selectedTextRange]; if (_enableDeltaModel) { @@ -1740,7 +1747,6 @@ - (void)updateEditingState { composingBase = ((FlutterTextPosition*)self.markedTextRange.start).index; composingExtent = ((FlutterTextPosition*)self.markedTextRange.end).index; } - NSDictionary* state = @{ @"selectionBase" : @(selectionBase), @"selectionExtent" : @(selectionExtent), diff --git a/shell/platform/darwin/ios/framework/Source/FlutterTextInputPluginTest.mm b/shell/platform/darwin/ios/framework/Source/FlutterTextInputPluginTest.mm index 59a96565fd147..231e44fb4a307 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterTextInputPluginTest.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterTextInputPluginTest.mm @@ -25,7 +25,7 @@ - (void)setMarkedRect:(CGRect)markedRect; - (void)updateEditingState; - (BOOL)isVisibleToAutofill; - (id)textInputDelegate; - +- (void)configureWithDictionary:(NSDictionary*)configuration; @end @interface FlutterTextInputViewSpy : FlutterTextInputView @@ -139,7 +139,8 @@ - (NSMutableDictionary*)mutableTemplateCopy { @"inputAction" : @"TextInputAction.unspecified", @"smartDashesType" : @"0", @"smartQuotesType" : @"0", - @"autocorrect" : @YES + @"autocorrect" : @YES, + @"enableInteractiveSelection" : @YES, }; } @@ -269,6 +270,34 @@ - (void)testAutocorrectionPromptRectAppears { withClient:0]); } +- (void)testIngoresSelectionChangeIfSelectionIsDisabled { + FlutterTextInputView* inputView = [[FlutterTextInputView alloc] initWithOwner:textInputPlugin]; + __block int updateCount = 0; + OCMStub([engine flutterTextInputView:inputView updateEditingClient:0 withState:[OCMArg isNotNil]]) + .andDo(^(NSInvocation* invocation) { + updateCount++; + }); + + [inputView.text setString:@"Some initial text"]; + XCTAssertEqual(updateCount, 0); + + FlutterTextRange* textRange = [FlutterTextRange rangeWithNSRange:NSMakeRange(0, 1)]; + [inputView setSelectedTextRange:textRange]; + XCTAssertEqual(updateCount, 1); + + // Disable the interactive selection. + NSDictionary* config = self.mutableTemplateCopy; + [config setValue:@(NO) forKey:@"enableInteractiveSelection"]; + [config setValue:@(NO) forKey:@"obscureText"]; + [config setValue:@(NO) forKey:@"enableDeltaModel"]; + [inputView configureWithDictionary:config]; + + textRange = [FlutterTextRange rangeWithNSRange:NSMakeRange(2, 3)]; + [inputView setSelectedTextRange:textRange]; + // The update count does not change. + XCTAssertEqual(updateCount, 1); +} + - (void)testAutocorrectionPromptRectDoesNotAppearDuringScribble { if (@available(iOS 14.0, *)) { FlutterTextInputView* inputView = [[FlutterTextInputView alloc] initWithOwner:textInputPlugin];