Skip to content

Commit 4344d62

Browse files
committed
[WIP] just the old PR rebased so far...
Closes: flutter#68988
1 parent 7ee910b commit 4344d62

File tree

4 files changed

+335
-3
lines changed

4 files changed

+335
-3
lines changed

packages/flutter/lib/src/services/text_input.dart

Lines changed: 119 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -856,6 +856,17 @@ abstract class TextInputClient {
856856
///
857857
/// [TextInputClient] should cleanup its connection and finalize editing.
858858
void connectionClosed();
859+
860+
/// Framework notified of a text input [source] that has been updated.
861+
///
862+
/// [TextInputClient] should re-attach itself if it wants to show the text
863+
/// input control from the new text input source.
864+
///
865+
/// See also:
866+
///
867+
/// * [TextInput.attach], a method used to re-attach the client.
868+
/// * [TextInput.setSource], a method used to change the text input source.
869+
void didUpdateInputSource(TextInputSource source);
859870
}
860871

861872
/// An interface for interacting with a text input control.
@@ -864,12 +875,26 @@ abstract class TextInputClient {
864875
/// over the [SystemChannels.textInput] method channel. See [SystemChannels.textInput]
865876
/// for more details about the method channel messages.
866877
///
878+
/// ### Connect to a different input source
879+
///
880+
/// The default [TextInputConnection] can be replaced by setting a custom
881+
/// [TextInputSource] with [TextInput.setSource]. The text input source is used
882+
/// to create [TextInputConnection] instances whenever a [TextInputClient] is
883+
/// attached.
884+
///
885+
/// A custom implementation of the [TextInputConnection] interface can override
886+
/// the default method channel connection, and delegate text input calls from the
887+
/// framework (i.e. the attached [TextInputClient]), for example, to an in-app
888+
/// virtual keyboard on platforms that don't have one provided by the system.
889+
///
867890
/// See also:
868891
///
869892
/// * [TextInput.attach], a method used to establish a [TextInputConnection]
870893
/// between the system's text input and a [TextInputClient].
871894
/// * [EditableText], a [TextInputClient] that connects to and interacts with
872895
/// the system's text input using a [TextInputConnection].
896+
/// * [TextInput.setSource], used to register a text input source for creating
897+
/// creating [TextInputConnection] instances.
873898
abstract class TextInputConnection {
874899
/// Creates a connection for a [TextInputClient].
875900
TextInputConnection(this._client)
@@ -1300,11 +1325,33 @@ class TextInput {
13001325
@visibleForTesting
13011326
static void setChannel(MethodChannel newChannel) {
13021327
assert(() {
1303-
_TextInputSource.setChannel(newChannel);
1328+
_DefaultTextInputSource.setChannel(newChannel);
13041329
return true;
13051330
}());
13061331
}
13071332

1333+
/// Sets the [TextInputSource] used to attach and detach text input clients.
1334+
/// The text input source is responsible for creating [TextInputConnection]
1335+
/// instances that are used to communicate with the currently attached
1336+
/// [TextInputClient].
1337+
///
1338+
/// The default text input source can be restored by passing
1339+
/// [TextInput.defaultSource].
1340+
///
1341+
/// If there is a [TextInputClient] attached at the time of calling
1342+
/// [TextInput.setSource], the current text input client is notified via
1343+
/// [TextInputClient.didUpdateInputSource].
1344+
///
1345+
/// See also:
1346+
///
1347+
/// * [TextInput.defaultSource], the default text input source instance.
1348+
static void setSource(TextInputSource source) {
1349+
_instance._currentSource.cleanup();
1350+
_instance._currentSource = source..init();
1351+
final TextInputClient? client = _instance._currentConnection?._client;
1352+
client?.didUpdateInputSource(source);
1353+
}
1354+
13081355
static final TextInput _instance = TextInput._();
13091356

13101357
static const List<TextInputAction> _androidSupportedInputActions = <TextInputAction>[
@@ -1384,7 +1431,20 @@ class TextInput {
13841431
return true;
13851432
}
13861433

1387-
final _TextInputSource _currentSource = _TextInputSource();
1434+
/// The default instance of [TextInputSource].
1435+
///
1436+
/// The default text input source creates [TextInputConnection] instances that
1437+
/// communicate with the platform text input plugin over the
1438+
/// [SystemChannels.textInput] method channel. See [SystemChannels.textInput]
1439+
/// for more details about the method channel messages.
1440+
///
1441+
/// See also:
1442+
///
1443+
/// * [TextInput.setSource], a method to set the current text input source.
1444+
static final TextInputSource defaultSource = _DefaultTextInputSource();
1445+
1446+
TextInputSource _currentSource = defaultSource;
1447+
13881448
TextInputConnection? _currentConnection;
13891449
late TextInputConfiguration _currentConfiguration;
13901450

@@ -1501,28 +1561,84 @@ class TextInput {
15011561
}
15021562
}
15031563

1504-
class _TextInputSource {
1564+
/// An interface for attaching and detaching [TextInputClient].
1565+
///
1566+
/// [TextInputSource] creates is responsible for creating [TextInputConnection]
1567+
/// instances that are used to communicate with the currently attached
1568+
/// [TextInputClient].
1569+
///
1570+
/// The default text input source, available via [TextInput.defaultSource],
1571+
/// creates [TextInputConnection] instances that communicate with the platform
1572+
/// text input plugin over the [SystemChannels.textInput] method channel. See
1573+
/// [SystemChannels.textInput] for more details about the text input method
1574+
/// channel messages.
1575+
///
1576+
/// ### Custom text input sources
1577+
///
1578+
/// A custom text input source can delegate text input calls from the framework
1579+
/// (i.e. the attached [TextInputClient]), for example, to an in-app virtual
1580+
/// keyboard on platforms that don't have one provided by the system.
1581+
///
1582+
/// See also:
1583+
///
1584+
/// * [TextInput.setSource], a method for setting the desired text input source.
1585+
abstract class TextInputSource {
1586+
/// TODO(jpnurmi)
1587+
void init();
1588+
1589+
/// TODO(jpnurmi)
1590+
void cleanup();
1591+
1592+
/// Attaches the current [TextInputClient] and creates a [TextInputConnection]
1593+
/// used to interact with the text input control.
1594+
///
1595+
/// This method is called by the framework when a [client] should be attached.
1596+
///
1597+
/// See also:
1598+
///
1599+
/// * [TextInput.attach]
1600+
TextInputConnection attach(TextInputClient client);
1601+
1602+
/// Detaches the current [TextInputClient] from the text input control.
1603+
///
1604+
/// This method is called by the framework when a [client] should be detached.
1605+
///
1606+
/// See also:
1607+
///
1608+
/// * [TextInput.attach]
1609+
void detach(TextInputClient client);
1610+
1611+
/// TODO(jpnurmi)
1612+
void finishAutofillContext({bool shouldSave = true});
1613+
}
1614+
1615+
class _DefaultTextInputSource implements TextInputSource {
15051616
static MethodChannel? _channel;
15061617

15071618
static void setChannel(MethodChannel newChannel) {
15081619
_channel = newChannel..setMethodCallHandler(_handleTextInputInvocation);
15091620
}
15101621

1622+
@override
15111623
void init() {
15121624
_channel ??= SystemChannels.textInput;
15131625
_channel!.setMethodCallHandler(_handleTextInputInvocation);
15141626
}
15151627

1628+
@override
15161629
void cleanup() {
15171630
_channel!.setMethodCallHandler((MethodCall methodCall) async {});
15181631
}
15191632

1633+
@override
15201634
TextInputConnection attach(TextInputClient client) {
15211635
return _TextInputChannelConnection(client, _channel!);
15221636
}
15231637

1638+
@override
15241639
void detach(TextInputClient client) {}
15251640

1641+
@override
15261642
void finishAutofillContext({bool shouldSave = true}) {
15271643
_channel!.invokeMethod<void>(
15281644
'TextInput.finishAutofillContext',

packages/flutter/lib/src/widgets/editable_text.dart

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2053,6 +2053,15 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien
20532053
}
20542054
}
20552055

2056+
@override
2057+
void didUpdateInputSource(TextInputSource source) {
2058+
if (_hasFocus && _hasInputConnection) {
2059+
_textInputConnection!.hide();
2060+
_closeInputConnectionIfNeeded();
2061+
_openInputConnection();
2062+
}
2063+
}
2064+
20562065
@override
20572066
void connectionClosed() {
20582067
if (_hasInputConnection) {

packages/flutter/test/services/autofill_test.dart

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,11 @@ class FakeAutofillClient implements TextInputClient, AutofillClient {
136136
latestMethodCall = 'connectionClosed';
137137
}
138138

139+
@override
140+
void didUpdateInputSource(TextInputSource source) {
141+
latestMethodCall = 'didUpdateInputSource';
142+
}
143+
139144
@override
140145
void showAutocorrectionPromptRect(int start, int end) {
141146
latestMethodCall = 'showAutocorrectionPromptRect';

0 commit comments

Comments
 (0)