Flutter Engine
The Flutter Engine
KeyEventChannelTest.java
Go to the documentation of this file.
1package io.flutter.embedding.engine.systemchannels;
2
3import static io.flutter.Build.API_LEVELS;
4import static org.junit.Assert.assertEquals;
5import static org.junit.Assert.assertNotNull;
6import static org.junit.Assert.assertTrue;
7import static org.mockito.Mockito.any;
8import static org.mockito.Mockito.mock;
9import static org.mockito.Mockito.times;
10import static org.mockito.Mockito.verify;
11import static org.mockito.Mockito.when;
12
13import android.annotation.TargetApi;
14import android.util.SparseArray;
15import android.view.InputDevice;
16import android.view.KeyEvent;
17import androidx.test.ext.junit.runners.AndroidJUnit4;
18import io.flutter.plugin.common.BinaryMessenger;
19import io.flutter.plugin.common.JSONMessageCodec;
20import io.flutter.util.FakeKeyEvent;
21import java.nio.ByteBuffer;
22import org.json.JSONException;
23import org.json.JSONObject;
24import org.junit.After;
25import org.junit.Before;
26import org.junit.Test;
27import org.junit.runner.RunWith;
28import org.mockito.ArgumentCaptor;
29import org.mockito.Mock;
30import org.mockito.MockitoAnnotations;
31import org.robolectric.annotation.Config;
32import org.robolectric.annotation.Implementation;
33import org.robolectric.annotation.Implements;
34import org.robolectric.annotation.Resetter;
35import org.robolectric.shadow.api.Shadow;
36
37@Config(manifest = Config.NONE)
38@RunWith(AndroidJUnit4.class)
39@TargetApi(API_LEVELS.API_24)
40public class KeyEventChannelTest {
41
42 KeyEvent keyEvent;
44 boolean[] handled;
46
47 private void sendReply(boolean handled, BinaryMessenger.BinaryReply messengerReply)
48 throws JSONException {
49 JSONObject reply = new JSONObject();
50 reply.put("handled", true);
51 ByteBuffer binaryReply = JSONMessageCodec.INSTANCE.encodeMessage(reply);
52 assertNotNull(binaryReply);
53 binaryReply.rewind();
54 messengerReply.reply(binaryReply);
55 }
56
57 @Before
58 public void setUp() {
59 MockitoAnnotations.openMocks(this);
60 keyEvent = new FakeKeyEvent(KeyEvent.ACTION_DOWN, 65);
61 handled = new boolean[] {false};
62 keyEventChannel = new KeyEventChannel(fakeMessenger);
63 }
64
65 @After
66 public void tearDown() {
68 }
69
70 @Test
71 @Config(shadows = {ShadowInputDevice.class})
72 public void keyDownEventIsSentToFramework() throws JSONException {
73 final InputDevice device = mock(InputDevice.class);
74 when(device.isVirtual()).thenReturn(false);
75 when(device.getName()).thenReturn("keyboard");
76 ShadowInputDevice.sDeviceIds = new int[] {0};
78
79 KeyEventChannel.FlutterKeyEvent flutterKeyEvent =
80 new KeyEventChannel.FlutterKeyEvent(keyEvent, null);
81 keyEventChannel.sendFlutterKeyEvent(
82 flutterKeyEvent,
83 false,
84 (isHandled) -> {
85 handled[0] = isHandled;
86 });
87
88 ArgumentCaptor<ByteBuffer> byteBufferArgumentCaptor = ArgumentCaptor.forClass(ByteBuffer.class);
89 ArgumentCaptor<BinaryMessenger.BinaryReply> replyArgumentCaptor =
90 ArgumentCaptor.forClass(BinaryMessenger.BinaryReply.class);
91 verify(fakeMessenger, times(1))
92 .send(any(), byteBufferArgumentCaptor.capture(), replyArgumentCaptor.capture());
93 ByteBuffer capturedMessage = byteBufferArgumentCaptor.getValue();
94 capturedMessage.rewind();
95 JSONObject message = (JSONObject) JSONMessageCodec.INSTANCE.decodeMessage(capturedMessage);
96 assertNotNull(message);
97 assertEquals("keydown", message.get("type"));
98
99 // Simulate a reply, and see that it is handled.
100 sendReply(true, replyArgumentCaptor.getValue());
101 assertTrue(handled[0]);
102 }
103
104 @Test
105 @Config(shadows = {ShadowInputDevice.class})
106 public void keyUpEventIsSentToFramework() throws JSONException {
107 final InputDevice device = mock(InputDevice.class);
108 when(device.isVirtual()).thenReturn(false);
109 when(device.getName()).thenReturn("keyboard");
110 ShadowInputDevice.sDeviceIds = new int[] {0};
112
113 keyEvent = new FakeKeyEvent(KeyEvent.ACTION_UP, 65);
114 KeyEventChannel.FlutterKeyEvent flutterKeyEvent =
115 new KeyEventChannel.FlutterKeyEvent(keyEvent, null);
116 keyEventChannel.sendFlutterKeyEvent(
117 flutterKeyEvent,
118 false,
119 (isHandled) -> {
120 handled[0] = isHandled;
121 });
122
123 ArgumentCaptor<ByteBuffer> byteBufferArgumentCaptor = ArgumentCaptor.forClass(ByteBuffer.class);
124 ArgumentCaptor<BinaryMessenger.BinaryReply> replyArgumentCaptor =
125 ArgumentCaptor.forClass(BinaryMessenger.BinaryReply.class);
126 verify(fakeMessenger, times(1))
127 .send(any(), byteBufferArgumentCaptor.capture(), replyArgumentCaptor.capture());
128 ByteBuffer capturedMessage = byteBufferArgumentCaptor.getValue();
129 capturedMessage.rewind();
130 JSONObject message = (JSONObject) JSONMessageCodec.INSTANCE.decodeMessage(capturedMessage);
131 assertNotNull(message);
132 assertEquals("keydown", message.get("type"));
133
134 // Simulate a reply, and see that it is handled.
135 sendReply(true, replyArgumentCaptor.getValue());
136 assertTrue(handled[0]);
137 }
138
139 @Implements(InputDevice.class)
140 public static class ShadowInputDevice extends org.robolectric.shadows.ShadowInputDevice {
141 public static int[] sDeviceIds;
142 private static SparseArray<InputDevice> sDeviceMap = new SparseArray<>();
143
144 private int mDeviceId;
145
146 @Implementation
147 protected static int[] getDeviceIds() {
148 return sDeviceIds;
149 }
150
151 @Implementation
152 protected static InputDevice getDevice(int id) {
153 return sDeviceMap.get(id);
154 }
155
156 public static void addDevice(int id, InputDevice device) {
157 sDeviceMap.append(id, device);
158 }
159
160 @Resetter
161 public static void reset() {
162 sDeviceIds = null;
163 sDeviceMap.clear();
164 }
165
166 @Implementation
167 protected int getId() {
168 return mDeviceId;
169 }
170
171 public static InputDevice makeInputDevicebyId(int id) {
172 final InputDevice inputDevice = Shadow.newInstanceOf(InputDevice.class);
173 final ShadowInputDevice shadowInputDevice = Shadow.extract(inputDevice);
174 shadowInputDevice.setId(id);
175 return inputDevice;
176 }
177
178 public void setId(int id) {
179 mDeviceId = id;
180 }
181 }
182}
static SkISize times(const SkISize &size, float factor)
void sendFlutterKeyEvent( @NonNull FlutterKeyEvent keyEvent, boolean isKeyUp, @NonNull EventResponseHandler responseHandler)
Object decodeMessage(@Nullable ByteBuffer message)
static final JSONMessageCodec INSTANCE
ByteBuffer encodeMessage(@Nullable Object message)
VkDevice device
Definition: main.cc:53
Win32Message message
SIT bool any(const Vec< 1, T > &x)
Definition: SkVx.h:530
const uintptr_t id