Simplify messages reader/writer

In Java, control messages were parsed using manual buffering, which was
convoluted and error-prone.

Instead, read the socket directly through a DataInputStream and a
BufferedInputStream. Symmetrically, use a DataOutputStream and a
BufferedOutputStream to write messages.
This commit is contained in:
Romain Vimont 2024-09-07 14:24:25 +02:00
parent 3b241af3f6
commit 21b412cd98
6 changed files with 210 additions and 336 deletions

View File

@ -3,31 +3,22 @@ package com.genymobile.scrcpy.control;
import android.net.LocalSocket; import android.net.LocalSocket;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
public final class ControlChannel { public final class ControlChannel {
private final InputStream inputStream;
private final OutputStream outputStream;
private final ControlMessageReader reader = new ControlMessageReader(); private final ControlMessageReader reader;
private final DeviceMessageWriter writer = new DeviceMessageWriter(); private final DeviceMessageWriter writer;
public ControlChannel(LocalSocket controlSocket) throws IOException { public ControlChannel(LocalSocket controlSocket) throws IOException {
this.inputStream = controlSocket.getInputStream(); reader = new ControlMessageReader(controlSocket.getInputStream());
this.outputStream = controlSocket.getOutputStream(); writer = new DeviceMessageWriter(controlSocket.getOutputStream());
} }
public ControlMessage recv() throws IOException { public ControlMessage recv() throws IOException {
ControlMessage msg = reader.next(); return reader.read();
while (msg == null) {
reader.readFrom(inputStream);
msg = reader.next();
}
return msg;
} }
public void send(DeviceMessage msg) throws IOException { public void send(DeviceMessage msg) throws IOException {
writer.writeTo(msg, outputStream); writer.write(msg);
} }
} }

View File

