Add enableIMEPersonalizedLearning flag to TextField and TextFormField (#87002)
* Add requestPrivacy parameter to TextField
* remove logs
* No need to pass _Editable requestPrivacy for now
* Forgot from last commit
* Add requestPrivacy flag to text form field
* Update docs
* Add requestPrivacy to CupertinoTextField
* Add test to verify requestPrivacy flag is sent to engine properly
* update docs
* fix tests
* rename requestPrivacy to enableIMEPersonalizedLearning
* Update text_input.dart
* default to true
* Have diagnostic properties default to true for enableIMEPersonalizedLearning
diff --git a/packages/flutter/lib/src/cupertino/text_field.dart b/packages/flutter/lib/src/cupertino/text_field.dart
index 8cc9e29..914caae 100644
--- a/packages/flutter/lib/src/cupertino/text_field.dart
+++ b/packages/flutter/lib/src/cupertino/text_field.dart
@@ -219,7 +219,8 @@
/// The [autocorrect], [autofocus], [clearButtonMode], [dragStartBehavior],
/// [expands], [maxLengthEnforced], [obscureText], [prefixMode], [readOnly],
/// [scrollPadding], [suffixMode], [textAlign], [selectionHeightStyle],
- /// [selectionWidthStyle], and [enableSuggestions] properties must not be null.
+ /// [selectionWidthStyle], [enableSuggestions], and [enableIMEPersonalizedLearning]
+ /// properties must not be null.
///
/// See also:
///
@@ -294,6 +295,7 @@
this.scrollPhysics,
this.autofillHints,
this.restorationId,
+ this.enableIMEPersonalizedLearning = true,
}) : assert(textAlign != null),
assert(readOnly != null),
assert(autofocus != null),
@@ -335,6 +337,7 @@
!identical(keyboardType, TextInputType.text),
'Use keyboardType TextInputType.multiline when using TextInputAction.newline on a multiline TextField.',
),
+ assert(enableIMEPersonalizedLearning != null),
keyboardType = keyboardType ?? (maxLines == 1 ? TextInputType.text : TextInputType.multiline),
toolbarOptions = toolbarOptions ?? (obscureText ?
const ToolbarOptions(
@@ -448,6 +451,7 @@
this.scrollPhysics,
this.autofillHints,
this.restorationId,
+ this.enableIMEPersonalizedLearning = true,
}) : assert(textAlign != null),
assert(readOnly != null),
assert(autofocus != null),
@@ -489,6 +493,7 @@
!identical(keyboardType, TextInputType.text),
'Use keyboardType TextInputType.multiline when using TextInputAction.newline on a multiline TextField.',
),
+ assert(enableIMEPersonalizedLearning != null),
keyboardType = keyboardType ?? (maxLines == 1 ? TextInputType.text : TextInputType.multiline),
toolbarOptions = toolbarOptions ?? (obscureText ?
const ToolbarOptions(
@@ -784,6 +789,9 @@
/// {@macro flutter.material.textfield.restorationId}
final String? restorationId;
+ /// {@macro flutter.services.TextInputConfiguration.enableIMEPersonalizedLearning}
+ final bool enableIMEPersonalizedLearning;
+
@override
State<CupertinoTextField> createState() => _CupertinoTextFieldState();
@@ -825,6 +833,7 @@
properties.add(EnumProperty<TextAlign>('textAlign', textAlign, defaultValue: TextAlign.start));
properties.add(DiagnosticsProperty<TextAlignVertical>('textAlignVertical', textAlignVertical, defaultValue: null));
properties.add(EnumProperty<TextDirection>('textDirection', textDirection, defaultValue: null));
+ properties.add(DiagnosticsProperty<bool>('enableIMEPersonalizedLearning', enableIMEPersonalizedLearning, defaultValue: true));
}
}
@@ -1221,6 +1230,7 @@
enableInteractiveSelection: widget.enableInteractiveSelection,
autofillHints: widget.autofillHints,
restorationId: 'editable',
+ enableIMEPersonalizedLearning: widget.enableIMEPersonalizedLearning,
),
),
),
diff --git a/packages/flutter/lib/src/material/text_field.dart b/packages/flutter/lib/src/material/text_field.dart
index 4c4f222..c85b977 100644
--- a/packages/flutter/lib/src/material/text_field.dart
+++ b/packages/flutter/lib/src/material/text_field.dart
@@ -325,8 +325,8 @@
///
/// The [textAlign], [autofocus], [obscureText], [readOnly], [autocorrect],
/// [maxLengthEnforced], [scrollPadding], [maxLines], [maxLength],
- /// [selectionHeightStyle], [selectionWidthStyle], and [enableSuggestions]
- /// arguments must not be null.
+ /// [selectionHeightStyle], [selectionWidthStyle], [enableSuggestions], and
+ /// [enableIMEPersonalizedLearning] arguments must not be null.
///
/// See also:
///
@@ -390,6 +390,7 @@
this.scrollPhysics,
this.autofillHints,
this.restorationId,
+ this.enableIMEPersonalizedLearning = true,
}) : assert(textAlign != null),
assert(readOnly != null),
assert(autofocus != null),
@@ -429,6 +430,7 @@
!identical(keyboardType, TextInputType.text),
'Use keyboardType TextInputType.multiline when using TextInputAction.newline on a multiline TextField.',
),
+ assert(enableIMEPersonalizedLearning != null),
keyboardType = keyboardType ?? (maxLines == 1 ? TextInputType.text : TextInputType.multiline),
toolbarOptions = toolbarOptions ?? (obscureText ?
const ToolbarOptions(
@@ -821,6 +823,9 @@
/// {@endtemplate}
final String? restorationId;
+ /// {@macro flutter.services.TextInputConfiguration.enableIMEPersonalizedLearning}
+ final bool enableIMEPersonalizedLearning;
+
@override
State<TextField> createState() => _TextFieldState();
@@ -861,6 +866,7 @@
properties.add(DiagnosticsProperty<TextSelectionControls>('selectionControls', selectionControls, defaultValue: null));
properties.add(DiagnosticsProperty<ScrollController>('scrollController', scrollController, defaultValue: null));
properties.add(DiagnosticsProperty<ScrollPhysics>('scrollPhysics', scrollPhysics, defaultValue: null));
+ properties.add(DiagnosticsProperty<bool>('enableIMEPersonalizedLearning', enableIMEPersonalizedLearning, defaultValue: true));
}
}
@@ -1263,6 +1269,7 @@
autofillHints: widget.autofillHints,
autocorrectionTextRectColor: autocorrectionTextRectColor,
restorationId: 'editable',
+ enableIMEPersonalizedLearning: widget.enableIMEPersonalizedLearning,
),
),
);
diff --git a/packages/flutter/lib/src/material/text_form_field.dart b/packages/flutter/lib/src/material/text_form_field.dart
index 9fd3e56..1f38f4b 100644
--- a/packages/flutter/lib/src/material/text_form_field.dart
+++ b/packages/flutter/lib/src/material/text_form_field.dart
@@ -196,6 +196,7 @@
AutovalidateMode? autovalidateMode,
ScrollController? scrollController,
String? restorationId,
+ bool enableIMEPersonalizedLearning = true,
}) : assert(initialValue == null || controller == null),
assert(textAlign != null),
assert(autofocus != null),
@@ -230,6 +231,7 @@
assert(!obscureText || maxLines == 1, 'Obscured fields cannot be multiline.'),
assert(maxLength == null || maxLength == TextField.noMaxLength || maxLength > 0),
assert(enableInteractiveSelection != null),
+ assert(enableIMEPersonalizedLearning != null),
super(
key: key,
restorationId: restorationId,
@@ -299,6 +301,7 @@
buildCounter: buildCounter,
autofillHints: autofillHints,
scrollController: scrollController,
+ enableIMEPersonalizedLearning: enableIMEPersonalizedLearning,
),
);
},
diff --git a/packages/flutter/lib/src/services/text_input.dart b/packages/flutter/lib/src/services/text_input.dart
index 15ab9f1..61a50fb 100644
--- a/packages/flutter/lib/src/services/text_input.dart
+++ b/packages/flutter/lib/src/services/text_input.dart
@@ -466,6 +466,7 @@
this.keyboardAppearance = Brightness.light,
this.textCapitalization = TextCapitalization.none,
this.autofillConfiguration,
+ this.enableIMEPersonalizedLearning = true,
}) : assert(inputType != null),
assert(obscureText != null),
smartDashesType = smartDashesType ?? (obscureText ? SmartDashesType.disabled : SmartDashesType.enabled),
@@ -474,7 +475,8 @@
assert(enableSuggestions != null),
assert(keyboardAppearance != null),
assert(inputAction != null),
- assert(textCapitalization != null);
+ assert(textCapitalization != null),
+ assert(enableIMEPersonalizedLearning != null);
/// The type of information for which to optimize the text input control.
final TextInputType inputType;
@@ -590,6 +592,20 @@
/// Defaults to [Brightness.light].
final Brightness keyboardAppearance;
+ /// {@template flutter.services.TextInputConfiguration.enableIMEPersonalizedLearning}
+ /// Whether to enable that the IME update personalized data such as typing
+ /// history and user dictionary data.
+ ///
+ /// This flag only affects Android. On iOS, there is no equivalent flag.
+ ///
+ /// Defaults to true. Cannot be null.
+ ///
+ /// See also:
+ ///
+ /// * <https://developer.android.com/reference/android/view/inputmethod/EditorInfo#IME_FLAG_NO_PERSONALIZED_LEARNING>
+ /// {@endtemplate}
+ final bool enableIMEPersonalizedLearning;
+
/// Returns a representation of this object as a JSON object.
Map<String, dynamic> toJson() {
return <String, dynamic>{
@@ -604,6 +620,7 @@
'inputAction': inputAction.toString(),
'textCapitalization': textCapitalization.toString(),
'keyboardAppearance': keyboardAppearance.toString(),
+ 'enableIMEPersonalizedLearning': enableIMEPersonalizedLearning,
if (autofillConfiguration != null) 'autofill': autofillConfiguration!.toJson(),
};
}
diff --git a/packages/flutter/lib/src/widgets/editable_text.dart b/packages/flutter/lib/src/widgets/editable_text.dart
index a123ae6..d84b6b3 100644
--- a/packages/flutter/lib/src/widgets/editable_text.dart
+++ b/packages/flutter/lib/src/widgets/editable_text.dart
@@ -426,8 +426,8 @@
/// [style], [cursorColor], [cursorOpacityAnimates],[backgroundCursorColor],
/// [enableSuggestions], [paintCursorAboveText], [selectionHeightStyle],
/// [selectionWidthStyle], [textAlign], [dragStartBehavior], [scrollPadding],
- /// [dragStartBehavior], [toolbarOptions], [rendererIgnoresPointer], and
- /// [readOnly] arguments must not be null.
+ /// [dragStartBehavior], [toolbarOptions], [rendererIgnoresPointer],
+ /// [readOnly], and [enableIMEPersonalizedLearning] arguments must not be null.
EditableText({
Key? key,
required this.controller,
@@ -495,6 +495,7 @@
this.clipBehavior = Clip.hardEdge,
this.restorationId,
this.scrollBehavior,
+ this.enableIMEPersonalizedLearning = true,
}) : assert(controller != null),
assert(focusNode != null),
assert(obscuringCharacter != null && obscuringCharacter.length == 1),
@@ -537,6 +538,7 @@
!readOnly || autofillHints == null,
"Read-only fields can't have autofill hints.",
),
+ assert(enableIMEPersonalizedLearning != null),
_strutStyle = strutStyle,
keyboardType = keyboardType ?? _inferKeyboardType(autofillHints: autofillHints, maxLines: maxLines),
inputFormatters = maxLines == 1
@@ -1346,6 +1348,9 @@
/// than 1.
final ScrollBehavior? scrollBehavior;
+ /// {@macro flutter.services.TextInputConfiguration.enableIMEPersonalizedLearning}
+ final bool enableIMEPersonalizedLearning;
+
// Infer the keyboard type of an `EditableText` if it's not specified.
static TextInputType _inferKeyboardType({
required Iterable<String>? autofillHints,
@@ -1513,6 +1518,7 @@
properties.add(DiagnosticsProperty<ScrollPhysics>('scrollPhysics', scrollPhysics, defaultValue: null));
properties.add(DiagnosticsProperty<Iterable<String>>('autofillHints', autofillHints, defaultValue: null));
properties.add(DiagnosticsProperty<TextHeightBehavior>('textHeightBehavior', textHeightBehavior, defaultValue: null));
+ properties.add(DiagnosticsProperty<bool>('enableIMEPersonalizedLearning', enableIMEPersonalizedLearning, defaultValue: true));
}
}
@@ -2607,6 +2613,7 @@
autofillHints: widget.autofillHints?.toList(growable: false) ?? <String>[],
currentEditingValue: currentTextEditingValue,
),
+ enableIMEPersonalizedLearning: widget.enableIMEPersonalizedLearning,
);
}
diff --git a/packages/flutter/test/widgets/editable_text_test.dart b/packages/flutter/test/widgets/editable_text_test.dart
index 63b55d7..d5e9200 100644
--- a/packages/flutter/test/widgets/editable_text_test.dart
+++ b/packages/flutter/test/widgets/editable_text_test.dart
@@ -199,6 +199,7 @@
expect(editableText.obscureText, isFalse);
expect(editableText.autocorrect, isTrue);
expect(editableText.enableSuggestions, isTrue);
+ expect(editableText.enableIMEPersonalizedLearning, isTrue);
expect(editableText.textAlign, TextAlign.start);
expect(editableText.cursorWidth, 2.0);
expect(editableText.cursorHeight, isNull);
@@ -576,6 +577,36 @@
expect(tester.testTextInput.setClientArgs!['enableSuggestions'], enableSuggestions);
});
+ testWidgets('enableIMEPersonalizedLearning flag is sent to the engine properly', (WidgetTester tester) async {
+ final TextEditingController controller = TextEditingController();
+ const bool enableIMEPersonalizedLearning = false;
+ await tester.pumpWidget(
+ MediaQuery(
+ data: const MediaQueryData(devicePixelRatio: 1.0),
+ child: Directionality(
+ textDirection: TextDirection.ltr,
+ child: FocusScope(
+ node: focusScopeNode,
+ autofocus: true,
+ child: EditableText(
+ controller: controller,
+ backgroundCursorColor: Colors.grey,
+ focusNode: focusNode,
+ enableIMEPersonalizedLearning: enableIMEPersonalizedLearning,
+ style: textStyle,
+ cursorColor: cursorColor,
+ ),
+ ),
+ ),
+ ),
+ );
+
+ await tester.tap(find.byType(EditableText));
+ await tester.showKeyboard(find.byType(EditableText));
+ await tester.idle();
+ expect(tester.testTextInput.setClientArgs!['enableIMEPersonalizedLearning'], enableIMEPersonalizedLearning);
+ });
+
group('smartDashesType and smartQuotesType', () {
testWidgets('sent to the engine properly', (WidgetTester tester) async {
final TextEditingController controller = TextEditingController();