Compare commits

...

8 Commits

Author SHA1 Message Date
Romain Vimont
5d4b8a7e6d Fix turn screen off on Android 14
On Android 14, the methods to access the display have been moved to
DisplayControl, which is not in the core framework. Use a specific
ClassLoader to access this class and its native dependencies.

Fixes #3927 <https://github.com/Genymobile/scrcpy/issues/3927>
Refs #3927 comment <https://github.com/Genymobile/scrcpy/issues/3927#issuecomment-1790031953>
Refs #4446 comment <https://github.com/Genymobile/scrcpy/pull/4446#issuecomment-1824660915>
PR #4456 <https://github.com/Genymobile/scrcpy/pull/4456>

Co-authored-by: Simon Chan <1330321+yume-chan@users.noreply.github.com>
Signed-off-by: Romain Vimont <rom@rom1v.com>
2023-11-25 21:25:26 +01:00
Romain Vimont
eed06b141a Upgrade sdl (2.28.5) for Windows
Include the latest version of SDL in Windows releases.
2023-11-25 21:06:45 +01:00
Romain Vimont
825d7f72c0 Extract $VERSION for dependency scripts
This will allow to update the version only once in these files.
2023-11-25 21:06:45 +01:00
Romain Vimont
2370298b61 Download SDL prebuilt binaries from github
The server is faster than libsdl.org.
2023-11-25 21:06:45 +01:00
Romain Vimont
67f356f881 Improve crossbuild
Install all the prebuilt dependencies for Windows to a specific folder,
and use meson command line options to specify their location.

This removes crossbuild-specific code from the meson scripts and will
simplify dependency upgrades.

PR #4460 <https://github.com/Genymobile/scrcpy/pull/4460>
2023-11-25 21:06:37 +01:00
Romain Vimont
c573bd2a33 Fix java code style 2023-11-23 23:50:00 +01:00
sam80180
acb2988837 Do not hardcode server path on the device
The path can be retrieved from the classpath.

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

Co-authored-by: Romain Vimont <rom@rom1v.com>
Signed-off-by: Romain Vimont <rom@rom1v.com>
2023-11-23 23:39:40 +01:00
Romain Vimont
85a94dd4b5 Fix meson deprecated 'pkgconfig' to 'pkg-config'
When running ./release.sh:

> DEPRECATION: "pkgconfig" entry is deprecated and should be replaced by
> "pkg-config"
2023-11-23 23:39:40 +01:00
21 changed files with 207 additions and 155 deletions

View File

@@ -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

View File

@@ -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

View File

@@ -6,9 +6,10 @@ cd "$DIR"
mkdir -p "$PREBUILT_DATA_DIR" mkdir -p "$PREBUILT_DATA_DIR"
cd "$PREBUILT_DATA_DIR" cd "$PREBUILT_DATA_DIR"
DEP_DIR=libusb-1.0.26 VERSION=1.0.26
DEP_DIR="libusb-$VERSION"
FILENAME=libusb-1.0.26-binaries.7z FILENAME="libusb-$VERSION-binaries.7z"
SHA256SUM=9c242696342dbde9cdc47239391f71833939bf9f7aa2bbb28cdaabe890465ec5 SHA256SUM=9c242696342dbde9cdc47239391f71833939bf9f7aa2bbb28cdaabe890465ec5
if [[ -d "$DEP_DIR" ]] if [[ -d "$DEP_DIR" ]]
@@ -17,17 +18,22 @@ then
exit 0 exit 0
fi fi
get_file "https://github.com/libusb/libusb/releases/download/v1.0.26/$FILENAME" "$FILENAME" "$SHA256SUM" get_file "https://github.com/libusb/libusb/releases/download/v$VERSION/$FILENAME" \
"$FILENAME" "$SHA256SUM"
mkdir "$DEP_DIR" 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-$VERSION-binaries/libusb-MinGW-Win32/" \
libusb-1.0.26-binaries/libusb-MinGW-Win32/include/ \ "libusb-$VERSION-binaries/libusb-MinGW-Win32/" \
libusb-1.0.26-binaries/libusb-MinGW-x64/bin/msys-usb-1.0.dll \ "libusb-$VERSION-binaries/libusb-MinGW-x64/" \
libusb-1.0.26-binaries/libusb-MinGW-x64/include/ "libusb-$VERSION-binaries/libusb-MinGW-x64/"
mv libusb-1.0.26-binaries/libusb-MinGW-Win32 . mv "libusb-$VERSION-binaries/libusb-MinGW-Win32" .
mv libusb-1.0.26-binaries/libusb-MinGW-x64 . mv "libusb-$VERSION-binaries/libusb-MinGW-x64" .
rm -rf libusb-1.0.26-binaries rm -rf "libusb-$VERSION-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

View File

@@ -6,10 +6,11 @@ cd "$DIR"
mkdir -p "$PREBUILT_DATA_DIR" mkdir -p "$PREBUILT_DATA_DIR"
cd "$PREBUILT_DATA_DIR" cd "$PREBUILT_DATA_DIR"
DEP_DIR=SDL2-2.28.4 VERSION=2.28.5
DEP_DIR="SDL2-$VERSION"
FILENAME=SDL2-devel-2.28.4-mingw.tar.gz FILENAME="SDL2-devel-$VERSION-mingw.tar.gz"
SHA256SUM=779d091072cf97291f80030f5232d97aa3d48ab0f2c14fe0b9d9a33c593cdc35 SHA256SUM=3c0c655c2ebf67cad48fead72761d1601740ded30808952c3274ba223d226c21
if [[ -d "$DEP_DIR" ]] if [[ -d "$DEP_DIR" ]]
then then
@@ -17,7 +18,8 @@ then
exit 0 exit 0
fi fi
get_file "https://libsdl.org/release/$FILENAME" "$FILENAME" "$SHA256SUM" get_file "https://github.com/libsdl-org/SDL/releases/download/release-$VERSION/$FILENAME" \
"$FILENAME" "$SHA256SUM"
mkdir "$DEP_DIR" mkdir "$DEP_DIR"
cd "$DEP_DIR" cd "$DEP_DIR"

View File

@@ -6,7 +6,7 @@ c = 'i686-w64-mingw32-gcc'
cpp = 'i686-w64-mingw32-g++' cpp = 'i686-w64-mingw32-g++'
ar = 'i686-w64-mingw32-ar' ar = 'i686-w64-mingw32-ar'
strip = 'i686-w64-mingw32-strip' strip = 'i686-w64-mingw32-strip'
pkgconfig = 'i686-w64-mingw32-pkg-config' pkg-config = 'i686-w64-mingw32-pkg-config'
windres = 'i686-w64-mingw32-windres' windres = 'i686-w64-mingw32-windres'
[host_machine] [host_machine]
@@ -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'

View File

@@ -6,7 +6,7 @@ c = 'x86_64-w64-mingw32-gcc'
cpp = 'x86_64-w64-mingw32-g++' cpp = 'x86_64-w64-mingw32-g++'
ar = 'x86_64-w64-mingw32-ar' ar = 'x86_64-w64-mingw32-ar'
strip = 'x86_64-w64-mingw32-strip' strip = 'x86_64-w64-mingw32-strip'
pkgconfig = 'x86_64-w64-mingw32-pkg-config' pkg-config = 'x86_64-w64-mingw32-pkg-config'
windres = 'x86_64-w64-mingw32-windres' windres = 'x86_64-w64-mingw32-windres'
[host_machine] [host_machine]
@@ -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'

View File

@@ -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.5/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.5/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)"; \

View File

@@ -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;
} }

View File

@@ -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);

View File

