Compare commits

..

5 Commits

Author SHA1 Message Date
309d0371eb Define UHID vendorId and productId from the client
Let the client choose the USB ids, that it transmits in UHID_CREATE
requests.
2024-12-07 15:01:26 +01:00
a582c0cc1b Split gamepad device added/removed events
Use two separate event structs for gamepad device added and gamepad
device removed.

In theory, some data (like vendorId and productId) could be added
specifically to "device added" events.
2024-12-07 15:00:40 +01:00
696295f66d Fix gamepad axis initial value
By default, initialize axis to 0, which is represented by 0x8000 as a
16-bit unsigned value.
2024-12-07 15:00:40 +01:00
347169aab6 Fix gamepad HID descriptor
Use Z and Rz for L2/R2, which are more widely supported than
Brake/Accelerator.

The right stick must then be bound to Rx and Ry.
2024-12-06 12:53:28 +01:00
75bdd0c831 Fix HID gamepad comments 2024-12-06 12:53:07 +01:00
47 changed files with 110 additions and 244 deletions

View File

@ -2,7 +2,7 @@
source for the project. Do not download releases from random websites, even if source for the project. Do not download releases from random websites, even if
their name contains `scrcpy`.** their name contains `scrcpy`.**
# scrcpy (v3.1) # scrcpy (v3.0.2)
<img src="app/data/icon.svg" width="128" height="128" alt="scrcpy" align="right" /> <img src="app/data/icon.svg" width="128" height="128" alt="scrcpy" align="right" />

View File

@ -57,7 +57,6 @@ _scrcpy() {
--no-mipmaps --no-mipmaps
--no-mouse-hover --no-mouse-hover
--no-power-on --no-power-on
--no-vd-destroy-content
--no-vd-system-decorations --no-vd-system-decorations
--no-video --no-video
--no-video-playback --no-video-playback

View File

@ -63,7 +63,6 @@ arguments=(
'--no-mipmaps[Disable the generation of mipmaps]' '--no-mipmaps[Disable the generation of mipmaps]'
'--no-mouse-hover[Do not forward mouse hover events]' '--no-mouse-hover[Do not forward mouse hover events]'
'--no-power-on[Do not power on the device on start]' '--no-power-on[Do not power on the device on start]'
'--no-vd-destroy-content[Disable virtual display "destroy content on removal" flag]'
'--no-vd-system-decorations[Disable virtual display system decorations flag]' '--no-vd-system-decorations[Disable virtual display system decorations flag]'
'--no-video[Disable video forwarding]' '--no-video[Disable video forwarding]'
'--no-video-playback[Disable video playback]' '--no-video-playback[Disable video playback]'

View File

@ -1,68 +0,0 @@
#!/usr/bin/env bash
set -ex
DEPS_DIR=$(dirname ${BASH_SOURCE[0]})
cd "$DEPS_DIR"
. common
process_args "$@"
VERSION=1.5.0
FILENAME=dav1d-$VERSION.tar.gz
PROJECT_DIR=dav1d-$VERSION
SHA256SUM=78b15d9954b513ea92d27f39362535ded2243e1b0924fde39f37a31ebed5f76b
cd "$SOURCES_DIR"
if [[ -d "$PROJECT_DIR" ]]
then
echo "$PWD/$PROJECT_DIR" found
else
get_file "https://code.videolan.org/videolan/dav1d/-/archive/$VERSION/$FILENAME" "$FILENAME" "$SHA256SUM"
tar xf "$FILENAME" # First level directory is "$PROJECT_DIR"
fi
mkdir -p "$BUILD_DIR/$PROJECT_DIR"
cd "$BUILD_DIR/$PROJECT_DIR"
if [[ -d "$DIRNAME" ]]
then
echo "'$PWD/$DIRNAME' already exists, not reconfigured"
cd "$DIRNAME"
else
mkdir "$DIRNAME"
cd "$DIRNAME"
conf=(
--prefix="$INSTALL_DIR/$DIRNAME"
--libdir=lib
-Denable_tests=false
-Denable_tools=false
# Always build dav1d statically
--default-library=static
)
if [[ "$BUILD_TYPE" == cross ]]
then
case "$HOST" in
win32)
conf+=(
--cross-file="$SOURCES_DIR/$PROJECT_DIR/package/crossfiles/i686-w64-mingw32.meson"
)
;;
win64)
conf+=(
--cross-file="$SOURCES_DIR/$PROJECT_DIR/package/crossfiles/x86_64-w64-mingw32.meson"
)
;;
*)
echo "Unsupported host: $HOST" >&2
exit 1
esac
fi
meson setup . "$SOURCES_DIR/$PROJECT_DIR" "${conf[@]}"
fi
ninja
ninja install

View File