@ -1,259 +1,152 @@
package com.genymobile.scrcpy.control; package com.genymobile.scrcpy.control;
import com.genymobile.scrcpy.util.Binary; import com.genymobile.scrcpy.util.Binary;
import com.genymobile.scrcpy.util.Ln;
import com.genymobile.scrcpy.device.Position; import com.genymobile.scrcpy.device.Position;
import java.io.EOFException; import java.io.BufferedInputStream;
import java.io.DataInputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
public class ControlMessageReader { public class ControlMessageReader {
static final int INJECT_KEYCODE_PAYLOAD_LENGTH = 13;
static final int INJECT_TOUCH_EVENT_PAYLOAD_LENGTH = 31;
static final int INJECT_SCROLL_EVENT_PAYLOAD_LENGTH = 20;
static final int BACK_OR_SCREEN_ON_LENGTH = 1;
static final int SET_SCREEN_POWER_MODE_PAYLOAD_LENGTH = 1;
static final int GET_CLIPBOARD_LENGTH = 1;
static final int SET_CLIPBOARD_FIXED_PAYLOAD_LENGTH = 9;
static final int UHID_CREATE_FIXED_PAYLOAD_LENGTH = 4;
static final int UHID_INPUT_FIXED_PAYLOAD_LENGTH = 4;
private static final int MESSAGE_MAX_SIZE = 1 << 18; // 256k private static final int MESSAGE_MAX_SIZE = 1 << 18; // 256k
public static final int CLIPBOARD_TEXT_MAX_LENGTH = MESSAGE_MAX_SIZE - 14; // type: 1 byte; sequence: 8 bytes; paste flag: 1 byte; length: 4 bytes public static final int CLIPBOARD_TEXT_MAX_LENGTH = MESSAGE_MAX_SIZE - 14; // type: 1 byte; sequence: 8 bytes; paste flag: 1 byte; length: 4 bytes
public static final int INJECT_TEXT_MAX_LENGTH = 300; public static final int INJECT_TEXT_MAX_LENGTH = 300;
private final byte[] rawBuffer = new byte[MESSAGE_MAX_SIZE]; private final DataInputStream dis;
private final ByteBuffer buffer = ByteBuffer.wrap(rawBuffer);
public ControlMessageReader() { public ControlMessageReader(InputStream rawInputStream) {
// invariant: the buffer is always in "get" mode dis = new DataInputStream(new BufferedInputStream(rawInputStream));
buffer.limit(0);
} }
public boolean isFull() { public ControlMessage read() throws IOException {
return buffer.remaining() == rawBuffer.length; int type = dis.readUnsignedByte();
}
public void readFrom(InputStream input) throws IOException {
if (isFull()) {
throw new IllegalStateException("Buffer full, call next() to consume");
}
buffer.compact();
int head = buffer.position();
int r = input.read(rawBuffer, head, rawBuffer.length - head);
if (r == -1) {
throw new EOFException("Controller socket closed");
}
buffer.position(head + r);
buffer.flip();
}
public ControlMessage next() {
if (!buffer.hasRemaining()) {
return null;
}
int savedPosition = buffer.position();
int type = buffer.get();
ControlMessage msg;
switch (type) { switch (type) {
case ControlMessage.TYPE_INJECT_KEYCODE: case ControlMessage.TYPE_INJECT_KEYCODE:
msg = parseInjectKeycode(); return parseInjectKeycode();
break;
case ControlMessage.TYPE_INJECT_TEXT: case ControlMessage.TYPE_INJECT_TEXT:
msg = parseInjectText(); return parseInjectText();
break;
case ControlMessage.TYPE_INJECT_TOUCH_EVENT: case ControlMessage.TYPE_INJECT_TOUCH_EVENT:
msg = parseInjectTouchEvent(); return parseInjectTouchEvent();
break;
case ControlMessage.TYPE_INJECT_SCROLL_EVENT: case ControlMessage.TYPE_INJECT_SCROLL_EVENT:
msg = parseInjectScrollEvent(); return parseInjectScrollEvent();
break;
case ControlMessage.TYPE_BACK_OR_SCREEN_ON: case ControlMessage.TYPE_BACK_OR_SCREEN_ON:
msg = parseBackOrScreenOnEvent(); return parseBackOrScreenOnEvent();
break;
case ControlMessage.TYPE_GET_CLIPBOARD: case ControlMessage.TYPE_GET_CLIPBOARD:
msg = parseGetClipboard(); return parseGetClipboard();
break;
case ControlMessage.TYPE_SET_CLIPBOARD: case ControlMessage.TYPE_SET_CLIPBOARD:
msg = parseSetClipboard(); return parseSetClipboard();
break;
case ControlMessage.TYPE_SET_SCREEN_POWER_MODE: case ControlMessage.TYPE_SET_SCREEN_POWER_MODE:
msg = parseSetScreenPowerMode(); return parseSetScreenPowerMode();
break;
case ControlMessage.TYPE_EXPAND_NOTIFICATION_PANEL: case ControlMessage.TYPE_EXPAND_NOTIFICATION_PANEL:
case ControlMessage.TYPE_EXPAND_SETTINGS_PANEL: case ControlMessage.TYPE_EXPAND_SETTINGS_PANEL:
case ControlMessage.TYPE_COLLAPSE_PANELS: case ControlMessage.TYPE_COLLAPSE_PANELS:
case ControlMessage.TYPE_ROTATE_DEVICE: case ControlMessage.TYPE_ROTATE_DEVICE:
case ControlMessage.TYPE_OPEN_HARD_KEYBOARD_SETTINGS: case ControlMessage.TYPE_OPEN_HARD_KEYBOARD_SETTINGS:
msg = ControlMessage.createEmpty(type); return ControlMessage.createEmpty(type);
break;
case ControlMessage.TYPE_UHID_CREATE: case ControlMessage.TYPE_UHID_CREATE:
msg = parseUhidCreate(); return parseUhidCreate();
break;
case ControlMessage.TYPE_UHID_INPUT: case ControlMessage.TYPE_UHID_INPUT:
msg = parseUhidInput(); return parseUhidInput();
break;
default: default:
Ln.w("Unknown event type: " + type); throw new ControlProtocolException("Unknown event type: " + type);
msg = null;
break;
} }
if (msg == null) {
// failure, reset savedPosition
buffer.position(savedPosition);
}
return msg;
} }
private ControlMessage parseInjectKeycode() { private ControlMessage parseInjectKeycode() throws IOException {
if (buffer.remaining() < INJECT_KEYCODE_PAYLOAD_LENGTH) { int action = dis.readUnsignedByte();
return null; int keycode = dis.readInt();
} int repeat = dis.readInt();
int action = Binary.toUnsigned(buffer.get()); int metaState = dis.readInt();
int keycode = buffer.getInt();
int repeat = buffer.getInt();
int metaState = buffer.getInt();
return ControlMessage.createInjectKeycode(action, keycode, repeat, metaState); return ControlMessage.createInjectKeycode(action, keycode, repeat, metaState);
} }
private int parseBufferLength(int sizeBytes) { private int parseBufferLength(int sizeBytes) throws IOException {
assert sizeBytes > 0 && sizeBytes <= 4; assert sizeBytes > 0 && sizeBytes <= 4;
if (buffer.remaining() < sizeBytes) {
return -1;
}
int value = 0; int value = 0;
for (int i = 0; i < sizeBytes; ++i) { for (int i = 0; i < sizeBytes; ++i) {
value = (value << 8) | (buffer.get() & 0xFF); value = (value << 8) | dis.readUnsignedByte();
} }
return value; return value;
} }
private String parseString() { private String parseString() throws IOException {
int len = parseBufferLength(4); byte[] data = parseByteArray(4);
if (len == -1 || buffer.remaining() < len) { return new String(data, StandardCharsets.UTF_8);
return null;
}
int position = buffer.position();
// Move the buffer position to consume the text
buffer.position(position + len);
return new String(rawBuffer, position, len, StandardCharsets.UTF_8);
} }
private byte[] parseByteArray(int sizeBytes) { private byte[] parseByteArray(int sizeBytes) throws IOException {
int len = parseBufferLength(sizeBytes); int len = parseBufferLength(sizeBytes);
if (len == -1 || buffer.remaining() < len) {
return null;
}
byte[] data = new byte[len]; byte[] data = new byte[len];
buffer.get(data); dis.readFully(data);
return data; return data;
} }
private ControlMessage parseInjectText() { private ControlMessage parseInjectText() throws IOException {
String text = parseString(); String text = parseString();
if (text == null) {
return null;
}
return ControlMessage.createInjectText(text); return ControlMessage.createInjectText(text);
} }
private ControlMessage parseInjectTouchEvent() { private ControlMessage parseInjectTouchEvent() throws IOException {
if (buffer.remaining() < INJECT_TOUCH_EVENT_PAYLOAD_LENGTH) { int action = dis.readUnsignedByte();
return null; long pointerId = dis.readLong();
} Position position = parsePosition();
int action = Binary.toUnsigned(buffer.get()); float pressure = Binary.u16FixedPointToFloat(dis.readShort());
long pointerId = buffer.getLong(); int actionButton = dis.readInt();
Position position = readPosition(buffer); int buttons = dis.readInt();
float pressure = Binary.u16FixedPointToFloat(buffer.getShort());
int actionButton = buffer.getInt();
int buttons = buffer.getInt();
return ControlMessage.createInjectTouchEvent(action, pointerId, position, pressure, actionButton, buttons); return ControlMessage.createInjectTouchEvent(action, pointerId, position, pressure, actionButton, buttons);
} }
private ControlMessage parseInjectScrollEvent() { private ControlMessage parseInjectScrollEvent() throws IOException {
if (buffer.remaining() < INJECT_SCROLL_EVENT_PAYLOAD_LENGTH) { Position position = parsePosition();
return null; float hScroll = Binary.i16FixedPointToFloat(dis.readShort());
} float vScroll = Binary.i16FixedPointToFloat(dis.readShort());
Position position = readPosition(buffer); int buttons = dis.readInt();
float hScroll = Binary.i16FixedPointToFloat(buffer.getShort());
float vScroll = Binary.i16FixedPointToFloat(buffer.getShort());
int buttons = buffer.getInt();
return ControlMessage.createInjectScrollEvent(position, hScroll, vScroll, buttons); return ControlMessage.createInjectScrollEvent(position, hScroll, vScroll, buttons);
} }
private ControlMessage parseBackOrScreenOnEvent() { private ControlMessage parseBackOrScreenOnEvent() throws IOException {
if (buffer.remaining() < BACK_OR_SCREEN_ON_LENGTH) { int action = dis.readUnsignedByte();
return null;
}
int action = Binary.toUnsigned(buffer.get());
return ControlMessage.createBackOrScreenOn(action); return ControlMessage.createBackOrScreenOn(action);
} }
private ControlMessage parseGetClipboard() { private ControlMessage parseGetClipboard() throws IOException {
if (buffer.remaining() < GET_CLIPBOARD_LENGTH) { int copyKey = dis.readUnsignedByte();
return null;
}
int copyKey = Binary.toUnsigned(buffer.get());
return ControlMessage.createGetClipboard(copyKey); return ControlMessage.createGetClipboard(copyKey);
} }
private ControlMessage parseSetClipboard() { private ControlMessage parseSetClipboard() throws IOException {
if (buffer.remaining() < SET_CLIPBOARD_FIXED_PAYLOAD_LENGTH) { long sequence = dis.readLong();
return null; boolean paste = dis.readByte() != 0;
}
long sequence = buffer.getLong();
boolean paste = buffer.get() != 0;
String text = parseString(); String text = parseString();
if (text == null) {
return null;
}
return ControlMessage.createSetClipboard(sequence, text, paste); return ControlMessage.createSetClipboard(sequence, text, paste);
} }
private ControlMessage parseSetScreenPowerMode() { private ControlMessage parseSetScreenPowerMode() throws IOException {
if (buffer.remaining() < SET_SCREEN_POWER_MODE_PAYLOAD_LENGTH) { int mode = dis.readUnsignedByte();
return null;
}
int mode = buffer.get();
return ControlMessage.createSetScreenPowerMode(mode); return ControlMessage.createSetScreenPowerMode(mode);
} }
private ControlMessage parseUhidCreate() { private ControlMessage parseUhidCreate() throws IOException {
if (buffer.remaining() < UHID_CREATE_FIXED_PAYLOAD_LENGTH) { int id = dis.readUnsignedShort();
return null;
}
int id = buffer.getShort();
byte[] data = parseByteArray(2); byte[] data = parseByteArray(2);
if (data == null) {
return null;
}
return ControlMessage.createUhidCreate(id, data); return ControlMessage.createUhidCreate(id, data);
} }
private ControlMessage parseUhidInput() { private ControlMessage parseUhidInput() throws IOException {
if (buffer.remaining() < UHID_INPUT_FIXED_PAYLOAD_LENGTH) { int id = dis.readUnsignedShort();
return null;
}
int id = buffer.getShort();
byte[] data = parseByteArray(2); byte[] data = parseByteArray(2);
if (data == null) {
return null;
}
return ControlMessage.createUhidInput(id, data); return ControlMessage.createUhidInput(id, data);
} }
private static Position readPosition(ByteBuffer buffer) { private Position parsePosition() throws IOException {
int x = buffer.getInt(); int x = dis.readInt();
int y = buffer.getInt(); int y = dis.readInt();
int screenWidth = Binary.toUnsigned(buffer.getShort()); int screenWidth = dis.readUnsignedShort();
int screenHeight = Binary.toUnsigned(buffer.getShort()); int screenHeight = dis.readUnsignedShort();
return new Position(x, y, screenWidth, screenHeight); return new Position(x, y, screenWidth, screenHeight);
} }
} }

