Compare commits

..

3 Commits

Author SHA1 Message Date
Romain Vimont
b81e0f92b5 Add horizontal scrolling support for HID mouse
PR #6172 <https://github.com/Genymobile/scrcpy/pull/6172>
2025-06-20 18:31:31 +02:00
Romain Vimont
be40ee5dd9 Fix HID mouse support with SDL precise input
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 18:31:24 +02:00
Romain Vimont
0498459c1f 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 18:31:17 +02:00
37 changed files with 152 additions and 207 deletions

View File

@@ -202,7 +202,8 @@ jobs:
- name: Install dependencies
run: |
brew install meson nasm libiconv zlib automake autoconf libtool
brew install meson ninja nasm libiconv zlib automake autoconf \
libtool
- name: Build
env:
@@ -244,7 +245,7 @@ jobs:
uses: actions/checkout@v4
- name: Install dependencies
run: brew install meson nasm libiconv zlib automake
run: brew install meson ninja 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.3)
# scrcpy (v3.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=d3e9fa1df3345cf728586908426615a60863d2632f73f1ce14f0f1349ef000fd
SHA256SUM=b241878e6ec20650b041bf715ea05f7d5dc73bd24529464bd9cf68946e3132bd
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=12c2841f354e92a0eb2fd7bf6f0f9bf8538abce7bd6b060ac8349d6f6a61107c
SHA256SUM=24bd8bebbbb58b9870db202b5c6775c4a49992632021c60750d9d8ec8179d5f0
cd "$SOURCES_DIR"

View File

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

View File

@@ -112,19 +112,13 @@ 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', static: static),
dependency('sdl2', version: '>= 2.0.5', 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.3"
VALUE "ProductVersion", "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 _WIN32
#ifndef __WINDOWS__
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 _WIN32
#ifdef __WINDOWS__
// 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 _WIN32
#ifdef __WINDOWS__
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 _WIN32
#ifdef __WINDOWS__
// 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 _WIN32
#ifdef __WINDOWS__
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,7 +170,6 @@ 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);
@@ -182,11 +181,6 @@ 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) {
@@ -202,8 +196,7 @@ 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_internal(display,
display->pending.frame);
bool ok = sc_display_update_texture(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,7 +1,6 @@
#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 || ctrl_type == CTRL_BREAK_EVENT) {
if (ctrl_type == CTRL_C_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(_WIN32)
#if defined(__APPLE__) || defined(__WINDOWS__)
# 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_window;
goto error_destroy_fps_counter;
}
SDL_Surface *icon_novideo = params->video ? NULL : icon;

View File

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

View File

@@ -191,8 +191,7 @@ 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 = 16,
.vscroll = -16,
.hscroll = 1,
.vscroll = -1,
.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, // 16 (float encoded as i16 in the range [-16, 16])
0x80, 0x00, // -16 (float encoded as i16 in the range [-16, 16])
0x7F, 0xFF, // 1 (float encoded as i16)
0x80, 0x00, // -1 (float encoded as i16)
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.13.0'
classpath 'com.android.tools.build:gradle:8.7.1'
// 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.3`][direct-scrcpy-server]
<sub>SHA-256: `7e70323ba7f259649dd4acce97ac4fefbae8102b2c6d91e2e7be613fd5354be0`</sub>
- [`scrcpy-server-v3.3`][direct-scrcpy-server]
<sub>SHA-256: `351cb2edc7e4c2c75f09a7933fdabcf137be52e2602df154f24ec02db46e9e51`</sub>
[direct-scrcpy-server]: https://github.com/Genymobile/scrcpy/releases/download/v3.3.3/scrcpy-server-v3.3.3
[direct-scrcpy-server]: https://github.com/Genymobile/scrcpy/releases/download/v3.3/scrcpy-server-v3.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.3.tar.gz`][direct-linux-x86_64] (x86_64)
<sub>SHA-256: `9b30e813e8191329ba8025dc80cb0f198fb0a318960a3b5c15395cf675c9c638`</sub>
- [`scrcpy-linux-x86_64-v3.3.tar.gz`][direct-linux-x86_64] (x86_64)
<sub>SHA-256: `a0abf37003c3c47a53c1b2a12420296a2b0ee323cf3610fd6fbf9d9bab9d99f3`</sub>
[latest release]: https://github.com/Genymobile/scrcpy/releases/latest
[direct-linux-x86_64]: https://github.com/Genymobile/scrcpy/releases/download/v3.3.3/scrcpy-linux-x86_64-v3.3.3.tar.gz
[direct-linux-x86_64]: https://github.com/Genymobile/scrcpy/releases/download/v3.3/scrcpy-linux-x86_64-v3.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.3.tar.gz`][direct-macos-aarch64] (aarch64)
<sub>SHA-256: `b93299468f19ae89ac70f7c1453914c41f1f2bcd31f6ab530038da885c19581f`</sub>
- [`scrcpy-macos-aarch64-v3.3.tar.gz`][direct-macos-aarch64] (aarch64)
<sub>SHA-256: `7a4cdaeb8ba74593edda278c000ddedc8d70a51263a80b16a6345475d42ac21e`</sub>
- [`scrcpy-macos-x86_64-v3.3.3.tar.gz`][direct-macos-x86_64] (x86_64)
<sub>SHA-256: `c767fc1d41e4ae26e40558656570962f474739924fd22ee023d8754889ee4366`</sub>
- [`scrcpy-macos-x86_64-v3.3.tar.gz`][direct-macos-x86_64] (x86_64)
<sub>SHA-256: `bb3c13aac166b92539371883a8781aa861a7cd18e3e6077e570ab7a1f562f774`</sub>
[latest release]: https://github.com/Genymobile/scrcpy/releases/latest
[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
[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
and extract it.

View File

@@ -6,14 +6,14 @@
Download the [latest release]:
- [`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>
- [`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>
[latest release]: https://github.com/Genymobile/scrcpy/releases/latest
[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
[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
and extract it.

View File

@@ -1,7 +1,7 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.3-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip
# https://gradle.org/release-checksums/
distributionSha256Sum=bd71102213493060956ec229d946beee57158dbd89d0e62b91bca0fa2c5f3531
distributionSha256Sum=d725d707bfabd4dfdc958c624003b3c80accc03f7037b5122c4b1d0ef15cecab
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.3/scrcpy-server-v3.3.3
PREBUILT_SERVER_SHA256=7e70323ba7f259649dd4acce97ac4fefbae8102b2c6d91e2e7be613fd5354be0
PREBUILT_SERVER_URL=https://github.com/Genymobile/scrcpy/releases/download/v3.3/scrcpy-server-v3.3
PREBUILT_SERVER_SHA256=351cb2edc7e4c2c75f09a7933fdabcf137be52e2602df154f24ec02db46e9e51
echo "[scrcpy] Downloading prebuilt server..."
wget "$PREBUILT_SERVER_URL" -O scrcpy-server

View File

@@ -1,5 +1,5 @@
project('scrcpy', 'c',
version: '3.3.3',
version: '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 36
namespace 'com.genymobile.scrcpy'
compileSdk 35
defaultConfig {
applicationId = "com.genymobile.scrcpy"
applicationId "com.genymobile.scrcpy"
minSdkVersion 21
targetSdkVersion 36
versionCode 30303
versionName "3.3.3"
testInstrumentationRunner = "android.support.test.runner.AndroidJUnitRunner"
targetSdkVersion 35
versionCode 30300
versionName "3.3"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
@@ -18,11 +18,8 @@ android {
}
}
buildFeatures {
buildConfig = true
aidl = true
}
lint {
disable 'UseRequiresApi'
buildConfig true
aidl true
}
}

View File

@@ -12,10 +12,10 @@
set -e
SCRCPY_DEBUG=false
SCRCPY_VERSION_NAME=3.3.3
SCRCPY_VERSION_NAME=3.3
PLATFORM=${ANDROID_PLATFORM:-36}
BUILD_TOOLS=${ANDROID_BUILD_TOOLS:-36.0.0}
PLATFORM=${ANDROID_PLATFORM:-35}
BUILD_TOOLS=${ANDROID_BUILD_TOOLS:-35.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,4 +48,19 @@ 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,7 +196,6 @@ 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,6 +5,7 @@ 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;
@@ -90,11 +91,6 @@ public final class FakeContext extends ContextWrapper {
return this;
}
@Override
public Context createPackageContext(String packageName, int flags) {
return this;
}
@Override
public ContentResolver getContentResolver() {
return contentResolver;
@@ -108,11 +104,9 @@ public final class FakeContext extends ContextWrapper {
return null;
}
// "semclipboard" is a Samsung-internal service
// See <https://github.com/Genymobile/scrcpy/issues/6224>
if (Context.CLIPBOARD_SERVICE.equals(name) || "semclipboard".equals(name)) {
if (Context.CLIPBOARD_SERVICE.equals(name)) {
try {
Field field = service.getClass().getDeclaredField("mContext");
Field field = ClipboardManager.class.getDeclaredField("mContext");
field.setAccessible(true);
field.set(service, this);
} catch (ReflectiveOperationException e) {

View File

@@ -226,11 +226,7 @@ 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,8 +1,13 @@
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;
@@ -13,26 +18,66 @@ public final class Settings {
/* not instantiable */
}
public static String getValue(String table, String key) throws SettingsException {
try (ContentProvider provider = ServiceManager.getActivityManager().createSettingsProvider()) {
return provider.getValue(table, key);
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);
}
}
return execSettingsGet(table, key);
}
public static void putValue(String table, String key, String value) throws SettingsException {
try (ContentProvider provider = ServiceManager.getActivityManager().createSettingsProvider()) {
provider.putValue(table, key, value);
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);
}
}
execSettingsPut(table, key, value);
}
public static String getAndPutValue(String table, String key, String value) throws SettingsException {
try (ContentProvider provider = ServiceManager.getActivityManager().createSettingsProvider()) {
String oldValue = provider.getValue(table, key);
if (!value.equals(oldValue)) {
provider.putValue(table, key, value);
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);
}
return oldValue;
}
String oldValue = getValue(table, key);
if (!value.equals(oldValue)) {
putValue(table, key, value);
}
return oldValue;
}
}

View File

@@ -25,7 +25,6 @@ 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;
@@ -170,7 +169,6 @@ 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,12 +1,11 @@
package com.genymobile.scrcpy.wrappers;
import com.genymobile.scrcpy.util.Ln;
import android.content.res.Configuration;
import android.os.Parcel;
import android.os.RemoteException;
import android.graphics.Rect;
import android.view.IDisplayWindowListener;
import java.util.List;
public class DisplayWindowListener extends IDisplayWindowListener.Stub {
@Override
public void onDisplayAdded(int displayId) {
@@ -24,14 +23,17 @@ public class DisplayWindowListener extends IDisplayWindowListener.Stub {
}
@Override
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;
}
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
}
}

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); // -16.0f encoded as i16 (the range is [-16, 16])
dos.writeShort(0x8000); // -1.0f encoded as i16
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(-16f, event.getVScroll(), 0f);
Assert.assertEquals(-1f, event.getVScroll(), 0f);
Assert.assertEquals(1, event.getButtons());
Assert.assertEquals(-1, bis.read()); // EOS

View File

@@ -1,77 +0,0 @@
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)

View File

@@ -1,9 +0,0 @@
[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