1package io.flutter.plugin.editing;
3import static io.flutter.Build.API_LEVELS;
4import static org.junit.Assert.assertEquals;
5import static org.junit.Assert.assertNotNull;
6import static org.junit.Assert.assertThrows;
7import static org.junit.Assert.assertTrue;
8import static org.mockito.AdditionalMatchers.aryEq;
9import static org.mockito.AdditionalMatchers.gt;
10import static org.mockito.ArgumentMatchers.anyInt;
11import static org.mockito.Mockito.any;
12import static org.mockito.Mockito.atLeast;
13import static org.mockito.Mockito.eq;
14import static org.mockito.Mockito.isNotNull;
15import static org.mockito.Mockito.isNull;
16import static org.mockito.Mockito.mock;
17import static org.mockito.Mockito.never;
18import static org.mockito.Mockito.spy;
19import static org.mockito.Mockito.times;
20import static org.mockito.Mockito.verify;
21import static org.mockito.Mockito.when;
23import android.annotation.TargetApi;
26import android.content.res.AssetManager;
31import android.provider.Settings;
35import android.util.SparseIntArray;
38import android.view.ViewStructure;
39import android.view.WindowInsets;
40import android.view.WindowInsetsAnimation;
41import android.view.autofill.AutofillManager;
42import android.view.autofill.AutofillValue;
43import android.view.inputmethod.CursorAnchorInfo;
44import android.view.inputmethod.EditorInfo;
45import android.view.inputmethod.InputConnection;
46import android.view.inputmethod.InputMethodManager;
47import android.view.inputmethod.InputMethodSubtype;
48import androidx.test.core.app.ApplicationProvider;
49import androidx.test.ext.junit.runners.AndroidJUnit4;
50import io.flutter.embedding.android.FlutterView;
51import io.flutter.embedding.android.KeyboardManager;
52import io.flutter.embedding.engine.FlutterEngine;
53import io.flutter.embedding.engine.FlutterJNI;
54import io.flutter.embedding.engine.dart.DartExecutor;
55import io.flutter.embedding.engine.loader.FlutterLoader;
56import io.flutter.embedding.engine.renderer.FlutterRenderer;
57import io.flutter.embedding.engine.systemchannels.TextInputChannel;
58import io.flutter.embedding.engine.systemchannels.TextInputChannel.TextEditState;
59import io.flutter.plugin.common.BinaryMessenger;
60import io.flutter.plugin.common.JSONMethodCodec;
61import io.flutter.plugin.common.MethodCall;
62import io.flutter.plugin.platform.PlatformViewsController;
63import java.nio.ByteBuffer;
64import java.util.ArrayList;
65import java.util.HashMap;
67import org.json.JSONArray;
68import org.json.JSONException;
69import org.json.JSONObject;
70import org.junit.Before;
72import org.junit.runner.RunWith;
73import org.mockito.ArgumentCaptor;
74import org.mockito.Mock;
75import org.mockito.MockitoAnnotations;
76import org.robolectric.Robolectric;
77import org.robolectric.annotation.Config;
78import org.robolectric.annotation.Implementation;
79import org.robolectric.annotation.Implements;
80import org.robolectric.shadow.api.Shadow;
81import org.robolectric.shadows.ShadowAutofillManager;
82import org.robolectric.shadows.ShadowBuild;
83import org.robolectric.shadows.ShadowInputMethodManager;
87 shadows = {TextInputPluginTest.TestImm.class, TextInputPluginTest.TestAfm.class})
88@RunWith(AndroidJUnit4.class)
90 private final Context ctx = ApplicationProvider.getApplicationContext();
96 MockitoAnnotations.openMocks(
this);
97 when(mockFlutterJni.isAttached()).thenReturn(
true);
101 private void verifyMethodCall(ByteBuffer
buffer, String methodName, String[] expectedArgs)
102 throws JSONException {
105 assertEquals(methodName, methodCall.method);
106 if (expectedArgs !=
null) {
107 JSONArray
args = methodCall.arguments();
108 assertEquals(expectedArgs.length,
args.length());
109 for (
int i = 0; i <
args.length(); i++) {
110 assertEquals(expectedArgs[i],
args.get(i).toString());
115 private static void sendToBinaryMessageHandler(
116 BinaryMessenger.BinaryMessageHandler binaryMessageHandler, String method, Object
args) {
118 ByteBuffer encodedMethodCall = JSONMethodCodec.INSTANCE.encodeMethodCall(methodCall);
119 binaryMessageHandler.onMessage(
120 (ByteBuffer) encodedMethodCall.flip(), mock(BinaryMessenger.BinaryReply.class));
123 @SuppressWarnings(
"deprecation")
128 InputMethodSubtype inputMethodSubtype = mock(InputMethodSubtype.class);
129 TestImm testImm = Shadow.extract(ctx.getSystemService(
Context.INPUT_METHOD_SERVICE));
131 View testView =
new View(ctx);
133 FlutterJNI mockFlutterJni = mock(FlutterJNI.class);
134 DartExecutor dartExecutor = spy(
new DartExecutor(mockFlutterJni, mock(AssetManager.class)));
135 TextInputChannel textInputChannel =
new TextInputChannel(dartExecutor);
137 new TextInputPlugin(testView, textInputChannel, mock(PlatformViewsController.class));
139 ArgumentCaptor<String> channelCaptor = ArgumentCaptor.forClass(String.class);
140 ArgumentCaptor<ByteBuffer> bufferCaptor = ArgumentCaptor.forClass(ByteBuffer.class);
142 verify(dartExecutor,
times(1)).send(channelCaptor.capture(), bufferCaptor.capture(), isNull());
143 assertEquals(
"flutter/textinput", channelCaptor.getValue());
144 verifyMethodCall(bufferCaptor.getValue(),
"TextInputClient.requestExistingInputState",
null);
150 InputMethodSubtype inputMethodSubtype = mock(InputMethodSubtype.class);
151 TestImm testImm = Shadow.extract(ctx.getSystemService(
Context.INPUT_METHOD_SERVICE));
153 View testView =
new View(ctx);
154 TextInputChannel textInputChannel = spy(
new TextInputChannel(mock(DartExecutor.class)));
156 new TextInputPlugin(testView, textInputChannel, mock(PlatformViewsController.class));
159 new TextInputChannel.Configuration(
165 TextInputChannel.TextCapitalization.NONE,
174 testView,
new TextInputChannel.TextEditState(
"initial input from framework", 0, 0, -1, -1));
175 assertTrue(
textInputPlugin.getEditable().toString().equals(
"initial input from framework"));
177 verify(textInputChannel,
times(0))
178 .updateEditingState(anyInt(), any(), anyInt(), anyInt(), anyInt(), anyInt());
182 new TextInputChannel.TextEditState(
"more update from the framework", 1, 2, -1, -1));
184 assertTrue(
textInputPlugin.getEditable().toString().equals(
"more update from the framework"));
185 verify(textInputChannel,
times(0))
186 .updateEditingState(anyInt(), any(), anyInt(), anyInt(), anyInt(), anyInt());
192 InputMethodSubtype inputMethodSubtype = mock(InputMethodSubtype.class);
193 TestImm testImm = Shadow.extract(ctx.getSystemService(
Context.INPUT_METHOD_SERVICE));
195 View testView =
new View(ctx);
196 TextInputChannel textInputChannel = spy(
new TextInputChannel(mock(DartExecutor.class)));
198 new TextInputPlugin(testView, textInputChannel, mock(PlatformViewsController.class));
202 testView,
new TextInputChannel.TextEditState(
"initial input from framework", 0, 0, -1, -1));
203 assertTrue(
textInputPlugin.getEditable().toString().equals(
"initial input from framework"));
209 InputMethodSubtype inputMethodSubtype = mock(InputMethodSubtype.class);
210 TestImm testImm = Shadow.extract(ctx.getSystemService(
Context.INPUT_METHOD_SERVICE));
212 View testView =
new View(ctx);
213 TextInputChannel textInputChannel = spy(
new TextInputChannel(mock(DartExecutor.class)));
215 new TextInputPlugin(testView, textInputChannel, mock(PlatformViewsController.class));
218 new TextInputChannel.Configuration(
224 TextInputChannel.TextCapitalization.NONE,
234 new TextInputChannel.TextEditState(
"receiving initial input from framework", 0, 0, -1, -1));
236 textInputPlugin.getEditable().toString().equals(
"receiving initial input from framework"));
238 verify(textInputChannel,
times(0)).updateEditingStateWithDeltas(anyInt(), any());
242 new TextInputChannel.TextEditState(
243 "receiving more updates from the framework", 1, 2, -1, -1));
249 .
equals(
"receiving more updates from the framework"));
250 verify(textInputChannel,
times(0)).updateEditingStateWithDeltas(anyInt(), any());
255 throws NullPointerException {
257 InputMethodSubtype inputMethodSubtype = mock(InputMethodSubtype.class);
258 TestImm testImm = Shadow.extract(ctx.getSystemService(
Context.INPUT_METHOD_SERVICE));
260 View testView =
new View(ctx);
261 EditorInfo outAttrs =
new EditorInfo();
262 outAttrs.inputType = InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_MULTI_LINE;
263 TextInputChannel textInputChannel = spy(
new TextInputChannel(mock(DartExecutor.class)));
265 new TextInputPlugin(testView, textInputChannel, mock(PlatformViewsController.class));
266 CharSequence newText =
"I do not fear computers. I fear the lack of them.";
271 new TextInputChannel.Configuration(
277 TextInputChannel.TextCapitalization.NONE,
278 new TextInputChannel.InputType(TextInputChannel.TextInputType.TEXT,
false,
false),
287 testView,
new TextInputChannel.TextEditState(
"", 0, 0, -1, -1));
288 verify(textInputChannel,
times(0)).updateEditingStateWithDeltas(anyInt(), any());
289 verify(textInputChannel,
times(0))
290 .updateEditingState(anyInt(), any(), anyInt(), anyInt(), anyInt(), anyInt());
294 .extractBatchTextEditingDeltas()
297 InputConnection inputConnection =
298 textInputPlugin.createInputConnection(testView, mock(KeyboardManager.class), outAttrs);
300 inputConnection.beginBatchEdit();
301 verify(textInputChannel,
times(0)).updateEditingStateWithDeltas(anyInt(), any());
302 verify(textInputChannel,
times(0))
303 .updateEditingState(anyInt(), any(), anyInt(), anyInt(), anyInt(), anyInt());
304 inputConnection.setComposingText(newText, newText.length());
305 verify(textInputChannel,
times(0)).updateEditingStateWithDeltas(anyInt(), any());
306 verify(textInputChannel,
times(0))
307 .updateEditingState(anyInt(), any(), anyInt(), anyInt(), anyInt(), anyInt());
308 inputConnection.endBatchEdit();
313 .extractBatchTextEditingDeltas()
316 verify(textInputChannel,
times(0)).updateEditingStateWithDeltas(anyInt(), any());
317 verify(textInputChannel,
times(1))
318 .updateEditingState(anyInt(), any(), anyInt(), anyInt(), anyInt(), anyInt());
320 inputConnection.beginBatchEdit();
322 verify(textInputChannel,
times(0)).updateEditingStateWithDeltas(anyInt(), any());
323 verify(textInputChannel,
times(1))
324 .updateEditingState(anyInt(), any(), anyInt(), anyInt(), anyInt(), anyInt());
326 inputConnection.endBatchEdit();
331 .extractBatchTextEditingDeltas()
334 verify(textInputChannel,
times(0)).updateEditingStateWithDeltas(anyInt(), any());
335 verify(textInputChannel,
times(1))
336 .updateEditingState(anyInt(), any(), anyInt(), anyInt(), anyInt(), anyInt());
338 inputConnection.beginBatchEdit();
340 verify(textInputChannel,
times(0)).updateEditingStateWithDeltas(anyInt(), any());
341 verify(textInputChannel,
times(1))
342 .updateEditingState(anyInt(), any(), anyInt(), anyInt(), anyInt(), anyInt());
347 inputConnection.setSelection(3, 4);
348 assertEquals(Selection.getSelectionStart(
textInputPlugin.getEditable()), 3);
349 assertEquals(Selection.getSelectionEnd(
textInputPlugin.getEditable()), 4);
351 verify(textInputChannel,
times(0)).updateEditingStateWithDeltas(anyInt(), any());
352 verify(textInputChannel,
times(1))
353 .updateEditingState(anyInt(), any(), anyInt(), anyInt(), anyInt(), anyInt());
355 verify(textInputChannel,
times(0)).updateEditingStateWithDeltas(anyInt(), any());
356 verify(textInputChannel,
times(1))
357 .updateEditingState(anyInt(), any(), anyInt(), anyInt(), anyInt(), anyInt());
359 inputConnection.endBatchEdit();
361 verify(textInputChannel,
times(0)).updateEditingStateWithDeltas(anyInt(), any());
362 verify(textInputChannel,
times(2))
363 .updateEditingState(anyInt(), any(), anyInt(), anyInt(), anyInt(), anyInt());
368 throws NullPointerException {
370 InputMethodSubtype inputMethodSubtype = mock(InputMethodSubtype.class);
371 TestImm testImm = Shadow.extract(ctx.getSystemService(
Context.INPUT_METHOD_SERVICE));
373 View testView =
new View(ctx);
374 EditorInfo outAttrs =
new EditorInfo();
375 outAttrs.inputType = InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_MULTI_LINE;
376 TextInputChannel textInputChannel = spy(
new TextInputChannel(mock(DartExecutor.class)));
378 new TextInputPlugin(testView, textInputChannel, mock(PlatformViewsController.class));
379 CharSequence newText =
"I do not fear computers. I fear the lack of them.";
381 new TextEditingDelta(
"", 0, 0, newText, newText.length(), newText.length(), 0, 49);
386 new TextInputChannel.Configuration(
392 TextInputChannel.TextCapitalization.NONE,
393 new TextInputChannel.InputType(TextInputChannel.TextInputType.TEXT,
false,
false),
402 testView,
new TextInputChannel.TextEditState(
"", 0, 0, -1, -1));
403 verify(textInputChannel,
times(0)).updateEditingStateWithDeltas(anyInt(), any());
404 verify(textInputChannel,
times(0))
405 .updateEditingState(anyInt(), any(), anyInt(), anyInt(), anyInt(), anyInt());
409 .extractBatchTextEditingDeltas()
412 InputConnection inputConnection =
413 textInputPlugin.createInputConnection(testView, mock(KeyboardManager.class), outAttrs);
415 inputConnection.beginBatchEdit();
416 verify(textInputChannel,
times(0)).updateEditingStateWithDeltas(anyInt(), any());
417 verify(textInputChannel,
times(0))
418 .updateEditingState(anyInt(), any(), anyInt(), anyInt(), anyInt(), anyInt());
419 inputConnection.setComposingText(newText, newText.length());
420 final ArrayList<TextEditingDelta> actualDeltas =
422 assertEquals(2, actualDeltas.size());
424 verify(textInputChannel,
times(0)).updateEditingStateWithDeltas(anyInt(), any());
425 verify(textInputChannel,
times(0))
426 .updateEditingState(anyInt(), any(), anyInt(), anyInt(), anyInt(), anyInt());
427 inputConnection.endBatchEdit();
432 .extractBatchTextEditingDeltas()
436 assertEquals(expectedDelta.
getOldText(), delta.getOldText());
437 assertEquals(expectedDelta.
getDeltaText(), delta.getDeltaText());
438 assertEquals(expectedDelta.
getDeltaStart(), delta.getDeltaStart());
439 assertEquals(expectedDelta.
getDeltaEnd(), delta.getDeltaEnd());
445 verify(textInputChannel,
times(1)).updateEditingStateWithDeltas(anyInt(), any());
446 verify(textInputChannel,
times(0))
447 .updateEditingState(anyInt(), any(), anyInt(), anyInt(), anyInt(), anyInt());
449 inputConnection.beginBatchEdit();
451 verify(textInputChannel,
times(1)).updateEditingStateWithDeltas(anyInt(), any());
452 verify(textInputChannel,
times(0))
453 .updateEditingState(anyInt(), any(), anyInt(), anyInt(), anyInt(), anyInt());
455 inputConnection.endBatchEdit();
460 .extractBatchTextEditingDeltas()
463 verify(textInputChannel,
times(1)).updateEditingStateWithDeltas(anyInt(), any());
464 verify(textInputChannel,
times(0))
465 .updateEditingState(anyInt(), any(), anyInt(), anyInt(), anyInt(), anyInt());
467 inputConnection.beginBatchEdit();
469 verify(textInputChannel,
times(1)).updateEditingStateWithDeltas(anyInt(), any());
470 verify(textInputChannel,
times(0))
471 .updateEditingState(anyInt(), any(), anyInt(), anyInt(), anyInt(), anyInt());
476 inputConnection.setSelection(3, 4);
477 assertEquals(Selection.getSelectionStart(
textInputPlugin.getEditable()), 3);
478 assertEquals(Selection.getSelectionEnd(
textInputPlugin.getEditable()), 4);
480 verify(textInputChannel,
times(1)).updateEditingStateWithDeltas(anyInt(), any());
481 verify(textInputChannel,
times(0))
482 .updateEditingState(anyInt(), any(), anyInt(), anyInt(), anyInt(), anyInt());
484 verify(textInputChannel,
times(1)).updateEditingStateWithDeltas(anyInt(), any());
485 verify(textInputChannel,
times(0))
486 .updateEditingState(anyInt(), any(), anyInt(), anyInt(), anyInt(), anyInt());
488 inputConnection.endBatchEdit();
490 verify(textInputChannel,
times(2)).updateEditingStateWithDeltas(anyInt(), any());
491 verify(textInputChannel,
times(0))
492 .updateEditingState(anyInt(), any(), anyInt(), anyInt(), anyInt(), anyInt());
497 throws NullPointerException {
499 InputMethodSubtype inputMethodSubtype = mock(InputMethodSubtype.class);
500 TestImm testImm = Shadow.extract(ctx.getSystemService(
Context.INPUT_METHOD_SERVICE));
502 View testView =
new View(ctx);
503 EditorInfo outAttrs =
new EditorInfo();
504 outAttrs.inputType = InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_MULTI_LINE;
505 TextInputChannel textInputChannel = spy(
new TextInputChannel(mock(DartExecutor.class)));
507 new TextInputPlugin(testView, textInputChannel, mock(PlatformViewsController.class));
508 CharSequence newText =
"I do not fear computers. I fear the lack of them.";
510 new TextEditingDelta(
"", 0, 0, newText, newText.length(), newText.length(), 0, 49);
515 new TextInputChannel.Configuration(
521 TextInputChannel.TextCapitalization.NONE,
522 new TextInputChannel.InputType(TextInputChannel.TextInputType.TEXT,
false,
false),
531 testView,
new TextInputChannel.TextEditState(
"", 0, 0, -1, -1));
532 verify(textInputChannel,
times(0)).updateEditingStateWithDeltas(anyInt(), any());
536 .extractBatchTextEditingDeltas()
539 InputConnection inputConnection =
540 textInputPlugin.createInputConnection(testView, mock(KeyboardManager.class), outAttrs);
542 inputConnection.beginBatchEdit();
543 verify(textInputChannel,
times(0)).updateEditingStateWithDeltas(anyInt(), any());
544 inputConnection.setComposingText(newText, newText.length());
545 final ArrayList<TextEditingDelta> actualDeltas =
547 assertEquals(2, actualDeltas.size());
549 verify(textInputChannel,
times(0)).updateEditingStateWithDeltas(anyInt(), any());
550 inputConnection.endBatchEdit();
555 .extractBatchTextEditingDeltas()
559 assertEquals(expectedDelta.
getOldText(), delta.getOldText());
560 assertEquals(expectedDelta.
getDeltaText(), delta.getDeltaText());
561 assertEquals(expectedDelta.
getDeltaStart(), delta.getDeltaStart());
562 assertEquals(expectedDelta.
getDeltaEnd(), delta.getDeltaEnd());
568 verify(textInputChannel,
times(1)).updateEditingStateWithDeltas(anyInt(), any());
570 inputConnection.beginBatchEdit();
572 verify(textInputChannel,
times(1)).updateEditingStateWithDeltas(anyInt(), any());
574 inputConnection.endBatchEdit();
579 .extractBatchTextEditingDeltas()
582 verify(textInputChannel,
times(1)).updateEditingStateWithDeltas(anyInt(), any());
584 inputConnection.beginBatchEdit();
586 verify(textInputChannel,
times(1)).updateEditingStateWithDeltas(anyInt(), any());
591 inputConnection.setSelection(3, 4);
592 assertEquals(Selection.getSelectionStart(
textInputPlugin.getEditable()), 3);
593 assertEquals(Selection.getSelectionEnd(
textInputPlugin.getEditable()), 4);
595 verify(textInputChannel,
times(1)).updateEditingStateWithDeltas(anyInt(), any());
597 verify(textInputChannel,
times(1)).updateEditingStateWithDeltas(anyInt(), any());
599 inputConnection.endBatchEdit();
601 verify(textInputChannel,
times(2)).updateEditingStateWithDeltas(anyInt(), any());
606 throws NullPointerException {
608 InputMethodSubtype inputMethodSubtype = mock(InputMethodSubtype.class);
609 TestImm testImm = Shadow.extract(ctx.getSystemService(
Context.INPUT_METHOD_SERVICE));
611 View testView =
new View(ctx);
612 EditorInfo outAttrs =
new EditorInfo();
613 outAttrs.inputType = InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_MULTI_LINE;
614 TextInputChannel textInputChannel = spy(
new TextInputChannel(mock(DartExecutor.class)));
616 new TextInputPlugin(testView, textInputChannel, mock(PlatformViewsController.class));
617 CharSequence newText =
"I do not fear computers. I fear the lack of them.";
620 newText, 0, 49,
"I do not fear computers. I fear the lack of them", 48, 48, 0, 48);
625 new TextInputChannel.Configuration(
631 TextInputChannel.TextCapitalization.NONE,
632 new TextInputChannel.InputType(TextInputChannel.TextInputType.TEXT,
false,
false),
641 testView,
new TextInputChannel.TextEditState(newText.toString(), 49, 49, 0, 49));
642 verify(textInputChannel,
times(0)).updateEditingStateWithDeltas(anyInt(), any());
646 .extractBatchTextEditingDeltas()
649 InputConnection inputConnection =
650 textInputPlugin.createInputConnection(testView, mock(KeyboardManager.class), outAttrs);
652 inputConnection.beginBatchEdit();
653 verify(textInputChannel,
times(0)).updateEditingStateWithDeltas(anyInt(), any());
654 inputConnection.setComposingText(
"I do not fear computers. I fear the lack of them", 48);
655 final ArrayList<TextEditingDelta> actualDeltas =
658 System.out.println(delta.getDeltaText());
659 verify(textInputChannel,
times(0)).updateEditingStateWithDeltas(anyInt(), any());
660 inputConnection.endBatchEdit();
665 .extractBatchTextEditingDeltas()
669 assertEquals(expectedDelta.
getOldText(), delta.getOldText());
670 assertEquals(expectedDelta.
getDeltaText(), delta.getDeltaText());
671 assertEquals(expectedDelta.
getDeltaStart(), delta.getDeltaStart());
672 assertEquals(expectedDelta.
getDeltaEnd(), delta.getDeltaEnd());
678 verify(textInputChannel,
times(1)).updateEditingStateWithDeltas(anyInt(), any());
680 inputConnection.beginBatchEdit();
682 verify(textInputChannel,
times(1)).updateEditingStateWithDeltas(anyInt(), any());
684 inputConnection.endBatchEdit();
689 .extractBatchTextEditingDeltas()
692 verify(textInputChannel,
times(1)).updateEditingStateWithDeltas(anyInt(), any());
694 inputConnection.beginBatchEdit();
696 verify(textInputChannel,
times(1)).updateEditingStateWithDeltas(anyInt(), any());
701 inputConnection.setSelection(3, 4);
702 assertEquals(Selection.getSelectionStart(
textInputPlugin.getEditable()), 3);
703 assertEquals(Selection.getSelectionEnd(
textInputPlugin.getEditable()), 4);
705 verify(textInputChannel,
times(1)).updateEditingStateWithDeltas(anyInt(), any());
707 verify(textInputChannel,
times(1)).updateEditingStateWithDeltas(anyInt(), any());
709 inputConnection.endBatchEdit();
711 verify(textInputChannel,
times(2)).updateEditingStateWithDeltas(anyInt(), any());
716 throws NullPointerException {
718 InputMethodSubtype inputMethodSubtype = mock(InputMethodSubtype.class);
719 TestImm testImm = Shadow.extract(ctx.getSystemService(
Context.INPUT_METHOD_SERVICE));
721 View testView =
new View(ctx);
722 EditorInfo outAttrs =
new EditorInfo();
723 outAttrs.inputType = InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_MULTI_LINE;
724 TextInputChannel textInputChannel = spy(
new TextInputChannel(mock(DartExecutor.class)));
726 new TextInputPlugin(testView, textInputChannel, mock(PlatformViewsController.class));
727 CharSequence newText =
"helfo";
733 new TextInputChannel.Configuration(
739 TextInputChannel.TextCapitalization.NONE,
740 new TextInputChannel.InputType(TextInputChannel.TextInputType.TEXT,
false,
false),
749 testView,
new TextInputChannel.TextEditState(newText.toString(), 5, 5, 0, 5));
750 verify(textInputChannel,
times(0)).updateEditingStateWithDeltas(anyInt(), any());
754 .extractBatchTextEditingDeltas()
757 InputConnection inputConnection =
758 textInputPlugin.createInputConnection(testView, mock(KeyboardManager.class), outAttrs);
760 inputConnection.beginBatchEdit();
761 verify(textInputChannel,
times(0)).updateEditingStateWithDeltas(anyInt(), any());
762 inputConnection.setComposingText(
"hello", 5);
763 final ArrayList<TextEditingDelta> actualDeltas =
766 System.out.println(delta.getDeltaText());
767 verify(textInputChannel,
times(0)).updateEditingStateWithDeltas(anyInt(), any());
768 inputConnection.endBatchEdit();
773 .extractBatchTextEditingDeltas()
777 assertEquals(expectedDelta.
getOldText(), delta.getOldText());
778 assertEquals(expectedDelta.
getDeltaText(), delta.getDeltaText());
779 assertEquals(expectedDelta.
getDeltaStart(), delta.getDeltaStart());
780 assertEquals(expectedDelta.
getDeltaEnd(), delta.getDeltaEnd());
786 verify(textInputChannel,
times(1)).updateEditingStateWithDeltas(anyInt(), any());
788 inputConnection.beginBatchEdit();
790 verify(textInputChannel,
times(1)).updateEditingStateWithDeltas(anyInt(), any());
792 inputConnection.endBatchEdit();
797 .extractBatchTextEditingDeltas()
800 verify(textInputChannel,
times(1)).updateEditingStateWithDeltas(anyInt(), any());
802 inputConnection.beginBatchEdit();
804 verify(textInputChannel,
times(1)).updateEditingStateWithDeltas(anyInt(), any());
809 inputConnection.setSelection(3, 4);
810 assertEquals(Selection.getSelectionStart(
textInputPlugin.getEditable()), 3);
811 assertEquals(Selection.getSelectionEnd(
textInputPlugin.getEditable()), 4);
813 verify(textInputChannel,
times(1)).updateEditingStateWithDeltas(anyInt(), any());
815 verify(textInputChannel,
times(1)).updateEditingStateWithDeltas(anyInt(), any());
817 inputConnection.endBatchEdit();
819 verify(textInputChannel,
times(2)).updateEditingStateWithDeltas(anyInt(), any());
825 InputMethodSubtype inputMethodSubtype = mock(InputMethodSubtype.class);
826 TestImm testImm = Shadow.extract(ctx.getSystemService(
Context.INPUT_METHOD_SERVICE));
828 View testView =
new View(ctx);
829 EditorInfo outAttrs =
new EditorInfo();
830 outAttrs.inputType = InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_MULTI_LINE;
831 TextInputChannel textInputChannel = spy(
new TextInputChannel(mock(DartExecutor.class)));
833 new TextInputPlugin(testView, textInputChannel, mock(PlatformViewsController.class));
838 new TextInputChannel.Configuration(
844 TextInputChannel.TextCapitalization.NONE,
845 new TextInputChannel.InputType(TextInputChannel.TextInputType.TEXT,
false,
false),
854 testView,
new TextInputChannel.TextEditState(
"", 0, 0, -1, -1));
855 verify(textInputChannel,
times(0))
856 .updateEditingState(anyInt(), any(), anyInt(), anyInt(), anyInt(), anyInt());
860 textInputPlugin.createInputConnection(testView, mock(KeyboardManager.class), outAttrs);
863 verify(textInputChannel,
times(0))
864 .updateEditingState(anyInt(), any(), anyInt(), anyInt(), anyInt(), anyInt());
865 inputConnectionAdaptor.
setComposingText(
"I do not fear computers. I fear the lack of them.", 1);
866 verify(textInputChannel,
times(0))
867 .updateEditingState(anyInt(), any(), anyInt(), anyInt(), anyInt(), anyInt());
869 verify(textInputChannel,
times(1))
872 eq(
"I do not fear computers. I fear the lack of them."),
880 verify(textInputChannel,
times(1))
881 .updateEditingState(anyInt(), any(), anyInt(), anyInt(), anyInt(), anyInt());
885 verify(textInputChannel,
times(1))
886 .updateEditingState(anyInt(), any(), anyInt(), anyInt(), anyInt(), anyInt());
890 verify(textInputChannel,
times(1))
891 .updateEditingState(anyInt(), any(), anyInt(), anyInt(), anyInt(), anyInt());
894 assertEquals(Selection.getSelectionStart(
textInputPlugin.getEditable()), 3);
895 assertEquals(Selection.getSelectionEnd(
textInputPlugin.getEditable()), 4);
897 verify(textInputChannel,
times(1))
898 .updateEditingState(anyInt(), any(), anyInt(), anyInt(), anyInt(), anyInt());
900 verify(textInputChannel,
times(1))
901 .updateEditingState(anyInt(), any(), anyInt(), anyInt(), anyInt(), anyInt());
905 verify(textInputChannel,
times(1))
908 eq(
"I do not fear computers. I fear the lack of them."),
918 InputMethodSubtype inputMethodSubtype = mock(InputMethodSubtype.class);
919 TestImm testImm = Shadow.extract(ctx.getSystemService(
Context.INPUT_METHOD_SERVICE));
921 View testView =
new View(ctx);
922 TextInputChannel textInputChannel =
new TextInputChannel(mock(DartExecutor.class));
924 new TextInputPlugin(testView, textInputChannel, mock(PlatformViewsController.class));
927 new TextInputChannel.Configuration(
933 TextInputChannel.TextCapitalization.NONE,
942 testView,
new TextInputChannel.TextEditState(
"", 0, 0, -1, -1));
947 testView,
new TextInputChannel.TextEditState(
"", 0, 0, -1, -1));
956 InputMethodSubtype inputMethodSubtype = mock(InputMethodSubtype.class);
957 TestImm testImm = Shadow.extract(ctx.getSystemService(
Context.INPUT_METHOD_SERVICE));
959 View testView =
new View(ctx);
960 TextInputChannel textInputChannel =
new TextInputChannel(mock(DartExecutor.class));
962 new TextInputPlugin(testView, textInputChannel, mock(PlatformViewsController.class));
965 new TextInputChannel.Configuration(
971 TextInputChannel.TextCapitalization.NONE,
982 testView,
new TextInputChannel.TextEditState(
"hello", 0, 0, -1, -1));
988 testView,
new TextInputChannel.TextEditState(
"Shibuyawoo", 0, 0, -1, -1));
990 assertTrue(
textInputPlugin.getEditable().toString().equals(
"Shibuyawoo"));
999 @SuppressWarnings(
"deprecation")
1003 InputMethodSubtype inputMethodSubtype =
1004 new InputMethodSubtype(0, 0,
"en",
"",
"",
false,
false);
1005 TestImm testImm = Shadow.extract(ctx.getSystemService(
Context.INPUT_METHOD_SERVICE));
1007 View testView =
new View(ctx);
1008 TextInputChannel textInputChannel =
new TextInputChannel(mock(DartExecutor.class));
1010 new TextInputPlugin(testView, textInputChannel, mock(PlatformViewsController.class));
1013 new TextInputChannel.Configuration(
1019 TextInputChannel.TextCapitalization.NONE,
1020 new TextInputChannel.InputType(TextInputChannel.TextInputType.TEXT,
false,
false),
1028 testView,
new TextInputChannel.TextEditState(
"", 0, 0, -1, -1));
1030 InputConnection connection =
1032 testView, mock(KeyboardManager.class),
new EditorInfo());
1033 connection.setComposingText(
"POWERRRRR", 1);
1036 testView,
new TextInputChannel.TextEditState(
"UNLIMITED POWERRRRR", 0, 0, 10, 19));
1040 connection.finishComposingText();
1045 connection.setComposingText(
"POWERRRRR", 1);
1050 testView,
new TextInputChannel.TextEditState(
"POWERRRRR", 0, 0, -1, -1));
1059 assertThrows(IndexOutOfBoundsException.class, () ->
new TextEditState(
"", 0, -9, -1, -1));
1060 assertThrows(IndexOutOfBoundsException.class, () ->
new TextEditState(
"", -9, 0, -1, -1));
1061 assertThrows(IndexOutOfBoundsException.class, () ->
new TextEditState(
"", 0, 1, -1, -1));
1062 assertThrows(IndexOutOfBoundsException.class, () ->
new TextEditState(
"", 1, 0, -1, -1));
1063 assertThrows(IndexOutOfBoundsException.class, () ->
new TextEditState(
"Text", 0, 0, 1, 5));
1064 assertThrows(IndexOutOfBoundsException.class, () ->
new TextEditState(
"Text", 0, 0, 5, 1));
1065 assertThrows(IndexOutOfBoundsException.class, () ->
new TextEditState(
"Text", 0, 0, 5, 5));
1068 assertThrows(IndexOutOfBoundsException.class, () ->
new TextEditState(
"", -1, -2, -1, -1));
1069 assertThrows(IndexOutOfBoundsException.class, () ->
new TextEditState(
"", -2, -1, -1, -1));
1070 assertThrows(IndexOutOfBoundsException.class, () ->
new TextEditState(
"", -9, -9, -1, -1));
1073 assertThrows(IndexOutOfBoundsException.class, () ->
new TextEditState(
"Text", 0, 0, -9, -1));
1074 assertThrows(IndexOutOfBoundsException.class, () ->
new TextEditState(
"Text", 0, 0, -1, -9));
1075 assertThrows(IndexOutOfBoundsException.class, () ->
new TextEditState(
"Text", 0, 0, -9, -9));
1076 assertThrows(IndexOutOfBoundsException.class, () ->
new TextEditState(
"Text", 0, 0, 2, 1));
1080 TextEditState
state =
new TextEditState(
"", -1, -1, -1, -1);
1081 assertEquals(
"",
state.text);
1082 assertEquals(-1,
state.selectionStart);
1083 assertEquals(-1,
state.selectionEnd);
1084 assertEquals(-1,
state.composingStart);
1085 assertEquals(-1,
state.composingEnd);
1087 state =
new TextEditState(
"x", 0, 0, 0, 1);
1088 assertEquals(0,
state.selectionStart);
1089 assertEquals(0,
state.selectionEnd);
1091 state =
new TextEditState(
"REEEE", 4, 2, -1, -1);
1092 assertEquals(4,
state.selectionStart);
1093 assertEquals(2,
state.selectionEnd);
1095 state =
new TextEditState(
"text", 0, 0, 0, 0);
1096 assertEquals(
"text",
state.text);
1097 assertEquals(0,
state.selectionStart);
1098 assertEquals(0,
state.selectionEnd);
1099 assertEquals(0,
state.composingStart);
1100 assertEquals(0,
state.composingEnd);
1105 TestImm testImm = Shadow.extract(ctx.getSystemService(
Context.INPUT_METHOD_SERVICE));
1108 View testView =
new View(ctx);
1109 TextInputChannel textInputChannel =
new TextInputChannel(mock(DartExecutor.class));
1111 new TextInputPlugin(testView, textInputChannel, mock(PlatformViewsController.class));
1114 new TextInputChannel.Configuration(
1120 TextInputChannel.TextCapitalization.NONE,
1129 testView,
new TextInputChannel.TextEditState(
"", 0, 0, -1, -1));
1136 InputMethodSubtype inputMethodSubtype = mock(InputMethodSubtype.class);
1137 TestImm testImm = Shadow.extract(ctx.getSystemService(
Context.INPUT_METHOD_SERVICE));
1139 View testView =
new View(ctx);
1140 TextInputChannel textInputChannel =
new TextInputChannel(mock(DartExecutor.class));
1142 new TextInputPlugin(testView, textInputChannel, mock(PlatformViewsController.class));
1145 new TextInputChannel.Configuration(
1151 TextInputChannel.TextCapitalization.NONE,
1160 testView,
new TextInputChannel.TextEditState(
"", 0, 0, -1, -1));
1170 View testView =
new View(ctx);
1171 TextInputChannel textInputChannel = spy(
new TextInputChannel(mock(DartExecutor.class)));
1173 new TextInputPlugin(testView, textInputChannel, mock(PlatformViewsController.class));
1174 verify(textInputChannel,
times(1)).setTextInputMethodHandler(isNotNull());
1176 verify(textInputChannel,
times(1)).setTextInputMethodHandler(isNull());
1179 @SuppressWarnings(
"deprecation")
1181 private
void verifyInputConnection(TextInputChannel.TextInputType textInputType)
1182 throws JSONException {
1183 TestImm testImm = Shadow.extract(ctx.getSystemService(
Context.INPUT_METHOD_SERVICE));
1184 FlutterJNI mockFlutterJni = mock(FlutterJNI.class);
1185 View testView =
new View(ctx);
1186 DartExecutor dartExecutor = spy(
new DartExecutor(mockFlutterJni, mock(AssetManager.class)));
1187 TextInputChannel textInputChannel =
new TextInputChannel(dartExecutor);
1189 new TextInputPlugin(testView, textInputChannel, mock(PlatformViewsController.class));
1192 new TextInputChannel.Configuration(
1198 TextInputChannel.TextCapitalization.NONE,
1199 new TextInputChannel.InputType(textInputType,
false,
false),
1207 testView,
new TextInputChannel.TextEditState(
"", 0, 0, -1, -1));
1209 ArgumentCaptor<String> channelCaptor = ArgumentCaptor.forClass(String.class);
1210 ArgumentCaptor<ByteBuffer> bufferCaptor = ArgumentCaptor.forClass(ByteBuffer.class);
1211 verify(dartExecutor,
times(1)).send(channelCaptor.capture(), bufferCaptor.capture(), isNull());
1212 assertEquals(
"flutter/textinput", channelCaptor.getValue());
1213 verifyMethodCall(bufferCaptor.getValue(),
"TextInputClient.requestExistingInputState",
null);
1217 testView, mock(KeyboardManager.class),
new EditorInfo());
1219 connection.
handleKeyEvent(
new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_ENTER));
1220 verify(dartExecutor,
times(2)).send(channelCaptor.capture(), bufferCaptor.capture(), isNull());
1221 assertEquals(
"flutter/textinput", channelCaptor.getValue());
1223 bufferCaptor.getValue(),
1224 "TextInputClient.performAction",
1225 new String[] {
"0",
"TextInputAction.done"});
1226 connection.
handleKeyEvent(
new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_ENTER));
1228 connection.
handleKeyEvent(
new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_NUMPAD_ENTER));
1229 verify(dartExecutor,
times(3)).send(channelCaptor.capture(), bufferCaptor.capture(), isNull());
1230 assertEquals(
"flutter/textinput", channelCaptor.getValue());
1232 bufferCaptor.getValue(),
1233 "TextInputClient.performAction",
1234 new String[] {
"0",
"TextInputAction.done"});
1239 verifyInputConnection(TextInputChannel.TextInputType.TEXT);
1244 verifyInputConnection(TextInputChannel.TextInputType.NONE);
1247 @SuppressWarnings(
"deprecation")
1250 ShadowBuild.setManufacturer(
"samsung");
1251 InputMethodSubtype inputMethodSubtype =
1252 new InputMethodSubtype(0, 0,
"en",
"",
"",
false,
false);
1253 Settings.Secure.putString(
1254 ctx.getContentResolver(),
1255 Settings.Secure.DEFAULT_INPUT_METHOD,
1256 "com.sec.android.inputmethod/.SamsungKeypad");
1257 TestImm testImm = Shadow.extract(ctx.getSystemService(
Context.INPUT_METHOD_SERVICE));
1259 FlutterJNI mockFlutterJni = mock(FlutterJNI.class);
1260 View testView =
new View(ctx);
1261 DartExecutor dartExecutor = spy(
new DartExecutor(mockFlutterJni, mock(AssetManager.class)));
1262 TextInputChannel textInputChannel =
new TextInputChannel(dartExecutor);
1264 new TextInputPlugin(testView, textInputChannel, mock(PlatformViewsController.class));
1267 new TextInputChannel.Configuration(
1273 TextInputChannel.TextCapitalization.NONE,
1274 new TextInputChannel.InputType(TextInputChannel.TextInputType.TEXT,
false,
false),
1282 testView,
new TextInputChannel.TextEditState(
"text", 0, 0, -1, -1));
1283 InputConnection connection =
1285 testView, mock(KeyboardManager.class),
new EditorInfo());
1287 connection.requestCursorUpdates(
1288 InputConnection.CURSOR_UPDATE_MONITOR | InputConnection.CURSOR_UPDATE_IMMEDIATE);
1290 connection.finishComposingText();
1298 View testView =
new View(ctx);
1299 DartExecutor dartExecutor = mock(DartExecutor.class);
1300 TextInputChannel textInputChannel =
new TextInputChannel(dartExecutor);
1302 new TextInputPlugin(testView, textInputChannel, mock(PlatformViewsController.class));
1305 new TextInputChannel.Configuration(
1311 TextInputChannel.TextCapitalization.NONE,
1312 new TextInputChannel.InputType(TextInputChannel.TextInputType.NONE,
false,
false),
1319 InputConnection connection =
1321 testView, mock(KeyboardManager.class),
new EditorInfo());
1322 assertNotNull(connection);
1327 TestImm testImm = Shadow.extract(ctx.getSystemService(
Context.INPUT_METHOD_SERVICE));
1328 View testView =
new View(ctx);
1329 DartExecutor dartExecutor = mock(DartExecutor.class);
1330 TextInputChannel textInputChannel =
new TextInputChannel(dartExecutor);
1332 new TextInputPlugin(testView, textInputChannel, mock(PlatformViewsController.class));
1335 new TextInputChannel.Configuration(
1341 TextInputChannel.TextCapitalization.NONE,
1342 new TextInputChannel.InputType(TextInputChannel.TextInputType.NONE,
false,
false),
1350 assertEquals(testImm.isSoftInputVisible(),
false);
1356 View testView =
new View(ctx);
1357 DartExecutor dartExecutor = mock(DartExecutor.class);
1358 TextInputChannel textInputChannel =
new TextInputChannel(dartExecutor);
1360 new TextInputPlugin(testView, textInputChannel, mock(PlatformViewsController.class));
1363 new TextInputChannel.Configuration(
1369 TextInputChannel.TextCapitalization.NONE,
1370 new TextInputChannel.InputType(TextInputChannel.TextInputType.MULTILINE,
false,
false),
1377 EditorInfo editorInfo =
new EditorInfo();
1378 InputConnection connection =
1379 textInputPlugin.createInputConnection(testView, mock(KeyboardManager.class), editorInfo);
1382 editorInfo.inputType,
1383 InputType.TYPE_CLASS_TEXT
1384 | InputType.TYPE_TEXT_FLAG_MULTI_LINE
1385 | InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS
1386 | InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD);
1392 if (
Build.VERSION.SDK_INT < API_LEVELS.API_26) {
1396 TextInputChannel textInputChannel =
new TextInputChannel(mock(DartExecutor.class));
1398 new TextInputPlugin(testView, textInputChannel, mock(PlatformViewsController.class));
1399 final TextInputChannel.Configuration.Autofill autofill =
1400 new TextInputChannel.Configuration.Autofill(
1401 "1",
new String[] {},
null,
new TextInputChannel.TextEditState(
"", 0, 0, -1, -1));
1403 final TextInputChannel.Configuration config =
1404 new TextInputChannel.Configuration(
1410 TextInputChannel.TextCapitalization.NONE,
1420 new TextInputChannel.Configuration(
1426 TextInputChannel.TextCapitalization.NONE,
1432 new TextInputChannel.Configuration[] {config}));
1434 final ViewStructure viewStructure = mock(ViewStructure.class);
1435 final ViewStructure[] children = {mock(ViewStructure.class), mock(ViewStructure.class)};
1437 when(viewStructure.newChild(anyInt()))
1438 .thenAnswer(invocation -> children[(
int) invocation.getArgument(0)]);
1442 verify(viewStructure).newChild(0);
1444 verify(children[0]).setAutofillId(any(),
eq(
"1".hashCode()));
1446 verify(children[0], never()).setAutofillHints(aryEq(
new String[] {}));
1447 verify(children[0]).setDimens(anyInt(), anyInt(), anyInt(), anyInt(), gt(0), gt(0));
1452 if (
Build.VERSION.SDK_INT < API_LEVELS.API_26) {
1456 TextInputChannel textInputChannel =
new TextInputChannel(mock(DartExecutor.class));
1458 new TextInputPlugin(testView, textInputChannel, mock(PlatformViewsController.class));
1459 final TextInputChannel.Configuration.Autofill autofill =
1460 new TextInputChannel.Configuration.Autofill(
1461 "1",
new String[] {},
null,
new TextInputChannel.TextEditState(
"", 0, 0, -1, -1));
1463 final TextInputChannel.Configuration config =
1464 new TextInputChannel.Configuration(
1470 TextInputChannel.TextCapitalization.NONE,
1480 final ViewStructure viewStructure = mock(ViewStructure.class);
1484 verify(viewStructure,
times(0)).newChild(anyInt());
1489 if (
Build.VERSION.SDK_INT < API_LEVELS.API_26) {
1493 TextInputChannel textInputChannel =
new TextInputChannel(mock(DartExecutor.class));
1495 new TextInputPlugin(testView, textInputChannel, mock(PlatformViewsController.class));
1496 final TextInputChannel.Configuration.Autofill autofill =
1497 new TextInputChannel.Configuration.Autofill(
1501 new TextInputChannel.TextEditState(
"", 0, 0, -1, -1));
1503 final TextInputChannel.Configuration config =
1504 new TextInputChannel.Configuration(
1510 TextInputChannel.TextCapitalization.NONE,
1520 final ViewStructure viewStructure = mock(ViewStructure.class);
1521 final ViewStructure[] children = {mock(ViewStructure.class), mock(ViewStructure.class)};
1523 when(viewStructure.newChild(anyInt()))
1524 .thenAnswer(invocation -> children[(
int) invocation.getArgument(0)]);
1527 verify(children[0]).setHint(
"placeholder");
1530 @Config(minSdk = API_LEVELS.API_26)
1531 @SuppressWarnings(
"deprecation")
1534 if (
Build.VERSION.SDK_INT < API_LEVELS.API_26) {
1538 TextInputChannel textInputChannel =
new TextInputChannel(mock(DartExecutor.class));
1540 new TextInputPlugin(testView, textInputChannel, mock(PlatformViewsController.class));
1541 final TextInputChannel.Configuration.Autofill autofill1 =
1542 new TextInputChannel.Configuration.Autofill(
1544 new String[] {
"HINT1"},
1546 new TextInputChannel.TextEditState(
"", 0, 0, -1, -1));
1547 final TextInputChannel.Configuration.Autofill autofill2 =
1548 new TextInputChannel.Configuration.Autofill(
1550 new String[] {
"HINT2",
"EXTRA"},
1552 new TextInputChannel.TextEditState(
"", 0, 0, -1, -1));
1554 final TextInputChannel.Configuration config1 =
1555 new TextInputChannel.Configuration(
1561 TextInputChannel.TextCapitalization.NONE,
1568 final TextInputChannel.Configuration config2 =
1569 new TextInputChannel.Configuration(
1575 TextInputChannel.TextCapitalization.NONE,
1585 new TextInputChannel.Configuration(
1591 TextInputChannel.TextCapitalization.NONE,
1597 new TextInputChannel.Configuration[] {config1, config2}));
1599 final ViewStructure viewStructure = mock(ViewStructure.class);
1600 final ViewStructure[] children = {mock(ViewStructure.class), mock(ViewStructure.class)};
1602 when(viewStructure.newChild(anyInt()))
1603 .thenAnswer(invocation -> children[(
int) invocation.getArgument(0)]);
1607 verify(viewStructure).newChild(0);
1608 verify(viewStructure).newChild(1);
1610 verify(children[0]).setAutofillId(any(),
eq(
"1".hashCode()));
1611 verify(children[0]).setAutofillHints(aryEq(
new String[] {
"HINT1"}));
1612 verify(children[0]).setDimens(anyInt(), anyInt(), anyInt(), anyInt(), gt(0), gt(0));
1613 verify(children[0]).setHint(
"placeholder1");
1615 verify(children[1]).setAutofillId(any(),
eq(
"2".hashCode()));
1616 verify(children[1]).setAutofillHints(aryEq(
new String[] {
"HINT2",
"EXTRA"}));
1617 verify(children[1]).setDimens(anyInt(), anyInt(), anyInt(), anyInt(), gt(0), gt(0));
1618 verify(children[1],
times(0)).setHint(any());
1621 @SuppressWarnings(
"deprecation")
1622 @Config(minSdk = API_LEVELS.API_26)
1625 if (
Build.VERSION.SDK_INT < API_LEVELS.API_26) {
1630 TextInputChannel textInputChannel =
new TextInputChannel(mock(DartExecutor.class));
1632 new TextInputPlugin(testView, textInputChannel, mock(PlatformViewsController.class));
1633 final TextInputChannel.Configuration.Autofill autofill =
1634 new TextInputChannel.Configuration.Autofill(
1636 new String[] {
"HINT1"},
1638 new TextInputChannel.TextEditState(
"", 0, 0, -1, -1));
1643 new TextInputChannel.Configuration(
1649 TextInputChannel.TextCapitalization.NONE,
1657 final ViewStructure viewStructure = mock(ViewStructure.class);
1658 final ViewStructure[] children = {mock(ViewStructure.class)};
1660 when(viewStructure.newChild(anyInt()))
1661 .thenAnswer(invocation -> children[(
int) invocation.getArgument(0)]);
1665 verify(viewStructure).newChild(0);
1667 verify(children[0]).setAutofillId(any(),
eq(
"1".hashCode()));
1668 verify(children[0]).setAutofillHints(aryEq(
new String[] {
"HINT1"}));
1669 verify(children[0]).setHint(
"placeholder");
1671 verify(children[0]).setDimens(anyInt(), anyInt(), anyInt(), anyInt(), gt(0), gt(0));
1674 @Config(minSdk = API_LEVELS.API_26)
1677 if (
Build.VERSION.SDK_INT < API_LEVELS.API_26) {
1681 TestAfm testAfm = Shadow.extract(ctx.getSystemService(AutofillManager.class));
1683 TextInputChannel textInputChannel =
new TextInputChannel(mock(DartExecutor.class));
1685 new TextInputPlugin(testView, textInputChannel, mock(PlatformViewsController.class));
1688 final TextInputChannel.Configuration.Autofill autofill1 =
1689 new TextInputChannel.Configuration.Autofill(
1691 new String[] {
"HINT1"},
1693 new TextInputChannel.TextEditState(
"", 0, 0, -1, -1));
1694 final TextInputChannel.Configuration.Autofill autofill2 =
1695 new TextInputChannel.Configuration.Autofill(
1697 new String[] {
"HINT2",
"EXTRA"},
1699 new TextInputChannel.TextEditState(
"", 0, 0, -1, -1));
1701 final TextInputChannel.Configuration config1 =
1702 new TextInputChannel.Configuration(
1708 TextInputChannel.TextCapitalization.NONE,
1715 final TextInputChannel.Configuration config2 =
1716 new TextInputChannel.Configuration(
1722 TextInputChannel.TextCapitalization.NONE,
1732 final TextInputChannel.Configuration autofillConfiguration =
1733 new TextInputChannel.Configuration(
1739 TextInputChannel.TextCapitalization.NONE,
1745 new TextInputChannel.Configuration[] {config1, config2});
1754 testView,
new TextInputChannel.TextEditState(
"new text", -1, -1, -1, -1));
1760 final KeyboardManager mockKeyboardManager = mock(KeyboardManager.class);
1765 mock(TextInputChannel.class),
1766 mockKeyboardManager,
1771 assertEquals(
"input from IME new text", testAfm.
changeString);
1778 new TextInputChannel.Configuration(
1784 TextInputChannel.TextCapitalization.NONE,
1792 assertEquals(
"1".hashCode(), testAfm.
exitId);
1799 assertEquals(
"1".hashCode(), testAfm.
exitId);
1806 assertEquals(
"1".hashCode(), testAfm.
exitId);
1809 @Config(minSdk = API_LEVELS.API_26)
1810 @SuppressWarnings(
"deprecation")
1813 if (
Build.VERSION.SDK_INT < API_LEVELS.API_26) {
1817 TestAfm testAfm = Shadow.extract(ctx.getSystemService(AutofillManager.class));
1819 TextInputChannel textInputChannel = spy(
new TextInputChannel(mock(DartExecutor.class)));
1821 new TextInputPlugin(testView, textInputChannel, mock(PlatformViewsController.class));
1824 final TextInputChannel.Configuration.Autofill autofill1 =
1825 new TextInputChannel.Configuration.Autofill(
1827 new String[] {
"HINT1"},
1829 new TextInputChannel.TextEditState(
"field 1", 0, 0, -1, -1));
1830 final TextInputChannel.Configuration.Autofill autofill2 =
1831 new TextInputChannel.Configuration.Autofill(
1833 new String[] {
"HINT2",
"EXTRA"},
1835 new TextInputChannel.TextEditState(
"field 2", 0, 0, -1, -1));
1837 final TextInputChannel.Configuration config1 =
1838 new TextInputChannel.Configuration(
1844 TextInputChannel.TextCapitalization.NONE,
1851 final TextInputChannel.Configuration config2 =
1852 new TextInputChannel.Configuration(
1858 TextInputChannel.TextCapitalization.NONE,
1866 final TextInputChannel.Configuration autofillConfiguration =
1867 new TextInputChannel.Configuration(
1873 TextInputChannel.TextCapitalization.NONE,
1879 new TextInputChannel.Configuration[] {config1, config2});
1883 testView,
new TextInputChannel.TextEditState(
"", 0, 0, -1, -1));
1885 final SparseArray<AutofillValue> autofillValues =
new SparseArray();
1886 autofillValues.append(
"1".hashCode(), AutofillValue.forText(
"focused field"));
1887 autofillValues.append(
"2".hashCode(), AutofillValue.forText(
"unfocused field"));
1893 assertTrue(
textInputPlugin.getEditable().toString().equals(
"focused field"));
1896 verify(textInputChannel,
times(1))
1897 .updateEditingState(anyInt(),
eq(
"focused field"),
eq(13),
eq(13),
eq(-1),
eq(-1));
1899 final ArgumentCaptor<HashMap> mapCaptor = ArgumentCaptor.forClass(HashMap.class);
1901 verify(textInputChannel,
times(1)).updateEditingStateWithTag(anyInt(), mapCaptor.capture());
1902 final TextInputChannel.TextEditState editState =
1903 (TextInputChannel.TextEditState) mapCaptor.getValue().get(
"2");
1904 assertEquals(editState.text,
"unfocused field");
1907 @Config(minSdk = API_LEVELS.API_26)
1910 if (
Build.VERSION.SDK_INT < API_LEVELS.API_26) {
1914 TextInputChannel textInputChannel = spy(
new TextInputChannel(mock(DartExecutor.class)));
1916 new TextInputPlugin(testView, textInputChannel, mock(PlatformViewsController.class));
1918 final TextInputChannel.Configuration.Autofill autofillConfig =
1919 new TextInputChannel.Configuration.Autofill(
1921 new String[] {
"HINT1"},
1923 new TextInputChannel.TextEditState(
"", 0, 0, -1, -1));
1924 final TextInputChannel.Configuration config =
1925 new TextInputChannel.Configuration(
1931 TextInputChannel.TextCapitalization.NONE,
1941 testView,
new TextInputChannel.TextEditState(
"", 0, 0, -1, -1));
1944 final SparseArray<AutofillValue> autofillValues =
new SparseArray();
1945 autofillValues.append(
"1".hashCode(), AutofillValue.forText(
"focused field"));
1946 autofillValues.append(
"2".hashCode(), AutofillValue.forText(
"unfocused field"));
1951 verify(textInputChannel, never()).updateEditingStateWithTag(anyInt(), any());
1952 verify(textInputChannel, never())
1953 .updateEditingState(anyInt(), any(), anyInt(), anyInt(), anyInt(), anyInt());
1956 @Config(minSdk = API_LEVELS.API_26)
1959 if (
Build.VERSION.SDK_INT < API_LEVELS.API_26) {
1963 TestAfm testAfm = Shadow.extract(ctx.getSystemService(AutofillManager.class));
1965 TextInputChannel textInputChannel =
new TextInputChannel(mock(DartExecutor.class));
1967 new TextInputPlugin(testView, textInputChannel, mock(PlatformViewsController.class));
1970 final TextInputChannel.Configuration.Autofill autofill1 =
1971 new TextInputChannel.Configuration.Autofill(
1973 new String[] {
"HINT1"},
1975 new TextInputChannel.TextEditState(
"", 0, 0, -1, -1));
1976 final TextInputChannel.Configuration.Autofill autofill2 =
1977 new TextInputChannel.Configuration.Autofill(
1979 new String[] {
"HINT2",
"EXTRA"},
1981 new TextInputChannel.TextEditState(
1982 "Unfocused fields need love like everything does", 0, 0, -1, -1));
1984 final TextInputChannel.Configuration config1 =
1985 new TextInputChannel.Configuration(
1991 TextInputChannel.TextCapitalization.NONE,
1998 final TextInputChannel.Configuration config2 =
1999 new TextInputChannel.Configuration(
2005 TextInputChannel.TextCapitalization.NONE,
2013 final TextInputChannel.Configuration autofillConfiguration =
2014 new TextInputChannel.Configuration(
2020 TextInputChannel.TextCapitalization.NONE,
2026 new TextInputChannel.Configuration[] {config1, config2});
2032 assertEquals(
"Unfocused fields need love like everything does", testAfm.
changeString);
2036 @SuppressWarnings(
"deprecation")
2039 return new FlutterView(Robolectric.setupActivity(Activity.class));
2042 @SuppressWarnings(
"deprecation")
2046 ArgumentCaptor<BinaryMessenger.BinaryMessageHandler> binaryMessageHandlerCaptor =
2047 ArgumentCaptor.forClass(BinaryMessenger.BinaryMessageHandler.class);
2048 DartExecutor mockBinaryMessenger = mock(DartExecutor.class);
2049 TextInputChannel.TextInputMethodHandler mockHandler =
2050 mock(TextInputChannel.TextInputMethodHandler.class);
2051 TextInputChannel textInputChannel =
new TextInputChannel(mockBinaryMessenger);
2053 textInputChannel.setTextInputMethodHandler(mockHandler);
2055 verify(mockBinaryMessenger,
times(1))
2056 .setMessageHandler(any(String.class), binaryMessageHandlerCaptor.capture());
2058 BinaryMessenger.BinaryMessageHandler binaryMessageHandler =
2059 binaryMessageHandlerCaptor.getValue();
2061 sendToBinaryMessageHandler(binaryMessageHandler,
"TextInput.requestAutofill",
null);
2062 verify(mockHandler,
times(1)).requestAutofill();
2064 sendToBinaryMessageHandler(binaryMessageHandler,
"TextInput.finishAutofillContext",
true);
2065 verify(mockHandler,
times(1)).finishAutofillContext(
true);
2067 sendToBinaryMessageHandler(binaryMessageHandler,
"TextInput.finishAutofillContext",
false);
2068 verify(mockHandler,
times(1)).finishAutofillContext(
false);
2071 @SuppressWarnings(
"deprecation")
2075 ArgumentCaptor<BinaryMessenger.BinaryMessageHandler> binaryMessageHandlerCaptor =
2076 ArgumentCaptor.forClass(BinaryMessenger.BinaryMessageHandler.class);
2077 DartExecutor mockBinaryMessenger = mock(DartExecutor.class);
2078 TextInputChannel textInputChannel =
new TextInputChannel(mockBinaryMessenger);
2081 TestImm testImm = Shadow.extract(ctx.getSystemService(
Context.INPUT_METHOD_SERVICE));
2084 View testView =
new View(ctx);
2086 new TextInputPlugin(testView, textInputChannel, mock(PlatformViewsController.class));
2088 verify(mockBinaryMessenger,
times(1))
2089 .setMessageHandler(any(String.class), binaryMessageHandlerCaptor.capture());
2091 JSONObject arguments =
new JSONObject();
2092 arguments.put(
"action",
"actionCommand");
2093 arguments.put(
"data",
"");
2095 BinaryMessenger.BinaryMessageHandler binaryMessageHandler =
2096 binaryMessageHandlerCaptor.getValue();
2097 sendToBinaryMessageHandler(binaryMessageHandler,
"TextInput.sendAppPrivateCommand", arguments);
2098 verify(mockEventHandler,
times(1))
2099 .sendAppPrivateCommand(any(View.class),
eq(
"actionCommand"),
eq(
null));
2102 @SuppressWarnings(
"deprecation")
2106 ArgumentCaptor<BinaryMessenger.BinaryMessageHandler> binaryMessageHandlerCaptor =
2107 ArgumentCaptor.forClass(BinaryMessenger.BinaryMessageHandler.class);
2108 DartExecutor mockBinaryMessenger = mock(DartExecutor.class);
2109 TextInputChannel textInputChannel =
new TextInputChannel(mockBinaryMessenger);
2112 TestImm testImm = Shadow.extract(ctx.getSystemService(
Context.INPUT_METHOD_SERVICE));
2115 View testView =
new View(ctx);
2117 new TextInputPlugin(testView, textInputChannel, mock(PlatformViewsController.class));
2119 verify(mockBinaryMessenger,
times(1))
2120 .setMessageHandler(any(String.class), binaryMessageHandlerCaptor.capture());
2122 JSONObject arguments =
new JSONObject();
2123 arguments.put(
"action",
"actionCommand");
2124 arguments.put(
"data",
"actionData");
2126 ArgumentCaptor<Bundle> bundleCaptor = ArgumentCaptor.forClass(Bundle.class);
2127 BinaryMessenger.BinaryMessageHandler binaryMessageHandler =
2128 binaryMessageHandlerCaptor.getValue();
2129 sendToBinaryMessageHandler(binaryMessageHandler,
"TextInput.sendAppPrivateCommand", arguments);
2130 verify(mockEventHandler,
times(1))
2131 .sendAppPrivateCommand(any(View.class),
eq(
"actionCommand"), bundleCaptor.capture());
2132 assertEquals(
"actionData", bundleCaptor.getValue().getCharSequence(
"data"));
2136 @TargetApi(API_LEVELS.API_30)
2137 @Config(sdk = API_LEVELS.API_30)
2138 @SuppressWarnings(
"deprecation")
2141 public
void ime_windowInsetsSync_notLaidOutBehindNavigation_excludesNavigationBars() {
2143 when(testView.getWindowSystemUiVisibility()).thenReturn(View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
2145 TextInputChannel textInputChannel =
new TextInputChannel(mock(DartExecutor.class));
2147 new TextInputPlugin(testView, textInputChannel, mock(PlatformViewsController.class));
2151 when(flutterEngine.getRenderer()).thenReturn(flutterRenderer);
2152 testView.attachToFlutterEngine(flutterEngine);
2154 WindowInsetsAnimation animation = mock(WindowInsetsAnimation.class);
2155 when(animation.getTypeMask()).thenReturn(WindowInsets.Type.ime());
2158 animationList.
add(animation);
2160 ArgumentCaptor<
FlutterRenderer.ViewportMetrics> viewportMetricsCaptor =
2163 WindowInsets.Builder builder =
new WindowInsets.Builder();
2166 imeSyncCallback.
getInsetsListener().onApplyWindowInsets(testView, builder.build());
2168 verify(flutterRenderer, atLeast(1)).setViewportMetrics(viewportMetricsCaptor.capture());
2169 assertEquals(0, viewportMetricsCaptor.getValue().viewInsetBottom);
2174 builder.setInsets(WindowInsets.Type.ime(), Insets.of(0, 0, 0, 100));
2175 builder.setInsets(WindowInsets.Type.navigationBars(), Insets.of(0, 0, 0, 0));
2176 imeSyncCallback.
getInsetsListener().onApplyWindowInsets(testView, builder.build());
2178 verify(flutterRenderer, atLeast(1)).setViewportMetrics(viewportMetricsCaptor.capture());
2179 assertEquals(0, viewportMetricsCaptor.getValue().viewInsetBottom);
2183 builder.setInsets(WindowInsets.Type.ime(), Insets.of(0, 0, 0, 50));
2184 builder.setInsets(WindowInsets.Type.navigationBars(), Insets.of(0, 0, 0, 40));
2185 imeSyncCallback.
getInsetsListener().onApplyWindowInsets(testView, builder.build());
2187 verify(flutterRenderer, atLeast(1)).setViewportMetrics(viewportMetricsCaptor.capture());
2188 assertEquals(0, viewportMetricsCaptor.getValue().viewInsetBottom);
2192 builder.setInsets(WindowInsets.Type.ime(), Insets.of(0, 0, 0, 25));
2193 builder.setInsets(WindowInsets.Type.navigationBars(), Insets.of(0, 0, 0, 40));
2196 verify(flutterRenderer, atLeast(1)).setViewportMetrics(viewportMetricsCaptor.capture());
2197 assertEquals(0, viewportMetricsCaptor.getValue().viewInsetBottom);
2199 builder.setInsets(WindowInsets.Type.ime(), Insets.of(0, 0, 0, 50));
2200 builder.setInsets(WindowInsets.Type.navigationBars(), Insets.of(0, 0, 0, 40));
2203 verify(flutterRenderer, atLeast(1)).setViewportMetrics(viewportMetricsCaptor.capture());
2204 assertEquals(10, viewportMetricsCaptor.getValue().viewInsetBottom);
2210 verify(flutterRenderer, atLeast(1)).setViewportMetrics(viewportMetricsCaptor.capture());
2211 assertEquals(100, viewportMetricsCaptor.getValue().viewInsetBottom);
2215 @TargetApi(API_LEVELS.API_30)
2216 @Config(sdk = API_LEVELS.API_30)
2217 @SuppressWarnings(
"deprecation")
2220 public
void ime_windowInsetsSync_laidOutBehindNavigation_includesNavigationBars() {
2222 when(testView.getWindowSystemUiVisibility())
2224 View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION);
2226 TextInputChannel textInputChannel =
new TextInputChannel(mock(DartExecutor.class));
2228 new TextInputPlugin(testView, textInputChannel, mock(PlatformViewsController.class));
2232 when(flutterEngine.getRenderer()).thenReturn(flutterRenderer);
2233 testView.attachToFlutterEngine(flutterEngine);
2235 WindowInsetsAnimation animation = mock(WindowInsetsAnimation.class);
2236 when(animation.getTypeMask()).thenReturn(WindowInsets.Type.ime());
2239 animationList.
add(animation);
2241 ArgumentCaptor<
FlutterRenderer.ViewportMetrics> viewportMetricsCaptor =
2244 WindowInsets.Builder builder =
new WindowInsets.Builder();
2247 imeSyncCallback.
getInsetsListener().onApplyWindowInsets(testView, builder.build());
2249 verify(flutterRenderer, atLeast(1)).setViewportMetrics(viewportMetricsCaptor.capture());
2250 assertEquals(0, viewportMetricsCaptor.getValue().viewInsetBottom);
2255 builder.setInsets(WindowInsets.Type.ime(), Insets.of(0, 0, 0, 100));
2256 builder.setInsets(WindowInsets.Type.navigationBars(), Insets.of(0, 0, 0, 0));
2257 imeSyncCallback.
getInsetsListener().onApplyWindowInsets(testView, builder.build());
2259 verify(flutterRenderer, atLeast(1)).setViewportMetrics(viewportMetricsCaptor.capture());
2260 assertEquals(0, viewportMetricsCaptor.getValue().viewInsetBottom);
2264 builder.setInsets(WindowInsets.Type.ime(), Insets.of(0, 0, 0, 50));
2265 builder.setInsets(WindowInsets.Type.navigationBars(), Insets.of(0, 0, 0, 40));
2266 imeSyncCallback.
getInsetsListener().onApplyWindowInsets(testView, builder.build());
2268 verify(flutterRenderer, atLeast(1)).setViewportMetrics(viewportMetricsCaptor.capture());
2269 assertEquals(0, viewportMetricsCaptor.getValue().viewInsetBottom);
2273 builder.setInsets(WindowInsets.Type.ime(), Insets.of(0, 0, 0, 25));
2274 builder.setInsets(WindowInsets.Type.navigationBars(), Insets.of(0, 0, 0, 40));
2277 verify(flutterRenderer, atLeast(1)).setViewportMetrics(viewportMetricsCaptor.capture());
2278 assertEquals(25, viewportMetricsCaptor.getValue().viewInsetBottom);
2280 builder.setInsets(WindowInsets.Type.ime(), Insets.of(0, 0, 0, 50));
2281 builder.setInsets(WindowInsets.Type.navigationBars(), Insets.of(0, 0, 0, 40));
2284 verify(flutterRenderer, atLeast(1)).setViewportMetrics(viewportMetricsCaptor.capture());
2285 assertEquals(50, viewportMetricsCaptor.getValue().viewInsetBottom);
2291 verify(flutterRenderer, atLeast(1)).setViewportMetrics(viewportMetricsCaptor.capture());
2292 assertEquals(100, viewportMetricsCaptor.getValue().viewInsetBottom);
2296 @TargetApi(API_LEVELS.API_30)
2297 @Config(sdk = API_LEVELS.API_30)
2298 @SuppressWarnings(
"deprecation")
2301 public
void lastWindowInsets_updatedOnSecondOnProgressCall() {
2303 when(testView.getWindowSystemUiVisibility()).thenReturn(View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
2305 TextInputChannel textInputChannel =
new TextInputChannel(mock(DartExecutor.class));
2307 new TextInputPlugin(testView, textInputChannel, mock(PlatformViewsController.class));
2311 when(flutterEngine.getRenderer()).thenReturn(flutterRenderer);
2312 testView.attachToFlutterEngine(flutterEngine);
2314 WindowInsetsAnimation imeAnimation = mock(WindowInsetsAnimation.class);
2315 when(imeAnimation.getTypeMask()).thenReturn(WindowInsets.Type.ime());
2316 WindowInsetsAnimation navigationBarAnimation = mock(WindowInsetsAnimation.class);
2317 when(navigationBarAnimation.getTypeMask()).thenReturn(WindowInsets.Type.navigationBars());
2320 animationList.
add(imeAnimation);
2321 animationList.
add(navigationBarAnimation);
2323 ArgumentCaptor<
FlutterRenderer.ViewportMetrics> viewportMetricsCaptor =
2326 WindowInsets.Builder builder =
new WindowInsets.Builder();
2329 builder.setInsets(WindowInsets.Type.ime(), Insets.of(0, 0, 0, 1000));
2330 builder.setInsets(WindowInsets.Type.navigationBars(), Insets.of(0, 0, 0, 100));
2331 imeSyncCallback.
getInsetsListener().onApplyWindowInsets(testView, builder.build());
2333 verify(flutterRenderer, atLeast(1)).setViewportMetrics(viewportMetricsCaptor.capture());
2334 assertEquals(100, viewportMetricsCaptor.getValue().viewPaddingBottom);
2339 builder.setInsets(WindowInsets.Type.ime(), Insets.of(0, 0, 0, 0));
2340 builder.setInsets(WindowInsets.Type.navigationBars(), Insets.of(0, 0, 0, 100));
2341 imeSyncCallback.
getInsetsListener().onApplyWindowInsets(testView, builder.build());
2343 verify(flutterRenderer, atLeast(1)).setViewportMetrics(viewportMetricsCaptor.capture());
2344 assertEquals(100, viewportMetricsCaptor.getValue().viewPaddingBottom);
2348 builder.setInsets(WindowInsets.Type.ime(), Insets.of(0, 0, 0, 0));
2349 builder.setInsets(WindowInsets.Type.navigationBars(), Insets.of(0, 0, 0, 0));
2350 imeSyncCallback.
getInsetsListener().onApplyWindowInsets(testView, builder.build());
2352 verify(flutterRenderer, atLeast(1)).setViewportMetrics(viewportMetricsCaptor.capture());
2353 assertEquals(100, viewportMetricsCaptor.getValue().viewPaddingBottom);
2357 builder.setInsets(WindowInsets.Type.ime(), Insets.of(0, 0, 0, 500));
2358 builder.setInsets(WindowInsets.Type.navigationBars(), Insets.of(0, 0, 0, 0));
2361 verify(flutterRenderer, atLeast(1)).setViewportMetrics(viewportMetricsCaptor.capture());
2362 assertEquals(0, viewportMetricsCaptor.getValue().viewPaddingBottom);
2364 builder.setInsets(WindowInsets.Type.ime(), Insets.of(0, 0, 0, 250));
2365 builder.setInsets(WindowInsets.Type.navigationBars(), Insets.of(0, 0, 0, 0));
2368 verify(flutterRenderer, atLeast(1)).setViewportMetrics(viewportMetricsCaptor.capture());
2369 assertEquals(0, viewportMetricsCaptor.getValue().viewPaddingBottom);
2375 verify(flutterRenderer, atLeast(1)).setViewportMetrics(viewportMetricsCaptor.capture());
2376 assertEquals(0, viewportMetricsCaptor.getValue().viewPaddingBottom);
2383 @Implements(InputMethodManager.class)
2384 public static class
TestImm extends ShadowInputMethodManager {
2385 private InputMethodSubtype currentInputMethodSubtype;
2386 private SparseIntArray restartCounter =
new SparseIntArray();
2387 private CursorAnchorInfo cursorAnchorInfo;
2388 private ArrayList<Integer> selectionUpdateValues;
2389 private boolean trackSelection =
false;
2393 selectionUpdateValues =
new ArrayList<Integer>();
2398 return currentInputMethodSubtype;
2403 int count = restartCounter.get(view.hashCode(), 0) + 1;
2404 restartCounter.put(view.hashCode(),
count);
2408 this.currentInputMethodSubtype = inputMethodSubtype;
2412 return restartCounter.get(view.hashCode(), 0);
2416 handler = eventHandler;
2426 this.cursorAnchorInfo = cursorAnchorInfo;
2432 View view,
int selStart,
int selEnd,
int candidatesStart,
int candidatesEnd) {
2433 if (trackSelection) {
2434 this.selectionUpdateValues.add(selStart);
2435 this.selectionUpdateValues.add(selEnd);
2436 this.selectionUpdateValues.add(candidatesStart);
2437 this.selectionUpdateValues.add(candidatesEnd);
2443 trackSelection = val;
2448 return selectionUpdateValues;
2452 return cursorAnchorInfo;
2456 @Implements(AutofillManager.class)
2457 public static class
TestAfm extends ShadowAutofillManager {
2469 finishState =
"cancel";
2473 finishState =
"commit";
2477 enterId = virtualId;
2485 if (
Build.VERSION.SDK_INT < API_LEVELS.API_26) {
2488 changeVirtualId = virtualId;
2489 changeString =
value.getTextValue().toString();
2494 changeVirtualId =
empty;
2495 changeString =
null;
static SkISize times(const SkISize &size, float factor)
static bool eq(const SkM44 &a, const SkM44 &b, float tol)
static bool equals(T *a, T *b)
void add(sk_sp< SkIDChangeListener > listener) SK_EXCLUDES(fMutex)
WindowInsetsAnimation.Callback getAnimationCallback()
View.OnApplyWindowInsetsListener getInsetsListener()
CharSequence getDeltaText()
int getNewSelectionStart()
CharSequence getOldText()
int getNewComposingStart()
void notifyViewExited(View view, int virtualId)
void notifyViewEntered(View view, int virtualId, Rect absBounds)
void notifyValueChanged(View view, int virtualId, AutofillValue value)
void updateCursorAnchorInfo(View view, CursorAnchorInfo cursorAnchorInfo)
ArrayList< Integer > getSelectionUpdateValues()
void setEventHandler(EventHandler eventHandler)
void setTrackSelection(boolean val)
void updateSelection(View view, int selStart, int selEnd, int candidatesStart, int candidatesEnd)
void restartInput(View view)
InputMethodSubtype getCurrentInputMethodSubtype()
void setCurrentInputMethodSubtype(InputMethodSubtype inputMethodSubtype)
void sendAppPrivateCommand(View view, String action, Bundle data)
CursorAnchorInfo getLastCursorAnchorInfo()
int getRestartCount(View view)
void textInputPlugin_RequestsReattachOnCreation()
void inputConnection_textInputTypeNone()
void autofill_testAutofillUpdatesTheFramework()
void inputConnection_textInputTypeMultilineAndSuggestionsDisabled()
void textEditingDelta_TestUpdateEditingValueIsNotInvokedWhenDeltaModelEnabled()
void setTextInputEditingState_doesNotInvokeUpdateEditingStateWithDeltas()
void autofill_canBeDisabled()
void autofill_doesNotCrashAfterClearClientCall()
void autofill_onProvideVirtualViewStructure_singular_textfield()
void autofill_onProvideVirtualViewStructure()
void autofill_testSetTextIpnutClientUpdatesSideFields()
void inputConnectionAdaptor_RepeatFilter()
void showTextInput_textInputTypeNone()
void textEditingDelta_TestDeltaIsCreatedWhenComposingTextSetIsDeleting()
void clearTextInputClient_alwaysRestartsImm()
void TextEditState_throwsOnInvalidStatesReceived()
void inputConnection_finishComposingTextUpdatesIMM()
void textEditingDelta_TestDeltaIsCreatedWhenComposingTextSetIsInserting()
void respondsToInputChannelMessages()
void setTextInputEditingState_alwaysSetEditableWhenDifferent()
void sendAppPrivateCommand_hasData()
void setTextInputEditingState_restartsIMEOnlyWhenFrameworkChangesComposingRegion()
void setTextInputEditingState_doesNotInvokeUpdateEditingState()
void autofill_testLifeCycle()
void sendAppPrivateCommand_dataIsEmpty()
void setTextInputEditingState_nullInputMethodSubtype()
void setTextInputEditingState_willNotThrowWithoutSetTextInputClient()
void destroy_clearTextInputMethodHandler()
void inputConnection_createsActionFromEnter()
void inputConnection_respondsToKeyEvents_textInputTypeNone()
void textEditingDelta_TestUpdateEditingValueWithDeltasIsNotInvokedWhenDeltaModelDisabled()
FlutterJNI mockFlutterJni
FlutterLoader mockFlutterLoader
void setTextInputEditingState_doesNotRestartWhenTextIsIdentical()
void autofill_enabledByDefault()
void textEditingDelta_TestDeltaIsCreatedWhenComposingTextSetIsReplacing()
EMSCRIPTEN_KEEPALIVE void empty()
G_BEGIN_DECLS G_MODULE_EXPORT FlValue * args
static const uint8_t buffer[]
void clearTextInputClient()
void sendAppPrivateCommand(View view, String action, Bundle data)
FlutterTextInputPlugin * textInputPlugin