Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit 0950274

Browse files
committed
Add test for out of order events
1 parent 726eff2 commit 0950274

File tree

1 file changed

+71
-0
lines changed

1 file changed

+71
-0
lines changed

shell/platform/android/test/io/flutter/embedding/android/AndroidKeyProcessorTest.java

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,77 @@ public Boolean answer(InvocationOnMock invocation) throws Throwable {
226226
verify(fakeRootView, times(1)).dispatchKeyEvent(fakeKeyEvent);
227227
}
228228

229+
public void respondsCorrectlyWhenEventsAreReturnedOutOfOrder() {
230+
FlutterEngine flutterEngine = mockFlutterEngine();
231+
KeyEventChannel fakeKeyEventChannel = flutterEngine.getKeyEventChannel();
232+
View fakeView = mock(View.class);
233+
View fakeRootView = mock(View.class);
234+
when(fakeView.getRootView())
235+
.then(
236+
new Answer<View>() {
237+
@Override
238+
public View answer(InvocationOnMock invocation) throws Throwable {
239+
return fakeRootView;
240+
}
241+
});
242+
243+
ArgumentCaptor<KeyEventChannel.EventResponseHandler> handlerCaptor =
244+
ArgumentCaptor.forClass(KeyEventChannel.EventResponseHandler.class);
245+
verify(fakeKeyEventChannel).setEventResponseHandler(handlerCaptor.capture());
246+
AndroidKeyProcessor processor =
247+
new AndroidKeyProcessor(fakeView, fakeKeyEventChannel, mock(TextInputPlugin.class));
248+
ArgumentCaptor<KeyEventChannel.FlutterKeyEvent> event1Captor =
249+
ArgumentCaptor.forClass(KeyEventChannel.FlutterKeyEvent.class);
250+
ArgumentCaptor<KeyEventChannel.FlutterKeyEvent> event2Captor =
251+
ArgumentCaptor.forClass(KeyEventChannel.FlutterKeyEvent.class);
252+
FakeKeyEvent fakeKeyEvent1 = new FakeKeyEvent(KeyEvent.ACTION_DOWN, 65);
253+
FakeKeyEvent fakeKeyEvent2 = new FakeKeyEvent(KeyEvent.ACTION_DOWN, 20);
254+
255+
boolean result1 = processor.onKeyEvent(fakeKeyEvent1);
256+
boolean result2 = processor.onKeyEvent(fakeKeyEvent2);
257+
assertEquals(true, processor.isPendingEvent(fakeKeyEvent1));
258+
assertEquals(true, processor.isPendingEvent(fakeKeyEvent2));
259+
assertEquals(true, result1);
260+
assertEquals(true, result2);
261+
262+
// Capture the FlutterKeyEvent so we can find out its event ID to use when
263+
// faking our response.
264+
verify(fakeKeyEventChannel, times(1)).keyDown(event1Captor.capture());
265+
verify(fakeKeyEventChannel, times(1)).keyDown(event2Captor.capture());
266+
boolean[] dispatchResult = {true, true};
267+
when(fakeView.dispatchKeyEvent(any(KeyEvent.class)))
268+
.then(
269+
new Answer<Boolean>() {
270+
@Override
271+
public Boolean answer(InvocationOnMock invocation) throws Throwable {
272+
KeyEvent event = (KeyEvent) invocation.getArguments()[0];
273+
assertEquals(true, fakeKeyEvent1 == event || fakeKeyEvent2 == event);
274+
if (fakeKeyEvent1 == event) {
275+
dispatchResult[0] = processor.onKeyEvent(fakeKeyEvent1);
276+
return dispatchResult[0];
277+
} else {
278+
dispatchResult[1] = processor.onKeyEvent(fakeKeyEvent2);
279+
return dispatchResult[1];
280+
}
281+
}
282+
});
283+
284+
assertEquals(true, processor.isPendingEvent(fakeKeyEvent1));
285+
assertEquals(true, processor.isPendingEvent(fakeKeyEvent2));
286+
287+
// Fake a "handled" response from the framework, but do it in reverse order.
288+
handlerCaptor.getValue().onKeyEventNotHandled(event2Captor.getValue().event);
289+
handlerCaptor.getValue().onKeyEventNotHandled(event1Captor.getValue().event);
290+
291+
verify(fakeView, times(1)).dispatchKeyEvent(fakeKeyEvent1);
292+
verify(fakeView, times(1)).dispatchKeyEvent(fakeKeyEvent2);
293+
assertEquals(false, dispatchResult[0]);
294+
assertEquals(false, dispatchResult[1]);
295+
verify(fakeKeyEventChannel, times(0)).keyUp(any(KeyEventChannel.FlutterKeyEvent.class));
296+
verify(fakeRootView, times(1)).dispatchKeyEvent(fakeKeyEvent1);
297+
verify(fakeRootView, times(1)).dispatchKeyEvent(fakeKeyEvent2);
298+
}
299+
229300
@NonNull
230301
private FlutterEngine mockFlutterEngine() {
231302
// Mock FlutterEngine and all of its required direct calls.

0 commit comments

Comments
 (0)