@ -40,14 +40,16 @@ else
export LDFLAGS='-static-libgcc -static' export LDFLAGS='-static-libgcc -static'
elif [[ "$HOST" == "macos" ]] elif [[ "$HOST" == "macos" ]]
then then
export LDFLAGS="$LDFLAGS -L/opt/homebrew/opt/zlib/lib"
export CPPFLAGS="$CPPFLAGS -I/opt/homebrew/opt/zlib/include"
export LDFLAGS="$LDFLAGS-L/opt/homebrew/opt/libiconv/lib"
export CPPFLAGS="$CPPFLAGS -I/opt/homebrew/opt/libiconv/include"
export PKG_CONFIG_PATH="/opt/homebrew/opt/zlib/lib/pkgconfig" export PKG_CONFIG_PATH="/opt/homebrew/opt/zlib/lib/pkgconfig"
fi fi
export PKG_CONFIG_PATH="$INSTALL_DIR/$DIRNAME/lib/pkgconfig:$PKG_CONFIG_PATH"
conf=( conf=(
--prefix="$INSTALL_DIR/$DIRNAME" --prefix="$INSTALL_DIR/$DIRNAME"
--pkg-config-flags="--static"
--extra-cflags="-O2 -fPIC" --extra-cflags="-O2 -fPIC"
--disable-programs --disable-programs
--disable-doc --disable-doc
@ -60,11 +62,9 @@ else
--disable-vaapi --disable-vaapi
--disable-vdpau --disable-vdpau
--enable-swresample --enable-swresample
--enable-libdav1d
--enable-decoder=h264 --enable-decoder=h264
--enable-decoder=hevc --enable-decoder=hevc
--enable-decoder=av1 --enable-decoder=av1
--enable-decoder=libdav1d
--enable-decoder=pcm_s16le --enable-decoder=pcm_s16le
--enable-decoder=opus --enable-decoder=opus
--enable-decoder=aac --enable-decoder=aac

View File

@ -5,10 +5,10 @@ cd "$DEPS_DIR"
. common . common
process_args "$@" process_args "$@"
VERSION=2.30.10 VERSION=2.30.9
FILENAME=SDL-$VERSION.tar.gz FILENAME=SDL-$VERSION.tar.gz
PROJECT_DIR=SDL-release-$VERSION PROJECT_DIR=SDL-release-$VERSION
SHA256SUM=35a8b9c4f3635d85762b904ac60ca4e0806bff89faeb269caafbe80860d67168 SHA256SUM=682a055004081e37d81a7d4ce546c3ee3ef2e0e6a675ed2651e430ccd14eb407
cd "$SOURCES_DIR" cd "$SOURCES_DIR"

View File

@ -13,7 +13,7 @@ BEGIN
VALUE "LegalCopyright", "Romain Vimont, Genymobile" VALUE "LegalCopyright", "Romain Vimont, Genymobile"
VALUE "OriginalFilename", "scrcpy.exe" VALUE "OriginalFilename", "scrcpy.exe"
VALUE "ProductName", "scrcpy" VALUE "ProductName", "scrcpy"
VALUE "ProductVersion", "3.1" VALUE "ProductVersion", "3.0.2"
END END
END END
BLOCK "VarFileInfo" BLOCK "VarFileInfo"

View File

@ -369,12 +369,6 @@ Do not forward mouse hover (mouse motion without any clicks) events.
.B \-\-no\-power\-on .B \-\-no\-power\-on
Do not power on the device on start. Do not power on the device on start.
.TP
.B \-\-no\-vd\-destroy\-content
Disable virtual display "destroy content on removal" flag.
With this option, when the virtual display is closed, the running apps are moved to the main display rather than being destroyed.
.TP .TP
.B \-\-no\-vd\-system\-decorations .B \-\-no\-vd\-system\-decorations
Disable virtual display system decorations flag. Disable virtual display system decorations flag.

View File

@ -110,7 +110,6 @@ enum {
OPT_CAPTURE_ORIENTATION, OPT_CAPTURE_ORIENTATION,
OPT_ANGLE, OPT_ANGLE,
OPT_NO_VD_SYSTEM_DECORATIONS, OPT_NO_VD_SYSTEM_DECORATIONS,
OPT_NO_VD_DESTROY_CONTENT,
}; };
struct sc_option { struct sc_option {
@ -660,15 +659,6 @@ static const struct sc_option options[] = {
.longopt = "no-power-on", .longopt = "no-power-on",
.text = "Do not power on the device on start.", .text = "Do not power on the device on start.",
}, },
{
.longopt_id = OPT_NO_VD_DESTROY_CONTENT,
.longopt = "no-vd-destroy-content",
.text = "Disable virtual display \"destroy content on removal\" "
"flag.\n"
"With this option, when the virtual display is closed, the "
"running apps are moved to the main display rather than being "
"destroyed.",
},
{ {
.longopt_id = OPT_NO_VD_SYSTEM_DECORATIONS, .longopt_id = OPT_NO_VD_SYSTEM_DECORATIONS,
.longopt = "no-vd-system-decorations", .longopt = "no-vd-system-decorations",
@ -2715,11 +2705,8 @@ parse_args_with_getopt(struct scrcpy_cli_args *args, int argc, char *argv[],
case OPT_ANGLE: case OPT_ANGLE:
opts->angle = optarg; opts->angle = optarg;
break; break;
case OPT_NO_VD_DESTROY_CONTENT:
opts->vd_destroy_content = false;
break;
case OPT_NO_VD_SYSTEM_DECORATIONS: case OPT_NO_VD_SYSTEM_DECORATIONS:
opts->vd_system_decorations = false; opts->vd_system_decorations = optarg;
break; break;
default: default:
// getopt prints the error message on stderr // getopt prints the error message on stderr

View File

@ -15,6 +15,9 @@ struct sc_hid_input {
struct sc_hid_open { struct sc_hid_open {
uint16_t hid_id; uint16_t hid_id;
uint16_t vendor_id;
uint16_t product_id;
const char *name; // pointer to static memory
const uint8_t *report_desc; // pointer to static memory const uint8_t *report_desc; // pointer to static memory
size_t report_desc_size; size_t report_desc_size;
}; };

View File

@ -236,7 +236,9 @@ sc_hid_gamepad_slot_get_id(size_t slot_idx) {
bool bool
sc_hid_gamepad_generate_open(struct sc_hid_gamepad *hid, sc_hid_gamepad_generate_open(struct sc_hid_gamepad *hid,
struct sc_hid_open *hid_open, struct sc_hid_open *hid_open,
uint32_t gamepad_id) { uint32_t gamepad_id,
uint16_t vendor_id,
uint16_t product_id) {
assert(gamepad_id != SC_GAMEPAD_ID_INVALID); assert(gamepad_id != SC_GAMEPAD_ID_INVALID);
ssize_t slot_idx = sc_hid_gamepad_slot_find(hid, SC_GAMEPAD_ID_INVALID); ssize_t slot_idx = sc_hid_gamepad_slot_find(hid, SC_GAMEPAD_ID_INVALID);
if (slot_idx == -1) { if (slot_idx == -1) {
@ -246,8 +248,16 @@ sc_hid_gamepad_generate_open(struct sc_hid_gamepad *hid,
sc_hid_gamepad_slot_init(&hid->slots[slot_idx], gamepad_id); sc_hid_gamepad_slot_init(&hid->slots[slot_idx], gamepad_id);
SDL_GameController* game_controller =
SDL_GameControllerFromInstanceID(gamepad_id);
assert(game_controller);
const char *name = SDL_GameControllerName(game_controller);
uint16_t hid_id = sc_hid_gamepad_slot_get_id(slot_idx); uint16_t hid_id = sc_hid_gamepad_slot_get_id(slot_idx);
hid_open->hid_id = hid_id; hid_open->hid_id = hid_id;
hid_open->vendor_id = vendor_id;
hid_open->product_id = product_id;
hid_open->name = name;
hid_open->report_desc = SC_HID_GAMEPAD_REPORT_DESC; hid_open->report_desc = SC_HID_GAMEPAD_REPORT_DESC;
hid_open->report_desc_size = sizeof(SC_HID_GAMEPAD_REPORT_DESC); hid_open->report_desc_size = sizeof(SC_HID_GAMEPAD_REPORT_DESC);

View File

@ -33,7 +33,9 @@ sc_hid_gamepad_init(struct sc_hid_gamepad *hid);
bool bool
sc_hid_gamepad_generate_open(struct sc_hid_gamepad *hid, sc_hid_gamepad_generate_open(struct sc_hid_gamepad *hid,
struct sc_hid_open *hid_open, struct sc_hid_open *hid_open,
uint32_t gamepad_id); uint32_t gamepad_id,
uint16_t vendor_id,
uint16_t product_id);
bool bool
sc_hid_gamepad_generate_close(struct sc_hid_gamepad *hid, sc_hid_gamepad_generate_close(struct sc_hid_gamepad *hid,

View File

@ -335,6 +335,9 @@ sc_hid_keyboard_generate_input_from_mods(struct sc_hid_input *hid_input,
void sc_hid_keyboard_generate_open(struct sc_hid_open *hid_open) { void sc_hid_keyboard_generate_open(struct sc_hid_open *hid_open) {
hid_open->hid_id = SC_HID_ID_KEYBOARD; hid_open->hid_id = SC_HID_ID_KEYBOARD;
hid_open->vendor_id = 0;
hid_open->product_id = 0;
hid_open->name = NULL; // No name specified after "scrcpy"
hid_open->report_desc = SC_HID_KEYBOARD_REPORT_DESC; hid_open->report_desc = SC_HID_KEYBOARD_REPORT_DESC;
hid_open->report_desc_size = sizeof(SC_HID_KEYBOARD_REPORT_DESC); hid_open->report_desc_size = sizeof(SC_HID_KEYBOARD_REPORT_DESC);
} }

View File

@ -190,6 +190,9 @@ sc_hid_mouse_generate_input_from_scroll(struct sc_hid_input *hid_input,
void sc_hid_mouse_generate_open(struct sc_hid_open *hid_open) { void sc_hid_mouse_generate_open(struct sc_hid_open *hid_open) {
hid_open->hid_id = SC_HID_ID_MOUSE; hid_open->hid_id = SC_HID_ID_MOUSE;
hid_open->vendor_id = 0;
hid_open->product_id = 0;
hid_open->name = NULL; // No name specified after "scrcpy"
hid_open->report_desc = SC_HID_MOUSE_REPORT_DESC; hid_open->report_desc = SC_HID_MOUSE_REPORT_DESC;
hid_open->report_desc_size = sizeof(SC_HID_MOUSE_REPORT_DESC); hid_open->report_desc_size = sizeof(SC_HID_MOUSE_REPORT_DESC);
} }

View File

@ -417,7 +417,11 @@ struct sc_touch_event {
// invalid ID. // invalid ID.
#define SC_GAMEPAD_ID_INVALID UINT32_C(-1) #define SC_GAMEPAD_ID_INVALID UINT32_C(-1)
struct sc_gamepad_device_event { struct sc_gamepad_added_event {
uint32_t gamepad_id;
};
struct sc_gamepad_removed_event {
uint32_t gamepad_id; uint32_t gamepad_id;
}; };

View File

@ -922,7 +922,7 @@ sc_input_manager_process_gamepad_device(struct sc_input_manager *im,
return; return;
} }
struct sc_gamepad_device_event evt = { struct sc_gamepad_added_event evt = {
.gamepad_id = SDL_JoystickInstanceID(joystick), .gamepad_id = SDL_JoystickInstanceID(joystick),
}; };
im->gp->ops->process_gamepad_added(im->gp, &evt); im->gp->ops->process_gamepad_added(im->gp, &evt);
@ -936,7 +936,7 @@ sc_input_manager_process_gamepad_device(struct sc_input_manager *im,
LOGW("Unknown gamepad device removed"); LOGW("Unknown gamepad device removed");
} }
struct sc_gamepad_device_event evt = { struct sc_gamepad_removed_event evt = {
.gamepad_id = id, .gamepad_id = id,
}; };
im->gp->ops->process_gamepad_removed(im->gp, &evt); im->gp->ops->process_gamepad_removed(im->gp, &evt);

View File

@ -108,7 +108,6 @@ const struct scrcpy_options scrcpy_options_default = {
.new_display = NULL, .new_display = NULL,
.start_app = NULL, .start_app = NULL,
.angle = NULL, .angle = NULL,
.vd_destroy_content = true,
.vd_system_decorations = true, .vd_system_decorations = true,
}; };

View File

@ -310,7 +310,6 @@ struct scrcpy_options {
bool audio_dup; bool audio_dup;
const char *new_display; // [<width>x<height>][/<dpi>] parsed by the server const char *new_display; // [<width>x<height>][/<dpi>] parsed by the server
const char *start_app; const char *start_app;
bool vd_destroy_content;
bool vd_system_decorations; bool vd_system_decorations;
}; };

View File

@ -458,7 +458,6 @@ scrcpy(struct scrcpy_options *options) {
.power_on = options->power_on, .power_on = options->power_on,
.kill_adb_on_close = options->kill_adb_on_close, .kill_adb_on_close = options->kill_adb_on_close,
.camera_high_speed = options->camera_high_speed, .camera_high_speed = options->camera_high_speed,
.vd_destroy_content = options->vd_destroy_content,
.vd_system_decorations = options->vd_system_decorations, .vd_system_decorations = options->vd_system_decorations,
.list = options->list, .list = options->list,
}; };

View File

@ -377,9 +377,6 @@ execute_server(struct sc_server *server,
VALIDATE_STRING(params->new_display); VALIDATE_STRING(params->new_display);
ADD_PARAM("new_display=%s", params->new_display); ADD_PARAM("new_display=%s", params->new_display);
} }
if (!params->vd_destroy_content) {
ADD_PARAM("vd_destroy_content=false");
}
if (!params->vd_system_decorations) { if (!params->vd_system_decorations) {
ADD_PARAM("vd_system_decorations=false"); ADD_PARAM("vd_system_decorations=false");
} }

View File

@ -69,7 +69,6 @@ struct sc_server_params {
bool power_on; bool power_on;
bool kill_adb_on_close; bool kill_adb_on_close;
bool camera_high_speed; bool camera_high_speed;
bool vd_destroy_content;
bool vd_system_decorations; bool vd_system_decorations;
uint8_t list; uint8_t list;
}; };

View File

@ -20,22 +20,22 @@ struct sc_gamepad_processor {
struct sc_gamepad_processor_ops { struct sc_gamepad_processor_ops {
/** /**
* Process a gamepad device added event * Process a gamepad device added
* *
* This function is mandatory. * This function is mandatory.
*/ */
void void
(*process_gamepad_added)(struct sc_gamepad_processor *gp, (*process_gamepad_added)(struct sc_gamepad_processor *gp,
const struct sc_gamepad_device_event *event); const struct sc_gamepad_added_event *event);
/** /**
* Process a gamepad device removed event * Process a gamepad device removed
* *
* This function is mandatory. * This function is mandatory.
*/ */
void void
(*process_gamepad_removed)(struct sc_gamepad_processor *gp, (*process_gamepad_removed)(struct sc_gamepad_processor *gp,
const struct sc_gamepad_device_event *event); const struct sc_gamepad_removed_event *event);
/** /**
* Process a gamepad axis event * Process a gamepad axis event

View File

@ -7,10 +7,8 @@
/** Downcast gamepad processor to sc_gamepad_uhid */ /** Downcast gamepad processor to sc_gamepad_uhid */
#define DOWNCAST(GP) container_of(GP, struct sc_gamepad_uhid, gamepad_processor) #define DOWNCAST(GP) container_of(GP, struct sc_gamepad_uhid, gamepad_processor)
// Xbox 360 #define SC_GAMEPAD_UHID_VENDOR_ID 0
#define SC_GAMEPAD_UHID_VENDOR_ID UINT16_C(0x045e) #define SC_GAMEPAD_UHID_PRODUCT_ID 0
#define SC_GAMEPAD_UHID_PRODUCT_ID UINT16_C(0x028e)
#define SC_GAMEPAD_UHID_NAME "Microsoft X-Box 360 Pad"
static void static void
sc_gamepad_uhid_send_input(struct sc_gamepad_uhid *gamepad, sc_gamepad_uhid_send_input(struct sc_gamepad_uhid *gamepad,
@ -35,9 +33,9 @@ sc_gamepad_uhid_send_open(struct sc_gamepad_uhid *gamepad,
struct sc_control_msg msg; struct sc_control_msg msg;
msg.type = SC_CONTROL_MSG_TYPE_UHID_CREATE; msg.type = SC_CONTROL_MSG_TYPE_UHID_CREATE;
msg.uhid_create.id = hid_open->hid_id; msg.uhid_create.id = hid_open->hid_id;
msg.uhid_create.vendor_id = SC_GAMEPAD_UHID_VENDOR_ID; msg.uhid_create.vendor_id = hid_open->vendor_id;
msg.uhid_create.product_id = SC_GAMEPAD_UHID_PRODUCT_ID; msg.uhid_create.product_id = hid_open->product_id;
msg.uhid_create.name = SC_GAMEPAD_UHID_NAME; msg.uhid_create.name = hid_open->name;
msg.uhid_create.report_desc = hid_open->report_desc; msg.uhid_create.report_desc = hid_open->report_desc;
msg.uhid_create.report_desc_size = hid_open->report_desc_size; msg.uhid_create.report_desc_size = hid_open->report_desc_size;
@ -60,27 +58,23 @@ sc_gamepad_uhid_send_close(struct sc_gamepad_uhid *gamepad,
static void static void
sc_gamepad_processor_process_gamepad_added(struct sc_gamepad_processor *gp, sc_gamepad_processor_process_gamepad_added(struct sc_gamepad_processor *gp,
const struct sc_gamepad_device_event *event) { const struct sc_gamepad_added_event *event) {
struct sc_gamepad_uhid *gamepad = DOWNCAST(gp); struct sc_gamepad_uhid *gamepad = DOWNCAST(gp);
struct sc_hid_open hid_open; struct sc_hid_open hid_open;
if (!sc_hid_gamepad_generate_open(&gamepad->hid, &hid_open, if (!sc_hid_gamepad_generate_open(&gamepad->hid, &hid_open,
event->gamepad_id)) { event->gamepad_id,
SC_GAMEPAD_UHID_VENDOR_ID,
SC_GAMEPAD_UHID_PRODUCT_ID)) {
return; return;
} }
SDL_GameController* game_controller =
SDL_GameControllerFromInstanceID(event->gamepad_id);
assert(game_controller);
const char *name = SDL_GameControllerName(game_controller);
LOGI("Gamepad added: [%" PRIu32 "] %s", event->gamepad_id, name);
sc_gamepad_uhid_send_open(gamepad, &hid_open); sc_gamepad_uhid_send_open(gamepad, &hid_open);
} }
static void static void
sc_gamepad_processor_process_gamepad_removed(struct sc_gamepad_processor *gp, sc_gamepad_processor_process_gamepad_removed(struct sc_gamepad_processor *gp,
const struct sc_gamepad_device_event *event) { const struct sc_gamepad_removed_event *event) {
struct sc_gamepad_uhid *gamepad = DOWNCAST(gp); struct sc_gamepad_uhid *gamepad = DOWNCAST(gp);
struct sc_hid_close hid_close; struct sc_hid_close hid_close;
@ -89,8 +83,6 @@ sc_gamepad_processor_process_gamepad_removed(struct sc_gamepad_processor *gp,
return; return;
} }
LOGI("Gamepad removed: [%" PRIu32 "]", event->gamepad_id);
sc_gamepad_uhid_send_close(gamepad, &hid_close); sc_gamepad_uhid_send_close(gamepad, &hid_close);
} }

View File

@ -141,9 +141,9 @@ sc_keyboard_uhid_init(struct sc_keyboard_uhid *kb,
struct sc_control_msg msg; struct sc_control_msg msg;
msg.type = SC_CONTROL_MSG_TYPE_UHID_CREATE; msg.type = SC_CONTROL_MSG_TYPE_UHID_CREATE;
msg.uhid_create.id = SC_HID_ID_KEYBOARD; msg.uhid_create.id = SC_HID_ID_KEYBOARD;
msg.uhid_create.vendor_id = 0; msg.uhid_create.vendor_id = hid_open.vendor_id;
msg.uhid_create.product_id = 0; msg.uhid_create.product_id = hid_open.product_id;
msg.uhid_create.name = NULL; msg.uhid_create.name = hid_open.name;
msg.uhid_create.report_desc = hid_open.report_desc; msg.uhid_create.report_desc = hid_open.report_desc;
msg.uhid_create.report_desc_size = hid_open.report_desc_size; msg.uhid_create.report_desc_size = hid_open.report_desc_size;
if (!sc_controller_push_msg(controller, &msg)) { if (!sc_controller_push_msg(controller, &msg)) {

View File

@ -81,9 +81,9 @@ sc_mouse_uhid_init(struct sc_mouse_uhid *mouse,
struct sc_control_msg msg; struct sc_control_msg msg;
msg.type = SC_CONTROL_MSG_TYPE_UHID_CREATE; msg.type = SC_CONTROL_MSG_TYPE_UHID_CREATE;
msg.uhid_create.id = SC_HID_ID_MOUSE; msg.uhid_create.id = SC_HID_ID_MOUSE;
msg.uhid_create.vendor_id = 0; msg.uhid_create.vendor_id = hid_open.vendor_id;
msg.uhid_create.product_id = 0; msg.uhid_create.product_id = hid_open.product_id;
msg.uhid_create.name = NULL; msg.uhid_create.name = hid_open.name;
msg.uhid_create.report_desc = hid_open.report_desc; msg.uhid_create.report_desc = hid_open.report_desc;
msg.uhid_create.report_desc_size = hid_open.report_desc_size; msg.uhid_create.report_desc_size = hid_open.report_desc_size;
if (!sc_controller_push_msg(controller, &msg)) { if (!sc_controller_push_msg(controller, &msg)) {

View File

@ -8,12 +8,12 @@
static void static void
sc_gamepad_processor_process_gamepad_added(struct sc_gamepad_processor *gp, sc_gamepad_processor_process_gamepad_added(struct sc_gamepad_processor *gp,
const struct sc_gamepad_device_event *event) { const struct sc_gamepad_added_event *event) {
struct sc_gamepad_aoa *gamepad = DOWNCAST(gp); struct sc_gamepad_aoa *gamepad = DOWNCAST(gp);
struct sc_hid_open hid_open; struct sc_hid_open hid_open;
if (!sc_hid_gamepad_generate_open(&gamepad->hid, &hid_open, if (!sc_hid_gamepad_generate_open(&gamepad->hid, &hid_open,
event->gamepad_id)) { event->gamepad_id, 0, 0)) {
return; return;
} }
@ -25,7 +25,7 @@ sc_gamepad_processor_process_gamepad_added(struct sc_gamepad_processor *gp,
static void static void
sc_gamepad_processor_process_gamepad_removed(struct sc_gamepad_processor *gp, sc_gamepad_processor_process_gamepad_removed(struct sc_gamepad_processor *gp,
const struct sc_gamepad_device_event *event) { const struct sc_gamepad_removed_event *event) {
struct sc_gamepad_aoa *gamepad = DOWNCAST(gp); struct sc_gamepad_aoa *gamepad = DOWNCAST(gp);
struct sc_hid_close hid_close; struct sc_hid_close hid_close;

View File

@ -189,7 +189,7 @@ sc_screen_otg_process_gamepad_device(struct sc_screen_otg *screen,
return; return;
} }
struct sc_gamepad_device_event evt = { struct sc_gamepad_added_event evt = {
.gamepad_id = SDL_JoystickInstanceID(joystick), .gamepad_id = SDL_JoystickInstanceID(joystick),
}; };
gp->ops->process_gamepad_added(gp, &evt); gp->ops->process_gamepad_added(gp, &evt);
@ -203,7 +203,7 @@ sc_screen_otg_process_gamepad_device(struct sc_screen_otg *screen,
LOGW("Unknown gamepad device removed"); LOGW("Unknown gamepad device removed");
} }
struct sc_gamepad_device_event evt = { struct sc_gamepad_removed_event evt = {
.gamepad_id = id, .gamepad_id = id,
}; };
gp->ops->process_gamepad_removed(gp, &evt); gp->ops->process_gamepad_removed(gp, &evt);

View File

@ -233,10 +233,10 @@ install` must be run as root)._
#### Option 2: Use prebuilt server #### Option 2: Use prebuilt server
- [`scrcpy-server-v3.1`][direct-scrcpy-server] - [`scrcpy-server-v3.0.2`][direct-scrcpy-server]
<sub>SHA-256: `958f0944a62f23b1f33a16e9eb14844c1a04b882ca175a738c16d23cb22b86c0`</sub> <sub>SHA-256: `e19fe024bfa3367809494407ad6ca809a6f6e77dac95e99f85ba75144e0ba35d`</sub>
[direct-scrcpy-server]: https://github.com/Genymobile/scrcpy/releases/download/v3.1/scrcpy-server-v3.1 [direct-scrcpy-server]: https://github.com/Genymobile/scrcpy/releases/download/v3.0.2/scrcpy-server-v3.0.2
Download the prebuilt server somewhere, and specify its path during the Meson Download the prebuilt server somewhere, and specify its path during the Meson
configuration: configuration:

View File

@ -6,11 +6,11 @@
Download a static build of the [latest release]: Download a static build of the [latest release]:
- [`scrcpy-linux-x86_64-v3.1.tar.gz`][direct-linux-x86_64] (x86_64) - [`scrcpy-linux-x86_64-v3.0.2.tar.gz`][direct-linux-x86_64] (x86_64)
<sub>SHA-256: `37dba54092ed9ec6b2f8f95432f61b8ea124aec9f1e9f2b3d22d4b10bb04c59a`</sub> <sub>SHA-256: `20b69dcd379bb7d7208bf1e4858cf04162fc856697be0e6c03863d7b3c1e734a`</sub>
[latest release]: https://github.com/Genymobile/scrcpy/releases/latest [latest release]: https://github.com/Genymobile/scrcpy/releases/latest
[direct-linux-x86_64]: https://github.com/Genymobile/scrcpy/releases/download/v3.1/scrcpy-linux-x86_64-v3.1.tar.gz [direct-linux-x86_64]: https://github.com/Genymobile/scrcpy/releases/download/v3.0.2/scrcpy-linux-x86_64-v3.0.2.tar.gz
and extract it. and extract it.

View File

@ -6,15 +6,15 @@
Download a static build of the [latest release]: Download a static build of the [latest release]:
- [`scrcpy-macos-aarch64-v3.1.tar.gz`][direct-macos-aarch64] (aarch64) - [`scrcpy-macos-aarch64-v3.0.2.tar.gz`][direct-macos-aarch64] (aarch64)
<sub>SHA-256: `478618d940421e5f57942f5479d493ecbb38210682937a200f712aee5f235daf`</sub> <sub>SHA-256: `811ba2f4e856146bdd161e24c3490d78efbec2339ca783fac791d041c0aecfb6`</sub>
- [`scrcpy-macos-x86_64-v3.1.tar.gz`][direct-macos-x86_64] (x86_64) - [`scrcpy-macos-x86_64-v3.0.2.tar.gz`][direct-macos-x86_64] (x86_64)
<sub>SHA-256: `acde98e29c273710ffa469371dbca4a728a44c41c380381f8a54e5b5301b9e87`</sub> <sub>SHA-256: `8effff54dca3a3e46eaaec242771a13a7f81af2e18670b3d0d8ed6b461bb4f79`</sub>
[latest release]: https://github.com/Genymobile/scrcpy/releases/latest [latest release]: https://github.com/Genymobile/scrcpy/releases/latest
[direct-macos-aarch64]: https://github.com/Genymobile/scrcpy/releases/download/v3.1/scrcpy-macos-aarch64-v3.1.tar.gz [direct-macos-aarch64]: https://github.com/Genymobile/scrcpy/releases/download/v3.0.2/scrcpy-macos-aarch64-v3.0.2.tar.gz
[direct-macos-x86_64]: https://github.com/Genymobile/scrcpy/releases/download/v3.1/scrcpy-macos-x86_64-v3.1.tar.gz [direct-macos-x86_64]: https://github.com/Genymobile/scrcpy/releases/download/v3.0.2/scrcpy-macos-x86_64-v3.0.2.tar.gz
and extract it. and extract it.

View File

@ -50,14 +50,3 @@ any default launcher UI available in virtual displays.
Note that if no app is started, no content will be rendered, so no video frame Note that if no app is started, no content will be rendered, so no video frame
will be produced at all. will be produced at all.
## Destroy on close
By default, when the virtual display is closed, the running apps are destroyed.
To move them to the main display instead, use:
```
scrcpy --new-display --no-vd-destroy-content
```

View File

@ -6,14 +6,14 @@
Download the [latest release]: Download the [latest release]:
- [`scrcpy-win64-v3.1.zip`][direct-win64] (64-bit) - [`scrcpy-win64-v3.0.2.zip`][direct-win64] (64-bit)
<sub>SHA-256: `0c05ea395d95cfe36bee974eeb435a3db87ea5594ff738370d5dc3068a9538ca`</sub> <sub>SHA-256: `f0de59f5d46127c87cd822d39d6665e016b86db4cd048101b262f6adb6766832`</sub>
- [`scrcpy-win32-v3.1.zip`][direct-win32] (32-bit) - [`scrcpy-win32-v3.0.2.zip`][direct-win32] (32-bit)
<sub>SHA-256: `2b4674ef76719680ac5a9b482d1943bdde3fa25821ad2e98f3c40c347d00d560`</sub> <sub>SHA-256: `8db8d4984d642012c55802de71f507f8ff9f68a8cfed456d7a1982d47e065f64`</sub>
[latest release]: https://github.com/Genymobile/scrcpy/releases/latest [latest release]: https://github.com/Genymobile/scrcpy/releases/latest
[direct-win64]: https://github.com/Genymobile/scrcpy/releases/download/v3.1/scrcpy-win64-v3.1.zip [direct-win64]: https://github.com/Genymobile/scrcpy/releases/download/v3.0.2/scrcpy-win64-v3.0.2.zip
[direct-win32]: https://github.com/Genymobile/scrcpy/releases/download/v3.1/scrcpy-win32-v3.1.zip [direct-win32]: https://github.com/Genymobile/scrcpy/releases/download/v3.0.2/scrcpy-win32-v3.0.2.zip
and extract it. and extract it.

View File

@ -2,8 +2,8 @@
set -e set -e
BUILDDIR=build-auto BUILDDIR=build-auto
PREBUILT_SERVER_URL=https://github.com/Genymobile/scrcpy/releases/download/v3.1/scrcpy-server-v3.1 PREBUILT_SERVER_URL=https://github.com/Genymobile/scrcpy/releases/download/v3.0.2/scrcpy-server-v3.0.2
PREBUILT_SERVER_SHA256=958f0944a62f23b1f33a16e9eb14844c1a04b882ca175a738c16d23cb22b86c0 PREBUILT_SERVER_SHA256=e19fe024bfa3367809494407ad6ca809a6f6e77dac95e99f85ba75144e0ba35d
echo "[scrcpy] Downloading prebuilt server..." echo "[scrcpy] Downloading prebuilt server..."
wget "$PREBUILT_SERVER_URL" -O scrcpy-server wget "$PREBUILT_SERVER_URL" -O scrcpy-server

View File

@ -1,5 +1,5 @@
project('scrcpy', 'c', project('scrcpy', 'c',
version: '3.1', version: '3.0.2',
meson_version: '>= 0.48', meson_version: '>= 0.48',
default_options: [ default_options: [
'c_std=c11', 'c_std=c11',

View File

@ -15,7 +15,6 @@ LINUX_BUILD_DIR="$WORK_DIR/build-linux-$ARCH"
app/deps/adb_linux.sh app/deps/adb_linux.sh
app/deps/sdl.sh linux native static app/deps/sdl.sh linux native static
app/deps/dav1d.sh linux native static
app/deps/ffmpeg.sh linux native static app/deps/ffmpeg.sh linux native static
app/deps/libusb.sh linux native static app/deps/libusb.sh linux native static

View File

@ -15,7 +15,6 @@ MACOS_BUILD_DIR="$WORK_DIR/build-macos-$ARCH"
app/deps/adb_macos.sh app/deps/adb_macos.sh
app/deps/sdl.sh macos native static app/deps/sdl.sh macos native static
app/deps/dav1d.sh macos native static
app/deps/ffmpeg.sh macos native static app/deps/ffmpeg.sh macos native static
app/deps/libusb.sh macos native static app/deps/libusb.sh macos native static

View File

@ -22,7 +22,6 @@ WINXX_BUILD_DIR="$WORK_DIR/build-$WINXX"
app/deps/adb_windows.sh app/deps/adb_windows.sh
app/deps/sdl.sh $WINXX cross shared app/deps/sdl.sh $WINXX cross shared
app/deps/dav1d.sh $WINXX cross shared
app/deps/ffmpeg.sh $WINXX cross shared app/deps/ffmpeg.sh $WINXX cross shared
app/deps/libusb.sh $WINXX cross shared app/deps/libusb.sh $WINXX cross shared

View File

@ -7,8 +7,8 @@ android {
applicationId "com.genymobile.scrcpy" applicationId "com.genymobile.scrcpy"
minSdkVersion 21 minSdkVersion 21
targetSdkVersion 35 targetSdkVersion 35
versionCode 30100 versionCode 30002
versionName "3.1" versionName "3.0.2"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
} }
buildTypes { buildTypes {

View File

@ -12,7 +12,7 @@
set -e set -e
SCRCPY_DEBUG=false SCRCPY_DEBUG=false
SCRCPY_VERSION_NAME=3.1 SCRCPY_VERSION_NAME=3.0.2
PLATFORM=${ANDROID_PLATFORM:-35} PLATFORM=${ANDROID_PLATFORM:-35}
BUILD_TOOLS=${ANDROID_BUILD_TOOLS:-35.0.0} BUILD_TOOLS=${ANDROID_BUILD_TOOLS:-35.0.0}

View File

@ -6,8 +6,6 @@ import com.genymobile.scrcpy.util.Settings;
import com.genymobile.scrcpy.util.SettingsException; import com.genymobile.scrcpy.util.SettingsException;
import android.os.BatteryManager; import android.os.BatteryManager;
import android.system.ErrnoException;
import android.system.Os;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
@ -26,7 +24,6 @@ public final class CleanUp {
private boolean pendingRestoreDisplayPower; private boolean pendingRestoreDisplayPower;
private Thread thread; private Thread thread;
private boolean interrupted;
private CleanUp(Options options) { private CleanUp(Options options) {
thread = new Thread(() -> runCleanUp(options), "cleanup"); thread = new Thread(() -> runCleanUp(options), "cleanup");
@ -37,10 +34,8 @@ public final class CleanUp {
return new CleanUp(options); return new CleanUp(options);
} }
public synchronized void interrupt() { public void interrupt() {
// Do not use thread.interrupt() because only the wait() call must be interrupted, not Command.exec() thread.interrupt();
interrupted = true;
notify();
} }
public void join() throws InterruptedException { public void join() throws InterruptedException {
@ -102,13 +97,15 @@ public final class CleanUp {
try { try {
run(displayId, restoreStayOn, disableShowTouches, powerOffScreen, restoreScreenOffTimeout); run(displayId, restoreStayOn, disableShowTouches, powerOffScreen, restoreScreenOffTimeout);
} catch (InterruptedException e) {
// ignore
} catch (IOException e) { } catch (IOException e) {
Ln.e("Clean up I/O exception", e); Ln.e("Clean up I/O exception", e);
} }
} }
private void run(int displayId, int restoreStayOn, boolean disableShowTouches, boolean powerOffScreen, int restoreScreenOffTimeout) private void run(int displayId, int restoreStayOn, boolean disableShowTouches, boolean powerOffScreen, int restoreScreenOffTimeout)
throws IOException { throws IOException, InterruptedException {
String[] cmd = { String[] cmd = {
"app_process", "app_process",
"/", "/",
@ -129,15 +126,8 @@ public final class CleanUp {
int localPendingChanges; int localPendingChanges;
boolean localPendingRestoreDisplayPower; boolean localPendingRestoreDisplayPower;
synchronized (this) { synchronized (this) {
while (!interrupted && pendingChanges == 0) { while (pendingChanges == 0) {
try { wait();
wait();
} catch (InterruptedException e) {
throw new AssertionError("Clean up thread MUST NOT be interrupted");
}
}
if (interrupted) {
break;
} }
localPendingChanges = pendingChanges; localPendingChanges = pendingChanges;
localPendingRestoreDisplayPower = pendingRestoreDisplayPower; localPendingRestoreDisplayPower = pendingRestoreDisplayPower;
@ -165,12 +155,6 @@ public final class CleanUp {
} }
public static void main(String... args) { public static void main(String... args) {
try {
// Start a new session to avoid being terminated along with the server process on some devices
Os.setsid();
} catch (ErrnoException e) {
Ln.e("setsid() failed", e);
}
unlinkSelf(); unlinkSelf();
int displayId = Integer.parseInt(args[0]); int displayId = Integer.parseInt(args[0]);

View File

@ -60,7 +60,6 @@ public class Options {
private boolean powerOn = true; private boolean powerOn = true;
private NewDisplay newDisplay; private NewDisplay newDisplay;
private boolean vdDestroyContent = true;
private boolean vdSystemDecorations = true; private boolean vdSystemDecorations = true;
private Orientation.Lock captureOrientationLock = Orientation.Lock.Unlocked; private Orientation.Lock captureOrientationLock = Orientation.Lock.Unlocked;
@ -234,10 +233,6 @@ public class Options {
return captureOrientationLock; return captureOrientationLock;
} }
public boolean getVDDestroyContent() {
return vdDestroyContent;
}
public boolean getVDSystemDecorations() { public boolean getVDSystemDecorations() {
return vdSystemDecorations; return vdSystemDecorations;
} }
@ -471,9 +466,6 @@ public class Options {
case "new_display": case "new_display":
options.newDisplay = parseNewDisplay(value); options.newDisplay = parseNewDisplay(value);
break; break;
case "vd_destroy_content":
options.vdDestroyContent = Boolean.parseBoolean(value);
break;
case "vd_system_decorations": case "vd_system_decorations":
options.vdSystemDecorations = Boolean.parseBoolean(value); options.vdSystemDecorations = Boolean.parseBoolean(value);
break; break;

View File

@ -174,7 +174,7 @@ public final class UhidManager {
ByteBuffer buf = ByteBuffer.allocate(280 + reportDesc.length).order(ByteOrder.nativeOrder()); ByteBuffer buf = ByteBuffer.allocate(280 + reportDesc.length).order(ByteOrder.nativeOrder());
buf.putInt(UHID_CREATE2); buf.putInt(UHID_CREATE2);
String actualName = name.isEmpty() ? "scrcpy" : name; String actualName = name.isEmpty() ? "scrcpy" : "scrcpy: " + name;
byte[] utf8Name = actualName.getBytes(StandardCharsets.UTF_8); byte[] utf8Name = actualName.getBytes(StandardCharsets.UTF_8);
int len = StringUtils.getUtf8TruncationIndex(utf8Name, 127); int len = StringUtils.getUtf8TruncationIndex(utf8Name, 127);
assert len <= 127; assert len <= 127;

View File

@ -206,10 +206,6 @@ public final class Device {
// restore auto-rotate if necessary // restore auto-rotate if necessary
if (accelerometerRotation) { if (accelerometerRotation) {
if (displayId == 0) {
// HACK: rotation on the main display often fail on recent Android devices if thawRotation() is called immediately
SystemClock.sleep(10);
}
wm.thawRotation(displayId); wm.thawRotation(displayId);
} }
} }

View File

@ -53,7 +53,6 @@ public class NewDisplayCapture extends SurfaceCapture {
private final boolean captureOrientationLocked; private final boolean captureOrientationLocked;
private final Orientation captureOrientation; private final Orientation captureOrientation;
private final float angle; private final float angle;
private final boolean vdDestroyContent;
private final boolean vdSystemDecorations; private final boolean vdSystemDecorations;
private VirtualDisplay virtualDisplay; private VirtualDisplay virtualDisplay;
@ -74,7 +73,6 @@ public class NewDisplayCapture extends SurfaceCapture {
this.captureOrientation = options.getCaptureOrientation(); this.captureOrientation = options.getCaptureOrientation();
assert captureOrientation != null; assert captureOrientation != null;
this.angle = options.getAngle(); this.angle = options.getAngle();
this.vdDestroyContent = options.getVDDestroyContent();
this.vdSystemDecorations = options.getVDSystemDecorations(); this.vdSystemDecorations = options.getVDSystemDecorations();
} }
@ -169,10 +167,8 @@ public class NewDisplayCapture extends SurfaceCapture {
int flags = VIRTUAL_DISPLAY_FLAG_PUBLIC int flags = VIRTUAL_DISPLAY_FLAG_PUBLIC
| VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY | VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY
| VIRTUAL_DISPLAY_FLAG_SUPPORTS_TOUCH | VIRTUAL_DISPLAY_FLAG_SUPPORTS_TOUCH
| VIRTUAL_DISPLAY_FLAG_ROTATES_WITH_CONTENT; | VIRTUAL_DISPLAY_FLAG_ROTATES_WITH_CONTENT
if (vdDestroyContent) { | VIRTUAL_DISPLAY_FLAG_DESTROY_CONTENT_ON_REMOVAL;
flags |= VIRTUAL_DISPLAY_FLAG_DESTROY_CONTENT_ON_REMOVAL;
}
if (vdSystemDecorations) { if (vdSystemDecorations) {
flags |= VIRTUAL_DISPLAY_FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS; flags |= VIRTUAL_DISPLAY_FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS;
} }

View File

@ -124,9 +124,15 @@ public class ScreenCapture extends SurfaceCapture {
inputSize = videoSize; inputSize = videoSize;
} }
int virtualDisplayId;
PositionMapper positionMapper;
try { try {
virtualDisplay = ServiceManager.getDisplayManager() virtualDisplay = ServiceManager.getDisplayManager()
.createVirtualDisplay("scrcpy", inputSize.getWidth(), inputSize.getHeight(), displayId, surface); .createVirtualDisplay("scrcpy", inputSize.getWidth(), inputSize.getHeight(), displayId, surface);
virtualDisplayId = virtualDisplay.getDisplay().getDisplayId();
// The positions are relative to the virtual display, not the original display (so use inputSize, not deviceSize!)
positionMapper = PositionMapper.create(videoSize, transform, inputSize);
Ln.d("Display: using DisplayManager API"); Ln.d("Display: using DisplayManager API");
} catch (Exception displayManagerException) { } catch (Exception displayManagerException) {
try { try {
@ -134,7 +140,11 @@ public class ScreenCapture extends SurfaceCapture {
Size deviceSize = displayInfo.getSize(); Size deviceSize = displayInfo.getSize();
int layerStack = displayInfo.getLayerStack(); int layerStack = displayInfo.getLayerStack();
setDisplaySurface(display, surface, deviceSize.toRect(), inputSize.toRect(), layerStack); setDisplaySurface(display, surface, deviceSize.toRect(), inputSize.toRect(), layerStack);
virtualDisplayId = displayId;
positionMapper = PositionMapper.create(videoSize, transform, deviceSize);
Ln.d("Display: using SurfaceControl API"); Ln.d("Display: using SurfaceControl API");
} catch (Exception surfaceControlException) { } catch (Exception surfaceControlException) {
Ln.e("Could not create display using DisplayManager", displayManagerException); Ln.e("Could not create display using DisplayManager", displayManagerException);
@ -144,18 +154,6 @@ public class ScreenCapture extends SurfaceCapture {
} }
if (vdListener != null) { if (vdListener != null) {
int virtualDisplayId;
PositionMapper positionMapper;
if (virtualDisplay == null || displayId == 0) {
// Surface control or main display: send all events to the original display, relative to the device size
Size deviceSize = displayInfo.getSize();
positionMapper = PositionMapper.create(videoSize, transform, deviceSize);
virtualDisplayId = displayId;
} else {
// The positions are relative to the virtual display, not the original display (so use inputSize, not deviceSize!)
positionMapper = PositionMapper.create(videoSize, transform, inputSize);
virtualDisplayId = virtualDisplay.getDisplay().getDisplayId();
}
vdListener.onNewVirtualDisplay(virtualDisplayId, positionMapper); vdListener.onNewVirtualDisplay(virtualDisplayId, positionMapper);
} }
} }

View File

@ -6,7 +6,6 @@ import com.genymobile.scrcpy.util.Ln;
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
import android.annotation.TargetApi; import android.annotation.TargetApi;
import android.os.IBinder; import android.os.IBinder;
import android.system.Os;
import java.lang.reflect.Method; import java.lang.reflect.Method;
@ -22,9 +21,7 @@ public final class DisplayControl {
Class<?> classLoaderFactoryClass = Class.forName("com.android.internal.os.ClassLoaderFactory"); Class<?> classLoaderFactoryClass = Class.forName("com.android.internal.os.ClassLoaderFactory");
Method createClassLoaderMethod = classLoaderFactoryClass.getDeclaredMethod("createClassLoader", String.class, String.class, String.class, Method createClassLoaderMethod = classLoaderFactoryClass.getDeclaredMethod("createClassLoader", String.class, String.class, String.class,
ClassLoader.class, int.class, boolean.class, String.class); ClassLoader.class, int.class, boolean.class, String.class);
ClassLoader classLoader = (ClassLoader) createClassLoaderMethod.invoke(null, "/system/framework/services.jar", null, null,
String systemServerClasspath = Os.getenv("SYSTEMSERVERCLASSPATH");
ClassLoader classLoader = (ClassLoader) createClassLoaderMethod.invoke(null, systemServerClasspath, null, null,
ClassLoader.getSystemClassLoader(), 0, true, null); ClassLoader.getSystemClassLoader(), 0, true, null);
displayControlClass = classLoader.loadClass("com.android.server.display.DisplayControl"); displayControlClass = classLoader.loadClass("com.android.server.display.DisplayControl");

View File

@ -322,8 +322,6 @@ public class ControlMessageReaderTest {
DataOutputStream dos = new DataOutputStream(bos); DataOutputStream dos = new DataOutputStream(bos);
dos.writeByte(ControlMessage.TYPE_UHID_CREATE); dos.writeByte(ControlMessage.TYPE_UHID_CREATE);
dos.writeShort(42); // id dos.writeShort(42); // id
dos.writeShort(0x1234); // vendorId
dos.writeShort(0x5678); // productId
dos.writeByte(3); // name size dos.writeByte(3); // name size
dos.write("ABC".getBytes(StandardCharsets.US_ASCII)); dos.write("ABC".getBytes(StandardCharsets.US_ASCII));
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};
@ -337,8 +335,6 @@ public class ControlMessageReaderTest {
ControlMessage event = reader.read(); 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.assertEquals(0x1234, event.getVendorId());
Assert.assertEquals(0x5678, event.getProductId());
Assert.assertEquals("ABC", event.getText()); Assert.assertEquals("ABC", event.getText());
Assert.assertArrayEquals(data, event.getData()); Assert.assertArrayEquals(data, event.getData());