[Android] Fix crash on some key repeat events (#165307)

## Description

This PR fixes a crash on Android related to specific keyboard events.
It is very similar to http://github.com/flutter/engine/issues/35924
which was related to down events. This PR fixes the similar logic
related to repeat events.

## Related Issue

Fixes [Flutter 3.29 Fatal crash with
java.lang.AssertionError](https://github.com/flutter/flutter/issues/164626)

## Tests

Adds 1 test.
This commit is contained in:
Bruno Leroux
2025-03-18 07:48:21 +01:00
committed by GitHub
parent df0e5d0913
commit d0ef1c1f86
2 changed files with 63 additions and 1 deletions

View File

@@ -183,7 +183,7 @@ public class KeyEmbedderResponder implements KeyboardManager.Responder {
postSynchronize.add(
() ->
synthesizeEvent(
false, key.logicalKey, key.physicalKey, event.getEventTime()));
false, key.logicalKey, eventPhysicalKey, event.getEventTime()));
}
preEventStates[keyIdx] = nowStates[keyIdx];
postEventAnyPressed = true;

View File

@@ -1669,6 +1669,68 @@ public class KeyboardManagerTest {
calls.clear();
}
// Regression test for https://github.com/flutter/flutter/issues/164626.
@Test
public void synchronizeModifiersForZeroedScanCodeOnRepeatEvent() {
// Test if ShiftLeft can be correctly synchronized during down events of
// ShiftLeft that have 0 for their metaState and 0 for their scanCode.
final KeyboardTester tester = new KeyboardTester();
final ArrayList<CallRecord> calls = new ArrayList<>();
tester.recordEmbedderCallsTo(calls);
tester.respondToTextInputWith(true); // Suppress redispatching
// Test: repeat event when the meta state is 0 and scanCode is 0.
final KeyEvent shiftLeftKeyEvent =
new FakeKeyEvent(ACTION_DOWN, 0, KEYCODE_SHIFT_LEFT, 1, '\0', 0);
// Compute physicalKey in the same way as KeyboardManager.getPhysicalKey.
final Long shiftLeftPhysicalKey = KEYCODE_SHIFT_LEFT | KeyboardMap.kAndroidPlane;
assertEquals(tester.keyboardManager.handleEvent(shiftLeftKeyEvent), true);
assertEquals(calls.size(), 2);
assertEmbedderEventEquals(
calls.get(0).keyData,
Type.kDown,
shiftLeftPhysicalKey,
LOGICAL_SHIFT_LEFT,
null,
false,
DeviceType.kKeyboard);
assertEmbedderEventEquals(
calls.get(1).keyData,
Type.kUp,
shiftLeftPhysicalKey,
LOGICAL_SHIFT_LEFT,
null,
true,
DeviceType.kKeyboard);
calls.clear();
// Similar check for AltLeft.
final KeyEvent altLeftKeyEvent = new FakeKeyEvent(ACTION_DOWN, 0, KEYCODE_ALT_LEFT, 1, '\0', 0);
final Long altLeftPhysicalKey = KEYCODE_ALT_LEFT | KeyboardMap.kAndroidPlane;
assertEquals(tester.keyboardManager.handleEvent(altLeftKeyEvent), true);
assertEquals(calls.size(), 2);
assertEmbedderEventEquals(
calls.get(0).keyData,
Type.kDown,
altLeftPhysicalKey,
LOGICAL_ALT_LEFT,
null,
false,
DeviceType.kKeyboard);
assertEmbedderEventEquals(
calls.get(1).keyData,
Type.kUp,
altLeftPhysicalKey,
LOGICAL_ALT_LEFT,
null,
true,
DeviceType.kKeyboard);
calls.clear();
}
@Test
public void normalCapsLockEvents() {
final KeyboardTester tester = new KeyboardTester();