@@ -14,8 +14,6 @@ import java.io.IOException;
*/ */
public final class CleanUp { public final class CleanUp {
public static final String SERVER_PATH = "/data/local/tmp/scrcpy-server.jar";
// A simple struct to be passed from the main process to the cleanup process // A simple struct to be passed from the main process to the cleanup process
public static class Config implements Parcelable { public static class Config implements Parcelable {
@@ -135,13 +133,13 @@ public final class CleanUp {
String[] cmd = {"app_process", "/", CleanUp.class.getName(), config.toBase64()}; String[] cmd = {"app_process", "/", CleanUp.class.getName(), config.toBase64()};
ProcessBuilder builder = new ProcessBuilder(cmd); ProcessBuilder builder = new ProcessBuilder(cmd);
builder.environment().put("CLASSPATH", SERVER_PATH); builder.environment().put("CLASSPATH", Server.SERVER_PATH);
builder.start(); builder.start();
} }
public static void unlinkSelf() { public static void unlinkSelf() {
try { try {
new File(SERVER_PATH).delete(); new File(Server.SERVER_PATH).delete();
} catch (Exception e) { } catch (Exception e) {
Ln.e("Could not unlink server", e); Ln.e("Could not unlink server", e);
} }

View File

@@ -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);
} }

View File

@@ -1,6 +1,7 @@
package com.genymobile.scrcpy; package com.genymobile.scrcpy;
import com.genymobile.scrcpy.wrappers.ClipboardManager; import com.genymobile.scrcpy.wrappers.ClipboardManager;
import com.genymobile.scrcpy.wrappers.DisplayControl;
import com.genymobile.scrcpy.wrappers.InputManager; import com.genymobile.scrcpy.wrappers.InputManager;
import com.genymobile.scrcpy.wrappers.ServiceManager; import com.genymobile.scrcpy.wrappers.ServiceManager;
import com.genymobile.scrcpy.wrappers.SurfaceControl; import com.genymobile.scrcpy.wrappers.SurfaceControl;
@@ -11,8 +12,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,8 +316,12 @@ 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) {
// On Android 14, these internal methods have been moved to DisplayControl
boolean useDisplayControl =
Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE && !SurfaceControl.hasPhysicalDisplayIdsMethod();
// Change the power mode for all physical displays // Change the power mode for all physical displays
long[] physicalDisplayIds = SurfaceControl.getPhysicalDisplayIds(); long[] physicalDisplayIds = useDisplayControl ? DisplayControl.getPhysicalDisplayIds() : SurfaceControl.getPhysicalDisplayIds();
if (physicalDisplayIds == null) { if (physicalDisplayIds == null) {
Ln.e("Could not get physical display ids"); Ln.e("Could not get physical display ids");
return false; return false;
@@ -324,7 +329,8 @@ public final class Device {
boolean allOk = true; boolean allOk = true;
for (long physicalDisplayId : physicalDisplayIds) { for (long physicalDisplayId : physicalDisplayIds) {
IBinder binder = SurfaceControl.getPhysicalDisplayToken(physicalDisplayId); IBinder binder = useDisplayControl ? DisplayControl.getPhysicalDisplayToken(
physicalDisplayId) : SurfaceControl.getPhysicalDisplayToken(physicalDisplayId);
allOk &= SurfaceControl.setDisplayPowerMode(binder, mode); allOk &= SurfaceControl.setDisplayPowerMode(binder, mode);
} }
return allOk; return allOk;

View File

@@ -51,6 +51,7 @@ public final class DeviceMessageSender {
} }
} }
} }
public void start() { public void start() {
thread = new Thread(() -> { thread = new Thread(() -> {
try { try {

View File

@@ -3,12 +3,21 @@ package com.genymobile.scrcpy;
import android.os.BatteryManager; import android.os.BatteryManager;
import android.os.Build; import android.os.Build;
import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
public final class Server { public final class Server {
public static final String SERVER_PATH;
static {
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
SERVER_PATH = classPaths[0];
}
private static class Completion { private static class Completion {
private int running; private int running;
private boolean fatalError; private boolean fatalError;

View File

@@ -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;
} }

View File

@@ -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;

View File

@@ -0,0 +1,80 @@
package com.genymobile.scrcpy.wrappers;
import com.genymobile.scrcpy.Ln;
import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.os.Build;
import android.os.IBinder;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
@SuppressLint({"PrivateApi", "SoonBlockedPrivateApi", "BlockedPrivateApi"})
@TargetApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
public final class DisplayControl {
private static final Class<?> CLASS;
static {
Class<?> displayControlClass = null;
try {
Class<?> classLoaderFactoryClass = Class.forName("com.android.internal.os.ClassLoaderFactory");
Method createClassLoaderMethod = classLoaderFactoryClass.getDeclaredMethod("createClassLoader", String.class, String.class, String.class,
ClassLoader.class, int.class, boolean.class, String.class);
ClassLoader classLoader = (ClassLoader) createClassLoaderMethod.invoke(null, "/system/framework/services.jar", null, null,
ClassLoader.getSystemClassLoader(), 0, true, null);
displayControlClass = classLoader.loadClass("com.android.server.display.DisplayControl");
Method loadMethod = Runtime.class.getDeclaredMethod("loadLibrary0", Class.class, String.class);
loadMethod.setAccessible(true);
loadMethod.invoke(Runtime.getRuntime(), displayControlClass, "android_servers");
} catch (Throwable e) {
Ln.e("Could not initialize DisplayControl", e);
// Do not throw an exception here, the methods will fail when they are called
}
CLASS = displayControlClass;
}
private static Method getPhysicalDisplayTokenMethod;
private static Method getPhysicalDisplayIdsMethod;
private DisplayControl() {
// only static methods
}
private static Method getGetPhysicalDisplayTokenMethod() throws NoSuchMethodException {
if (getPhysicalDisplayTokenMethod == null) {
getPhysicalDisplayTokenMethod = CLASS.getMethod("getPhysicalDisplayToken", long.class);
}
return getPhysicalDisplayTokenMethod;
}
public static IBinder getPhysicalDisplayToken(long physicalDisplayId) {
try {
Method method = getGetPhysicalDisplayTokenMethod();
return (IBinder) method.invoke(null, physicalDisplayId);
} catch (InvocationTargetException | IllegalAccessException | NoSuchMethodException e) {
Ln.e("Could not invoke method", e);
return null;
}
}
private static Method getGetPhysicalDisplayIdsMethod() throws NoSuchMethodException {
if (getPhysicalDisplayIdsMethod == null) {
getPhysicalDisplayIdsMethod = CLASS.getMethod("getPhysicalDisplayIds");
}
return getPhysicalDisplayIdsMethod;
}
public static long[] getPhysicalDisplayIds() {
try {
Method method = getGetPhysicalDisplayIdsMethod();
return (long[]) method.invoke(null);
} catch (InvocationTargetException | IllegalAccessException | NoSuchMethodException e) {
Ln.e("Could not invoke method", e);
return null;
}
}
}

View File

@@ -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;

View File

@@ -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);

View File

@@ -139,6 +139,15 @@ 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();

View File

@@ -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;