Skip to content

Commit fbed8a7

Browse files
authored
Add support for language hints in TextFields (Android only) (flutter#165554)
## Description This PR adds support for language hints in TextFields. This is supported only on Android for the moment and the property name, aka `TextField.hintLocales`, is based on Android's `EditorInfo.hintLocales` property, see https://developer.android.com/reference/android/view/inputmethod/EditorInfo#hintLocales. ## Related Issue Fixes [Support for language hints in TextFields](flutter#163698) ## Tests Adds 4 tests. Updates several tests.
1 parent 6a7428d commit fbed8a7

File tree

9 files changed

+223
-9
lines changed

9 files changed

+223
-9
lines changed

engine/src/flutter/shell/platform/android/io/flutter/embedding/engine/systemchannels/TextInputChannel.java

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import java.util.Arrays;
2020
import java.util.HashMap;
2121
import java.util.List;
22+
import java.util.Locale;
2223
import java.util.Map;
2324
import java.util.Set;
2425
import org.json.JSONArray;
@@ -478,6 +479,16 @@ public static Configuration fromJson(@NonNull JSONObject json)
478479
}
479480
}
480481

482+
// Build an array of hint locales from the data in the JSON list.
483+
Locale[] hintLocales = null;
484+
if (!json.isNull("hintLocales")) {
485+
JSONArray hintLocalesJson = json.getJSONArray("hintLocales");
486+
hintLocales = new Locale[hintLocalesJson.length()];
487+
for (int i = 0; i < hintLocalesJson.length(); i++) {
488+
hintLocales[i] = Locale.forLanguageTag(hintLocalesJson.optString(i));
489+
}
490+
}
491+
481492
return new Configuration(
482493
json.optBoolean("obscureText"),
483494
json.optBoolean("autocorrect", true),
@@ -490,7 +501,8 @@ public static Configuration fromJson(@NonNull JSONObject json)
490501
json.isNull("actionLabel") ? null : json.getString("actionLabel"),
491502
json.isNull("autofill") ? null : Autofill.fromJson(json.getJSONObject("autofill")),
492503
contentList.toArray(new String[contentList.size()]),
493-
fields);
504+
fields,
505+
hintLocales);
494506
}
495507

496508
@NonNull
@@ -649,6 +661,7 @@ public Autofill(
649661
@Nullable public final Autofill autofill;
650662
@Nullable public final String[] contentCommitMimeTypes;
651663
@Nullable public final Configuration[] fields;
664+
@Nullable public final Locale[] hintLocales;
652665

653666
public Configuration(
654667
boolean obscureText,
@@ -662,7 +675,8 @@ public Configuration(
662675
@Nullable String actionLabel,
663676
@Nullable Autofill autofill,
664677
@Nullable String[] contentCommitMimeTypes,
665-
@Nullable Configuration[] fields) {
678+
@Nullable Configuration[] fields,
679+
@Nullable Locale[] hintLocales) {
666680
this.obscureText = obscureText;
667681
this.autocorrect = autocorrect;
668682
this.enableSuggestions = enableSuggestions;
@@ -675,6 +689,7 @@ public Configuration(
675689
this.autofill = autofill;
676690
this.contentCommitMimeTypes = contentCommitMimeTypes;
677691
this.fields = fields;
692+
this.hintLocales = hintLocales;
678693
}
679694
}
680695

engine/src/flutter/shell/platform/android/io/flutter/plugin/editing/TextInputPlugin.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import android.graphics.Rect;
1212
import android.os.Build;
1313
import android.os.Bundle;
14+
import android.os.LocaleList;
1415
import android.text.Editable;
1516
import android.text.InputType;
1617
import android.util.SparseArray;
@@ -349,6 +350,10 @@ public InputConnection createInputConnection(
349350
}
350351
outAttrs.imeOptions |= enterAction;
351352

353+
if (Build.VERSION.SDK_INT >= API_LEVELS.API_24 && configuration.hintLocales != null) {
354+
outAttrs.hintLocales = new LocaleList(configuration.hintLocales);
355+
}
356+
352357
if (configuration.contentCommitMimeTypes != null) {
353358
String[] imgTypeString = configuration.contentCommitMimeTypes;
354359
EditorInfoCompat.setContentMimeTypes(outAttrs, imgTypeString);

engine/src/flutter/shell/platform/android/test/io/flutter/embedding/engine/systemchannels/TextInputChannelTest.java

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
package io.flutter.embedding.engine.systemchannels;
66

77
import static io.flutter.Build.API_LEVELS;
8+
import static org.junit.Assert.assertEquals;
89
import static org.mockito.Mockito.mock;
910
import static org.mockito.Mockito.verify;
1011

@@ -13,6 +14,7 @@
1314
import io.flutter.embedding.engine.dart.DartExecutor;
1415
import io.flutter.plugin.common.MethodCall;
1516
import io.flutter.plugin.common.MethodChannel;
17+
import java.util.Locale;
1618
import org.json.JSONArray;
1719
import org.json.JSONException;
1820
import org.json.JSONObject;
@@ -39,4 +41,27 @@ public void setEditableSizeAndTransformCompletes() throws JSONException {
3941
textInputChannel.parsingMethodHandler.onMethodCall(call, result);
4042
verify(result).success(null);
4143
}
44+
45+
@Test
46+
@TargetApi(API_LEVELS.API_24)
47+
@Config(sdk = API_LEVELS.API_24)
48+
public void configurationFromJsonParsesHintLocales() throws JSONException, NoSuchFieldException {
49+
JSONObject arguments = new JSONObject();
50+
51+
// Mandatory parameters.
52+
arguments.put("inputAction", "TextInputAction.done");
53+
arguments.put("textCapitalization", "TextCapitalization.none");
54+
JSONObject inputType = new JSONObject();
55+
inputType.put("name", "TextInputType.text");
56+
arguments.put("inputType", inputType);
57+
58+
arguments.put("hintLocales", new JSONArray(new String[] {"en", "fr"}));
59+
final TextInputChannel.Configuration configuration =
60+
TextInputChannel.Configuration.fromJson(arguments);
61+
62+
final Locale[] hintLocales = {new Locale("en"), new Locale("fr")};
63+
assertEquals(configuration.hintLocales.length, hintLocales.length);
64+
assertEquals(configuration.hintLocales[0], hintLocales[0]);
65+
assertEquals(configuration.hintLocales[1], hintLocales[1]);
66+
}
4267
}

0 commit comments

Comments
 (0)