View File

@ -0,0 +1,9 @@
package com.genymobile.scrcpy.control;
import java.io.IOException;
public class ControlProtocolException extends IOException {
public ControlProtocolException(String message) {
super(message);
}
}

View File

@ -1,11 +1,11 @@
package com.genymobile.scrcpy.control; package com.genymobile.scrcpy.control;
import com.genymobile.scrcpy.util.Ln;
import com.genymobile.scrcpy.util.StringUtils; import com.genymobile.scrcpy.util.StringUtils;
import java.io.BufferedOutputStream;
import java.io.DataOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.OutputStream; import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
public class DeviceMessageWriter { public class DeviceMessageWriter {
@ -13,35 +13,35 @@ public class DeviceMessageWriter {
private static final int MESSAGE_MAX_SIZE = 1 << 18; // 256k private static final int MESSAGE_MAX_SIZE = 1 << 18; // 256k
public static final int CLIPBOARD_TEXT_MAX_LENGTH = MESSAGE_MAX_SIZE - 5; // type: 1 byte; length: 4 bytes public static final int CLIPBOARD_TEXT_MAX_LENGTH = MESSAGE_MAX_SIZE - 5; // type: 1 byte; length: 4 bytes
private final byte[] rawBuffer = new byte[MESSAGE_MAX_SIZE]; private final DataOutputStream dos;
private final ByteBuffer buffer = ByteBuffer.wrap(rawBuffer);
public void writeTo(DeviceMessage msg, OutputStream output) throws IOException { public DeviceMessageWriter(OutputStream rawOutputStream) {
buffer.clear(); dos = new DataOutputStream(new BufferedOutputStream(rawOutputStream));
buffer.put((byte) msg.getType()); }
switch (msg.getType()) {
public void write(DeviceMessage msg) throws IOException {
int type = msg.getType();
dos.writeByte(type);
switch (type) {
case DeviceMessage.TYPE_CLIPBOARD: case DeviceMessage.TYPE_CLIPBOARD:
String text = msg.getText(); String text = msg.getText();
byte[] raw = text.getBytes(StandardCharsets.UTF_8); byte[] raw = text.getBytes(StandardCharsets.UTF_8);
int len = StringUtils.getUtf8TruncationIndex(raw, CLIPBOARD_TEXT_MAX_LENGTH); int len = StringUtils.getUtf8TruncationIndex(raw, CLIPBOARD_TEXT_MAX_LENGTH);
buffer.putInt(len); dos.writeInt(len);
buffer.put(raw, 0, len); dos.write(raw, 0, len);
output.write(rawBuffer, 0, buffer.position());
break; break;
case DeviceMessage.TYPE_ACK_CLIPBOARD: case DeviceMessage.TYPE_ACK_CLIPBOARD:
buffer.putLong(msg.getSequence()); dos.writeLong(msg.getSequence());
output.write(rawBuffer, 0, buffer.position());
break; break;
case DeviceMessage.TYPE_UHID_OUTPUT: case DeviceMessage.TYPE_UHID_OUTPUT:
buffer.putShort((short) msg.getId()); dos.writeShort(msg.getId());
byte[] data = msg.getData(); byte[] data = msg.getData();
buffer.putShort((short) data.length); dos.writeShort(data.length);
buffer.put(data); dos.write(data);
output.write(rawBuffer, 0, buffer.position());
break; break;
default: default:
Ln.w("Unknown device message: " + msg.getType()); throw new ControlProtocolException("Unknown event type: " + type);
break;
} }
dos.flush();
} }
} }

View File

@ -10,6 +10,7 @@ import org.junit.Test;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream; import java.io.DataOutputStream;
import java.io.EOFException;
import java.io.IOException; import java.io.IOException;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.Arrays; import java.util.Arrays;
@ -18,8 +19,6 @@ public class ControlMessageReaderTest {
@Test @Test
public void testParseKeycodeEvent() throws IOException { public void testParseKeycodeEvent() throws IOException {
ControlMessageReader reader = new ControlMessageReader();
ByteArrayOutputStream bos = new ByteArrayOutputStream(); ByteArrayOutputStream bos = new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(bos); DataOutputStream dos = new DataOutputStream(bos);
dos.writeByte(ControlMessage.TYPE_INJECT_KEYCODE); dos.writeByte(ControlMessage.TYPE_INJECT_KEYCODE);
@ -29,23 +28,21 @@ public class ControlMessageReaderTest {
dos.writeInt(KeyEvent.META_CTRL_ON); dos.writeInt(KeyEvent.META_CTRL_ON);
byte[] packet = bos.toByteArray(); byte[] packet = bos.toByteArray();
// The message type (1 byte) does not count ByteArrayInputStream bis = new ByteArrayInputStream(packet);
Assert.assertEquals(ControlMessageReader.INJECT_KEYCODE_PAYLOAD_LENGTH, packet.length - 1); ControlMessageReader reader = new ControlMessageReader(bis);
reader.readFrom(new ByteArrayInputStream(packet));
ControlMessage event = reader.next();
ControlMessage event = reader.read();
Assert.assertEquals(ControlMessage.TYPE_INJECT_KEYCODE, event.getType()); Assert.assertEquals(ControlMessage.TYPE_INJECT_KEYCODE, event.getType());
Assert.assertEquals(KeyEvent.ACTION_UP, event.getAction()); Assert.assertEquals(KeyEvent.ACTION_UP, event.getAction());
Assert.assertEquals(KeyEvent.KEYCODE_ENTER, event.getKeycode()); Assert.assertEquals(KeyEvent.KEYCODE_ENTER, event.getKeycode());
Assert.assertEquals(5, event.getRepeat()); Assert.assertEquals(5, event.getRepeat());
Assert.assertEquals(KeyEvent.META_CTRL_ON, event.getMetaState()); Assert.assertEquals(KeyEvent.META_CTRL_ON, event.getMetaState());
Assert.assertEquals(-1, bis.read()); // EOS
} }
@Test @Test
public void testParseTextEvent() throws IOException { public void testParseTextEvent() throws IOException {
ControlMessageReader reader = new ControlMessageReader();
ByteArrayOutputStream bos = new ByteArrayOutputStream(); ByteArrayOutputStream bos = new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(bos); DataOutputStream dos = new DataOutputStream(bos);
dos.writeByte(ControlMessage.TYPE_INJECT_TEXT); dos.writeByte(ControlMessage.TYPE_INJECT_TEXT);
@ -54,17 +51,18 @@ public class ControlMessageReaderTest {
dos.write(text); dos.write(text);
byte[] packet = bos.toByteArray(); byte[] packet = bos.toByteArray();
reader.readFrom(new ByteArrayInputStream(packet)); ByteArrayInputStream bis = new ByteArrayInputStream(packet);
ControlMessage event = reader.next(); ControlMessageReader reader = new ControlMessageReader(bis);
ControlMessage event = reader.read();
Assert.assertEquals(ControlMessage.TYPE_INJECT_TEXT, event.getType()); Assert.assertEquals(ControlMessage.TYPE_INJECT_TEXT, event.getType());
Assert.assertEquals("testé", event.getText()); Assert.assertEquals("testé", event.getText());
Assert.assertEquals(-1, bis.read()); // EOS
} }
@Test @Test
public void testParseLongTextEvent() throws IOException { public void testParseLongTextEvent() throws IOException {
ControlMessageReader reader = new ControlMessageReader();
ByteArrayOutputStream bos = new ByteArrayOutputStream(); ByteArrayOutputStream bos = new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(bos); DataOutputStream dos = new DataOutputStream(bos);
dos.writeByte(ControlMessage.TYPE_INJECT_TEXT); dos.writeByte(ControlMessage.TYPE_INJECT_TEXT);
@ -74,17 +72,18 @@ public class ControlMessageReaderTest {
dos.write(text); dos.write(text);
byte[] packet = bos.toByteArray(); byte[] packet = bos.toByteArray();
reader.readFrom(new ByteArrayInputStream(packet)); ByteArrayInputStream bis = new ByteArrayInputStream(packet);
ControlMessage event = reader.next(); ControlMessageReader reader = new ControlMessageReader(bis);
ControlMessage event = reader.read();
Assert.assertEquals(ControlMessage.TYPE_INJECT_TEXT, event.getType()); Assert.assertEquals(ControlMessage.TYPE_INJECT_TEXT, event.getType());
Assert.assertEquals(new String(text, StandardCharsets.US_ASCII), event.getText()); Assert.assertEquals(new String(text, StandardCharsets.US_ASCII), event.getText());
Assert.assertEquals(-1, bis.read()); // EOS
} }
@Test @Test
public void testParseTouchEvent() throws IOException { public void testParseTouchEvent() throws IOException {
ControlMessageReader reader = new ControlMessageReader();
ByteArrayOutputStream bos = new ByteArrayOutputStream(); ByteArrayOutputStream bos = new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(bos); DataOutputStream dos = new DataOutputStream(bos);
dos.writeByte(ControlMessage.TYPE_INJECT_TOUCH_EVENT); dos.writeByte(ControlMessage.TYPE_INJECT_TOUCH_EVENT);
@ -100,12 +99,10 @@ public class ControlMessageReaderTest {
byte[] packet = bos.toByteArray(); byte[] packet = bos.toByteArray();
// The message type (1 byte) does not count ByteArrayInputStream bis = new ByteArrayInputStream(packet);
Assert.assertEquals(ControlMessageReader.INJECT_TOUCH_EVENT_PAYLOAD_LENGTH, packet.length - 1); ControlMessageReader reader = new ControlMessageReader(bis);
reader.readFrom(new ByteArrayInputStream(packet));
ControlMessage event = reader.next();
ControlMessage event = reader.read();
Assert.assertEquals(ControlMessage.TYPE_INJECT_TOUCH_EVENT, event.getType()); Assert.assertEquals(ControlMessage.TYPE_INJECT_TOUCH_EVENT, event.getType());
Assert.assertEquals(MotionEvent.ACTION_DOWN, event.getAction()); Assert.assertEquals(MotionEvent.ACTION_DOWN, event.getAction());
Assert.assertEquals(-42, event.getPointerId()); Assert.assertEquals(-42, event.getPointerId());
@ -116,12 +113,12 @@ public class ControlMessageReaderTest {
Assert.assertEquals(1f, event.getPressure(), 0f); // must be exact Assert.assertEquals(1f, event.getPressure(), 0f); // must be exact
Assert.assertEquals(MotionEvent.BUTTON_PRIMARY, event.getActionButton()); Assert.assertEquals(MotionEvent.BUTTON_PRIMARY, event.getActionButton());
Assert.assertEquals(MotionEvent.BUTTON_PRIMARY, event.getButtons()); Assert.assertEquals(MotionEvent.BUTTON_PRIMARY, event.getButtons());
Assert.assertEquals(-1, bis.read()); // EOS
} }
@Test @Test
public void testParseScrollEvent() throws IOException { public void testParseScrollEvent() throws IOException {
ControlMessageReader reader = new ControlMessageReader();
ByteArrayOutputStream bos = new ByteArrayOutputStream(); ByteArrayOutputStream bos = new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(bos); DataOutputStream dos = new DataOutputStream(bos);
dos.writeByte(ControlMessage.TYPE_INJECT_SCROLL_EVENT); dos.writeByte(ControlMessage.TYPE_INJECT_SCROLL_EVENT);
@ -132,15 +129,12 @@ public class ControlMessageReaderTest {
dos.writeShort(0); // 0.0f encoded as i16 dos.writeShort(0); // 0.0f encoded as i16
dos.writeShort(0x8000); // -1.0f encoded as i16 dos.writeShort(0x8000); // -1.0f encoded as i16
dos.writeInt(1); dos.writeInt(1);
byte[] packet = bos.toByteArray(); byte[] packet = bos.toByteArray();
// The message type (1 byte) does not count ByteArrayInputStream bis = new ByteArrayInputStream(packet);
Assert.assertEquals(ControlMessageReader.INJECT_SCROLL_EVENT_PAYLOAD_LENGTH, packet.length - 1); ControlMessageReader reader = new ControlMessageReader(bis);
reader.readFrom(new ByteArrayInputStream(packet));
ControlMessage event = reader.next();
ControlMessage event = reader.read();
Assert.assertEquals(ControlMessage.TYPE_INJECT_SCROLL_EVENT, event.getType()); Assert.assertEquals(ControlMessage.TYPE_INJECT_SCROLL_EVENT, event.getType());
Assert.assertEquals(260, event.getPosition().getPoint().getX()); Assert.assertEquals(260, event.getPosition().getPoint().getX());
Assert.assertEquals(1026, event.getPosition().getPoint().getY()); Assert.assertEquals(1026, event.getPosition().getPoint().getY());
@ -149,96 +143,96 @@ public class ControlMessageReaderTest {
Assert.assertEquals(0f, event.getHScroll(), 0f); Assert.assertEquals(0f, event.getHScroll(), 0f);
Assert.assertEquals(-1f, event.getVScroll(), 0f); Assert.assertEquals(-1f, event.getVScroll(), 0f);
Assert.assertEquals(1, event.getButtons()); Assert.assertEquals(1, event.getButtons());
Assert.assertEquals(-1, bis.read()); // EOS
} }
@Test @Test
public void testParseBackOrScreenOnEvent() throws IOException { public void testParseBackOrScreenOnEvent() throws IOException {
ControlMessageReader reader = new ControlMessageReader();
ByteArrayOutputStream bos = new ByteArrayOutputStream(); ByteArrayOutputStream bos = new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(bos); DataOutputStream dos = new DataOutputStream(bos);
dos.writeByte(ControlMessage.TYPE_BACK_OR_SCREEN_ON); dos.writeByte(ControlMessage.TYPE_BACK_OR_SCREEN_ON);
dos.writeByte(KeyEvent.ACTION_UP); dos.writeByte(KeyEvent.ACTION_UP);
byte[] packet = bos.toByteArray(); byte[] packet = bos.toByteArray();
reader.readFrom(new ByteArrayInputStream(packet)); ByteArrayInputStream bis = new ByteArrayInputStream(packet);
ControlMessage event = reader.next(); ControlMessageReader reader = new ControlMessageReader(bis);
ControlMessage event = reader.read();
Assert.assertEquals(ControlMessage.TYPE_BACK_OR_SCREEN_ON, event.getType()); Assert.assertEquals(ControlMessage.TYPE_BACK_OR_SCREEN_ON, event.getType());
Assert.assertEquals(KeyEvent.ACTION_UP, event.getAction()); Assert.assertEquals(KeyEvent.ACTION_UP, event.getAction());
Assert.assertEquals(-1, bis.read()); // EOS
} }
@Test @Test
public void testParseExpandNotificationPanelEvent() throws IOException { public void testParseExpandNotificationPanelEvent() throws IOException {
ControlMessageReader reader = new ControlMessageReader();
ByteArrayOutputStream bos = new ByteArrayOutputStream(); ByteArrayOutputStream bos = new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(bos); DataOutputStream dos = new DataOutputStream(bos);
dos.writeByte(ControlMessage.TYPE_EXPAND_NOTIFICATION_PANEL); dos.writeByte(ControlMessage.TYPE_EXPAND_NOTIFICATION_PANEL);
byte[] packet = bos.toByteArray(); byte[] packet = bos.toByteArray();
reader.readFrom(new ByteArrayInputStream(packet)); ByteArrayInputStream bis = new ByteArrayInputStream(packet);
ControlMessage event = reader.next(); ControlMessageReader reader = new ControlMessageReader(bis);
ControlMessage event = reader.read();
Assert.assertEquals(ControlMessage.TYPE_EXPAND_NOTIFICATION_PANEL, event.getType()); Assert.assertEquals(ControlMessage.TYPE_EXPAND_NOTIFICATION_PANEL, event.getType());
Assert.assertEquals(-1, bis.read()); // EOS
} }
@Test @Test
public void testParseExpandSettingsPanelEvent() throws IOException { public void testParseExpandSettingsPanelEvent() throws IOException {
ControlMessageReader reader = new ControlMessageReader();
ByteArrayOutputStream bos = new ByteArrayOutputStream(); ByteArrayOutputStream bos = new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(bos); DataOutputStream dos = new DataOutputStream(bos);
dos.writeByte(ControlMessage.TYPE_EXPAND_SETTINGS_PANEL); dos.writeByte(ControlMessage.TYPE_EXPAND_SETTINGS_PANEL);
byte[] packet = bos.toByteArray(); byte[] packet = bos.toByteArray();
reader.readFrom(new ByteArrayInputStream(packet)); ByteArrayInputStream bis = new ByteArrayInputStream(packet);
ControlMessage event = reader.next(); ControlMessageReader reader = new ControlMessageReader(bis);
ControlMessage event = reader.read();
Assert.assertEquals(ControlMessage.TYPE_EXPAND_SETTINGS_PANEL, event.getType()); Assert.assertEquals(ControlMessage.TYPE_EXPAND_SETTINGS_PANEL, event.getType());
Assert.assertEquals(-1, bis.read()); // EOS
} }
@Test @Test
public void testParseCollapsePanelsEvent() throws IOException { public void testParseCollapsePanelsEvent() throws IOException {
ControlMessageReader reader = new ControlMessageReader();
ByteArrayOutputStream bos = new ByteArrayOutputStream(); ByteArrayOutputStream bos = new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(bos); DataOutputStream dos = new DataOutputStream(bos);
dos.writeByte(ControlMessage.TYPE_COLLAPSE_PANELS); dos.writeByte(ControlMessage.TYPE_COLLAPSE_PANELS);
byte[] packet = bos.toByteArray(); byte[] packet = bos.toByteArray();
reader.readFrom(new ByteArrayInputStream(packet)); ByteArrayInputStream bis = new ByteArrayInputStream(packet);
ControlMessage event = reader.next(); ControlMessageReader reader = new ControlMessageReader(bis);
ControlMessage event = reader.read();
Assert.assertEquals(ControlMessage.TYPE_COLLAPSE_PANELS, event.getType()); Assert.assertEquals(ControlMessage.TYPE_COLLAPSE_PANELS, event.getType());
Assert.assertEquals(-1, bis.read()); // EOS
} }
@Test @Test
public void testParseGetClipboardEvent() throws IOException { public void testParseGetClipboardEvent() throws IOException {
ControlMessageReader reader = new ControlMessageReader();
ByteArrayOutputStream bos = new ByteArrayOutputStream(); ByteArrayOutputStream bos = new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(bos); DataOutputStream dos = new DataOutputStream(bos);
dos.writeByte(ControlMessage.TYPE_GET_CLIPBOARD); dos.writeByte(ControlMessage.TYPE_GET_CLIPBOARD);
dos.writeByte(ControlMessage.COPY_KEY_COPY); dos.writeByte(ControlMessage.COPY_KEY_COPY);
byte[] packet = bos.toByteArray(); byte[] packet = bos.toByteArray();
reader.readFrom(new ByteArrayInputStream(packet)); ByteArrayInputStream bis = new ByteArrayInputStream(packet);
ControlMessage event = reader.next(); ControlMessageReader reader = new ControlMessageReader(bis);
ControlMessage event = reader.read();
Assert.assertEquals(ControlMessage.TYPE_GET_CLIPBOARD, event.getType()); Assert.assertEquals(ControlMessage.TYPE_GET_CLIPBOARD, event.getType());
Assert.assertEquals(ControlMessage.COPY_KEY_COPY, event.getCopyKey()); Assert.assertEquals(ControlMessage.COPY_KEY_COPY, event.getCopyKey());
Assert.assertEquals(-1, bis.read()); // EOS
} }
@Test @Test
public void testParseSetClipboardEvent() throws IOException { public void testParseSetClipboardEvent() throws IOException {
ControlMessageReader reader = new ControlMessageReader();
ByteArrayOutputStream bos = new ByteArrayOutputStream(); ByteArrayOutputStream bos = new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(bos); DataOutputStream dos = new DataOutputStream(bos);
dos.writeByte(ControlMessage.TYPE_SET_CLIPBOARD); dos.writeByte(ControlMessage.TYPE_SET_CLIPBOARD);
@ -247,22 +241,22 @@ public class ControlMessageReaderTest {
byte[] text = "testé".getBytes(StandardCharsets.UTF_8); byte[] text = "testé".getBytes(StandardCharsets.UTF_8);
dos.writeInt(text.length); dos.writeInt(text.length);
dos.write(text); dos.write(text);
byte[] packet = bos.toByteArray(); byte[] packet = bos.toByteArray();
reader.readFrom(new ByteArrayInputStream(packet)); ByteArrayInputStream bis = new ByteArrayInputStream(packet);
ControlMessage event = reader.next(); ControlMessageReader reader = new ControlMessageReader(bis);
ControlMessage event = reader.read();
Assert.assertEquals(ControlMessage.TYPE_SET_CLIPBOARD, event.getType()); Assert.assertEquals(ControlMessage.TYPE_SET_CLIPBOARD, event.getType());
Assert.assertEquals(0x0102030405060708L, event.getSequence()); Assert.assertEquals(0x0102030405060708L, event.getSequence());
Assert.assertEquals("testé", event.getText()); Assert.assertEquals("testé", event.getText());
Assert.assertTrue(event.getPaste()); Assert.assertTrue(event.getPaste());
Assert.assertEquals(-1, bis.read()); // EOS
} }
@Test @Test
public void testParseBigSetClipboardEvent() throws IOException { public void testParseBigSetClipboardEvent() throws IOException {
ControlMessageReader reader = new ControlMessageReader();
ByteArrayOutputStream bos = new ByteArrayOutputStream(); ByteArrayOutputStream bos = new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(bos); DataOutputStream dos = new DataOutputStream(bos);
dos.writeByte(ControlMessage.TYPE_SET_CLIPBOARD); dos.writeByte(ControlMessage.TYPE_SET_CLIPBOARD);
@ -278,56 +272,54 @@ public class ControlMessageReaderTest {
byte[] packet = bos.toByteArray(); byte[] packet = bos.toByteArray();
reader.readFrom(new ByteArrayInputStream(packet)); ByteArrayInputStream bis = new ByteArrayInputStream(packet);
ControlMessage event = reader.next(); ControlMessageReader reader = new ControlMessageReader(bis);
ControlMessage event = reader.read();
Assert.assertEquals(ControlMessage.TYPE_SET_CLIPBOARD, event.getType()); Assert.assertEquals(ControlMessage.TYPE_SET_CLIPBOARD, event.getType());
Assert.assertEquals(0x0807060504030201L, event.getSequence()); Assert.assertEquals(0x0807060504030201L, event.getSequence());
Assert.assertEquals(text, event.getText()); Assert.assertEquals(text, event.getText());
Assert.assertTrue(event.getPaste()); Assert.assertTrue(event.getPaste());
Assert.assertEquals(-1, bis.read()); // EOS
} }
@Test @Test
public void testParseSetScreenPowerMode() throws IOException { public void testParseSetScreenPowerMode() throws IOException {
ControlMessageReader reader = new ControlMessageReader();
ByteArrayOutputStream bos = new ByteArrayOutputStream(); ByteArrayOutputStream bos = new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(bos); DataOutputStream dos = new DataOutputStream(bos);
dos.writeByte(ControlMessage.TYPE_SET_SCREEN_POWER_MODE); dos.writeByte(ControlMessage.TYPE_SET_SCREEN_POWER_MODE);
dos.writeByte(Device.POWER_MODE_NORMAL); dos.writeByte(Device.POWER_MODE_NORMAL);
byte[] packet = bos.toByteArray(); byte[] packet = bos.toByteArray();
// The message type (1 byte) does not count ByteArrayInputStream bis = new ByteArrayInputStream(packet);
Assert.assertEquals(ControlMessageReader.SET_SCREEN_POWER_MODE_PAYLOAD_LENGTH, packet.length - 1); ControlMessageReader reader = new ControlMessageReader(bis);
reader.readFrom(new ByteArrayInputStream(packet));
ControlMessage event = reader.next();
ControlMessage event = reader.read();
Assert.assertEquals(ControlMessage.TYPE_SET_SCREEN_POWER_MODE, event.getType()); Assert.assertEquals(ControlMessage.TYPE_SET_SCREEN_POWER_MODE, event.getType());
Assert.assertEquals(Device.POWER_MODE_NORMAL, event.getAction()); Assert.assertEquals(Device.POWER_MODE_NORMAL, event.getAction());
Assert.assertEquals(-1, bis.read()); // EOS
} }
@Test @Test
public void testParseRotateDevice() throws IOException { public void testParseRotateDevice() throws IOException {
ControlMessageReader reader = new ControlMessageReader();
ByteArrayOutputStream bos = new ByteArrayOutputStream(); ByteArrayOutputStream bos = new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(bos); DataOutputStream dos = new DataOutputStream(bos);
dos.writeByte(ControlMessage.TYPE_ROTATE_DEVICE); dos.writeByte(ControlMessage.TYPE_ROTATE_DEVICE);
byte[] packet = bos.toByteArray(); byte[] packet = bos.toByteArray();
reader.readFrom(new ByteArrayInputStream(packet)); ByteArrayInputStream bis = new ByteArrayInputStream(packet);
ControlMessage event = reader.next(); ControlMessageReader reader = new ControlMessageReader(bis);
ControlMessage event = reader.read();
Assert.assertEquals(ControlMessage.TYPE_ROTATE_DEVICE, event.getType()); Assert.assertEquals(ControlMessage.TYPE_ROTATE_DEVICE, event.getType());
Assert.assertEquals(-1, bis.read()); // EOS
} }
@Test @Test
public void testParseUhidCreate() throws IOException { public void testParseUhidCreate() throws IOException {
ControlMessageReader reader = new ControlMessageReader();
ByteArrayOutputStream bos = new ByteArrayOutputStream(); ByteArrayOutputStream bos = new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(bos); DataOutputStream dos = new DataOutputStream(bos);
dos.writeByte(ControlMessage.TYPE_UHID_CREATE); dos.writeByte(ControlMessage.TYPE_UHID_CREATE);
@ -335,21 +327,21 @@ public class ControlMessageReaderTest {
byte[] data = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}; byte[] data = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11};
dos.writeShort(data.length); // size dos.writeShort(data.length); // size
dos.write(data); dos.write(data);
byte[] packet = bos.toByteArray(); byte[] packet = bos.toByteArray();
reader.readFrom(new ByteArrayInputStream(packet)); ByteArrayInputStream bis = new ByteArrayInputStream(packet);
ControlMessage event = reader.next(); ControlMessageReader reader = new ControlMessageReader(bis);
ControlMessage event = reader.read();
Assert.assertEquals(ControlMessage.TYPE_UHID_CREATE, event.getType()); Assert.assertEquals(ControlMessage.TYPE_UHID_CREATE, event.getType());
Assert.assertEquals(42, event.getId()); Assert.assertEquals(42, event.getId());
Assert.assertArrayEquals(data, event.getData()); Assert.assertArrayEquals(data, event.getData());
Assert.assertEquals(-1, bis.read()); // EOS
} }
@Test @Test
public void testParseUhidInput() throws IOException { public void testParseUhidInput() throws IOException {
ControlMessageReader reader = new ControlMessageReader();
ByteArrayOutputStream bos = new ByteArrayOutputStream(); ByteArrayOutputStream bos = new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(bos); DataOutputStream dos = new DataOutputStream(bos);
dos.writeByte(ControlMessage.TYPE_UHID_INPUT); dos.writeByte(ControlMessage.TYPE_UHID_INPUT);
@ -357,37 +349,37 @@ public class ControlMessageReaderTest {
byte[] data = {1, 2, 3, 4, 5}; byte[] data = {1, 2, 3, 4, 5};
dos.writeShort(data.length); // size dos.writeShort(data.length); // size
dos.write(data); dos.write(data);
byte[] packet = bos.toByteArray(); byte[] packet = bos.toByteArray();
reader.readFrom(new ByteArrayInputStream(packet)); ByteArrayInputStream bis = new ByteArrayInputStream(packet);
ControlMessage event = reader.next(); ControlMessageReader reader = new ControlMessageReader(bis);
ControlMessage event = reader.read();
Assert.assertEquals(ControlMessage.TYPE_UHID_INPUT, event.getType()); Assert.assertEquals(ControlMessage.TYPE_UHID_INPUT, event.getType());
Assert.assertEquals(42, event.getId()); Assert.assertEquals(42, event.getId());
Assert.assertArrayEquals(data, event.getData()); Assert.assertArrayEquals(data, event.getData());
Assert.assertEquals(-1, bis.read()); // EOS
} }
@Test @Test
public void testParseOpenHardKeyboardSettings() throws IOException { public void testParseOpenHardKeyboardSettings() throws IOException {
ControlMessageReader reader = new ControlMessageReader();
ByteArrayOutputStream bos = new ByteArrayOutputStream(); ByteArrayOutputStream bos = new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(bos); DataOutputStream dos = new DataOutputStream(bos);
dos.writeByte(ControlMessage.TYPE_OPEN_HARD_KEYBOARD_SETTINGS); dos.writeByte(ControlMessage.TYPE_OPEN_HARD_KEYBOARD_SETTINGS);
byte[] packet = bos.toByteArray(); byte[] packet = bos.toByteArray();
reader.readFrom(new ByteArrayInputStream(packet)); ByteArrayInputStream bis = new ByteArrayInputStream(packet);
ControlMessage event = reader.next(); ControlMessageReader reader = new ControlMessageReader(bis);
ControlMessage event = reader.read();
Assert.assertEquals(ControlMessage.TYPE_OPEN_HARD_KEYBOARD_SETTINGS, event.getType()); Assert.assertEquals(ControlMessage.TYPE_OPEN_HARD_KEYBOARD_SETTINGS, event.getType());
Assert.assertEquals(-1, bis.read()); // EOS
} }
@Test @Test
public void testMultiEvents() throws IOException { public void testMultiEvents() throws IOException {
ControlMessageReader reader = new ControlMessageReader();
ByteArrayOutputStream bos = new ByteArrayOutputStream(); ByteArrayOutputStream bos = new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(bos); DataOutputStream dos = new DataOutputStream(bos);
@ -404,27 +396,29 @@ public class ControlMessageReaderTest {
dos.writeInt(KeyEvent.META_CTRL_ON); dos.writeInt(KeyEvent.META_CTRL_ON);
byte[] packet = bos.toByteArray(); byte[] packet = bos.toByteArray();
reader.readFrom(new ByteArrayInputStream(packet));
ControlMessage event = reader.next(); ByteArrayInputStream bis = new ByteArrayInputStream(packet);
ControlMessageReader reader = new ControlMessageReader(bis);
ControlMessage event = reader.read();
Assert.assertEquals(ControlMessage.TYPE_INJECT_KEYCODE, event.getType()); Assert.assertEquals(ControlMessage.TYPE_INJECT_KEYCODE, event.getType());
Assert.assertEquals(KeyEvent.ACTION_UP, event.getAction()); Assert.assertEquals(KeyEvent.ACTION_UP, event.getAction());
Assert.assertEquals(KeyEvent.KEYCODE_ENTER, event.getKeycode()); Assert.assertEquals(KeyEvent.KEYCODE_ENTER, event.getKeycode());
Assert.assertEquals(0, event.getRepeat()); Assert.assertEquals(0, event.getRepeat());
Assert.assertEquals(KeyEvent.META_CTRL_ON, event.getMetaState()); Assert.assertEquals(KeyEvent.META_CTRL_ON, event.getMetaState());
event = reader.next(); event = reader.read();
Assert.assertEquals(ControlMessage.TYPE_INJECT_KEYCODE, event.getType()); Assert.assertEquals(ControlMessage.TYPE_INJECT_KEYCODE, event.getType());
Assert.assertEquals(MotionEvent.ACTION_DOWN, event.getAction()); Assert.assertEquals(MotionEvent.ACTION_DOWN, event.getAction());
Assert.assertEquals(MotionEvent.BUTTON_PRIMARY, event.getKeycode()); Assert.assertEquals(MotionEvent.BUTTON_PRIMARY, event.getKeycode());
Assert.assertEquals(1, event.getRepeat()); Assert.assertEquals(1, event.getRepeat());
Assert.assertEquals(KeyEvent.META_CTRL_ON, event.getMetaState()); Assert.assertEquals(KeyEvent.META_CTRL_ON, event.getMetaState());
Assert.assertEquals(-1, bis.read()); // EOS
} }
@Test @Test
public void testPartialEvents() throws IOException { public void testPartialEvents() throws IOException {
ControlMessageReader reader = new ControlMessageReader();
ByteArrayOutputStream bos = new ByteArrayOutputStream(); ByteArrayOutputStream bos = new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(bos); DataOutputStream dos = new DataOutputStream(bos);
@ -438,31 +432,21 @@ public class ControlMessageReaderTest {
dos.writeByte(MotionEvent.ACTION_DOWN); dos.writeByte(MotionEvent.ACTION_DOWN);
byte[] packet = bos.toByteArray(); byte[] packet = bos.toByteArray();
reader.readFrom(new ByteArrayInputStream(packet)); ByteArrayInputStream bis = new ByteArrayInputStream(packet);
ControlMessageReader reader = new ControlMessageReader(bis);
ControlMessage event = reader.next(); ControlMessage event = reader.read();
Assert.assertEquals(ControlMessage.TYPE_INJECT_KEYCODE, event.getType()); Assert.assertEquals(ControlMessage.TYPE_INJECT_KEYCODE, event.getType());
Assert.assertEquals(KeyEvent.ACTION_UP, event.getAction()); Assert.assertEquals(KeyEvent.ACTION_UP, event.getAction());
Assert.assertEquals(KeyEvent.KEYCODE_ENTER, event.getKeycode()); Assert.assertEquals(KeyEvent.KEYCODE_ENTER, event.getKeycode());
Assert.assertEquals(4, event.getRepeat()); Assert.assertEquals(4, event.getRepeat());
Assert.assertEquals(KeyEvent.META_CTRL_ON, event.getMetaState()); Assert.assertEquals(KeyEvent.META_CTRL_ON, event.getMetaState());
event = reader.next(); try {
Assert.assertNull(event); // the event is not complete event = reader.read();
Assert.fail("Reader did not reach EOF");
bos.reset(); } catch (EOFException e) {
dos.writeInt(MotionEvent.BUTTON_PRIMARY); // expected
dos.writeInt(5); // repeat }
dos.writeInt(KeyEvent.META_CTRL_ON);
packet = bos.toByteArray();
reader.readFrom(new ByteArrayInputStream(packet));
// the event is now complete
event = reader.next();
Assert.assertEquals(ControlMessage.TYPE_INJECT_KEYCODE, event.getType());
Assert.assertEquals(MotionEvent.ACTION_DOWN, event.getAction());
Assert.assertEquals(MotionEvent.BUTTON_PRIMARY, event.getKeycode());
Assert.assertEquals(5, event.getRepeat());
Assert.assertEquals(KeyEvent.META_CTRL_ON, event.getMetaState());
} }
} }

View File

@ -12,8 +12,6 @@ public class DeviceMessageWriterTest {
@Test @Test
public void testSerializeClipboard() throws IOException { public void testSerializeClipboard() throws IOException {
DeviceMessageWriter writer = new DeviceMessageWriter();
String text = "aéûoç"; String text = "aéûoç";
byte[] data = text.getBytes(StandardCharsets.UTF_8); byte[] data = text.getBytes(StandardCharsets.UTF_8);
ByteArrayOutputStream bos = new ByteArrayOutputStream(); ByteArrayOutputStream bos = new ByteArrayOutputStream();
@ -21,12 +19,13 @@ public class DeviceMessageWriterTest {
dos.writeByte(DeviceMessage.TYPE_CLIPBOARD); dos.writeByte(DeviceMessage.TYPE_CLIPBOARD);
dos.writeInt(data.length); dos.writeInt(data.length);
dos.write(data); dos.write(data);
byte[] expected = bos.toByteArray(); byte[] expected = bos.toByteArray();
DeviceMessage msg = DeviceMessage.createClipboard(text);
bos = new ByteArrayOutputStream(); bos = new ByteArrayOutputStream();
writer.writeTo(msg, bos); DeviceMessageWriter writer = new DeviceMessageWriter(bos);
DeviceMessage msg = DeviceMessage.createClipboard(text);
writer.write(msg);
byte[] actual = bos.toByteArray(); byte[] actual = bos.toByteArray();
@ -35,18 +34,17 @@ public class DeviceMessageWriterTest {
@Test @Test
public void testSerializeAckSetClipboard() throws IOException { public void testSerializeAckSetClipboard() throws IOException {
DeviceMessageWriter writer = new DeviceMessageWriter();
ByteArrayOutputStream bos = new ByteArrayOutputStream(); ByteArrayOutputStream bos = new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(bos); DataOutputStream dos = new DataOutputStream(bos);
dos.writeByte(DeviceMessage.TYPE_ACK_CLIPBOARD); dos.writeByte(DeviceMessage.TYPE_ACK_CLIPBOARD);
dos.writeLong(0x0102030405060708L); dos.writeLong(0x0102030405060708L);
byte[] expected = bos.toByteArray(); byte[] expected = bos.toByteArray();
DeviceMessage msg = DeviceMessage.createAckClipboard(0x0102030405060708L);
bos = new ByteArrayOutputStream(); bos = new ByteArrayOutputStream();
writer.writeTo(msg, bos); DeviceMessageWriter writer = new DeviceMessageWriter(bos);
DeviceMessage msg = DeviceMessage.createAckClipboard(0x0102030405060708L);
writer.write(msg);
byte[] actual = bos.toByteArray(); byte[] actual = bos.toByteArray();
@ -55,8 +53,6 @@ public class DeviceMessageWriterTest {
@Test @Test
public void testSerializeUhidOutput() throws IOException { public void testSerializeUhidOutput() throws IOException {
DeviceMessageWriter writer = new DeviceMessageWriter();
ByteArrayOutputStream bos = new ByteArrayOutputStream(); ByteArrayOutputStream bos = new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(bos); DataOutputStream dos = new DataOutputStream(bos);
dos.writeByte(DeviceMessage.TYPE_UHID_OUTPUT); dos.writeByte(DeviceMessage.TYPE_UHID_OUTPUT);
@ -64,12 +60,13 @@ public class DeviceMessageWriterTest {
byte[] data = {1, 2, 3, 4, 5}; byte[] data = {1, 2, 3, 4, 5};
dos.writeShort(data.length); dos.writeShort(data.length);
dos.write(data); dos.write(data);
byte[] expected = bos.toByteArray(); byte[] expected = bos.toByteArray();
DeviceMessage msg = DeviceMessage.createUhidOutput(42, data);
bos = new ByteArrayOutputStream(); bos = new ByteArrayOutputStream();
writer.writeTo(msg, bos); DeviceMessageWriter writer = new DeviceMessageWriter(bos);
DeviceMessage msg = DeviceMessage.createUhidOutput(42, data);
writer.write(msg);
byte[] actual = bos.toByteArray(); byte[] actual = bos.toByteArray();