Unverified Commit 9c32e5a1 authored by Renzo Olivares's avatar Renzo Olivares Committed by GitHub

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
parent ade9f6a9
...@@ -219,7 +219,8 @@ class CupertinoTextField extends StatefulWidget { ...@@ -219,7 +219,8 @@ class CupertinoTextField extends StatefulWidget {
/// The [autocorrect], [autofocus], [clearButtonMode], [dragStartBehavior], /// The [autocorrect], [autofocus], [clearButtonMode], [dragStartBehavior],
/// [expands], [maxLengthEnforced], [obscureText], [prefixMode], [readOnly], /// [expands], [maxLengthEnforced], [obscureText], [prefixMode], [readOnly],
/// [scrollPadding], [suffixMode], [textAlign], [selectionHeightStyle], /// [scrollPadding], [suffixMode], [textAlign], [selectionHeightStyle],
/// [selectionWidthStyle], and [enableSuggestions] properties must not be null. /// [selectionWidthStyle], [enableSuggestions], and [enableIMEPersonalizedLearning]
/// properties must not be null.
/// ///
/// See also: /// See also:
/// ///
...@@ -294,6 +295,7 @@ class CupertinoTextField extends StatefulWidget { ...@@ -294,6 +295,7 @@ class CupertinoTextField extends StatefulWidget {
this.scrollPhysics, this.scrollPhysics,
this.autofillHints, this.autofillHints,
this.restorationId, this.restorationId,
this.enableIMEPersonalizedLearning = true,
}) : assert(textAlign != null), }) : assert(textAlign != null),
assert(readOnly != null), assert(readOnly != null),
assert(autofocus != null), assert(autofocus != null),
...@@ -335,6 +337,7 @@ class CupertinoTextField extends StatefulWidget { ...@@ -335,6 +337,7 @@ class CupertinoTextField extends StatefulWidget {
!identical(keyboardType, TextInputType.text), !identical(keyboardType, TextInputType.text),
'Use keyboardType TextInputType.multiline when using TextInputAction.newline on a multiline TextField.', 'Use keyboardType TextInputType.multiline when using TextInputAction.newline on a multiline TextField.',
), ),
assert(enableIMEPersonalizedLearning != null),
keyboardType = keyboardType ?? (maxLines == 1 ? TextInputType.text : TextInputType.multiline), keyboardType = keyboardType ?? (maxLines == 1 ? TextInputType.text : TextInputType.multiline),
toolbarOptions = toolbarOptions ?? (obscureText ? toolbarOptions = toolbarOptions ?? (obscureText ?
const ToolbarOptions( const ToolbarOptions(
...@@ -448,6 +451,7 @@ class CupertinoTextField extends StatefulWidget { ...@@ -448,6 +451,7 @@ class CupertinoTextField extends StatefulWidget {
this.scrollPhysics, this.scrollPhysics,
this.autofillHints, this.autofillHints,
this.restorationId, this.restorationId,
this.enableIMEPersonalizedLearning = true,
}) : assert(textAlign != null), }) : assert(textAlign != null),
assert(readOnly != null), assert(readOnly != null),
assert(autofocus != null), assert(autofocus != null),
...@@ -489,6 +493,7 @@ class CupertinoTextField extends StatefulWidget { ...@@ -489,6 +493,7 @@ class CupertinoTextField extends StatefulWidget {
!identical(keyboardType, TextInputType.text), !identical(keyboardType, TextInputType.text),
'Use keyboardType TextInputType.multiline when using TextInputAction.newline on a multiline TextField.', 'Use keyboardType TextInputType.multiline when using TextInputAction.newline on a multiline TextField.',
), ),
assert(enableIMEPersonalizedLearning != null),
keyboardType = keyboardType ?? (maxLines == 1 ? TextInputType.text : TextInputType.multiline), keyboardType = keyboardType ?? (maxLines == 1 ? TextInputType.text : TextInputType.multiline),
toolbarOptions = toolbarOptions ?? (obscureText ? toolbarOptions = toolbarOptions ?? (obscureText ?
const ToolbarOptions( const ToolbarOptions(
...@@ -784,6 +789,9 @@ class CupertinoTextField extends StatefulWidget { ...@@ -784,6 +789,9 @@ class CupertinoTextField extends StatefulWidget {
/// {@macro flutter.material.textfield.restorationId} /// {@macro flutter.material.textfield.restorationId}
final String? restorationId; final String? restorationId;
/// {@macro flutter.services.TextInputConfiguration.enableIMEPersonalizedLearning}
final bool enableIMEPersonalizedLearning;
@override @override
State<CupertinoTextField> createState() => _CupertinoTextFieldState(); State<CupertinoTextField> createState() => _CupertinoTextFieldState();
...@@ -825,6 +833,7 @@ class CupertinoTextField extends StatefulWidget { ...@@ -825,6 +833,7 @@ class CupertinoTextField extends StatefulWidget {
properties.add(EnumProperty<TextAlign>('textAlign', textAlign, defaultValue: TextAlign.start)); properties.add(EnumProperty<TextAlign>('textAlign', textAlign, defaultValue: TextAlign.start));
properties.add(DiagnosticsProperty<TextAlignVertical>('textAlignVertical', textAlignVertical, defaultValue: null)); properties.add(DiagnosticsProperty<TextAlignVertical>('textAlignVertical', textAlignVertical, defaultValue: null));
properties.add(EnumProperty<TextDirection>('textDirection', textDirection, defaultValue: null)); properties.add(EnumProperty<TextDirection>('textDirection', textDirection, defaultValue: null));
properties.add(DiagnosticsProperty<bool>('enableIMEPersonalizedLearning', enableIMEPersonalizedLearning, defaultValue: true));
} }
} }
...@@ -1221,6 +1230,7 @@ class _CupertinoTextFieldState extends State<CupertinoTextField> with Restoratio ...@@ -1221,6 +1230,7 @@ class _CupertinoTextFieldState extends State<CupertinoTextField> with Restoratio
enableInteractiveSelection: widget.enableInteractiveSelection, enableInteractiveSelection: widget.enableInteractiveSelection,
autofillHints: widget.autofillHints, autofillHints: widget.autofillHints,
restorationId: 'editable', restorationId: 'editable',
enableIMEPersonalizedLearning: widget.enableIMEPersonalizedLearning,
), ),
), ),
), ),
......
...@@ -325,8 +325,8 @@ class TextField extends StatefulWidget { ...@@ -325,8 +325,8 @@ class TextField extends StatefulWidget {
/// ///
/// The [textAlign], [autofocus], [obscureText], [readOnly], [autocorrect], /// The [textAlign], [autofocus], [obscureText], [readOnly], [autocorrect],
/// [maxLengthEnforced], [scrollPadding], [maxLines], [maxLength], /// [maxLengthEnforced], [scrollPadding], [maxLines], [maxLength],
/// [selectionHeightStyle], [selectionWidthStyle], and [enableSuggestions] /// [selectionHeightStyle], [selectionWidthStyle], [enableSuggestions], and
/// arguments must not be null. /// [enableIMEPersonalizedLearning] arguments must not be null.
/// ///
/// See also: /// See also:
/// ///
...@@ -390,6 +390,7 @@ class TextField extends StatefulWidget { ...@@ -390,6 +390,7 @@ class TextField extends StatefulWidget {
this.scrollPhysics, this.scrollPhysics,
this.autofillHints, this.autofillHints,
this.restorationId, this.restorationId,
this.enableIMEPersonalizedLearning = true,
}) : assert(textAlign != null), }) : assert(textAlign != null),
assert(readOnly != null), assert(readOnly != null),
assert(autofocus != null), assert(autofocus != null),
...@@ -429,6 +430,7 @@ class TextField extends StatefulWidget { ...@@ -429,6 +430,7 @@ class TextField extends StatefulWidget {
!identical(keyboardType, TextInputType.text), !identical(keyboardType, TextInputType.text),
'Use keyboardType TextInputType.multiline when using TextInputAction.newline on a multiline TextField.', 'Use keyboardType TextInputType.multiline when using TextInputAction.newline on a multiline TextField.',
), ),
assert(enableIMEPersonalizedLearning != null),
keyboardType = keyboardType ?? (maxLines == 1 ? TextInputType.text : TextInputType.multiline), keyboardType = keyboardType ?? (maxLines == 1 ? TextInputType.text : TextInputType.multiline),
toolbarOptions = toolbarOptions ?? (obscureText ? toolbarOptions = toolbarOptions ?? (obscureText ?
const ToolbarOptions( const ToolbarOptions(
...@@ -821,6 +823,9 @@ class TextField extends StatefulWidget { ...@@ -821,6 +823,9 @@ class TextField extends StatefulWidget {
/// {@endtemplate} /// {@endtemplate}
final String? restorationId; final String? restorationId;
/// {@macro flutter.services.TextInputConfiguration.enableIMEPersonalizedLearning}
final bool enableIMEPersonalizedLearning;
@override @override
State<TextField> createState() => _TextFieldState(); State<TextField> createState() => _TextFieldState();
...@@ -861,6 +866,7 @@ class TextField extends StatefulWidget { ...@@ -861,6 +866,7 @@ class TextField extends StatefulWidget {
properties.add(DiagnosticsProperty<TextSelectionControls>('selectionControls', selectionControls, defaultValue: null)); properties.add(DiagnosticsProperty<TextSelectionControls>('selectionControls', selectionControls, defaultValue: null));
properties.add(DiagnosticsProperty<ScrollController>('scrollController', scrollController, defaultValue: null)); properties.add(DiagnosticsProperty<ScrollController>('scrollController', scrollController, defaultValue: null));
properties.add(DiagnosticsProperty<ScrollPhysics>('scrollPhysics', scrollPhysics, defaultValue: null)); properties.add(DiagnosticsProperty<ScrollPhysics>('scrollPhysics', scrollPhysics, defaultValue: null));
properties.add(DiagnosticsProperty<bool>('enableIMEPersonalizedLearning', enableIMEPersonalizedLearning, defaultValue: true));
} }
} }
...@@ -1263,6 +1269,7 @@ class _TextFieldState extends State<TextField> with RestorationMixin implements ...@@ -1263,6 +1269,7 @@ class _TextFieldState extends State<TextField> with RestorationMixin implements
autofillHints: widget.autofillHints, autofillHints: widget.autofillHints,
autocorrectionTextRectColor: autocorrectionTextRectColor, autocorrectionTextRectColor: autocorrectionTextRectColor,
restorationId: 'editable', restorationId: 'editable',
enableIMEPersonalizedLearning: widget.enableIMEPersonalizedLearning,
), ),
), ),
); );
......
...@@ -196,6 +196,7 @@ class TextFormField extends FormField<String> { ...@@ -196,6 +196,7 @@ class TextFormField extends FormField<String> {
AutovalidateMode? autovalidateMode, AutovalidateMode? autovalidateMode,
ScrollController? scrollController, ScrollController? scrollController,
String? restorationId, String? restorationId,
bool enableIMEPersonalizedLearning = true,
}) : assert(initialValue == null || controller == null), }) : assert(initialValue == null || controller == null),
assert(textAlign != null), assert(textAlign != null),
assert(autofocus != null), assert(autofocus != null),
...@@ -230,6 +231,7 @@ class TextFormField extends FormField<String> { ...@@ -230,6 +231,7 @@ class TextFormField extends FormField<String> {
assert(!obscureText || maxLines == 1, 'Obscured fields cannot be multiline.'), assert(!obscureText || maxLines == 1, 'Obscured fields cannot be multiline.'),
assert(maxLength == null || maxLength == TextField.noMaxLength || maxLength > 0), assert(maxLength == null || maxLength == TextField.noMaxLength || maxLength > 0),
assert(enableInteractiveSelection != null), assert(enableInteractiveSelection != null),
assert(enableIMEPersonalizedLearning != null),
super( super(
key: key, key: key,
restorationId: restorationId, restorationId: restorationId,
...@@ -299,6 +301,7 @@ class TextFormField extends FormField<String> { ...@@ -299,6 +301,7 @@ class TextFormField extends FormField<String> {
buildCounter: buildCounter, buildCounter: buildCounter,
autofillHints: autofillHints, autofillHints: autofillHints,
scrollController: scrollController, scrollController: scrollController,
enableIMEPersonalizedLearning: enableIMEPersonalizedLearning,
), ),
); );
}, },
......
...@@ -466,6 +466,7 @@ class TextInputConfiguration { ...@@ -466,6 +466,7 @@ class TextInputConfiguration {
this.keyboardAppearance = Brightness.light, this.keyboardAppearance = Brightness.light,
this.textCapitalization = TextCapitalization.none, this.textCapitalization = TextCapitalization.none,
this.autofillConfiguration, this.autofillConfiguration,
this.enableIMEPersonalizedLearning = true,
}) : assert(inputType != null), }) : assert(inputType != null),
assert(obscureText != null), assert(obscureText != null),
smartDashesType = smartDashesType ?? (obscureText ? SmartDashesType.disabled : SmartDashesType.enabled), smartDashesType = smartDashesType ?? (obscureText ? SmartDashesType.disabled : SmartDashesType.enabled),
...@@ -474,7 +475,8 @@ class TextInputConfiguration { ...@@ -474,7 +475,8 @@ class TextInputConfiguration {
assert(enableSuggestions != null), assert(enableSuggestions != null),
assert(keyboardAppearance != null), assert(keyboardAppearance != null),
assert(inputAction != 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. /// The type of information for which to optimize the text input control.
final TextInputType inputType; final TextInputType inputType;
...@@ -590,6 +592,20 @@ class TextInputConfiguration { ...@@ -590,6 +592,20 @@ class TextInputConfiguration {
/// Defaults to [Brightness.light]. /// Defaults to [Brightness.light].
final Brightness keyboardAppearance; 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. /// Returns a representation of this object as a JSON object.
Map<String, dynamic> toJson() { Map<String, dynamic> toJson() {
return <String, dynamic>{ return <String, dynamic>{
...@@ -604,6 +620,7 @@ class TextInputConfiguration { ...@@ -604,6 +620,7 @@ class TextInputConfiguration {
'inputAction': inputAction.toString(), 'inputAction': inputAction.toString(),
'textCapitalization': textCapitalization.toString(), 'textCapitalization': textCapitalization.toString(),
'keyboardAppearance': keyboardAppearance.toString(), 'keyboardAppearance': keyboardAppearance.toString(),
'enableIMEPersonalizedLearning': enableIMEPersonalizedLearning,
if (autofillConfiguration != null) 'autofill': autofillConfiguration!.toJson(), if (autofillConfiguration != null) 'autofill': autofillConfiguration!.toJson(),
}; };
} }
......
...@@ -426,8 +426,8 @@ class EditableText extends StatefulWidget { ...@@ -426,8 +426,8 @@ class EditableText extends StatefulWidget {
/// [style], [cursorColor], [cursorOpacityAnimates],[backgroundCursorColor], /// [style], [cursorColor], [cursorOpacityAnimates],[backgroundCursorColor],
/// [enableSuggestions], [paintCursorAboveText], [selectionHeightStyle], /// [enableSuggestions], [paintCursorAboveText], [selectionHeightStyle],
/// [selectionWidthStyle], [textAlign], [dragStartBehavior], [scrollPadding], /// [selectionWidthStyle], [textAlign], [dragStartBehavior], [scrollPadding],
/// [dragStartBehavior], [toolbarOptions], [rendererIgnoresPointer], and /// [dragStartBehavior], [toolbarOptions], [rendererIgnoresPointer],
/// [readOnly] arguments must not be null. /// [readOnly], and [enableIMEPersonalizedLearning] arguments must not be null.
EditableText({ EditableText({
Key? key, Key? key,
required this.controller, required this.controller,
...@@ -495,6 +495,7 @@ class EditableText extends StatefulWidget { ...@@ -495,6 +495,7 @@ class EditableText extends StatefulWidget {
this.clipBehavior = Clip.hardEdge, this.clipBehavior = Clip.hardEdge,
this.restorationId, this.restorationId,
this.scrollBehavior, this.scrollBehavior,
this.enableIMEPersonalizedLearning = true,
}) : assert(controller != null), }) : assert(controller != null),
assert(focusNode != null), assert(focusNode != null),
assert(obscuringCharacter != null && obscuringCharacter.length == 1), assert(obscuringCharacter != null && obscuringCharacter.length == 1),
...@@ -537,6 +538,7 @@ class EditableText extends StatefulWidget { ...@@ -537,6 +538,7 @@ class EditableText extends StatefulWidget {
!readOnly || autofillHints == null, !readOnly || autofillHints == null,
"Read-only fields can't have autofill hints.", "Read-only fields can't have autofill hints.",
), ),
assert(enableIMEPersonalizedLearning != null),
_strutStyle = strutStyle, _strutStyle = strutStyle,
keyboardType = keyboardType ?? _inferKeyboardType(autofillHints: autofillHints, maxLines: maxLines), keyboardType = keyboardType ?? _inferKeyboardType(autofillHints: autofillHints, maxLines: maxLines),
inputFormatters = maxLines == 1 inputFormatters = maxLines == 1
...@@ -1346,6 +1348,9 @@ class EditableText extends StatefulWidget { ...@@ -1346,6 +1348,9 @@ class EditableText extends StatefulWidget {
/// than 1. /// than 1.
final ScrollBehavior? scrollBehavior; final ScrollBehavior? scrollBehavior;
/// {@macro flutter.services.TextInputConfiguration.enableIMEPersonalizedLearning}
final bool enableIMEPersonalizedLearning;
// Infer the keyboard type of an `EditableText` if it's not specified. // Infer the keyboard type of an `EditableText` if it's not specified.
static TextInputType _inferKeyboardType({ static TextInputType _inferKeyboardType({
required Iterable<String>? autofillHints, required Iterable<String>? autofillHints,
...@@ -1513,6 +1518,7 @@ class EditableText extends StatefulWidget { ...@@ -1513,6 +1518,7 @@ class EditableText extends StatefulWidget {
properties.add(DiagnosticsProperty<ScrollPhysics>('scrollPhysics', scrollPhysics, defaultValue: null)); properties.add(DiagnosticsProperty<ScrollPhysics>('scrollPhysics', scrollPhysics, defaultValue: null));
properties.add(DiagnosticsProperty<Iterable<String>>('autofillHints', autofillHints, defaultValue: null)); properties.add(DiagnosticsProperty<Iterable<String>>('autofillHints', autofillHints, defaultValue: null));
properties.add(DiagnosticsProperty<TextHeightBehavior>('textHeightBehavior', textHeightBehavior, defaultValue: null)); properties.add(DiagnosticsProperty<TextHeightBehavior>('textHeightBehavior', textHeightBehavior, defaultValue: null));
properties.add(DiagnosticsProperty<bool>('enableIMEPersonalizedLearning', enableIMEPersonalizedLearning, defaultValue: true));
} }
} }
...@@ -2607,6 +2613,7 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien ...@@ -2607,6 +2613,7 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien
autofillHints: widget.autofillHints?.toList(growable: false) ?? <String>[], autofillHints: widget.autofillHints?.toList(growable: false) ?? <String>[],
currentEditingValue: currentTextEditingValue, currentEditingValue: currentTextEditingValue,
), ),
enableIMEPersonalizedLearning: widget.enableIMEPersonalizedLearning,
); );
} }
......
...@@ -199,6 +199,7 @@ void main() { ...@@ -199,6 +199,7 @@ void main() {
expect(editableText.obscureText, isFalse); expect(editableText.obscureText, isFalse);
expect(editableText.autocorrect, isTrue); expect(editableText.autocorrect, isTrue);
expect(editableText.enableSuggestions, isTrue); expect(editableText.enableSuggestions, isTrue);
expect(editableText.enableIMEPersonalizedLearning, isTrue);
expect(editableText.textAlign, TextAlign.start); expect(editableText.textAlign, TextAlign.start);
expect(editableText.cursorWidth, 2.0); expect(editableText.cursorWidth, 2.0);
expect(editableText.cursorHeight, isNull); expect(editableText.cursorHeight, isNull);
...@@ -576,6 +577,36 @@ void main() { ...@@ -576,6 +577,36 @@ void main() {
expect(tester.testTextInput.setClientArgs!['enableSuggestions'], enableSuggestions); 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', () { group('smartDashesType and smartQuotesType', () {
testWidgets('sent to the engine properly', (WidgetTester tester) async { testWidgets('sent to the engine properly', (WidgetTester tester) async {
final TextEditingController controller = TextEditingController(); final TextEditingController controller = TextEditingController();
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment