Compare commits

..

6 Commits

Author SHA1 Message Date
eiyooooo
63dd07109f Add rotation support for non-default display
Use new methods introduced by this commit:
<90c9005e68%5E%21/>

PR #4698 <https://github.com/Genymobile/scrcpy/pull/4698>

Signed-off-by: Romain Vimont <rom@rom1v.com>
2024-02-26 10:07:11 +01:00
Romain Vimont
746eaea556 Add missing clipboard workaround for IQOO device
The first part of the workaround fixed getPrimaryClip(). This part fixes
setPrimaryClip().

Fixes #4703 <https://github.com/Genymobile/scrcpy/issues/4703>
Refs 5ce8672ebc
Refs #4492 <https://github.com/Genymobile/scrcpy/issues/4492>
2024-02-26 08:36:18 +01:00
Romain Vimont
78a7e4f293 Use sc_ prefix for device sender 2024-02-23 20:07:52 +01:00
Romain Vimont
9858eff856 Fix device message deserialization checks
If any message is incomplete, the deserialization method must return
immediately.
2024-02-23 20:07:52 +01:00
Romain Vimont
9e22f3bf1c Replace unsigned char by uint8_t for buffers
For consistency.
2024-02-23 20:07:52 +01:00
Romain Vimont
25f1e703b7 Extract ControlChannel class
This prevents many components from depending on the whole
DesktopConnection.
2024-02-23 20:07:16 +01:00
19 changed files with 223 additions and 125 deletions

View File

@@ -87,7 +87,7 @@ write_position(uint8_t *buf, const struct sc_position *position) {
// write length (4 bytes) + string (non null-terminated)
static size_t
write_string(const char *utf8, size_t max_len, unsigned char *buf) {
write_string(const char *utf8, size_t max_len, uint8_t *buf) {
size_t len = sc_str_utf8_truncation_index(utf8, max_len);
sc_write32be(buf, len);
memcpy(&buf[4], utf8, len);
@@ -95,7 +95,7 @@ write_string(const char *utf8, size_t max_len, unsigned char *buf) {
}
size_t
sc_control_msg_serialize(const struct sc_control_msg *msg, unsigned char *buf) {
sc_control_msg_serialize(const struct sc_control_msg *msg, uint8_t *buf) {
buf[0] = msg->type;
switch (msg->type) {
case SC_CONTROL_MSG_TYPE_INJECT_KEYCODE:

View File

@@ -98,7 +98,7 @@ struct sc_control_msg {
// buf size must be at least CONTROL_MSG_MAX_SIZE
// return the number of bytes written
size_t
sc_control_msg_serialize(const struct sc_control_msg *msg, unsigned char *buf);
sc_control_msg_serialize(const struct sc_control_msg *msg, uint8_t *buf);
void
sc_control_msg_log(const struct sc_control_msg *msg);

View File

@@ -84,7 +84,7 @@ sc_controller_push_msg(struct sc_controller *controller,
static bool
process_msg(struct sc_controller *controller,
const struct sc_control_msg *msg) {
static unsigned char serialized_msg[SC_CONTROL_MSG_MAX_SIZE];
static uint8_t serialized_msg[SC_CONTROL_MSG_MAX_SIZE];
size_t length = sc_control_msg_serialize(msg, serialized_msg);
if (!length) {
return false;

View File

@@ -8,19 +8,22 @@
#include "util/log.h"
ssize_t
device_msg_deserialize(const unsigned char *buf, size_t len,
struct device_msg *msg) {
if (len < 5) {
// at least type + empty string length
return 0; // not available
sc_device_msg_deserialize(const uint8_t *buf, size_t len,
struct sc_device_msg *msg) {
if (!len) {
return 0; // no message
}
msg->type = buf[0];
switch (msg->type) {
case DEVICE_MSG_TYPE_CLIPBOARD: {
if (len < 5) {
// at least type + empty string length
return 0; // no complete message
}
size_t clipboard_len = sc_read32be(&buf[1]);
if (clipboard_len > len - 5) {
return 0; // not available
return 0; // no complete message
}
char *text = malloc(clipboard_len + 1);
if (!text) {
@@ -36,6 +39,9 @@ device_msg_deserialize(const unsigned char *buf, size_t len,
return 5 + clipboard_len;
}
case DEVICE_MSG_TYPE_ACK_CLIPBOARD: {
if (len < 9) {
return 0; // no complete message
}
uint64_t sequence = sc_read64be(&buf[1]);
msg->ack_clipboard.sequence = sequence;
return 9;
@@ -47,7 +53,7 @@ device_msg_deserialize(const unsigned char *buf, size_t len,
}
void
device_msg_destroy(struct device_msg *msg) {
sc_device_msg_destroy(struct sc_device_msg *msg) {
if (msg->type == DEVICE_MSG_TYPE_CLIPBOARD) {
free(msg->clipboard.text);
}

View File

@@ -11,13 +11,13 @@
// type: 1 byte; length: 4 bytes
#define DEVICE_MSG_TEXT_MAX_LENGTH (DEVICE_MSG_MAX_SIZE - 5)
enum device_msg_type {
enum sc_device_msg_type {
DEVICE_MSG_TYPE_CLIPBOARD,
DEVICE_MSG_TYPE_ACK_CLIPBOARD,
};
struct device_msg {
enum device_msg_type type;
struct sc_device_msg {
enum sc_device_msg_type type;
union {
struct {
char *text; // owned, to be freed by free()
@@ -30,10 +30,10 @@ struct device_msg {
// return the number of bytes consumed (0 for no msg available, -1 on error)
ssize_t
device_msg_deserialize(const unsigned char *buf, size_t len,
struct device_msg *msg);
sc_device_msg_deserialize(const uint8_t *buf, size_t len,
struct sc_device_msg *msg);
void
device_msg_destroy(struct device_msg *msg);
sc_device_msg_destroy(struct sc_device_msg *msg);
#endif

View File

@@ -1,6 +1,7 @@
#include "receiver.h"
#include <assert.h>
#include <stdint.h>
#include <SDL2/SDL_clipboard.h>
#include "device_msg.h"
@@ -26,7 +27,7 @@ sc_receiver_destroy(struct sc_receiver *receiver) {
}
static void
process_msg(struct sc_receiver *receiver, struct device_msg *msg) {
process_msg(struct sc_receiver *receiver, struct sc_device_msg *msg) {
switch (msg->type) {
case DEVICE_MSG_TYPE_CLIPBOARD: {
char *current = SDL_GetClipboardText();
@@ -51,11 +52,11 @@ process_msg(struct sc_receiver *receiver, struct device_msg *msg) {
}
static ssize_t
process_msgs(struct sc_receiver *receiver, const unsigned char *buf, size_t len) {
process_msgs(struct sc_receiver *receiver, const uint8_t *buf, size_t len) {
size_t head = 0;
for (;;) {
struct device_msg msg;
ssize_t r = device_msg_deserialize(&buf[head], len - head, &msg);
struct sc_device_msg msg;
ssize_t r = sc_device_msg_deserialize(&buf[head], len - head, &msg);
if (r == -1) {
return -1;
}
@@ -64,7 +65,7 @@ process_msgs(struct sc_receiver *receiver, const unsigned char *buf, size_t len)
}
process_msg(receiver, &msg);
device_msg_destroy(&msg);
sc_device_msg_destroy(&msg);
head += r;
assert(head <= len);
@@ -78,7 +79,7 @@ static int
run_receiver(void *data) {
struct sc_receiver *receiver = data;
static unsigned char buf[DEVICE_MSG_MAX_SIZE];
static uint8_t buf[DEVICE_MSG_MAX_SIZE];
size_t head = 0;
for (;;) {

View File

@@ -498,7 +498,7 @@ sc_server_init(struct sc_server *server, const struct sc_server_params *params,
static bool
device_read_info(struct sc_intr *intr, sc_socket device_socket,
struct sc_server_info *info) {
unsigned char buf[SC_DEVICE_NAME_FIELD_LENGTH];
uint8_t buf[SC_DEVICE_NAME_FIELD_LENGTH];
ssize_t r = net_recv_all_intr(intr, device_socket, buf, sizeof(buf));
if (r < SC_DEVICE_NAME_FIELD_LENGTH) {
LOGE("Could not retrieve device information");

View File

@@ -113,7 +113,7 @@ sc_aoa_register_hid(struct sc_aoa *aoa, uint16_t accessory_id,
static bool
sc_aoa_set_hid_report_desc(struct sc_aoa *aoa, uint16_t accessory_id,
const unsigned char *report_desc,
const uint8_t *report_desc,
uint16_t report_desc_size) {
uint8_t request_type = LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR;
uint8_t request = ACCESSORY_SET_HID_REPORT_DESC;
@@ -150,7 +150,7 @@ sc_aoa_set_hid_report_desc(struct sc_aoa *aoa, uint16_t accessory_id,
bool
sc_aoa_setup_hid(struct sc_aoa *aoa, uint16_t accessory_id,
const unsigned char *report_desc, uint16_t report_desc_size) {
const uint8_t *report_desc, uint16_t report_desc_size) {
bool ok = sc_aoa_register_hid(aoa, accessory_id, report_desc_size);
if (!ok) {
return false;

View File

@@ -57,7 +57,7 @@ sc_aoa_join(struct sc_aoa *aoa);
bool
sc_aoa_setup_hid(struct sc_aoa *aoa, uint16_t accessory_id,
const unsigned char *report_desc, uint16_t report_desc_size);
const uint8_t *report_desc, uint16_t report_desc_size);
bool
sc_aoa_unregister_hid(struct sc_aoa *aoa, uint16_t accessory_id);

View File

@@ -1,6 +1,7 @@
#include "common.h"
#include <assert.h>
#include <stdint.h>
#include <string.h>
#include "control_msg.h"
@@ -16,11 +17,11 @@ static void test_serialize_inject_keycode(void) {
},
};
unsigned char buf[SC_CONTROL_MSG_MAX_SIZE];
uint8_t buf[SC_CONTROL_MSG_MAX_SIZE];
size_t size = sc_control_msg_serialize(&msg, buf);
assert(size == 14);
const unsigned char expected[] = {
const uint8_t expected[] = {
SC_CONTROL_MSG_TYPE_INJECT_KEYCODE,
0x01, // AKEY_EVENT_ACTION_UP
0x00, 0x00, 0x00, 0x42, // AKEYCODE_ENTER
@@ -38,11 +39,11 @@ static void test_serialize_inject_text(void) {
},
};
unsigned char buf[SC_CONTROL_MSG_MAX_SIZE];
uint8_t buf[SC_CONTROL_MSG_MAX_SIZE];
size_t size = sc_control_msg_serialize(&msg, buf);
assert(size == 18);
const unsigned char expected[] = {
const uint8_t expected[] = {
SC_CONTROL_MSG_TYPE_INJECT_TEXT,
0x00, 0x00, 0x00, 0x0d, // text length
'h', 'e', 'l', 'l', 'o', ',', ' ', 'w', 'o', 'r', 'l', 'd', '!', // text
@@ -58,11 +59,11 @@ static void test_serialize_inject_text_long(void) {
text[SC_CONTROL_MSG_INJECT_TEXT_MAX_LENGTH] = '\0';
msg.inject_text.text = text;
unsigned char buf[SC_CONTROL_MSG_MAX_SIZE];
uint8_t buf[SC_CONTROL_MSG_MAX_SIZE];
size_t size = sc_control_msg_serialize(&msg, buf);
assert(size == 5 + SC_CONTROL_MSG_INJECT_TEXT_MAX_LENGTH);
unsigned char expected[5 + SC_CONTROL_MSG_INJECT_TEXT_MAX_LENGTH];
uint8_t expected[5 + SC_CONTROL_MSG_INJECT_TEXT_MAX_LENGTH];
expected[0] = SC_CONTROL_MSG_TYPE_INJECT_TEXT;
expected[1] = 0x00;
expected[2] = 0x00;
@@ -95,11 +96,11 @@ static void test_serialize_inject_touch_event(void) {
},
};
unsigned char buf[SC_CONTROL_MSG_MAX_SIZE];
uint8_t buf[SC_CONTROL_MSG_MAX_SIZE];
size_t size = sc_control_msg_serialize(&msg, buf);
assert(size == 32);
const unsigned char expected[] = {
const uint8_t expected[] = {
SC_CONTROL_MSG_TYPE_INJECT_TOUCH_EVENT,
0x00, // AKEY_EVENT_ACTION_DOWN
0x12, 0x34, 0x56, 0x78, 0x87, 0x65, 0x43, 0x21, // pointer id
@@ -132,11 +133,11 @@ static void test_serialize_inject_scroll_event(void) {
},
};
unsigned char buf[SC_CONTROL_MSG_MAX_SIZE];
uint8_t buf[SC_CONTROL_MSG_MAX_SIZE];
size_t size = sc_control_msg_serialize(&msg, buf);
assert(size == 21);
const unsigned char expected[] = {
const uint8_t expected[] = {
SC_CONTROL_MSG_TYPE_INJECT_SCROLL_EVENT,
0x00, 0x00, 0x01, 0x04, 0x00, 0x00, 0x04, 0x02, // 260 1026
0x04, 0x38, 0x07, 0x80, // 1080 1920
@@ -155,11 +156,11 @@ static void test_serialize_back_or_screen_on(void) {
},
};
unsigned char buf[SC_CONTROL_MSG_MAX_SIZE];
uint8_t buf[SC_CONTROL_MSG_MAX_SIZE];
size_t size = sc_control_msg_serialize(&msg, buf);
assert(size == 2);
const unsigned char expected[] = {
const uint8_t expected[] = {
SC_CONTROL_MSG_TYPE_BACK_OR_SCREEN_ON,
0x01, // AKEY_EVENT_ACTION_UP
};
@@ -171,11 +172,11 @@ static void test_serialize_expand_notification_panel(void) {
.type = SC_CONTROL_MSG_TYPE_EXPAND_NOTIFICATION_PANEL,
};
unsigned char buf[SC_CONTROL_MSG_MAX_SIZE];
uint8_t buf[SC_CONTROL_MSG_MAX_SIZE];
size_t size = sc_control_msg_serialize(&msg, buf);
assert(size == 1);
const unsigned char expected[] = {
const uint8_t expected[] = {
SC_CONTROL_MSG_TYPE_EXPAND_NOTIFICATION_PANEL,
};
assert(!memcmp(buf, expected, sizeof(expected)));
@@ -186,11 +187,11 @@ static void test_serialize_expand_settings_panel(void) {
.type = SC_CONTROL_MSG_TYPE_EXPAND_SETTINGS_PANEL,
};
unsigned char buf[SC_CONTROL_MSG_MAX_SIZE];
uint8_t buf[SC_CONTROL_MSG_MAX_SIZE];
size_t size = sc_control_msg_serialize(&msg, buf);
assert(size == 1);
const unsigned char expected[] = {
const uint8_t expected[] = {
SC_CONTROL_MSG_TYPE_EXPAND_SETTINGS_PANEL,
};
assert(!memcmp(buf, expected, sizeof(expected)));
@@ -201,11 +202,11 @@ static void test_serialize_collapse_panels(void) {
.type = SC_CONTROL_MSG_TYPE_COLLAPSE_PANELS,
};
unsigned char buf[SC_CONTROL_MSG_MAX_SIZE];
uint8_t buf[SC_CONTROL_MSG_MAX_SIZE];
size_t size = sc_control_msg_serialize(&msg, buf);
assert(size == 1);
const unsigned char expected[] = {
const uint8_t expected[] = {
SC_CONTROL_MSG_TYPE_COLLAPSE_PANELS,
};
assert(!memcmp(buf, expected, sizeof(expected)));
@@ -219,11 +220,11 @@ static void test_serialize_get_clipboard(void) {
},
};
unsigned char buf[SC_CONTROL_MSG_MAX_SIZE];
uint8_t buf[SC_CONTROL_MSG_MAX_SIZE];
size_t size = sc_control_msg_serialize(&msg, buf);
assert(size == 2);
const unsigned char expected[] = {
const uint8_t expected[] = {
SC_CONTROL_MSG_TYPE_GET_CLIPBOARD,
SC_COPY_KEY_COPY,
};
@@ -240,11 +241,11 @@ static void test_serialize_set_clipboard(void) {
},
};
unsigned char buf[SC_CONTROL_MSG_MAX_SIZE];
uint8_t buf[SC_CONTROL_MSG_MAX_SIZE];
size_t size = sc_control_msg_serialize(&msg, buf);
assert(size == 27);
const unsigned char expected[] = {
const uint8_t expected[] = {
SC_CONTROL_MSG_TYPE_SET_CLIPBOARD,
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, // sequence
1, // paste
@@ -269,11 +270,11 @@ static void test_serialize_set_clipboard_long(void) {
text[SC_CONTROL_MSG_CLIPBOARD_TEXT_MAX_LENGTH] = '\0';
msg.set_clipboard.text = text;
unsigned char buf[SC_CONTROL_MSG_MAX_SIZE];
uint8_t buf[SC_CONTROL_MSG_MAX_SIZE];
size_t size = sc_control_msg_serialize(&msg, buf);
assert(size == SC_CONTROL_MSG_MAX_SIZE);
unsigned char expected[SC_CONTROL_MSG_MAX_SIZE] = {
uint8_t expected[SC_CONTROL_MSG_MAX_SIZE] = {
SC_CONTROL_MSG_TYPE_SET_CLIPBOARD,
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, // sequence
1, // paste
@@ -296,11 +297,11 @@ static void test_serialize_set_screen_power_mode(void) {
},
};
unsigned char buf[SC_CONTROL_MSG_MAX_SIZE];
uint8_t buf[SC_CONTROL_MSG_MAX_SIZE];
size_t size = sc_control_msg_serialize(&msg, buf);
assert(size == 2);
const unsigned char expected[] = {
const uint8_t expected[] = {
SC_CONTROL_MSG_TYPE_SET_SCREEN_POWER_MODE,
0x02, // SC_SCREEN_POWER_MODE_NORMAL
};
@@ -312,11 +313,11 @@ static void test_serialize_rotate_device(void) {
.type = SC_CONTROL_MSG_TYPE_ROTATE_DEVICE,
};
unsigned char buf[SC_CONTROL_MSG_MAX_SIZE];
uint8_t buf[SC_CONTROL_MSG_MAX_SIZE];
size_t size = sc_control_msg_serialize(&msg, buf);
assert(size == 1);
const unsigned char expected[] = {
const uint8_t expected[] = {
SC_CONTROL_MSG_TYPE_ROTATE_DEVICE,
};
assert(!memcmp(buf, expected, sizeof(expected)));

View File

@@ -1,32 +1,32 @@
#include "common.h"
#include <assert.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include "device_msg.h"
#include <stdio.h>
static void test_deserialize_clipboard(void) {
const unsigned char input[] = {
const uint8_t input[] = {
DEVICE_MSG_TYPE_CLIPBOARD,
0x00, 0x00, 0x00, 0x03, // text length
0x41, 0x42, 0x43, // "ABC"
};
struct device_msg msg;
ssize_t r = device_msg_deserialize(input, sizeof(input), &msg);
struct sc_device_msg msg;
ssize_t r = sc_device_msg_deserialize(input, sizeof(input), &msg);
assert(r == 8);
assert(msg.type == DEVICE_MSG_TYPE_CLIPBOARD);
assert(msg.clipboard.text);
assert(!strcmp("ABC", msg.clipboard.text));
device_msg_destroy(&msg);
sc_device_msg_destroy(&msg);
}
static void test_deserialize_clipboard_big(void) {
unsigned char input[DEVICE_MSG_MAX_SIZE];
uint8_t input[DEVICE_MSG_MAX_SIZE];
input[0] = DEVICE_MSG_TYPE_CLIPBOARD;
input[1] = (DEVICE_MSG_TEXT_MAX_LENGTH & 0xff000000u) >> 24;
input[2] = (DEVICE_MSG_TEXT_MAX_LENGTH & 0x00ff0000u) >> 16;
@@ -35,8 +35,8 @@ static void test_deserialize_clipboard_big(void) {
memset(input + 5, 'a', DEVICE_MSG_TEXT_MAX_LENGTH);
struct device_msg msg;
ssize_t r = device_msg_deserialize(input, sizeof(input), &msg);
struct sc_device_msg msg;
ssize_t r = sc_device_msg_deserialize(input, sizeof(input), &msg);
assert(r == DEVICE_MSG_MAX_SIZE);
assert(msg.type == DEVICE_MSG_TYPE_CLIPBOARD);
@@ -44,17 +44,17 @@ static void test_deserialize_clipboard_big(void) {
assert(strlen(msg.clipboard.text) == DEVICE_MSG_TEXT_MAX_LENGTH);
assert(msg.clipboard.text[0] == 'a');
device_msg_destroy(&msg);
sc_device_msg_destroy(&msg);
}
static void test_deserialize_ack_set_clipboard(void) {
const unsigned char input[] = {
const uint8_t input[] = {
DEVICE_MSG_TYPE_ACK_CLIPBOARD,
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, // sequence
};
struct device_msg msg;
ssize_t r = device_msg_deserialize(input, sizeof(input), &msg);
struct sc_device_msg msg;
ssize_t r = sc_device_msg_deserialize(input, sizeof(input), &msg);
assert(r == 9);
assert(msg.type == DEVICE_MSG_TYPE_ACK_CLIPBOARD);

View File

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

View File

@@ -27,7 +27,7 @@ public class Controller implements AsyncProcessor {
private Thread thread;
private final Device device;
private final DesktopConnection connection;
private final ControlChannel controlChannel;
private final CleanUp cleanUp;
private final DeviceMessageSender sender;
private final boolean clipboardAutosync;
@@ -42,14 +42,14 @@ public class Controller implements AsyncProcessor {
private boolean keepPowerModeOff;
public Controller(Device device, DesktopConnection connection, CleanUp cleanUp, boolean clipboardAutosync, boolean powerOn) {
public Controller(Device device, ControlChannel controlChannel, CleanUp cleanUp, boolean clipboardAutosync, boolean powerOn) {
this.device = device;
this.connection = connection;
this.controlChannel = controlChannel;
this.cleanUp = cleanUp;
this.clipboardAutosync = clipboardAutosync;
this.powerOn = powerOn;
initPointers();
sender = new DeviceMessageSender(connection);
sender = new DeviceMessageSender(controlChannel);
}
private void initPointers() {
@@ -123,7 +123,7 @@ public class Controller implements AsyncProcessor {
}
private void handleEvent() throws IOException {
ControlMessage msg = connection.receiveControlMessage();
ControlMessage msg = controlChannel.recv();
switch (msg.getType()) {
case ControlMessage.TYPE_INJECT_KEYCODE:
if (device.supportsInputEvents()) {
@@ -180,7 +180,7 @@ public class Controller implements AsyncProcessor {
}
break;
case ControlMessage.TYPE_ROTATE_DEVICE:
Device.rotateDevice();
device.rotateDevice();
break;
default:
// do nothing

View File

@@ -7,8 +7,6 @@ import android.net.LocalSocketAddress;
import java.io.Closeable;
import java.io.FileDescriptor;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
public final class DesktopConnection implements Closeable {
@@ -24,25 +22,16 @@ public final class DesktopConnection implements Closeable {
private final FileDescriptor audioFd;
private final LocalSocket controlSocket;
private final InputStream controlInputStream;
private final OutputStream controlOutputStream;
private final ControlMessageReader reader = new ControlMessageReader();
private final DeviceMessageWriter writer = new DeviceMessageWriter();
private final ControlChannel controlChannel;
private DesktopConnection(LocalSocket videoSocket, LocalSocket audioSocket, LocalSocket controlSocket) throws IOException {
this.videoSocket = videoSocket;
this.controlSocket = controlSocket;
this.audioSocket = audioSocket;
if (controlSocket != null) {
controlInputStream = controlSocket.getInputStream();
controlOutputStream = controlSocket.getOutputStream();
} else {
controlInputStream = null;
controlOutputStream = null;
}
this.controlSocket = controlSocket;
videoFd = videoSocket != null ? videoSocket.getFileDescriptor() : null;
audioFd = audioSocket != null ? audioSocket.getFileDescriptor() : null;
controlChannel = controlSocket != null ? new ControlChannel(controlSocket) : null;
}
private static LocalSocket connect(String abstractName) throws IOException {
@@ -179,16 +168,7 @@ public final class DesktopConnection implements Closeable {
return audioFd;
}
public ControlMessage receiveControlMessage() throws IOException {
ControlMessage msg = reader.next();
while (msg == null) {
reader.readFrom(controlInputStream);
msg = reader.next();
}
return msg;
}
public void sendDeviceMessage(DeviceMessage msg) throws IOException {
writer.writeTo(msg, controlOutputStream);
public ControlChannel getControlChannel() {
return controlChannel;
}
}

View File

@@ -359,21 +359,30 @@ public final class Device {
/**
* Disable auto-rotation (if enabled), set the screen rotation and re-enable auto-rotation (if it was enabled).
*/
public static void rotateDevice() {
public void rotateDevice() {
WindowManager wm = ServiceManager.getWindowManager();
boolean accelerometerRotation = !wm.isRotationFrozen();
boolean accelerometerRotation = !wm.isRotationFrozen(displayId);
int currentRotation = wm.getRotation();
int currentRotation = getCurrentRotation(displayId);
int newRotation = (currentRotation & 1) ^ 1; // 0->1, 1->0, 2->1, 3->0
String newRotationString = newRotation == 0 ? "portrait" : "landscape";
Ln.i("Device rotation requested: " + newRotationString);
wm.freezeRotation(newRotation);
wm.freezeRotation(displayId, newRotation);
// restore auto-rotate if necessary
if (accelerometerRotation) {
wm.thawRotation();
wm.thawRotation(displayId);
}
}
}
private static int getCurrentRotation(int displayId) {
if (displayId == 0) {
return ServiceManager.getWindowManager().getRotation();
}
DisplayInfo displayInfo = ServiceManager.getDisplayManager().getDisplayInfo(displayId);
return displayInfo.getRotation();
}
}

View File

@@ -4,7 +4,7 @@ import java.io.IOException;
public final class DeviceMessageSender {
private final DesktopConnection connection;
private final ControlChannel controlChannel;
private Thread thread;
@@ -12,8 +12,8 @@ public final class DeviceMessageSender {
private long ack;
public DeviceMessageSender(DesktopConnection connection) {
this.connection = connection;
public DeviceMessageSender(ControlChannel controlChannel) {
this.controlChannel = controlChannel;
}
public synchronized void pushClipboardText(String text) {
@@ -43,11 +43,11 @@ public final class DeviceMessageSender {
if (sequence != DeviceMessage.SEQUENCE_INVALID) {
DeviceMessage event = DeviceMessage.createAckClipboard(sequence);
connection.sendDeviceMessage(event);
controlChannel.send(event);
}
if (text != null) {
DeviceMessage event = DeviceMessage.createClipboard(text);
connection.sendDeviceMessage(event);
controlChannel.send(event);
}
}
}

View File

@@ -131,7 +131,8 @@ public final class Server {
}
if (control) {
Controller controller = new Controller(device, connection, cleanUp, options.getClipboardAutosync(), options.getPowerOn());
ControlChannel controlChannel = connection.getControlChannel();
Controller controller = new Controller(device, controlChannel, cleanUp, options.getClipboardAutosync(), options.getPowerOn());
device.setClipboardListener(text -> controller.getSender().pushClipboardText(text));
asyncProcessors.add(controller);
}

View File

@@ -87,9 +87,15 @@ public final class ClipboardManager {
setPrimaryClipMethod = manager.getClass().getMethod("setPrimaryClip", ClipData.class, String.class, String.class, int.class);
setMethodVersion = 1;
} catch (NoSuchMethodException e2) {
setPrimaryClipMethod = manager.getClass()
.getMethod("setPrimaryClip", ClipData.class, String.class, String.class, int.class, int.class);
setMethodVersion = 2;
try {
setPrimaryClipMethod = manager.getClass()
.getMethod("setPrimaryClip", ClipData.class, String.class, String.class, int.class, int.class);
setMethodVersion = 2;
} catch (NoSuchMethodException e3) {
setPrimaryClipMethod = manager.getClass()
.getMethod("setPrimaryClip", ClipData.class, String.class, String.class, int.class, int.class, boolean.class);
setMethodVersion = 3;
}
}
}
}
@@ -132,9 +138,12 @@ public final class ClipboardManager {
case 1:
method.invoke(manager, clipData, FakeContext.PACKAGE_NAME, null, FakeContext.ROOT_UID);
break;
default:
case 2:
method.invoke(manager, clipData, FakeContext.PACKAGE_NAME, null, FakeContext.ROOT_UID, 0);
break;
default:
// The last boolean parameter is "userOperate"
method.invoke(manager, clipData, FakeContext.PACKAGE_NAME, null, FakeContext.ROOT_UID, 0, true);
}
}

View File

@@ -13,8 +13,11 @@ public final class WindowManager {
private final IInterface manager;
private Method getRotationMethod;
private Method freezeRotationMethod;
private Method freezeDisplayRotationMethod;
private Method isRotationFrozenMethod;
private Method isDisplayRotationFrozenMethod;
private Method thawRotationMethod;
private Method thawDisplayRotationMethod;
static WindowManager create() {
IInterface manager = ServiceManager.getService("window", "android.view.IWindowManager");
@@ -47,6 +50,15 @@ public final class WindowManager {
return freezeRotationMethod;
}
// New method added by this commit:
// <https://android.googlesource.com/platform/frameworks/base/+/90c9005e687aa0f63f1ac391adc1e8878ab31759%5E%21/>
private Method getFreezeDisplayRotationMethod() throws NoSuchMethodException {
if (freezeDisplayRotationMethod == null) {
freezeDisplayRotationMethod = manager.getClass().getMethod("freezeDisplayRotation", int.class, int.class);
}
return freezeDisplayRotationMethod;
}
private Method getIsRotationFrozenMethod() throws NoSuchMethodException {
if (isRotationFrozenMethod == null) {
isRotationFrozenMethod = manager.getClass().getMethod("isRotationFrozen");
@@ -54,6 +66,15 @@ public final class WindowManager {
return isRotationFrozenMethod;
}
// New method added by this commit:
// <https://android.googlesource.com/platform/frameworks/base/+/90c9005e687aa0f63f1ac391adc1e8878ab31759%5E%21/>
private Method getIsDisplayRotationFrozenMethod() throws NoSuchMethodException {
if (isDisplayRotationFrozenMethod == null) {
isDisplayRotationFrozenMethod = manager.getClass().getMethod("isDisplayRotationFrozen", int.class);
}
return isDisplayRotationFrozenMethod;
}
private Method getThawRotationMethod() throws NoSuchMethodException {
if (thawRotationMethod == null) {
thawRotationMethod = manager.getClass().getMethod("thawRotation");
@@ -61,6 +82,15 @@ public final class WindowManager {
return thawRotationMethod;
}
// New method added by this commit:
// <https://android.googlesource.com/platform/frameworks/base/+/90c9005e687aa0f63f1ac391adc1e8878ab31759%5E%21/>
private Method getThawDisplayRotationMethod() throws NoSuchMethodException {
if (thawDisplayRotationMethod == null) {
thawDisplayRotationMethod = manager.getClass().getMethod("thawDisplayRotation", int.class);
}
return thawDisplayRotationMethod;
}
public int getRotation() {
try {
Method method = getGetRotationMethod();
@@ -71,29 +101,57 @@ public final class WindowManager {
}
}
public void freezeRotation(int rotation) {
public void freezeRotation(int displayId, int rotation) {
try {
Method method = getFreezeRotationMethod();
method.invoke(manager, rotation);
try {
Method method = getFreezeDisplayRotationMethod();
method.invoke(manager, displayId, rotation);
} catch (ReflectiveOperationException e) {
if (displayId == 0) {
Method method = getFreezeRotationMethod();
method.invoke(manager, rotation);
} else {
Ln.e("Could not invoke method", e);
}
}
} catch (ReflectiveOperationException e) {
Ln.e("Could not invoke method", e);
}
}
public boolean isRotationFrozen() {
public boolean isRotationFrozen(int displayId) {
try {
Method method = getIsRotationFrozenMethod();
return (boolean) method.invoke(manager);
try {
Method method = getIsDisplayRotationFrozenMethod();
return (boolean) method.invoke(manager, displayId);
} catch (ReflectiveOperationException e) {
if (displayId == 0) {
Method method = getIsRotationFrozenMethod();
return (boolean) method.invoke(manager);
} else {
Ln.e("Could not invoke method", e);
return false;
}
}
} catch (ReflectiveOperationException e) {
Ln.e("Could not invoke method", e);
return false;
}
}
public void thawRotation() {
public void thawRotation(int displayId) {
try {
Method method = getThawRotationMethod();
method.invoke(manager);
try {
Method method = getThawDisplayRotationMethod();
method.invoke(manager, displayId);
} catch (ReflectiveOperationException e) {
if (displayId == 0) {
Method method = getThawRotationMethod();
method.invoke(manager);
} else {
Ln.e("Could not invoke method", e);
}
}
} catch (ReflectiveOperationException e) {
Ln.e("Could not invoke method", e);
}