Compare commits
9 Commits
turn_scree
...
crossbuild
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
67f356f881 | ||
|
|
c573bd2a33 | ||
|
|
acb2988837 | ||
|
|
85a94dd4b5 | ||
|
|
94031dfe97 | ||
|
|
b43a9e8e7a | ||
|
|
a9d6cb5837 | ||
|
|
2f92686930 | ||
|
|
bb88b60227 |
@@ -98,77 +98,24 @@ endif
|
|||||||
|
|
||||||
cc = meson.get_compiler('c')
|
cc = meson.get_compiler('c')
|
||||||
|
|
||||||
crossbuild_windows = meson.is_cross_build() and host_machine.system() == 'windows'
|
dependencies = [
|
||||||
|
dependency('libavformat', version: '>= 57.33'),
|
||||||
|
dependency('libavcodec', version: '>= 57.37'),
|
||||||
|
dependency('libavutil'),
|
||||||
|
dependency('libswresample'),
|
||||||
|
dependency('sdl2', version: '>= 2.0.5'),
|
||||||
|
]
|
||||||
|
|
||||||
if not crossbuild_windows
|
if v4l2_support
|
||||||
|
dependencies += dependency('libavdevice')
|
||||||
# native build
|
endif
|
||||||
dependencies = [
|
|
||||||
dependency('libavformat', version: '>= 57.33'),
|
|
||||||
dependency('libavcodec', version: '>= 57.37'),
|
|
||||||
dependency('libavutil'),
|
|
||||||
dependency('libswresample'),
|
|
||||||
dependency('sdl2', version: '>= 2.0.5'),
|
|
||||||
]
|
|
||||||
|
|
||||||
if v4l2_support
|
|
||||||
dependencies += dependency('libavdevice')
|
|
||||||
endif
|
|
||||||
|
|
||||||
if usb_support
|
|
||||||
dependencies += dependency('libusb-1.0')
|
|
||||||
endif
|
|
||||||
|
|
||||||
else
|
|
||||||
# cross-compile mingw32 build (from Linux to Windows)
|
|
||||||
prebuilt_sdl2 = meson.get_cross_property('prebuilt_sdl2')
|
|
||||||
sdl2_bin_dir = meson.current_source_dir() + '/prebuilt-deps/data/' + prebuilt_sdl2 + '/bin'
|
|
||||||
sdl2_lib_dir = meson.current_source_dir() + '/prebuilt-deps/data/' + prebuilt_sdl2 + '/lib'
|
|
||||||
sdl2_include_dir = 'prebuilt-deps/data/' + prebuilt_sdl2 + '/include'
|
|
||||||
|
|
||||||
sdl2 = declare_dependency(
|
|
||||||
dependencies: [
|
|
||||||
cc.find_library('SDL2', dirs: sdl2_bin_dir),
|
|
||||||
cc.find_library('SDL2main', dirs: sdl2_lib_dir),
|
|
||||||
],
|
|
||||||
include_directories: include_directories(sdl2_include_dir)
|
|
||||||
)
|
|
||||||
|
|
||||||
prebuilt_ffmpeg = meson.get_cross_property('prebuilt_ffmpeg')
|
|
||||||
ffmpeg_bin_dir = meson.current_source_dir() + '/prebuilt-deps/data/' + prebuilt_ffmpeg + '/bin'
|
|
||||||
ffmpeg_include_dir = 'prebuilt-deps/data/' + prebuilt_ffmpeg + '/include'
|
|
||||||
|
|
||||||
ffmpeg = declare_dependency(
|
|
||||||
dependencies: [
|
|
||||||
cc.find_library('avcodec-60', dirs: ffmpeg_bin_dir),
|
|
||||||
cc.find_library('avformat-60', dirs: ffmpeg_bin_dir),
|
|
||||||
cc.find_library('avutil-58', dirs: ffmpeg_bin_dir),
|
|
||||||
cc.find_library('swresample-4', dirs: ffmpeg_bin_dir),
|
|
||||||
],
|
|
||||||
include_directories: include_directories(ffmpeg_include_dir)
|
|
||||||
)
|
|
||||||
|
|
||||||
prebuilt_libusb = meson.get_cross_property('prebuilt_libusb')
|
|
||||||
libusb_bin_dir = meson.current_source_dir() + '/prebuilt-deps/data/' + prebuilt_libusb + '/bin'
|
|
||||||
libusb_include_dir = 'prebuilt-deps/data/' + prebuilt_libusb + '/include'
|
|
||||||
|
|
||||||
libusb = declare_dependency(
|
|
||||||
dependencies: [
|
|
||||||
cc.find_library('msys-usb-1.0', dirs: libusb_bin_dir),
|
|
||||||
],
|
|
||||||
include_directories: include_directories(libusb_include_dir)
|
|
||||||
)
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
ffmpeg,
|
|
||||||
sdl2,
|
|
||||||
libusb,
|
|
||||||
cc.find_library('mingw32')
|
|
||||||
]
|
|
||||||
|
|
||||||
|
if usb_support
|
||||||
|
dependencies += dependency('libusb-1.0')
|
||||||
endif
|
endif
|
||||||
|
|
||||||
if host_machine.system() == 'windows'
|
if host_machine.system() == 'windows'
|
||||||
|
dependencies += cc.find_library('mingw32')
|
||||||
dependencies += cc.find_library('ws2_32')
|
dependencies += cc.find_library('ws2_32')
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
|||||||
@@ -6,11 +6,11 @@ cd "$DIR"
|
|||||||
mkdir -p "$PREBUILT_DATA_DIR"
|
mkdir -p "$PREBUILT_DATA_DIR"
|
||||||
cd "$PREBUILT_DATA_DIR"
|
cd "$PREBUILT_DATA_DIR"
|
||||||
|
|
||||||
VERSION=6.1-scrcpy-2
|
VERSION=6.1-scrcpy-3
|
||||||
DEP_DIR="ffmpeg-$VERSION"
|
DEP_DIR="ffmpeg-$VERSION"
|
||||||
|
|
||||||
FILENAME="$DEP_DIR".7z
|
FILENAME="$DEP_DIR".7z
|
||||||
SHA256SUM=7f25f638dc24a0f5d4af07a088b6a604cf33548900bbfd2f6ce0bae050b7664d
|
SHA256SUM=b646d18a3d543a4e4c46881568213499f22e4454a464e1552f03f2ac9cc3a05a
|
||||||
|
|
||||||
if [[ -d "$DEP_DIR" ]]
|
if [[ -d "$DEP_DIR" ]]
|
||||||
then
|
then
|
||||||
|
|||||||
@@ -23,11 +23,15 @@ mkdir "$DEP_DIR"
|
|||||||
cd "$DEP_DIR"
|
cd "$DEP_DIR"
|
||||||
|
|
||||||
7z x "../$FILENAME" \
|
7z x "../$FILENAME" \
|
||||||
libusb-1.0.26-binaries/libusb-MinGW-Win32/bin/msys-usb-1.0.dll \
|
libusb-1.0.26-binaries/libusb-MinGW-Win32/ \
|
||||||
libusb-1.0.26-binaries/libusb-MinGW-Win32/include/ \
|
libusb-1.0.26-binaries/libusb-MinGW-Win32/ \
|
||||||
libusb-1.0.26-binaries/libusb-MinGW-x64/bin/msys-usb-1.0.dll \
|
libusb-1.0.26-binaries/libusb-MinGW-x64/ \
|
||||||
libusb-1.0.26-binaries/libusb-MinGW-x64/include/
|
libusb-1.0.26-binaries/libusb-MinGW-x64/
|
||||||
|
|
||||||
mv libusb-1.0.26-binaries/libusb-MinGW-Win32 .
|
mv libusb-1.0.26-binaries/libusb-MinGW-Win32 .
|
||||||
mv libusb-1.0.26-binaries/libusb-MinGW-x64 .
|
mv libusb-1.0.26-binaries/libusb-MinGW-x64 .
|
||||||
rm -rf libusb-1.0.26-binaries
|
rm -rf libusb-1.0.26-binaries
|
||||||
|
|
||||||
|
# Rename the dll to get the same library name on all platforms
|
||||||
|
mv libusb-MinGW-Win32/bin/msys-usb-1.0.dll libusb-MinGW-Win32/bin/libusb-1.0.dll
|
||||||
|
mv libusb-MinGW-x64/bin/msys-usb-1.0.dll libusb-MinGW-x64/bin/libusb-1.0.dll
|
||||||
|
|||||||
@@ -2138,7 +2138,7 @@ parse_args_with_getopt(struct scrcpy_cli_args *args, int argc, char *argv[],
|
|||||||
opts->display_orientation = SC_ORIENTATION_180;
|
opts->display_orientation = SC_ORIENTATION_180;
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
// rotation 1 was 270° counterclockwise, but orientation
|
// rotation 3 was 270° counterclockwise, but orientation
|
||||||
// is expressed clockwise
|
// is expressed clockwise
|
||||||
opts->display_orientation = SC_ORIENTATION_90;
|
opts->display_orientation = SC_ORIENTATION_90;
|
||||||
break;
|
break;
|
||||||
@@ -2531,7 +2531,8 @@ parse_args_with_getopt(struct scrcpy_cli_args *args, int argc, char *argv[],
|
|||||||
if (opts->record_orientation != SC_ORIENTATION_0) {
|
if (opts->record_orientation != SC_ORIENTATION_0) {
|
||||||
if (sc_orientation_is_mirror(opts->record_orientation)) {
|
if (sc_orientation_is_mirror(opts->record_orientation)) {
|
||||||
LOGE("Record orientation only supports rotation, not "
|
LOGE("Record orientation only supports rotation, not "
|
||||||
"flipping: %s", optarg);
|
"flipping: %s",
|
||||||
|
sc_orientation_get_name(opts->record_orientation));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -113,10 +113,10 @@ sc_orientation_apply(enum sc_orientation src, enum sc_orientation transform) {
|
|||||||
// In the final result, we want all the hflips then all the rotations,
|
// In the final result, we want all the hflips then all the rotations,
|
||||||
// so we must move hflip2 to the left:
|
// so we must move hflip2 to the left:
|
||||||
//
|
//
|
||||||
// hflip1 × hflip2 × f(rotate1) × rotate2
|
// hflip1 × hflip2 × rotate1' × rotate2
|
||||||
//
|
//
|
||||||
// with f(rotate1) = | rotate1 if src is 0 or 180
|
// with rotate1' = | rotate1 if src is 0° or 180°
|
||||||
// | rotate1 + 180 if src is 90 or 270
|
// | rotate1 + 180° if src is 90° or 270°
|
||||||
|
|
||||||
src_rotation += 2;
|
src_rotation += 2;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,6 +18,7 @@
|
|||||||
#define SC_SERVER_FILENAME "scrcpy-server"
|
#define SC_SERVER_FILENAME "scrcpy-server"
|
||||||
|
|
||||||
#define SC_SERVER_PATH_DEFAULT PREFIX "/share/scrcpy/" SC_SERVER_FILENAME
|
#define SC_SERVER_PATH_DEFAULT PREFIX "/share/scrcpy/" SC_SERVER_FILENAME
|
||||||
|
#define SC_DEVICE_SERVER_PATH "/data/local/tmp/scrcpy-server.jar"
|
||||||
|
|
||||||
#define SC_ADB_PORT_DEFAULT 5555
|
#define SC_ADB_PORT_DEFAULT 5555
|
||||||
#define SC_SOCKET_NAME_PREFIX "scrcpy_"
|
#define SC_SOCKET_NAME_PREFIX "scrcpy_"
|
||||||
@@ -116,7 +117,7 @@ error:
|
|||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
push_server(struct sc_intr *intr, uint32_t scid, const char *serial) {
|
push_server(struct sc_intr *intr, const char *serial) {
|
||||||
char *server_path = get_server_path();
|
char *server_path = get_server_path();
|
||||||
if (!server_path) {
|
if (!server_path) {
|
||||||
return false;
|
return false;
|
||||||
@@ -126,16 +127,7 @@ push_server(struct sc_intr *intr, uint32_t scid, const char *serial) {
|
|||||||
free(server_path);
|
free(server_path);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
bool ok = sc_adb_push(intr, serial, server_path, SC_DEVICE_SERVER_PATH, 0);
|
||||||
char *device_server_path;
|
|
||||||
if (asprintf(&device_server_path, "/data/local/tmp/scrcpy-server-%08x.jar",
|
|
||||||
scid) == -1) {
|
|
||||||
LOG_OOM();
|
|
||||||
free(server_path);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
bool ok = sc_adb_push(intr, serial, server_path, device_server_path, 0);
|
|
||||||
free(device_server_path);
|
|
||||||
free(server_path);
|
free(server_path);
|
||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
@@ -217,20 +209,13 @@ execute_server(struct sc_server *server,
|
|||||||
const char *serial = server->serial;
|
const char *serial = server->serial;
|
||||||
assert(serial);
|
assert(serial);
|
||||||
|
|
||||||
char *classpath;
|
|
||||||
if (asprintf(&classpath, "CLASSPATH=/data/local/tmp/scrcpy-server-%08x.jar",
|
|
||||||
params->scid) == -1) {
|
|
||||||
LOG_OOM();
|
|
||||||
return SC_PROCESS_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
const char *cmd[128];
|
const char *cmd[128];
|
||||||
unsigned count = 0;
|
unsigned count = 0;
|
||||||
cmd[count++] = sc_adb_get_executable();
|
cmd[count++] = sc_adb_get_executable();
|
||||||
cmd[count++] = "-s";
|
cmd[count++] = "-s";
|
||||||
cmd[count++] = serial;
|
cmd[count++] = serial;
|
||||||
cmd[count++] = "shell";
|
cmd[count++] = "shell";
|
||||||
cmd[count++] = classpath;
|
cmd[count++] = "CLASSPATH=" SC_DEVICE_SERVER_PATH;
|
||||||
cmd[count++] = "app_process";
|
cmd[count++] = "app_process";
|
||||||
|
|
||||||
#ifdef SERVER_DEBUGGER
|
#ifdef SERVER_DEBUGGER
|
||||||
@@ -403,7 +388,6 @@ end:
|
|||||||
for (unsigned i = dyn_idx; i < count; ++i) {
|
for (unsigned i = dyn_idx; i < count; ++i) {
|
||||||
free((char *) cmd[i]);
|
free((char *) cmd[i]);
|
||||||
}
|
}
|
||||||
free(classpath);
|
|
||||||
|
|
||||||
return pid;
|
return pid;
|
||||||
}
|
}
|
||||||
@@ -953,7 +937,7 @@ run_server(void *data) {
|
|||||||
assert(serial);
|
assert(serial);
|
||||||
LOGD("Device serial: %s", serial);
|
LOGD("Device serial: %s", serial);
|
||||||
|
|
||||||
ok = push_server(&server->intr, params->scid, serial);
|
ok = push_server(&server->intr, serial);
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
goto error_connection_failed;
|
goto error_connection_failed;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,8 +14,3 @@ system = 'windows'
|
|||||||
cpu_family = 'x86'
|
cpu_family = 'x86'
|
||||||
cpu = 'i686'
|
cpu = 'i686'
|
||||||
endian = 'little'
|
endian = 'little'
|
||||||
|
|
||||||
[properties]
|
|
||||||
prebuilt_ffmpeg = 'ffmpeg-6.1-scrcpy-2/win32'
|
|
||||||
prebuilt_sdl2 = 'SDL2-2.28.4/i686-w64-mingw32'
|
|
||||||
prebuilt_libusb = 'libusb-1.0.26/libusb-MinGW-Win32'
|
|
||||||
|
|||||||
@@ -14,8 +14,3 @@ system = 'windows'
|
|||||||
cpu_family = 'x86'
|
cpu_family = 'x86'
|
||||||
cpu = 'x86_64'
|
cpu = 'x86_64'
|
||||||
endian = 'little'
|
endian = 'little'
|
||||||
|
|
||||||
[properties]
|
|
||||||
prebuilt_ffmpeg = 'ffmpeg-6.1-scrcpy-2/win64'
|
|
||||||
prebuilt_sdl2 = 'SDL2-2.28.4/x86_64-w64-mingw32'
|
|
||||||
prebuilt_libusb = 'libusb-1.0.26/libusb-MinGW-x64'
|
|
||||||
|
|||||||
@@ -130,7 +130,7 @@ scrcpy --orientation=270 # 270° clockwise
|
|||||||
scrcpy --orientation=flip0 # hflip
|
scrcpy --orientation=flip0 # hflip
|
||||||
scrcpy --orientation=flip90 # hflip + 90° clockwise
|
scrcpy --orientation=flip90 # hflip + 90° clockwise
|
||||||
scrcpy --orientation=flip180 # vflip (hflip + 180°)
|
scrcpy --orientation=flip180 # vflip (hflip + 180°)
|
||||||
scrcpy --orientation=flip270 # hflip + 270°
|
scrcpy --orientation=flip270 # hflip + 270° clockwise
|
||||||
```
|
```
|
||||||
|
|
||||||
The orientation can be set separately for display and record if necessary, via
|
The orientation can be set separately for display and record if necessary, via
|
||||||
|
|||||||
68
release.mk
68
release.mk
@@ -69,58 +69,62 @@ prepare-deps:
|
|||||||
@app/prebuilt-deps/prepare-libusb.sh
|
@app/prebuilt-deps/prepare-libusb.sh
|
||||||
|
|
||||||
build-win32: prepare-deps
|
build-win32: prepare-deps
|
||||||
[ -d "$(WIN32_BUILD_DIR)" ] || ( mkdir "$(WIN32_BUILD_DIR)" && \
|
rm -rf "$(WIN32_BUILD_DIR)"
|
||||||
meson setup "$(WIN32_BUILD_DIR)" \
|
mkdir -p "$(WIN32_BUILD_DIR)/local"
|
||||||
--cross-file cross_win32.txt \
|
cp -r app/prebuilt-deps/data/ffmpeg-6.1-scrcpy-3/win32/. "$(WIN32_BUILD_DIR)/local/"
|
||||||
--buildtype release --strip -Db_lto=true \
|
cp -r app/prebuilt-deps/data/SDL2-2.28.4/i686-w64-mingw32/. "$(WIN32_BUILD_DIR)/local/"
|
||||||
-Dcompile_server=false \
|
cp -r app/prebuilt-deps/data/libusb-1.0.26/libusb-MinGW-Win32/. "$(WIN32_BUILD_DIR)/local/"
|
||||||
-Dportable=true )
|
meson setup "$(WIN32_BUILD_DIR)" \
|
||||||
|
--pkg-config-path="$(WIN32_BUILD_DIR)/local/lib/pkgconfig" \
|
||||||
|
-Dc_args="-I$(PWD)/$(WIN32_BUILD_DIR)/local/include" \
|
||||||
|
-Dc_link_args="-L$(PWD)/$(WIN32_BUILD_DIR)/local/lib" \
|
||||||
|
--cross-file=cross_win32.txt \
|
||||||
|
--buildtype=release --strip -Db_lto=true \
|
||||||
|
-Dcompile_server=false \
|
||||||
|
-Dportable=true
|
||||||
ninja -C "$(WIN32_BUILD_DIR)"
|
ninja -C "$(WIN32_BUILD_DIR)"
|
||||||
|
|
||||||
build-win64: prepare-deps
|
build-win64: prepare-deps
|
||||||
[ -d "$(WIN64_BUILD_DIR)" ] || ( mkdir "$(WIN64_BUILD_DIR)" && \
|
rm -rf "$(WIN64_BUILD_DIR)"
|
||||||
meson setup "$(WIN64_BUILD_DIR)" \
|
mkdir -p "$(WIN64_BUILD_DIR)/local"
|
||||||
--cross-file cross_win64.txt \
|
cp -r app/prebuilt-deps/data/ffmpeg-6.1-scrcpy-3/win64/. "$(WIN64_BUILD_DIR)/local/"
|
||||||
--buildtype release --strip -Db_lto=true \
|
cp -r app/prebuilt-deps/data/SDL2-2.28.4/x86_64-w64-mingw32/. "$(WIN64_BUILD_DIR)/local/"
|
||||||
-Dcompile_server=false \
|
cp -r app/prebuilt-deps/data/libusb-1.0.26/libusb-MinGW-x64/. "$(WIN64_BUILD_DIR)/local/"
|
||||||
-Dportable=true )
|
meson setup "$(WIN64_BUILD_DIR)" \
|
||||||
|
--pkg-config-path="$(WIN64_BUILD_DIR)/local/lib/pkgconfig" \
|
||||||
|
-Dc_args="-I$(PWD)/$(WIN64_BUILD_DIR)/local/include" \
|
||||||
|
-Dc_link_args="-L$(PWD)/$(WIN64_BUILD_DIR)/local/lib" \
|
||||||
|
--cross-file=cross_win64.txt \
|
||||||
|
--buildtype=release --strip -Db_lto=true \
|
||||||
|
-Dcompile_server=false \
|
||||||
|
-Dportable=true
|
||||||
ninja -C "$(WIN64_BUILD_DIR)"
|
ninja -C "$(WIN64_BUILD_DIR)"
|
||||||
|
|
||||||
dist-win32: build-server build-win32
|
dist-win32: build-server build-win32
|
||||||
mkdir -p "$(DIST)/$(WIN32_TARGET_DIR)"
|
mkdir -p "$(DIST)/$(WIN32_TARGET_DIR)"
|
||||||
cp "$(SERVER_BUILD_DIR)"/server/scrcpy-server "$(DIST)/$(WIN32_TARGET_DIR)/"
|
cp "$(SERVER_BUILD_DIR)"/server/scrcpy-server "$(DIST)/$(WIN32_TARGET_DIR)/"
|
||||||
cp "$(WIN32_BUILD_DIR)"/app/scrcpy.exe "$(DIST)/$(WIN32_TARGET_DIR)/"
|
cp "$(WIN32_BUILD_DIR)"/app/scrcpy.exe "$(DIST)/$(WIN32_TARGET_DIR)/"
|
||||||
cp app/data/scrcpy-console.bat "$(DIST)/$(WIN32_TARGET_DIR)"
|
cp app/data/scrcpy-console.bat "$(DIST)/$(WIN32_TARGET_DIR)/"
|
||||||
cp app/data/scrcpy-noconsole.vbs "$(DIST)/$(WIN32_TARGET_DIR)"
|
cp app/data/scrcpy-noconsole.vbs "$(DIST)/$(WIN32_TARGET_DIR)/"
|
||||||
cp app/data/icon.png "$(DIST)/$(WIN32_TARGET_DIR)"
|
cp app/data/icon.png "$(DIST)/$(WIN32_TARGET_DIR)/"
|
||||||
cp app/data/open_a_terminal_here.bat "$(DIST)/$(WIN32_TARGET_DIR)"
|
cp app/data/open_a_terminal_here.bat "$(DIST)/$(WIN32_TARGET_DIR)/"
|
||||||
cp app/prebuilt-deps/data/ffmpeg-6.1-scrcpy-2/win32/bin/avutil-58.dll "$(DIST)/$(WIN32_TARGET_DIR)/"
|
|
||||||
cp app/prebuilt-deps/data/ffmpeg-6.1-scrcpy-2/win32/bin/avcodec-60.dll "$(DIST)/$(WIN32_TARGET_DIR)/"
|
|
||||||
cp app/prebuilt-deps/data/ffmpeg-6.1-scrcpy-2/win32/bin/avformat-60.dll "$(DIST)/$(WIN32_TARGET_DIR)/"
|
|
||||||
cp app/prebuilt-deps/data/ffmpeg-6.1-scrcpy-2/win32/bin/swresample-4.dll "$(DIST)/$(WIN32_TARGET_DIR)/"
|
|
||||||
cp app/prebuilt-deps/data/platform-tools-34.0.5/adb.exe "$(DIST)/$(WIN32_TARGET_DIR)/"
|
cp app/prebuilt-deps/data/platform-tools-34.0.5/adb.exe "$(DIST)/$(WIN32_TARGET_DIR)/"
|
||||||
cp app/prebuilt-deps/data/platform-tools-34.0.5/AdbWinApi.dll "$(DIST)/$(WIN32_TARGET_DIR)/"
|
cp app/prebuilt-deps/data/platform-tools-34.0.5/AdbWinApi.dll "$(DIST)/$(WIN32_TARGET_DIR)/"
|
||||||
cp app/prebuilt-deps/data/platform-tools-34.0.5/AdbWinUsbApi.dll "$(DIST)/$(WIN32_TARGET_DIR)/"
|
cp app/prebuilt-deps/data/platform-tools-34.0.5/AdbWinUsbApi.dll "$(DIST)/$(WIN32_TARGET_DIR)/"
|
||||||
cp app/prebuilt-deps/data/SDL2-2.28.4/i686-w64-mingw32/bin/SDL2.dll "$(DIST)/$(WIN32_TARGET_DIR)/"
|
cp "$(WIN32_BUILD_DIR)"/local/bin/*.dll "$(DIST)/$(WIN32_TARGET_DIR)/"
|
||||||
cp app/prebuilt-deps/data/libusb-1.0.26/libusb-MinGW-Win32/bin/msys-usb-1.0.dll "$(DIST)/$(WIN32_TARGET_DIR)/"
|
|
||||||
|
|
||||||
dist-win64: build-server build-win64
|
dist-win64: build-server build-win64
|
||||||
mkdir -p "$(DIST)/$(WIN64_TARGET_DIR)"
|
mkdir -p "$(DIST)/$(WIN64_TARGET_DIR)"
|
||||||
cp "$(SERVER_BUILD_DIR)"/server/scrcpy-server "$(DIST)/$(WIN64_TARGET_DIR)/"
|
cp "$(SERVER_BUILD_DIR)"/server/scrcpy-server "$(DIST)/$(WIN64_TARGET_DIR)/"
|
||||||
cp "$(WIN64_BUILD_DIR)"/app/scrcpy.exe "$(DIST)/$(WIN64_TARGET_DIR)/"
|
cp "$(WIN64_BUILD_DIR)"/app/scrcpy.exe "$(DIST)/$(WIN64_TARGET_DIR)/"
|
||||||
cp app/data/scrcpy-console.bat "$(DIST)/$(WIN64_TARGET_DIR)"
|
cp app/data/scrcpy-console.bat "$(DIST)/$(WIN64_TARGET_DIR)/"
|
||||||
cp app/data/scrcpy-noconsole.vbs "$(DIST)/$(WIN64_TARGET_DIR)"
|
cp app/data/scrcpy-noconsole.vbs "$(DIST)/$(WIN64_TARGET_DIR)/"
|
||||||
cp app/data/icon.png "$(DIST)/$(WIN64_TARGET_DIR)"
|
cp app/data/icon.png "$(DIST)/$(WIN64_TARGET_DIR)/"
|
||||||
cp app/data/open_a_terminal_here.bat "$(DIST)/$(WIN64_TARGET_DIR)"
|
cp app/data/open_a_terminal_here.bat "$(DIST)/$(WIN64_TARGET_DIR)/"
|
||||||
cp app/prebuilt-deps/data/ffmpeg-6.1-scrcpy-2/win64/bin/avutil-58.dll "$(DIST)/$(WIN64_TARGET_DIR)/"
|
|
||||||
cp app/prebuilt-deps/data/ffmpeg-6.1-scrcpy-2/win64/bin/avcodec-60.dll "$(DIST)/$(WIN64_TARGET_DIR)/"
|
|
||||||
cp app/prebuilt-deps/data/ffmpeg-6.1-scrcpy-2/win64/bin/avformat-60.dll "$(DIST)/$(WIN64_TARGET_DIR)/"
|
|
||||||
cp app/prebuilt-deps/data/ffmpeg-6.1-scrcpy-2/win64/bin/swresample-4.dll "$(DIST)/$(WIN64_TARGET_DIR)/"
|
|
||||||
cp app/prebuilt-deps/data/platform-tools-34.0.5/adb.exe "$(DIST)/$(WIN64_TARGET_DIR)/"
|
cp app/prebuilt-deps/data/platform-tools-34.0.5/adb.exe "$(DIST)/$(WIN64_TARGET_DIR)/"
|
||||||
cp app/prebuilt-deps/data/platform-tools-34.0.5/AdbWinApi.dll "$(DIST)/$(WIN64_TARGET_DIR)/"
|
cp app/prebuilt-deps/data/platform-tools-34.0.5/AdbWinApi.dll "$(DIST)/$(WIN64_TARGET_DIR)/"
|
||||||
cp app/prebuilt-deps/data/platform-tools-34.0.5/AdbWinUsbApi.dll "$(DIST)/$(WIN64_TARGET_DIR)/"
|
cp app/prebuilt-deps/data/platform-tools-34.0.5/AdbWinUsbApi.dll "$(DIST)/$(WIN64_TARGET_DIR)/"
|
||||||
cp app/prebuilt-deps/data/SDL2-2.28.4/x86_64-w64-mingw32/bin/SDL2.dll "$(DIST)/$(WIN64_TARGET_DIR)/"
|
cp "$(WIN64_BUILD_DIR)"/local/bin/*.dll "$(DIST)/$(WIN64_TARGET_DIR)/"
|
||||||
cp app/prebuilt-deps/data/libusb-1.0.26/libusb-MinGW-x64/bin/msys-usb-1.0.dll "$(DIST)/$(WIN64_TARGET_DIR)/"
|
|
||||||
|
|
||||||
zip-win32: dist-win32
|
zip-win32: dist-win32
|
||||||
cd "$(DIST)"; \
|
cd "$(DIST)"; \
|
||||||
|
|||||||
@@ -11,6 +11,8 @@ public interface AsyncProcessor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void start(TerminationListener listener);
|
void start(TerminationListener listener);
|
||||||
|
|
||||||
void stop();
|
void stop();
|
||||||
|
|
||||||
void join() throws InterruptedException;
|
void join() throws InterruptedException;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -289,18 +289,17 @@ public class CameraCapture extends SurfaceCapture {
|
|||||||
List<OutputConfiguration> outputs = Arrays.asList(outputConfig);
|
List<OutputConfiguration> outputs = Arrays.asList(outputConfig);
|
||||||
|
|
||||||
int sessionType = highSpeed ? SessionConfiguration.SESSION_HIGH_SPEED : SessionConfiguration.SESSION_REGULAR;
|
int sessionType = highSpeed ? SessionConfiguration.SESSION_HIGH_SPEED : SessionConfiguration.SESSION_REGULAR;
|
||||||
SessionConfiguration sessionConfig = new SessionConfiguration(sessionType, outputs, cameraExecutor,
|
SessionConfiguration sessionConfig = new SessionConfiguration(sessionType, outputs, cameraExecutor, new CameraCaptureSession.StateCallback() {
|
||||||
new CameraCaptureSession.StateCallback() {
|
@Override
|
||||||
@Override
|
public void onConfigured(CameraCaptureSession session) {
|
||||||
public void onConfigured(CameraCaptureSession session) {
|
future.complete(session);
|
||||||
future.complete(session);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onConfigureFailed(CameraCaptureSession session) {
|
public void onConfigureFailed(CameraCaptureSession session) {
|
||||||
future.completeExceptionally(new CameraAccessException(CameraAccessException.CAMERA_ERROR));
|
future.completeExceptionally(new CameraAccessException(CameraAccessException.CAMERA_ERROR));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
camera.createCaptureSession(sessionConfig);
|
camera.createCaptureSession(sessionConfig);
|
||||||
|
|
||||||
|
|||||||
@@ -146,6 +146,8 @@ public final class CleanUp {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static void main(String... args) {
|
public static void main(String... args) {
|
||||||
|
unlinkSelf();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Wait for the server to die
|
// Wait for the server to die
|
||||||
System.in.read();
|
System.in.read();
|
||||||
@@ -183,11 +185,7 @@ public final class CleanUp {
|
|||||||
} else if (config.restoreNormalPowerMode) {
|
} else if (config.restoreNormalPowerMode) {
|
||||||
Ln.i("Restoring normal power mode");
|
Ln.i("Restoring normal power mode");
|
||||||
Device.setScreenPowerMode(Device.POWER_MODE_NORMAL);
|
Device.setScreenPowerMode(Device.POWER_MODE_NORMAL);
|
||||||
// Make sure the request is performed before exiting
|
|
||||||
DisplayPowerMode.stopAndJoin();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unlinkSelf();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -318,9 +318,8 @@ public class Controller implements AsyncProcessor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MotionEvent event = MotionEvent
|
MotionEvent event = MotionEvent.obtain(lastTouchDown, now, action, pointerCount, pointerProperties, pointerCoords, 0, buttons, 1f, 1f,
|
||||||
.obtain(lastTouchDown, now, action, pointerCount, pointerProperties, pointerCoords, 0, buttons, 1f, 1f, DEFAULT_DEVICE_ID, 0, source,
|
DEFAULT_DEVICE_ID, 0, source, 0);
|
||||||
0);
|
|
||||||
return device.injectEvent(event, Device.INJECT_MODE_ASYNC);
|
return device.injectEvent(event, Device.INJECT_MODE_ASYNC);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -341,9 +340,8 @@ public class Controller implements AsyncProcessor {
|
|||||||
coords.setAxisValue(MotionEvent.AXIS_HSCROLL, hScroll);
|
coords.setAxisValue(MotionEvent.AXIS_HSCROLL, hScroll);
|
||||||
coords.setAxisValue(MotionEvent.AXIS_VSCROLL, vScroll);
|
coords.setAxisValue(MotionEvent.AXIS_VSCROLL, vScroll);
|
||||||
|
|
||||||
MotionEvent event = MotionEvent
|
MotionEvent event = MotionEvent.obtain(lastTouchDown, now, MotionEvent.ACTION_SCROLL, 1, pointerProperties, pointerCoords, 0, buttons, 1f, 1f,
|
||||||
.obtain(lastTouchDown, now, MotionEvent.ACTION_SCROLL, 1, pointerProperties, pointerCoords, 0, buttons, 1f, 1f, DEFAULT_DEVICE_ID, 0,
|
DEFAULT_DEVICE_ID, 0, InputDevice.SOURCE_MOUSE, 0);
|
||||||
InputDevice.SOURCE_MOUSE, 0);
|
|
||||||
return device.injectEvent(event, Device.INJECT_MODE_ASYNC);
|
return device.injectEvent(event, Device.INJECT_MODE_ASYNC);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,8 +11,8 @@ import android.graphics.Rect;
|
|||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.IBinder;
|
import android.os.IBinder;
|
||||||
import android.os.SystemClock;
|
import android.os.SystemClock;
|
||||||
import android.view.IRotationWatcher;
|
|
||||||
import android.view.IDisplayFoldListener;
|
import android.view.IDisplayFoldListener;
|
||||||
|
import android.view.IRotationWatcher;
|
||||||
import android.view.InputDevice;
|
import android.view.InputDevice;
|
||||||
import android.view.InputEvent;
|
import android.view.InputEvent;
|
||||||
import android.view.KeyCharacterMap;
|
import android.view.KeyCharacterMap;
|
||||||
@@ -315,14 +315,6 @@ public final class Device {
|
|||||||
*/
|
*/
|
||||||
public static boolean setScreenPowerMode(int mode) {
|
public static boolean setScreenPowerMode(int mode) {
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE && !SurfaceControl.hasPhysicalDisplayIdsMethod()) {
|
|
||||||
// On Android 14+, these internal methods have been moved to system server classes.
|
|
||||||
// Run a separate process with the correct classpath and LD_PRELOAD to change the display power mode.
|
|
||||||
DisplayPowerMode.setRemoteDisplayPowerMode(mode);
|
|
||||||
// The call is asynchronous (we don't want to block)
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Change the power mode for all physical displays
|
// Change the power mode for all physical displays
|
||||||
long[] physicalDisplayIds = SurfaceControl.getPhysicalDisplayIds();
|
long[] physicalDisplayIds = SurfaceControl.getPhysicalDisplayIds();
|
||||||
if (physicalDisplayIds == null) {
|
if (physicalDisplayIds == null) {
|
||||||
|
|||||||
@@ -51,6 +51,7 @@ public final class DeviceMessageSender {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void start() {
|
public void start() {
|
||||||
thread = new Thread(() -> {
|
thread = new Thread(() -> {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -1,184 +0,0 @@
|
|||||||
package com.genymobile.scrcpy;
|
|
||||||
|
|
||||||
import android.annotation.SuppressLint;
|
|
||||||
import android.os.IBinder;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.OutputStream;
|
|
||||||
import java.io.PrintStream;
|
|
||||||
import java.lang.reflect.Method;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* On Android 14, the methods used to turn the device screen off have been moved from SurfaceControl (in framework.jar) to DisplayControl (a system
|
|
||||||
* server class). As a consequence, they could not be called directly. See {@url https://github.com/Genymobile/scrcpy/issues/3927}.
|
|
||||||
* <p>
|
|
||||||
* Instead, run a separate process with a different classpath and LD_PRELOAD just to set the display power mode. The scrcpy server can request to
|
|
||||||
* this process to set the display mode by writing the mode (a single byte, the value of one of the SurfaceControl.POWER_MODE_* constants,
|
|
||||||
* typically 0=off, 2=on) to the process stdin. In return, it receives the status of the request (0=ok, 1=error) on the process stdout.
|
|
||||||
* <p>
|
|
||||||
* This separate process is started on the first display mode request.
|
|
||||||
* <p>
|
|
||||||
* Since the client must not block, and calling/joining a process is blocking (this specific one takes a few hundred milliseconds to complete),
|
|
||||||
* this class uses an internal thread to execute the requests asynchronously, and serialize them (so that two successive requests are guaranteed to
|
|
||||||
* be executed in order). In addition, it only executes the last pending request (setting power mode to value X then to value Y is equivalent to
|
|
||||||
* just setting it to value Y).
|
|
||||||
*/
|
|
||||||
public final class DisplayPowerMode {
|
|
||||||
|
|
||||||
private static final Proxy PROXY = new Proxy();
|
|
||||||
|
|
||||||
private static final class Proxy implements Runnable {
|
|
||||||
|
|
||||||
private Process process;
|
|
||||||
private Thread thread;
|
|
||||||
private int requestedMode = -1;
|
|
||||||
private boolean stopped;
|
|
||||||
|
|
||||||
synchronized boolean requestMode(int mode) {
|
|
||||||
try {
|
|
||||||
if (process == null) {
|
|
||||||
process = executeDisplayPowerModeDaemon();
|
|
||||||
thread = new Thread(this, "DisplayPowerModeProxy");
|
|
||||||
thread.setDaemon(true);
|
|
||||||
thread.start();
|
|
||||||
}
|
|
||||||
requestedMode = mode;
|
|
||||||
notify();
|
|
||||||
return true;
|
|
||||||
} catch (IOException e) {
|
|
||||||
Ln.e("Could not start display power mode daemon", e);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void stopAndJoin() {
|
|
||||||
boolean hasThread;
|
|
||||||
synchronized (this) {
|
|
||||||
hasThread = thread != null;
|
|
||||||
if (thread != null) {
|
|
||||||
stopped = true;
|
|
||||||
notify();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hasThread) {
|
|
||||||
// Join the thread without holding the mutex (that would cause a deadlock)
|
|
||||||
try {
|
|
||||||
thread.join();
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
Ln.e("Thread join interrupted", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
try {
|
|
||||||
OutputStream out = process.getOutputStream();
|
|
||||||
InputStream in = process.getInputStream();
|
|
||||||
while (true) {
|
|
||||||
int mode;
|
|
||||||
synchronized (this) {
|
|
||||||
while (!stopped && requestedMode == -1) {
|
|
||||||
wait();
|
|
||||||
}
|
|
||||||
mode = requestedMode;
|
|
||||||
requestedMode = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Even if stopped, the last request must be executed to restore the display power mode to normal
|
|
||||||
if (mode == -1) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
out.write(mode);
|
|
||||||
out.flush();
|
|
||||||
int status = in.read();
|
|
||||||
if (status != 0) {
|
|
||||||
Ln.e("Set display power mode failed remotely: status=" + status);
|
|
||||||
}
|
|
||||||
} catch (IOException e) {
|
|
||||||
Ln.e("Could not request display power mode", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
// end of thread
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private DisplayPowerMode() {
|
|
||||||
// not instantiable
|
|
||||||
}
|
|
||||||
|
|
||||||
// Called from the scrcpy process
|
|
||||||
public static boolean setRemoteDisplayPowerMode(int mode) {
|
|
||||||
return PROXY.requestMode(mode);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void stopAndJoin() {
|
|
||||||
PROXY.stopAndJoin();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Called from the proxy thread in the scrcpy process
|
|
||||||
private static Process executeDisplayPowerModeDaemon() throws IOException {
|
|
||||||
String[] ldPreloadLibs = {"/system/lib64/libandroid_servers.so"};
|
|
||||||
String[] cmd = {"app_process", "/", DisplayPowerMode.class.getName()};
|
|
||||||
|
|
||||||
ProcessBuilder builder = new ProcessBuilder(cmd);
|
|
||||||
builder.environment().put("LD_PRELOAD", String.join(" ", ldPreloadLibs));
|
|
||||||
builder.environment().put("CLASSPATH", Server.SERVER_PATH + ":/system/framework/services.jar");
|
|
||||||
return builder.start();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Executed in the DisplayPowerMode-specific process
|
|
||||||
@SuppressLint({"PrivateApi", "SoonBlockedPrivateApi"})
|
|
||||||
private static void setDisplayPowerModeUsingDisplayControl(int mode) throws Exception {
|
|
||||||
System.loadLibrary("android_servers");
|
|
||||||
|
|
||||||
@SuppressLint("PrivateApi")
|
|
||||||
Class<?> displayControlClass = Class.forName("com.android.server.display.DisplayControl");
|
|
||||||
Method getPhysicalDisplayIdsMethod = displayControlClass.getDeclaredMethod("getPhysicalDisplayIds");
|
|
||||||
Method getPhysicalDisplayTokenMethod = displayControlClass.getDeclaredMethod("getPhysicalDisplayToken", long.class);
|
|
||||||
|
|
||||||
Class<?> surfaceControlClass = Class.forName("android.view.SurfaceControl");
|
|
||||||
Method setDisplayPowerModeMethod = surfaceControlClass.getDeclaredMethod("setDisplayPowerMode", IBinder.class, int.class);
|
|
||||||
|
|
||||||
long[] displayIds = (long[]) getPhysicalDisplayIdsMethod.invoke(null);
|
|
||||||
for (long displayId : displayIds) {
|
|
||||||
Object token = getPhysicalDisplayTokenMethod.invoke(null, displayId);
|
|
||||||
setDisplayPowerModeMethod.invoke(null, token, mode);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void main(String... args) {
|
|
||||||
// This process uses stdin/stdout to communicate with the caller, make sure nothing else writes to stdout
|
|
||||||
// (and never use Ln methods other than Ln.w() and Ln.e()).
|
|
||||||
PrintStream nullStream = new PrintStream(new Ln.NullOutputStream());
|
|
||||||
System.setOut(nullStream);
|
|
||||||
PrintStream stdout = Ln.CONSOLE_OUT;
|
|
||||||
|
|
||||||
try {
|
|
||||||
while (true) {
|
|
||||||
// Wait for requests
|
|
||||||
int request = System.in.read();
|
|
||||||
if (request == -1) {
|
|
||||||
// EOF
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
setDisplayPowerModeUsingDisplayControl(request);
|
|
||||||
stdout.write(0); // ok
|
|
||||||
} catch (Throwable e) {
|
|
||||||
Ln.e("Could not set display power mode", e);
|
|
||||||
stdout.write(1); // error
|
|
||||||
}
|
|
||||||
stdout.flush();
|
|
||||||
}
|
|
||||||
} catch (IOException e) {
|
|
||||||
// Expected when the server is dead
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -16,8 +16,8 @@ public final class Ln {
|
|||||||
private static final String TAG = "scrcpy";
|
private static final String TAG = "scrcpy";
|
||||||
private static final String PREFIX = "[server] ";
|
private static final String PREFIX = "[server] ";
|
||||||
|
|
||||||
public static final PrintStream CONSOLE_OUT = new PrintStream(new FileOutputStream(FileDescriptor.out));
|
private static final PrintStream CONSOLE_OUT = new PrintStream(new FileOutputStream(FileDescriptor.out));
|
||||||
public static final PrintStream CONSOLE_ERR = new PrintStream(new FileOutputStream(FileDescriptor.err));
|
private static final PrintStream CONSOLE_ERR = new PrintStream(new FileOutputStream(FileDescriptor.err));
|
||||||
|
|
||||||
enum Level {
|
enum Level {
|
||||||
VERBOSE, DEBUG, INFO, WARN, ERROR
|
VERBOSE, DEBUG, INFO, WARN, ERROR
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import java.util.List;
|
|||||||
public final class Server {
|
public final class Server {
|
||||||
|
|
||||||
public static final String SERVER_PATH;
|
public static final String SERVER_PATH;
|
||||||
|
|
||||||
static {
|
static {
|
||||||
String[] classPaths = System.getProperty("java.class.path").split(File.pathSeparator);
|
String[] classPaths = System.getProperty("java.class.path").split(File.pathSeparator);
|
||||||
// By convention, scrcpy is always executed with the absolute path of scrcpy-server.jar as the first item in the classpath
|
// By convention, scrcpy is always executed with the absolute path of scrcpy-server.jar as the first item in the classpath
|
||||||
|
|||||||
@@ -75,7 +75,7 @@ public final class Settings {
|
|||||||
|
|
||||||
String oldValue = getValue(table, key);
|
String oldValue = getValue(table, key);
|
||||||
if (!value.equals(oldValue)) {
|
if (!value.equals(oldValue)) {
|
||||||
putValue(table, key, value);
|
putValue(table, key, value);
|
||||||
}
|
}
|
||||||
return oldValue;
|
return oldValue;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -138,8 +138,8 @@ public final class ClipboardManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void addPrimaryClipChangedListener(Method method, int methodVersion, IInterface manager,
|
private static void addPrimaryClipChangedListener(Method method, int methodVersion, IInterface manager, IOnPrimaryClipChangedListener listener)
|
||||||
IOnPrimaryClipChangedListener listener) throws InvocationTargetException, IllegalAccessException {
|
throws InvocationTargetException, IllegalAccessException {
|
||||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
|
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
|
||||||
method.invoke(manager, listener, FakeContext.PACKAGE_NAME);
|
method.invoke(manager, listener, FakeContext.PACKAGE_NAME);
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ public final class PowerManager {
|
|||||||
private Method getIsScreenOnMethod() throws NoSuchMethodException {
|
private Method getIsScreenOnMethod() throws NoSuchMethodException {
|
||||||
if (isScreenOnMethod == null) {
|
if (isScreenOnMethod == null) {
|
||||||
@SuppressLint("ObsoleteSdkInt") // we may lower minSdkVersion in the future
|
@SuppressLint("ObsoleteSdkInt") // we may lower minSdkVersion in the future
|
||||||
String methodName = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT_WATCH ? "isInteractive" : "isScreenOn";
|
String methodName = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT_WATCH ? "isInteractive" : "isScreenOn";
|
||||||
isScreenOnMethod = manager.getClass().getMethod(methodName);
|
isScreenOnMethod = manager.getClass().getMethod(methodName);
|
||||||
}
|
}
|
||||||
return isScreenOnMethod;
|
return isScreenOnMethod;
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import java.lang.reflect.Method;
|
|||||||
public final class ServiceManager {
|
public final class ServiceManager {
|
||||||
|
|
||||||
private static final Method GET_SERVICE_METHOD;
|
private static final Method GET_SERVICE_METHOD;
|
||||||
|
|
||||||
static {
|
static {
|
||||||
try {
|
try {
|
||||||
GET_SERVICE_METHOD = Class.forName("android.os.ServiceManager").getDeclaredMethod("getService", String.class);
|
GET_SERVICE_METHOD = Class.forName("android.os.ServiceManager").getDeclaredMethod("getService", String.class);
|
||||||
|
|||||||
@@ -139,15 +139,6 @@ public final class SurfaceControl {
|
|||||||
return getPhysicalDisplayIdsMethod;
|
return getPhysicalDisplayIdsMethod;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean hasPhysicalDisplayIdsMethod() {
|
|
||||||
try {
|
|
||||||
getGetPhysicalDisplayIdsMethod();
|
|
||||||
return true;
|
|
||||||
} catch (NoSuchMethodException e) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static long[] getPhysicalDisplayIds() {
|
public static long[] getPhysicalDisplayIds() {
|
||||||
try {
|
try {
|
||||||
Method method = getGetPhysicalDisplayIdsMethod();
|
Method method = getGetPhysicalDisplayIdsMethod();
|
||||||
|
|||||||
@@ -4,8 +4,8 @@ import com.genymobile.scrcpy.Ln;
|
|||||||
|
|
||||||
import android.annotation.TargetApi;
|
import android.annotation.TargetApi;
|
||||||
import android.os.IInterface;
|
import android.os.IInterface;
|
||||||
import android.view.IRotationWatcher;
|
|
||||||
import android.view.IDisplayFoldListener;
|
import android.view.IDisplayFoldListener;
|
||||||
|
import android.view.IRotationWatcher;
|
||||||
|
|
||||||
import java.lang.reflect.InvocationTargetException;
|
import java.lang.reflect.InvocationTargetException;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
|
|||||||
Reference in New Issue
Block a user