Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Sign in
Toggle navigation
F
Front-End
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
abdullh.alsoleman
Front-End
Commits
7957c569
Unverified
Commit
7957c569
authored
Nov 05, 2019
by
Dan Field
Committed by
GitHub
Nov 05, 2019
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Respond to TextInputClient.reattach messages. (#43959)
parent
b94c1a41
Changes
4
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
297 additions
and
85 deletions
+297
-85
system_channels.dart
packages/flutter/lib/src/services/system_channels.dart
+7
-0
text_input.dart
packages/flutter/lib/src/services/text_input.dart
+150
-72
editable_text.dart
packages/flutter/lib/src/widgets/editable_text.dart
+13
-12
text_input_test.dart
packages/flutter/test/services/text_input_test.dart
+127
-1
No files found.
packages/flutter/lib/src/services/system_channels.dart
View file @
7957c569
...
...
@@ -159,6 +159,13 @@ class SystemChannels {
/// second argument is a [String] consisting of the stringification of one
/// of the values of the [TextInputAction] enum.
///
/// * `TextInputClient.requestExistingInputState`: The embedding may have
/// lost its internal state about the current editing client, if there is
/// one. The framework should call `TextInput.setClient` and
/// `TextInput.setEditingState` again with its most recent information. If
/// there is no existing state on the framework side, the call should
/// fizzle.
///
/// * `TextInputClient.onConnectionClosed`: The text input connection closed
/// on the platform side. For example the application is moved to
/// background or used closed the virtual keyboard. This method informs
...
...
packages/flutter/lib/src/services/text_input.dart
View file @
7957c569
This diff is collapsed.
Click to expand it.
packages/flutter/lib/src/widgets/editable_text.dart
View file @
7957c569
...
...
@@ -1395,19 +1395,20 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien
if
(!
_hasInputConnection
)
{
final
TextEditingValue
localValue
=
_value
;
_lastKnownRemoteTextEditingValue
=
localValue
;
_textInputConnection
=
TextInput
.
attach
(
this
,
TextInputConfiguration
(
inputType:
widget
.
keyboardType
,
obscureText:
widget
.
obscureText
,
autocorrect:
widget
.
autocorrect
,
enableSuggestions:
widget
.
enableSuggestions
,
inputAction:
widget
.
textInputAction
??
(
widget
.
keyboardType
==
TextInputType
.
multiline
?
TextInputAction
.
newline
:
TextInputAction
.
done
),
textCapitalization:
widget
.
textCapitalization
,
keyboardAppearance:
widget
.
keyboardAppearance
,
_textInputConnection
=
TextInput
.
attach
(
this
,
TextInputConfiguration
(
inputType:
widget
.
keyboardType
,
obscureText:
widget
.
obscureText
,
autocorrect:
widget
.
autocorrect
,
enableSuggestions:
widget
.
enableSuggestions
,
inputAction:
widget
.
textInputAction
??
(
widget
.
keyboardType
==
TextInputType
.
multiline
?
TextInputAction
.
newline
:
TextInputAction
.
done
),
textCapitalization:
widget
.
textCapitalization
,
keyboardAppearance:
widget
.
keyboardAppearance
,
),
);
_textInputConnection
.
show
();
...
...
packages/flutter/test/services/text_input_test.dart
View file @
7957c569
...
...
@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import
'dart:convert'
show
utf8
;
import
'package:flutter/services.dart'
;
import
'package:flutter_test/flutter_test.dart'
show
TestWidgetsFlutterBinding
;
import
'../flutter_test_alternative.dart'
;
...
...
@@ -9,6 +11,66 @@ import '../flutter_test_alternative.dart';
void
main
(
)
{
TestWidgetsFlutterBinding
.
ensureInitialized
();
group
(
'TextInput message channels'
,
()
{
FakeTextChannel
fakeTextChannel
;
FakeTextInputClient
client
;
setUp
(()
{
fakeTextChannel
=
FakeTextChannel
((
MethodCall
call
)
async
{});
TextInput
.
setChannel
(
fakeTextChannel
);
client
=
FakeTextInputClient
();
});
tearDown
(()
{
TextInputConnection
.
debugResetId
();
TextInput
.
setChannel
(
SystemChannels
.
textInput
);
});
test
(
'text input client handler responds to reattach with setClient'
,
()
async
{
TextInput
.
attach
(
client
,
client
.
configuration
);
fakeTextChannel
.
validateOutgoingMethodCalls
(<
MethodCall
>[
MethodCall
(
'TextInput.setClient'
,
<
dynamic
>[
1
,
client
.
configuration
.
toJson
()]),
]);
fakeTextChannel
.
incoming
(
const
MethodCall
(
'TextInputClient.requestExistingInputState'
,
null
));
expect
(
fakeTextChannel
.
outgoingCalls
.
length
,
2
);
fakeTextChannel
.
validateOutgoingMethodCalls
(<
MethodCall
>[
// From original attach
MethodCall
(
'TextInput.setClient'
,
<
dynamic
>[
1
,
client
.
configuration
.
toJson
()]),
// From requestExistingInputState
MethodCall
(
'TextInput.setClient'
,
<
dynamic
>[
1
,
client
.
configuration
.
toJson
()]),
]);
});
test
(
'text input client handler responds to reattach with setClient and text state'
,
()
async
{
final
TextInputConnection
connection
=
TextInput
.
attach
(
client
,
client
.
configuration
);
fakeTextChannel
.
validateOutgoingMethodCalls
(<
MethodCall
>[
MethodCall
(
'TextInput.setClient'
,
<
dynamic
>[
1
,
client
.
configuration
.
toJson
()]),
]);
const
TextEditingValue
editingState
=
TextEditingValue
(
text:
'foo'
);
connection
.
setEditingState
(
editingState
);
fakeTextChannel
.
validateOutgoingMethodCalls
(<
MethodCall
>[
MethodCall
(
'TextInput.setClient'
,
<
dynamic
>[
1
,
client
.
configuration
.
toJson
()]),
MethodCall
(
'TextInput.setEditingState'
,
editingState
.
toJSON
()),
]);
fakeTextChannel
.
incoming
(
const
MethodCall
(
'TextInputClient.requestExistingInputState'
,
null
));
expect
(
fakeTextChannel
.
outgoingCalls
.
length
,
4
);
fakeTextChannel
.
validateOutgoingMethodCalls
(<
MethodCall
>[
// attach
MethodCall
(
'TextInput.setClient'
,
<
dynamic
>[
1
,
client
.
configuration
.
toJson
()]),
// set editing state 1
MethodCall
(
'TextInput.setEditingState'
,
editingState
.
toJSON
()),
// both from requestExistingInputState
MethodCall
(
'TextInput.setClient'
,
<
dynamic
>[
1
,
client
.
configuration
.
toJson
()]),
MethodCall
(
'TextInput.setEditingState'
,
editingState
.
toJSON
()),
]);
});
});
group
(
'TextInputConfiguration'
,
()
{
test
(
'sets expected defaults'
,
()
{
const
TextInputConfiguration
configuration
=
TextInputConfiguration
();
...
...
@@ -113,7 +175,7 @@ void main() {
});
}
class
FakeTextInputClient
extend
s
TextInputClient
{
class
FakeTextInputClient
implement
s
TextInputClient
{
String
latestMethodCall
=
''
;
@override
...
...
@@ -135,4 +197,68 @@ class FakeTextInputClient extends TextInputClient {
void
connectionClosed
()
{
latestMethodCall
=
'connectionClosed'
;
}
TextInputConfiguration
get
configuration
=>
const
TextInputConfiguration
();
}
class
FakeTextChannel
implements
MethodChannel
{
FakeTextChannel
(
this
.
outgoing
)
:
assert
(
outgoing
!=
null
);
Future
<
void
>
Function
(
MethodCall
)
outgoing
;
Future
<
void
>
Function
(
MethodCall
)
incoming
;
List
<
MethodCall
>
outgoingCalls
=
<
MethodCall
>[];
@override
BinaryMessenger
get
binaryMessenger
=>
throw
UnimplementedError
();
@override
MethodCodec
get
codec
=>
const
JSONMethodCodec
();
@override
Future
<
List
<
T
>>
invokeListMethod
<
T
>(
String
method
,
[
dynamic
arguments
])
=>
throw
UnimplementedError
();
@override
Future
<
Map
<
K
,
V
>>
invokeMapMethod
<
K
,
V
>(
String
method
,
[
dynamic
arguments
])
=>
throw
UnimplementedError
();
@override
Future
<
T
>
invokeMethod
<
T
>(
String
method
,
[
dynamic
arguments
])
{
final
MethodCall
call
=
MethodCall
(
method
,
arguments
);
outgoingCalls
.
add
(
call
);
return
outgoing
(
call
);
}
@override
String
get
name
=>
'flutter/textinput'
;
@override
void
setMethodCallHandler
(
Future
<
void
>
Function
(
MethodCall
call
)
handler
)
{
incoming
=
handler
;
}
@override
void
setMockMethodCallHandler
(
Future
<
void
>
Function
(
MethodCall
call
)
handler
)
=>
throw
UnimplementedError
();
void
validateOutgoingMethodCalls
(
List
<
MethodCall
>
calls
)
{
expect
(
outgoingCalls
.
length
,
calls
.
length
);
bool
hasError
=
false
;
for
(
int
i
=
0
;
i
<
calls
.
length
;
i
++)
{
final
ByteData
outgoingData
=
codec
.
encodeMethodCall
(
outgoingCalls
[
i
]);
final
ByteData
expectedData
=
codec
.
encodeMethodCall
(
calls
[
i
]);
final
String
outgoingString
=
utf8
.
decode
(
outgoingData
.
buffer
.
asUint8List
());
final
String
expectedString
=
utf8
.
decode
(
expectedData
.
buffer
.
asUint8List
());
if
(
outgoingString
!=
expectedString
)
{
print
(
'Index
$i
did not match:
\n
'
' actual:
${outgoingCalls[i]}
'
' expected:
${calls[i]}
'
);
hasError
=
true
;
}
}
if
(
hasError
)
{
fail
(
'Calls did not match.'
);
}
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment