Compare commits

..

30 Commits

Author SHA1 Message Date
Romain Vimont
9521b2f22a meson-wrap-subprojects wip 2025-10-26 11:51:48 +01:00
Yan
f3d4fde15b Fix handling of non-integer ANDROID_PLATFORM
ANDROID_PLATFORM is not always an integer; it can also be a value like
"36.1". Handle such cases properly.

This fixes the following error:

    server/build_without_gradle.sh: line 89:
    [[: 36.1: syntax error: invalid arithmetic operator (error token is ".1")

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

Signed-off-by: Romain Vimont <rom@rom1v.com>
2025-10-19 21:00:05 +02:00
Romain Vimont
eee3f24739 Upgrade Gradle and use Android SDK 36 2025-10-19 21:00:05 +02:00
Romain Vimont
3e40b24737 Fix UHID_OUTPUT message parsing
The bounds check was incorrect.

Fixes #6415 <https://github.com/Genymobile/scrcpy/issues/6415>
2025-10-09 09:35:14 +02:00
Romain Vimont
9d7a4c88e0 Apply workarounds in the cleanup process
Accessing settings may require workarounds on certain devices.

Fixes #6405 <https://github.com/Genymobile/scrcpy/issues/6405>
2025-10-05 21:36:10 +02:00
Romain Vimont
e5e58b1b30 Upgrade links to 3.3.3 2025-09-27 16:10:10 +02:00
Romain Vimont
10a0974f43 Bump version to 3.3.3 2025-09-23 21:18:45 +02:00
Romain Vimont
be21e43be5 Fix frame leak on pending frame update
The previous pending frame was not unreferenced before referencing the
new one, causing frames to leak whenever a texture update failed
(typically on Windows when the window is minimized with D3D9).

Refs 6298ef095f
Fixes #4297 <https://github.com/Genymobile/scrcpy/issues/4297>
Fixes #6357 <https://github.com/Genymobile/scrcpy/issues/6357>
2025-09-23 21:18:45 +02:00
Romain Vimont
bfb0872493 Avoid resetting pending frame
The function update_texture() calls update_texture_internal() and falls
back to set_pending_frame() if it fails.

When the frame passed is the pending frame, call only the _internal()
version instead.

This will prevent issues with frame reference counts by ensuring the
source and destination frames are never the same.

Refs 6298ef095f
Refs #6357 <https://github.com/Genymobile/scrcpy/issues/6357>
2025-09-23 21:18:08 +02:00
Romain Vimont
e11399aff0 Ignore unknown methods in IDisplayWindowListener
New Android versions may add methods to IDisplayWindowListener.aidl.
When these methods are called by the system, they result in an
AbstractMethodError because they are not implemented on the scrcpy side.

To avoid releasing a new version for each newly added method, ignore
them at the Binder level.

Refs afaca80b37
Fixes #6362 <https://github.com/Genymobile/scrcpy/issues/6362>
2025-09-18 10:29:42 +02:00
David Griswold
9d56d26d45 Make virtual display presentable
With this flag, apps with baked in two-screen support can see the
virtual display as an external display they can present to.

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

Signed-off-by: Romain Vimont <rom@rom1v.com>
2025-09-11 21:02:13 +02:00
Romain Vimont
f663bbec12 Update links to 3.3.2 2025-09-06 14:54:36 +02:00
Romain Vimont
2506d1768b Bump version to 3.3.2 2025-09-06 14:36:37 +02:00
Romain Vimont
4ee94cb845 Workaround clipboard issue on Samsung devices
Fixes #6224 <https://github.com/Genymobile/scrcpy/issues/6224>

Co-authored-by: Simon Chan <1330321+yume-chan@users.noreply.github.com>
2025-09-06 14:36:33 +02:00
Romain Vimont
afaca80b37 Fix virtual display after Android 16 upgrade
Several methods have been added upstream to IDisplayWindowListener.aidl,
causing an AbstractMethodError when they are called on the listener
instance implemented by scrcpy.

Fixes #6234 <https://github.com/Genymobile/scrcpy/issues/6234>
Fixes #6331 <https://github.com/Genymobile/scrcpy/issues/6331>
2025-09-06 14:19:43 +02:00
Filip Buda
8057835a0d Catch CTRL_BREAK_EVENT signal on Windows
This ensures the process can terminate properly when a CTRL_BREAK_EVENT
signal is sent programmatically.

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

Signed-off-by: Romain Vimont <rom@rom1v.com>
2025-08-12 18:17:32 +02:00
Yan
e47529ab9c Fix gl_context declared type
The field gl_context is initialized from SDL_GL_CreateContext(), which
returns a raw SDL_GLContext, not a pointer.

The type mismatch was silently ignored by SDL2 because SDL_GLContext
was defined as an alias to `void *` (in SDL3, it is instead an alias to
`struct SDL_GLContextState *`, so compilation fails).

Refs #3895 <https://github.com/Genymobile/scrcpy/pull/3895>
PR #6259 <https://github.com/Genymobile/scrcpy/pull/6259>

Signed-off-by: Romain Vimont <rom@rom1v.com>
2025-08-12 18:08:22 +02:00
Romain Vimont
939c8e7f68 Simplify settings access
For Android >= 12, scrcpy executed "settings" commands (in a new
process) rather than using the ContentProvider directly, due to
permission issues [1].

However, these permission issues were resolved by introducing
FakeContext.getContentResolver() [2].

Therefore, remove the use of "settings" commands and use the
ContentProvider directly in all cases.

Refs [1] cc0902b13c
Refs [2] 91373d906b
Refs #6224 comment <https://github.com/Genymobile/scrcpy/issues/6224#issuecomment-3078418268>
2025-07-17 18:27:21 +02:00
Romain Vimont
eb576c44f8 Replace __WINDOWS__ by _WIN32
Replace the SDL2-specific preprocessor macro __WINDOWS__ by the
"standard" _WIN32 macro.
2025-07-17 18:23:25 +02:00
Romain Vimont
0522d02d40 Add missing includes
The headers were implicitly included recursively, but include them
explicitly.
2025-07-17 18:23:12 +02:00
Romain Vimont
30bfc80f9b Fix style for 80-char limit 2025-07-17 13:20:45 +02:00
Romain Vimont
c3d2ef1b1f Remove redundant ninja install for GA macOS runner
The ninja package is already installed, so this triggered a warning:

> ninja 1.13.0 is already installed and up-to-date. To reinstall 1.13.0,
> run: brew reinstall ninja
2025-07-17 13:20:45 +02:00
Romain Vimont
a79ddc35a7 Update platform-tools checksums
The release binaries of platform-tools_r36.0.0 have changed upstream.

Both releases versions are referenced from
<https://dl.google.com/android/repository/repository2-2.xml>

Refs #6214 <https://github.com/Genymobile/scrcpy/issues/6214>
Refs <https://issuetracker.google.com/issues/431119334>
2025-07-17 13:20:45 +02:00
Romain Vimont
04542a9f58 Fix window leak on icon error 2025-07-17 13:19:15 +02:00
Romain Vimont
8761dcb7a8 Fix SDL dependency script error message
Commit 360936248c mistakenly left an
additional 'H' when replacing $HOST with $DIRNAME.

Refs <https://github.com/Genymobile/scrcpy/pull/6216#issuecomment-3076069802>
2025-07-16 19:09:47 +02:00
Romain Vimont
f01231dff8 Update links to 3.3.1 2025-06-20 20:14:42 +02:00
Romain Vimont
5b18ce0d2e Bump version to 3.3.1 2025-06-20 19:54:16 +02:00
Romain Vimont
4841fdd1ef Add horizontal scrolling support for HID mouse
PR #6172 <https://github.com/Genymobile/scrcpy/pull/6172>
2025-06-20 19:54:16 +02:00
Romain Vimont
fc75319bb2 Fix HID mouse support with SDL precise scrolling
Over HID, only integral scroll values can be sent. When SDL precise
scrolling is active, scroll events may include fractional values (e.g.,
0.05), which are truncated to 0 in the HID event.

To fix the problem, use the integral scroll value reported by SDL, which
internally accumulates fractional deltas.

Fixes #6156 <https://github.com/Genymobile/scrcpy/issues/6156>
PR #6172 <https://github.com/Genymobile/scrcpy/pull/6172>
2025-06-20 19:54:16 +02:00
Romain Vimont
7c8bdccbdc Extend value range for SDK mouse scrolling
SDL precise scrolling can sometimes produce values greater than 1 or
less than -1.

On the wire, the value is encoded as a 16-bit fixed-point number.

Previously, the range was interpreted as [-1, 1], using 1 bit for the
integral part (the sign) and 15 bits for the fractional part.

To support larger values, interpret the range as [-16, 16] instead,
using 5 bits for the integral part and 11 bits for the fractional part
(which is more than enough).

PR #6172 <https://github.com/Genymobile/scrcpy/pull/6172>
2025-06-20 19:54:16 +02:00
37 changed files with 207 additions and 152 deletions

View File

@@ -202,8 +202,7 @@ jobs:
- name: Install dependencies
run: |
brew install meson ninja nasm libiconv zlib automake autoconf \
libtool
brew install meson nasm libiconv zlib automake autoconf libtool
- name: Build
env:
@@ -245,7 +244,7 @@ jobs:
uses: actions/checkout@v4
- name: Install dependencies
run: brew install meson ninja nasm libiconv zlib automake
run: brew install meson nasm libiconv zlib automake
# autoconf and libtool are already installed on macos-13
- name: Build

View File

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

View File

@@ -7,7 +7,7 @@ cd "$DEPS_DIR"
VERSION=36.0.0
FILENAME=platform-tools_r$VERSION-darwin.zip
PROJECT_DIR=platform-tools-$VERSION-darwin
SHA256SUM=b241878e6ec20650b041bf715ea05f7d5dc73bd24529464bd9cf68946e3132bd
SHA256SUM=d3e9fa1df3345cf728586908426615a60863d2632f73f1ce14f0f1349ef000fd
cd "$SOURCES_DIR"

View File

@@ -7,7 +7,7 @@ cd "$DEPS_DIR"
VERSION=36.0.0
FILENAME=platform-tools_r$VERSION-win.zip
PROJECT_DIR=platform-tools-$VERSION-windows
SHA256SUM=24bd8bebbbb58b9870db202b5c6775c4a49992632021c60750d9d8ec8179d5f0
SHA256SUM=12c2841f354e92a0eb2fd7bf6f0f9bf8538abce7bd6b060ac8349d6f6a61107c
cd "$SOURCES_DIR"

View File

@@ -28,7 +28,7 @@ export CXXFLAGS="$CFLAGS"
if [[ -d "$DIRNAME" ]]
then
echo "'$PWD/$HDIRNAME' already exists, not reconfigured"
echo "'$PWD/$DIRNAME' already exists, not reconfigured"
cd "$DIRNAME"
else
mkdir "$DIRNAME"

View File

@@ -112,13 +112,19 @@ cc = meson.get_compiler('c')
static = get_option('static')
sdl2_proj = subproject('sdl2')
sdl2_dep = sdl2_proj.get_variable('sdl2_dep')
meson.override_dependency('sdl2', sdl2_dep)
dependencies = [
dependency('libavformat', version: '>= 57.33', static: static),
dependency('libavcodec', version: '>= 57.37', static: static),
dependency('libavutil', static: static),
dependency('libswresample', static: static),
dependency('sdl2', version: '>= 2.0.5', static: static),
dependency('sdl2', static: static),
]
#dependency('sdl2', version: '>= 2.0.5', static: static),
if v4l2_support
dependencies += dependency('libavdevice', static: static)

View File

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

View File

@@ -103,7 +103,7 @@ argv_to_string(const char *const *argv, char *buf, size_t bufsize) {
static void
show_adb_installation_msg(void) {
#ifndef __WINDOWS__
#ifndef _WIN32
static const struct {
const char *binary;
const char *command;
@@ -331,7 +331,7 @@ sc_adb_reverse_remove(struct sc_intr *intr, const char *serial,
bool
sc_adb_push(struct sc_intr *intr, const char *serial, const char *local,
const char *remote, unsigned flags) {
#ifdef __WINDOWS__
#ifdef _WIN32
// Windows will parse the string, so the paths must be quoted
// (see sys/win/command.c)
local = sc_str_quote(local);
@@ -351,7 +351,7 @@ sc_adb_push(struct sc_intr *intr, const char *serial, const char *local,
sc_pid pid = sc_adb_execute(argv, flags);
#ifdef __WINDOWS__
#ifdef _WIN32
free((void *) remote);
free((void *) local);
#endif
@@ -362,7 +362,7 @@ sc_adb_push(struct sc_intr *intr, const char *serial, const char *local,
bool
sc_adb_install(struct sc_intr *intr, const char *serial, const char *local,
unsigned flags) {
#ifdef __WINDOWS__
#ifdef _WIN32
// Windows will parse the string, so the local name must be quoted
// (see sys/win/command.c)
local = sc_str_quote(local);
@@ -377,7 +377,7 @@ sc_adb_install(struct sc_intr *intr, const char *serial, const char *local,
sc_pid pid = sc_adb_execute(argv, flags);
#ifdef __WINDOWS__
#ifdef _WIN32
free((void *) local);
#endif

View File

@@ -53,7 +53,7 @@ sc_device_msg_deserialize(const uint8_t *buf, size_t len,
}
uint16_t id = sc_read16be(&buf[1]);
size_t size = sc_read16be(&buf[3]);
if (size < len - 5) {
if (size > len - 5) {
return 0; // not available
}
uint8_t *data = malloc(size);

View File

@@ -170,6 +170,7 @@ sc_display_set_pending_frame(struct sc_display *display, const AVFrame *frame) {
}
}
av_frame_unref(display->pending.frame);
int r = av_frame_ref(display->pending.frame, frame);
if (r) {
LOGE("Could not ref frame: %d", r);
@@ -181,6 +182,11 @@ sc_display_set_pending_frame(struct sc_display *display, const AVFrame *frame) {
return true;
}
// Forward declaration
static bool
sc_display_update_texture_internal(struct sc_display *display,
const AVFrame *frame);
static bool
sc_display_apply_pending(struct sc_display *display) {
if (display->pending.flags & SC_DISPLAY_PENDING_FLAG_SIZE) {
@@ -196,7 +202,8 @@ sc_display_apply_pending(struct sc_display *display) {
if (display->pending.flags & SC_DISPLAY_PENDING_FLAG_FRAME) {
assert(display->pending.frame);
bool ok = sc_display_update_texture(display, display->pending.frame);
bool ok = sc_display_update_texture_internal(display,
display->pending.frame);
if (!ok) {
return false;
}

View File

@@ -22,7 +22,7 @@ struct sc_display {
struct sc_opengl gl;
#ifdef SC_DISPLAY_FORCE_OPENGL_CORE_PROFILE
SDL_GLContext *gl_context;
SDL_GLContext gl_context;
#endif
bool mipmaps;

View File

@@ -1,6 +1,7 @@
#include "common.h"
#include <stdbool.h>
#include <stdio.h>
#ifdef HAVE_V4L2
# include <libavdevice/avdevice.h>
#endif

View File

@@ -93,7 +93,7 @@ struct scrcpy {
#ifdef _WIN32
static BOOL WINAPI windows_ctrl_handler(DWORD ctrl_type) {
if (ctrl_type == CTRL_C_EVENT) {
if (ctrl_type == CTRL_C_EVENT || ctrl_type == CTRL_BREAK_EVENT) {
sc_push_event(SDL_QUIT);
return TRUE;
}

View File

@@ -225,7 +225,7 @@ sc_screen_render_novideo(struct sc_screen *screen) {
(void) res; // any error already logged
}
#if defined(__APPLE__) || defined(__WINDOWS__)
#if defined(__APPLE__) || defined(_WIN32)
# define CONTINUOUS_RESIZING_WORKAROUND
#endif
@@ -409,7 +409,7 @@ sc_screen_init(struct sc_screen *screen,
} else {
// without video, the icon is used as window content, it must be present
LOGE("Could not load icon");
goto error_destroy_fps_counter;
goto error_destroy_window;
}
SDL_Surface *icon_novideo = params->video ? NULL : icon;

View File

@@ -2,6 +2,7 @@
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#ifdef _WIN32
# include <ws2tcpip.h>

View File

@@ -191,7 +191,8 @@ sc_vecdeque_reallocdata_(void *ptr, size_t newcap, size_t item_size,
size_t right_len = MIN(size, oldcap - oldorigin);
assert(right_len);
memcpy(newptr, (char *) ptr + (oldorigin * item_size), right_len * item_size);
memcpy(newptr, (char *) ptr + (oldorigin * item_size),
right_len * item_size);
if (size > right_len) {
memcpy((char *) newptr + (right_len * item_size), ptr,

View File

@@ -127,8 +127,8 @@ static void test_serialize_inject_scroll_event(void) {
.height = 1920,
},
},
.hscroll = 1,
.vscroll = -1,
.hscroll = 16,
.vscroll = -16,
.buttons = 1,
},
};
@@ -141,8 +141,8 @@ static void test_serialize_inject_scroll_event(void) {
SC_CONTROL_MSG_TYPE_INJECT_SCROLL_EVENT,
0x00, 0x00, 0x01, 0x04, 0x00, 0x00, 0x04, 0x02, // 260 1026
0x04, 0x38, 0x07, 0x80, // 1080 1920
0x7F, 0xFF, // 1 (float encoded as i16)
0x80, 0x00, // -1 (float encoded as i16)
0x7F, 0xFF, // 16 (float encoded as i16 in the range [-16, 16])
0x80, 0x00, // -16 (float encoded as i16 in the range [-16, 16])
0x00, 0x00, 0x00, 0x01, // 1
};
assert(!memcmp(buf, expected, sizeof(expected)));

View File

@@ -7,7 +7,7 @@ buildscript {
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:8.7.1'
classpath 'com.android.tools.build:gradle:8.13.0'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files

View File

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

View File

@@ -6,11 +6,11 @@
Download a static build of the [latest release]:
- [`scrcpy-linux-x86_64-v3.3.tar.gz`][direct-linux-x86_64] (x86_64)
<sub>SHA-256: `a0abf37003c3c47a53c1b2a12420296a2b0ee323cf3610fd6fbf9d9bab9d99f3`</sub>
- [`scrcpy-linux-x86_64-v3.3.3.tar.gz`][direct-linux-x86_64] (x86_64)
<sub>SHA-256: `9b30e813e8191329ba8025dc80cb0f198fb0a318960a3b5c15395cf675c9c638`</sub>
[latest release]: https://github.com/Genymobile/scrcpy/releases/latest
[direct-linux-x86_64]: https://github.com/Genymobile/scrcpy/releases/download/v3.3/scrcpy-linux-x86_64-v3.3.tar.gz
[direct-linux-x86_64]: https://github.com/Genymobile/scrcpy/releases/download/v3.3.3/scrcpy-linux-x86_64-v3.3.3.tar.gz
and extract it.

View File

@@ -6,15 +6,15 @@
Download a static build of the [latest release]:
- [`scrcpy-macos-aarch64-v3.3.tar.gz`][direct-macos-aarch64] (aarch64)
<sub>SHA-256: `7a4cdaeb8ba74593edda278c000ddedc8d70a51263a80b16a6345475d42ac21e`</sub>
- [`scrcpy-macos-aarch64-v3.3.3.tar.gz`][direct-macos-aarch64] (aarch64)
<sub>SHA-256: `b93299468f19ae89ac70f7c1453914c41f1f2bcd31f6ab530038da885c19581f`</sub>
- [`scrcpy-macos-x86_64-v3.3.tar.gz`][direct-macos-x86_64] (x86_64)
<sub>SHA-256: `bb3c13aac166b92539371883a8781aa861a7cd18e3e6077e570ab7a1f562f774`</sub>
- [`scrcpy-macos-x86_64-v3.3.3.tar.gz`][direct-macos-x86_64] (x86_64)
<sub>SHA-256: `c767fc1d41e4ae26e40558656570962f474739924fd22ee023d8754889ee4366`</sub>
[latest release]: https://github.com/Genymobile/scrcpy/releases/latest
[direct-macos-aarch64]: https://github.com/Genymobile/scrcpy/releases/download/v3.3/scrcpy-macos-aarch64-v3.3.tar.gz
[direct-macos-x86_64]: https://github.com/Genymobile/scrcpy/releases/download/v3.3/scrcpy-macos-x86_64-v3.3.tar.gz
[direct-macos-aarch64]: https://github.com/Genymobile/scrcpy/releases/download/v3.3.3/scrcpy-macos-aarch64-v3.3.3.tar.gz
[direct-macos-x86_64]: https://github.com/Genymobile/scrcpy/releases/download/v3.3.3/scrcpy-macos-x86_64-v3.3.3.tar.gz
and extract it.

View File

@@ -6,14 +6,14 @@
Download the [latest release]:
- [`scrcpy-win64-v3.3.zip`][direct-win64] (64-bit)
<sub>SHA-256: `a120cb4be7cde2891af38e83d2008173a0b6b6b5e344b2dfe668d0f892999933`</sub>
- [`scrcpy-win32-v3.3.zip`][direct-win32] (32-bit)
<sub>SHA-256: `e409ab83f8c57bd6ac741d652635cab7699fcf3d384e233833872f117b993ca6`</sub>
- [`scrcpy-win64-v3.3.3.zip`][direct-win64] (64-bit)
<sub>SHA-256: `4b458d33d0436688c69875cd267cae6fa8be08aa3c17772edf3a940a3dc4b17e`</sub>
- [`scrcpy-win32-v3.3.3.zip`][direct-win32] (32-bit)
<sub>SHA-256: `e3d43e21c0bd6e070381c390c1e4cccd48a1e71ae73a8c217e6e6b8506598c79`</sub>
[latest release]: https://github.com/Genymobile/scrcpy/releases/latest
[direct-win64]: https://github.com/Genymobile/scrcpy/releases/download/v3.3/scrcpy-win64-v3.3.zip
[direct-win32]: https://github.com/Genymobile/scrcpy/releases/download/v3.3/scrcpy-win32-v3.3.zip
[direct-win64]: https://github.com/Genymobile/scrcpy/releases/download/v3.3.3/scrcpy-win64-v3.3.3.zip
[direct-win32]: https://github.com/Genymobile/scrcpy/releases/download/v3.3.3/scrcpy-win32-v3.3.3.zip
and extract it.

View File

@@ -1,7 +1,7 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.3-bin.zip
# https://gradle.org/release-checksums/
distributionSha256Sum=d725d707bfabd4dfdc958c624003b3c80accc03f7037b5122c4b1d0ef15cecab
distributionSha256Sum=bd71102213493060956ec229d946beee57158dbd89d0e62b91bca0fa2c5f3531
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

View File

@@ -2,8 +2,8 @@
set -e
BUILDDIR=build-auto
PREBUILT_SERVER_URL=https://github.com/Genymobile/scrcpy/releases/download/v3.3/scrcpy-server-v3.3
PREBUILT_SERVER_SHA256=351cb2edc7e4c2c75f09a7933fdabcf137be52e2602df154f24ec02db46e9e51
PREBUILT_SERVER_URL=https://github.com/Genymobile/scrcpy/releases/download/v3.3.3/scrcpy-server-v3.3.3
PREBUILT_SERVER_SHA256=7e70323ba7f259649dd4acce97ac4fefbae8102b2c6d91e2e7be613fd5354be0
echo "[scrcpy] Downloading prebuilt server..."
wget "$PREBUILT_SERVER_URL" -O scrcpy-server

View File

@@ -1,5 +1,5 @@
project('scrcpy', 'c',
version: '3.3',
version: '3.3.3',
meson_version: '>= 0.49',
default_options: [
'c_std=c11',

View File

@@ -1,15 +1,15 @@
apply plugin: 'com.android.application'
android {
namespace 'com.genymobile.scrcpy'
compileSdk 35
namespace = 'com.genymobile.scrcpy'
compileSdk 36
defaultConfig {
applicationId "com.genymobile.scrcpy"
applicationId = "com.genymobile.scrcpy"
minSdkVersion 21
targetSdkVersion 35
versionCode 30300
versionName "3.3"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
targetSdkVersion 36
versionCode 30303
versionName "3.3.3"
testInstrumentationRunner = "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
@@ -18,8 +18,11 @@ android {
}
}
buildFeatures {
buildConfig true
aidl true
buildConfig = true
aidl = true
}
lint {
disable 'UseRequiresApi'
}
}

View File

@@ -12,10 +12,10 @@
set -e
SCRCPY_DEBUG=false
SCRCPY_VERSION_NAME=3.3
SCRCPY_VERSION_NAME=3.3.3
PLATFORM=${ANDROID_PLATFORM:-35}
BUILD_TOOLS=${ANDROID_BUILD_TOOLS:-35.0.0}
PLATFORM=${ANDROID_PLATFORM:-36}
BUILD_TOOLS=${ANDROID_BUILD_TOOLS:-36.0.0}
PLATFORM_TOOLS="$ANDROID_HOME/platforms/android-$PLATFORM"
BUILD_TOOLS_DIR="$ANDROID_HOME/build-tools/$BUILD_TOOLS"
@@ -86,7 +86,7 @@ javac -encoding UTF-8 -bootclasspath "$ANDROID_JAR" \
echo "Dexing..."
cd "$CLASSES_DIR"
if [[ $PLATFORM -lt 31 ]]
if [[ "${PLATFORM%%.*}" -lt 31 ]]
then
# use dx
"$BUILD_TOOLS_DIR/dx" --dex --output "$BUILD_DIR/classes.dex" \

View File

@@ -48,19 +48,4 @@ oneway interface IDisplayWindowListener {
* Called when a display is removed from the hierarchy.
*/
void onDisplayRemoved(int displayId);
/**
* Called when fixed rotation is started on a display.
*/
void onFixedRotationStarted(int displayId, int newRotation);
/**
* Called when the previous fixed rotation on a display is finished.
*/
void onFixedRotationFinished(int displayId);
/**
* Called when the keep clear ares on a display have changed.
*/
void onKeepClearAreasChanged(int displayId, in List<Rect> restricted, in List<Rect> unrestricted);
}

View File

@@ -196,6 +196,7 @@ public final class CleanUp {
// Needed for workarounds
prepareMainLooper();
Workarounds.apply();
int displayId = Integer.parseInt(args[0]);
int restoreStayOn = Integer.parseInt(args[1]);

View File

@@ -5,7 +5,6 @@ import com.genymobile.scrcpy.wrappers.ServiceManager;
import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.content.AttributionSource;
import android.content.ClipboardManager;
import android.content.ContentResolver;
import android.content.Context;
import android.content.ContextWrapper;
@@ -91,6 +90,11 @@ public final class FakeContext extends ContextWrapper {
return this;
}
@Override
public Context createPackageContext(String packageName, int flags) {
return this;
}
@Override
public ContentResolver getContentResolver() {
return contentResolver;
@@ -104,9 +108,11 @@ public final class FakeContext extends ContextWrapper {
return null;
}
if (Context.CLIPBOARD_SERVICE.equals(name)) {
// "semclipboard" is a Samsung-internal service
// See <https://github.com/Genymobile/scrcpy/issues/6224>
if (Context.CLIPBOARD_SERVICE.equals(name) || "semclipboard".equals(name)) {
try {
Field field = ClipboardManager.class.getDeclaredField("mContext");
Field field = service.getClass().getDeclaredField("mContext");
field.setAccessible(true);
field.set(service, this);
} catch (ReflectiveOperationException e) {

View File

@@ -226,7 +226,11 @@ public final class Server {
private static void internalMain(String... args) throws Exception {
Thread.setDefaultUncaughtExceptionHandler((t, e) -> {
Thread.UncaughtExceptionHandler defaultHandler = Thread.getDefaultUncaughtExceptionHandler();
Ln.e("Exception on thread " + t, e);
if (defaultHandler != null) {
defaultHandler.uncaughtException(t, e);
}
});
prepareMainLooper();

View File

@@ -1,13 +1,8 @@
package com.genymobile.scrcpy.util;
import com.genymobile.scrcpy.AndroidVersions;
import com.genymobile.scrcpy.wrappers.ContentProvider;
import com.genymobile.scrcpy.wrappers.ServiceManager;
import android.os.Build;
import java.io.IOException;
public final class Settings {
public static final String TABLE_SYSTEM = ContentProvider.TABLE_SYSTEM;
@@ -18,66 +13,26 @@ public final class Settings {
/* not instantiable */
}
private static void execSettingsPut(String table, String key, String value) throws SettingsException {
try {
Command.exec("settings", "put", table, key, value);
} catch (IOException | InterruptedException e) {
throw new SettingsException("put", table, key, value, e);
}
}
private static String execSettingsGet(String table, String key) throws SettingsException {
try {
return Command.execReadLine("settings", "get", table, key);
} catch (IOException | InterruptedException e) {
throw new SettingsException("get", table, key, null, e);
}
}
public static String getValue(String table, String key) throws SettingsException {
if (Build.VERSION.SDK_INT <= AndroidVersions.API_30_ANDROID_11) {
// on Android >= 12, it always fails: <https://github.com/Genymobile/scrcpy/issues/2788>
try (ContentProvider provider = ServiceManager.getActivityManager().createSettingsProvider()) {
return provider.getValue(table, key);
} catch (SettingsException e) {
Ln.w("Could not get settings value via ContentProvider, fallback to settings process", e);
}
try (ContentProvider provider = ServiceManager.getActivityManager().createSettingsProvider()) {
return provider.getValue(table, key);
}
return execSettingsGet(table, key);
}
public static void putValue(String table, String key, String value) throws SettingsException {
if (Build.VERSION.SDK_INT <= AndroidVersions.API_30_ANDROID_11) {
// on Android >= 12, it always fails: <https://github.com/Genymobile/scrcpy/issues/2788>
try (ContentProvider provider = ServiceManager.getActivityManager().createSettingsProvider()) {
provider.putValue(table, key, value);
} catch (SettingsException e) {
Ln.w("Could not put settings value via ContentProvider, fallback to settings process", e);
}
try (ContentProvider provider = ServiceManager.getActivityManager().createSettingsProvider()) {
provider.putValue(table, key, value);
}
execSettingsPut(table, key, value);
}
public static String getAndPutValue(String table, String key, String value) throws SettingsException {
if (Build.VERSION.SDK_INT <= AndroidVersions.API_30_ANDROID_11) {
// on Android >= 12, it always fails: <https://github.com/Genymobile/scrcpy/issues/2788>
try (ContentProvider provider = ServiceManager.getActivityManager().createSettingsProvider()) {
String oldValue = provider.getValue(table, key);
if (!value.equals(oldValue)) {
provider.putValue(table, key, value);
}
return oldValue;
} catch (SettingsException e) {
Ln.w("Could not get and put settings value via ContentProvider, fallback to settings process", e);
try (ContentProvider provider = ServiceManager.getActivityManager().createSettingsProvider()) {
String oldValue = provider.getValue(table, key);
if (!value.equals(oldValue)) {
provider.putValue(table, key, value);
}
return oldValue;
}
String oldValue = getValue(table, key);
if (!value.equals(oldValue)) {
putValue(table, key, value);
}
return oldValue;
}
}

View File

@@ -25,6 +25,7 @@ public class NewDisplayCapture extends SurfaceCapture {
// Internal fields copied from android.hardware.display.DisplayManager
private static final int VIRTUAL_DISPLAY_FLAG_PUBLIC = android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC;
private static final int VIRTUAL_DISPLAY_FLAG_PRESENTATION = android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_PRESENTATION;
private static final int VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY = android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY;
private static final int VIRTUAL_DISPLAY_FLAG_SUPPORTS_TOUCH = 1 << 6;
private static final int VIRTUAL_DISPLAY_FLAG_ROTATES_WITH_CONTENT = 1 << 7;
@@ -169,6 +170,7 @@ public class NewDisplayCapture extends SurfaceCapture {
int virtualDisplayId;
try {
int flags = VIRTUAL_DISPLAY_FLAG_PUBLIC
| VIRTUAL_DISPLAY_FLAG_PRESENTATION
| VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY
| VIRTUAL_DISPLAY_FLAG_SUPPORTS_TOUCH
| VIRTUAL_DISPLAY_FLAG_ROTATES_WITH_CONTENT;

View File

@@ -1,10 +1,11 @@
package com.genymobile.scrcpy.wrappers;
import android.content.res.Configuration;
import android.graphics.Rect;
import android.view.IDisplayWindowListener;
import com.genymobile.scrcpy.util.Ln;
import java.util.List;
import android.content.res.Configuration;
import android.os.Parcel;
import android.os.RemoteException;
import android.view.IDisplayWindowListener;
public class DisplayWindowListener extends IDisplayWindowListener.Stub {
@Override
@@ -23,17 +24,14 @@ public class DisplayWindowListener extends IDisplayWindowListener.Stub {
}
@Override
public void onFixedRotationStarted(int displayId, int newRotation) {
// empty default implementation
}
@Override
public void onFixedRotationFinished(int displayId) {
// empty default implementation
}
@Override
public void onKeepClearAreasChanged(int displayId, List<Rect> restricted, List<Rect> unrestricted) {
// empty default implementation
public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
try {
return super.onTransact(code, data, reply, flags);
} catch (AbstractMethodError e) {
Ln.v("Ignoring AbstractMethodError: " + e.getMessage());
// Ignore unknown methods, write default response to reply parcel
reply.writeNoException();
return true;
}
}
}

View File

@@ -125,7 +125,7 @@ public class ControlMessageReaderTest {
dos.writeShort(1080);
dos.writeShort(1920);
dos.writeShort(0); // 0.0f encoded as i16
dos.writeShort(0x8000); // -1.0f encoded as i16
dos.writeShort(0x8000); // -16.0f encoded as i16 (the range is [-16, 16])
dos.writeInt(1);
byte[] packet = bos.toByteArray();
@@ -139,7 +139,7 @@ public class ControlMessageReaderTest {
Assert.assertEquals(1080, event.getPosition().getScreenSize().getWidth());
Assert.assertEquals(1920, event.getPosition().getScreenSize().getHeight());
Assert.assertEquals(0f, event.getHScroll(), 0f);
Assert.assertEquals(-1f, event.getVScroll(), 0f);
Assert.assertEquals(-16f, event.getVScroll(), 0f);
Assert.assertEquals(1, event.getButtons());
Assert.assertEquals(-1, bis.read()); // EOS

View File

@@ -0,0 +1,77 @@
project('sdl2', 'c')
prefix = get_option('prefix')
link_type = get_option('default_library')
make_prog = find_program('make', required: true)
configure_command = []
configure_args = [
'./configure',
'--prefix=' + prefix,
]
if host_machine.system() == 'linux'
configure_args += [
'--enable-video-wayland',
'--enable-video-x11',
]
endif
if link_type == 'static'
configure_args += [
'--enable-static',
'--disable-shared',
]
else
configure_args += [
'--disable-static',
'--enable-shared',
]
endif
if meson.is_cross_build()
configure_args += [
'--host=' + host_machine.cpu_family() + '-w64-mingw32',
]
endif
configure_env = environment()
configure_env.set('CFLAGS', '-O2')
configure_env.set('CXXFLAGS', '-O2')
configure_target = custom_target('sdl2_configure',
output: 'config.h',
command: configure_args,
env: configure_env,
console: true
)
if host_machine.system() == 'windows' and link_type == 'shared'
build_output = ['SDL2.dll']
elif link_type == 'shared'
build_output = ['libSDL2.so']
else
build_output = ['libSDL2.a']
endif
sdl2_build = custom_target('sdl2_build',
depends: configure_target,
output: build_output,
command: [make_prog, '-j'],
console: true,
build_by_default: true
)
sdl2_install = custom_target('sdl2_install',
depends: sdl2_build,
output: 'install_done',
command: [make_prog, 'install', '&&', 'touch', '@OUTPUT@'],
console: true,
build_by_default: true,
install: false
)
sdl2_dep = declare_dependency(sources: sdl2_install)

9
subprojects/sdl2.wrap Normal file
View File

@@ -0,0 +1,9 @@
[wrap-file]
directory = SDL-release-2.32.8
source_url = https://github.com/libsdl-org/SDL/archive/refs/tags/release-2.32.8.tar.gz
source_filename = libsdl2-2.32.8.tar.gz
source_hash = dd35e05644ae527848d02433bec24dd0ea65db59faecf1a0e5d1880c533dac2c
patch_directory = sdl2
[provide]
sdl2 = sdl2_dep