Compare commits
24 Commits
turnscreen
...
tilt.2
Author | SHA1 | Date | |
---|---|---|---|
d2ed4510a7 | |||
604dfd7c6b | |||
af69689ec1 | |||
cbce42336d | |||
c9a4d2b38f | |||
1beec99f82 | |||
5ce8672ebc | |||
3001f8a2d5 | |||
c6ff78f414 | |||
40f2560d98 | |||
26aa28c998 | |||
ef79fcbbd2 | |||
9497f39fb4 | |||
bf056b1fee | |||
bd9292931e | |||
140a49b8be | |||
4135c411af | |||
5e061636f6 | |||
5f3fb843f5 | |||
ce8126f322 | |||
d037b02cc2 | |||
89761213c3 | |||
8db4e78b34 | |||
25e33566f5 |
@ -1,4 +1,4 @@
|
||||
# scrcpy (v2.2)
|
||||
# scrcpy (v2.3.1)
|
||||
|
||||
<img src="app/data/icon.svg" width="128" height="128" alt="scrcpy" align="right" />
|
||||
|
||||
|
@ -115,13 +115,12 @@ _scrcpy() {
|
||||
COMPREPLY=($(compgen -W 'front back external' -- "$cur"))
|
||||
return
|
||||
;;
|
||||
--orientation
|
||||
--display-orientation)
|
||||
COMPREPLY=($(compgen -> '0 90 180 270 flip0 flip90 flip180 flip270' -- "$cur"))
|
||||
--orientation|--display-orientation)
|
||||
COMPREPLY=($(compgen -W '0 90 180 270 flip0 flip90 flip180 flip270' -- "$cur"))
|
||||
return
|
||||
;;
|
||||
--record-orientation)
|
||||
COMPREPLY=($(compgen -> '0 90 180 270' -- "$cur"))
|
||||
COMPREPLY=($(compgen -W '0 90 180 270' -- "$cur"))
|
||||
return
|
||||
;;
|
||||
--lock-video-orientation)
|
||||
|
@ -5,7 +5,7 @@ Comment=Display and control your Android device
|
||||
# For some users, the PATH or ADB environment variables are set from the shell
|
||||
# startup file, like .bashrc or .zshrc… Run an interactive shell to get
|
||||
# environment correctly initialized.
|
||||
Exec=/bin/sh -c "\"\\$SHELL\" -i -c scrcpy --pause-on-exit=if-error"
|
||||
Exec=/bin/sh -c "\\$SHELL -i -c 'scrcpy --pause-on-exit=if-error'"
|
||||
Icon=scrcpy
|
||||
Terminal=true
|
||||
Type=Application
|
||||
|
@ -5,7 +5,7 @@ Comment=Display and control your Android device
|
||||
# For some users, the PATH or ADB environment variables are set from the shell
|
||||
# startup file, like .bashrc or .zshrc… Run an interactive shell to get
|
||||
# environment correctly initialized.
|
||||
Exec=/bin/sh -c "\"\\$SHELL\" -i -c scrcpy"
|
||||
Exec=/bin/sh -c "\\$SHELL -i -c scrcpy"
|
||||
Icon=scrcpy
|
||||
Terminal=false
|
||||
Type=Application
|
||||
|
@ -13,7 +13,7 @@ BEGIN
|
||||
VALUE "LegalCopyright", "Romain Vimont, Genymobile"
|
||||
VALUE "OriginalFilename", "scrcpy.exe"
|
||||
VALUE "ProductName", "scrcpy"
|
||||
VALUE "ProductVersion", "v2.2"
|
||||
VALUE "ProductVersion", "2.3.1"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
|
@ -124,7 +124,7 @@ Use USB device (if there is exactly one, like adb -d).
|
||||
Also see \fB\-e\fR (\fB\-\-select\-tcpip\fR).
|
||||
|
||||
.TP
|
||||
.BI "\-\-disable-screensaver"
|
||||
.BI "\-\-disable\-screensaver"
|
||||
Disable screensaver while scrcpy is running.
|
||||
|
||||
.TP
|
||||
@ -642,7 +642,11 @@ Enable/disable FPS counter (print frames/second in logs)
|
||||
|
||||
.TP
|
||||
.B Ctrl+click-and-move
|
||||
Pinch-to-zoom from the center of the screen
|
||||
Pinch-to-zoom and rotate from the center of the screen
|
||||
|
||||
.TP
|
||||
.B Shift+click-and-move
|
||||
Tilt (slide vertically with two fingers)
|
||||
|
||||
.TP
|
||||
.B Drag & drop APK file
|
||||
|
@ -947,7 +947,11 @@ static const struct sc_shortcut shortcuts[] = {
|
||||
},
|
||||
{
|
||||
.shortcuts = { "Ctrl+click-and-move" },
|
||||
.text = "Pinch-to-zoom from the center of the screen",
|
||||
.text = "Pinch-to-zoom and rotate from the center of the screen",
|
||||
},
|
||||
{
|
||||
.shortcuts = { "Shift+click-and-move" },
|
||||
.text = "Tilt (slide vertically with two fingers)",
|
||||
},
|
||||
{
|
||||
.shortcuts = { "Drag & drop APK file" },
|
||||
@ -2154,7 +2158,7 @@ parse_args_with_getopt(struct scrcpy_cli_args *args, int argc, char *argv[],
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case OPT_ORIENTATION:
|
||||
case OPT_ORIENTATION: {
|
||||
enum sc_orientation orientation;
|
||||
if (!parse_orientation(optarg, &orientation)) {
|
||||
return false;
|
||||
@ -2162,6 +2166,7 @@ parse_args_with_getopt(struct scrcpy_cli_args *args, int argc, char *argv[],
|
||||
opts->display_orientation = orientation;
|
||||
opts->record_orientation = orientation;
|
||||
break;
|
||||
}
|
||||
case OPT_RENDER_DRIVER:
|
||||
opts->render_driver = optarg;
|
||||
break;
|
||||
|
@ -227,8 +227,9 @@ run_demuxer(void *data) {
|
||||
}
|
||||
|
||||
// Config packets must be merged with the next non-config packet only for
|
||||
// video streams
|
||||
bool must_merge_config_packet = codec->type == AVMEDIA_TYPE_VIDEO;
|
||||
// H.26x
|
||||
bool must_merge_config_packet = raw_codec_id == SC_CODEC_ID_H264
|
||||
|| raw_codec_id == SC_CODEC_ID_H265;
|
||||
|
||||
struct sc_packet_merger merger;
|
||||
|
||||
|
@ -76,6 +76,8 @@ sc_input_manager_init(struct sc_input_manager *im,
|
||||
im->sdl_shortcut_mods.count = shortcut_mods->count;
|
||||
|
||||
im->vfinger_down = false;
|
||||
im->vfinger_invert_x = false;
|
||||
im->vfinger_invert_y = false;
|
||||
|
||||
im->last_keycode = SDLK_UNKNOWN;
|
||||
im->last_mod = 0;
|
||||
@ -347,9 +349,14 @@ simulate_virtual_finger(struct sc_input_manager *im,
|
||||
}
|
||||
|
||||
static struct sc_point
|
||||
inverse_point(struct sc_point point, struct sc_size size) {
|
||||
point.x = size.width - point.x;
|
||||
point.y = size.height - point.y;
|
||||
inverse_point(struct sc_point point, struct sc_size size,
|
||||
bool invert_x, bool invert_y) {
|
||||
if (invert_x) {
|
||||
point.x = size.width - point.x;
|
||||
}
|
||||
if (invert_y) {
|
||||
point.y = size.height - point.y;
|
||||
}
|
||||
return point;
|
||||
}
|
||||
|
||||
@ -605,7 +612,9 @@ sc_input_manager_process_mouse_motion(struct sc_input_manager *im,
|
||||
struct sc_point mouse =
|
||||
sc_screen_convert_window_to_frame_coords(im->screen, event->x,
|
||||
event->y);
|
||||
struct sc_point vfinger = inverse_point(mouse, im->screen->frame_size);
|
||||
struct sc_point vfinger = inverse_point(mouse, im->screen->frame_size,
|
||||
im->vfinger_invert_x,
|
||||
im->vfinger_invert_y);
|
||||
simulate_virtual_finger(im, AMOTION_EVENT_ACTION_MOVE, vfinger);
|
||||
}
|
||||
}
|
||||
@ -726,7 +735,7 @@ sc_input_manager_process_mouse_button(struct sc_input_manager *im,
|
||||
return;
|
||||
}
|
||||
|
||||
// Pinch-to-zoom simulation.
|
||||
// Pinch-to-zoom, rotate and tilt simulation.
|
||||
//
|
||||
// If Ctrl is hold when the left-click button is pressed, then
|
||||
// pinch-to-zoom mode is enabled: on every mouse event until the left-click
|
||||
@ -735,14 +744,29 @@ sc_input_manager_process_mouse_button(struct sc_input_manager *im,
|
||||
//
|
||||
// In other words, the center of the rotation/scaling is the center of the
|
||||
// screen.
|
||||
#define CTRL_PRESSED (SDL_GetModState() & (KMOD_LCTRL | KMOD_RCTRL))
|
||||
//
|
||||
// To simulate a tilt gesture (a vertical slide with two fingers), Shift
|
||||
// can be used instead of Ctrl. The "virtual finger" has a position
|
||||
// inverted with respect to the vertical axis of symmetry in the middle of
|
||||
// the screen.
|
||||
const SDL_Keymod keymod = SDL_GetModState();
|
||||
const bool ctrl_pressed = keymod & KMOD_CTRL;
|
||||
const bool shift_pressed = keymod & KMOD_SHIFT;
|
||||
if (event->button == SDL_BUTTON_LEFT &&
|
||||
((down && !im->vfinger_down && CTRL_PRESSED) ||
|
||||
((down && !im->vfinger_down &&
|
||||
((ctrl_pressed && !shift_pressed) ||
|
||||
(!ctrl_pressed && shift_pressed))) ||
|
||||
(!down && im->vfinger_down))) {
|
||||
struct sc_point mouse =
|
||||
sc_screen_convert_window_to_frame_coords(im->screen, event->x,
|
||||
event->y);
|
||||
struct sc_point vfinger = inverse_point(mouse, im->screen->frame_size);
|
||||
if (down) {
|
||||
im->vfinger_invert_x = ctrl_pressed || shift_pressed;
|
||||
im->vfinger_invert_y = ctrl_pressed;
|
||||
}
|
||||
struct sc_point vfinger = inverse_point(mouse, im->screen->frame_size,
|
||||
im->vfinger_invert_x,
|
||||
im->vfinger_invert_y);
|
||||
enum android_motionevent_action action = down
|
||||
? AMOTION_EVENT_ACTION_DOWN
|
||||
: AMOTION_EVENT_ACTION_UP;
|
||||
|
@ -32,6 +32,8 @@ struct sc_input_manager {
|
||||
} sdl_shortcut_mods;
|
||||
|
||||
bool vfinger_down;
|
||||
bool vfinger_invert_x;
|
||||
bool vfinger_invert_y;
|
||||
|
||||
// Tracks the number of identical consecutive shortcut key down events.
|
||||
// Not to be confused with event->repeat, which counts the number of
|
||||
|
@ -419,12 +419,21 @@ scrcpy(struct scrcpy_options *options) {
|
||||
sdl_set_hints(options->render_driver);
|
||||
}
|
||||
|
||||
// Initialize the video subsystem even if --no-video or --no-video-playback
|
||||
// is passed so that clipboard synchronization still works.
|
||||
// <https://github.com/Genymobile/scrcpy/issues/4418>
|
||||
if (SDL_Init(SDL_INIT_VIDEO)) {
|
||||
LOGE("Could not initialize SDL video: %s", SDL_GetError());
|
||||
goto end;
|
||||
if (options->video_playback ||
|
||||
(options->control && options->clipboard_autosync)) {
|
||||
// Initialize the video subsystem even if --no-video or
|
||||
// --no-video-playback is passed so that clipboard synchronization
|
||||
// still works.
|
||||
// <https://github.com/Genymobile/scrcpy/issues/4418>
|
||||
if (SDL_Init(SDL_INIT_VIDEO)) {
|
||||
// If it fails, it is an error only if video playback is enabled
|
||||
if (options->video_playback) {
|
||||
LOGE("Could not initialize SDL video: %s", SDL_GetError());
|
||||
goto end;
|
||||
} else {
|
||||
LOGW("Could not initialize SDL video: %s", SDL_GetError());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (options->audio_playback) {
|
||||
|
@ -233,10 +233,10 @@ install` must be run as root)._
|
||||
|
||||
#### Option 2: Use prebuilt server
|
||||
|
||||
- [`scrcpy-server-v2.2`][direct-scrcpy-server]
|
||||
<sub>SHA-256: `c85c4aa84305efb69115cd497a120ebdd10258993b4cf123a8245b3d99d49874`</sub>
|
||||
- [`scrcpy-server-v2.3.1`][direct-scrcpy-server]
|
||||
<sub>SHA-256: `f6814822fc308a7a532f253485c9038183c6296a6c5df470a9e383b4f8e7605b`</sub>
|
||||
|
||||
[direct-scrcpy-server]: https://github.com/Genymobile/scrcpy/releases/download/v2.2/scrcpy-server-v2.2
|
||||
[direct-scrcpy-server]: https://github.com/Genymobile/scrcpy/releases/download/v2.3.1/scrcpy-server-v2.3.1
|
||||
|
||||
Download the prebuilt server somewhere, and specify its path during the Meson
|
||||
configuration:
|
||||
|
@ -18,6 +18,17 @@ scrcpy --video-source=display --audio-source=mic # force display AND micropho
|
||||
scrcpy --video-source=camera --audio-source=output # force camera AND device audio output
|
||||
```
|
||||
|
||||
Audio can be disabled:
|
||||
|
||||
```bash
|
||||
# audio not captured at all
|
||||
scrcpy --video-source=camera --no-audio
|
||||
scrcpy --video-source=camera --no-audio --record=file.mp4
|
||||
|
||||
# audio captured and recorded, but not played
|
||||
scrcpy --video-source=camera --no-audio-playback --record=file.mp4
|
||||
```
|
||||
|
||||
|
||||
## List
|
||||
|
||||
|
@ -85,7 +85,7 @@ way as <kbd>MOD</kbd>+<kbd>Shift</kbd>+<kbd>v</kbd>).
|
||||
To disable automatic clipboard synchronization, use
|
||||
`--no-clipboard-autosync`.
|
||||
|
||||
## Pinch-to-zoom
|
||||
## Pinch-to-zoom, rotate and tilt simulation
|
||||
|
||||
To simulate "pinch-to-zoom": <kbd>Ctrl</kbd>+_click-and-move_.
|
||||
|
||||
@ -93,8 +93,12 @@ More precisely, hold down <kbd>Ctrl</kbd> while pressing the left-click button.
|
||||
Until the left-click button is released, all mouse movements scale and rotate
|
||||
the content (if supported by the app) relative to the center of the screen.
|
||||
|
||||
To simulate a tilt gesture: <kbd>Shift</kbd>+_click-and-move-up-or-down_.
|
||||
|
||||
Technically, _scrcpy_ generates additional touch events from a "virtual finger"
|
||||
at a location inverted through the center of the screen.
|
||||
at a location inverted through the center of the screen. When pressing
|
||||
<kbd>Ctrl</kbd> the x and y coordinates are inverted. Using <kbd>Shift</kbd>
|
||||
only inverts x.
|
||||
|
||||
|
||||
## Key repeat
|
||||
|
@ -49,7 +49,8 @@ _<kbd>[Super]</kbd> is typically the <kbd>Windows</kbd> or <kbd>Cmd</kbd> key._
|
||||
| Synchronize clipboards and paste⁵ | <kbd>MOD</kbd>+<kbd>v</kbd>
|
||||
| Inject computer clipboard text | <kbd>MOD</kbd>+<kbd>Shift</kbd>+<kbd>v</kbd>
|
||||
| Enable/disable FPS counter (on stdout) | <kbd>MOD</kbd>+<kbd>i</kbd>
|
||||
| Pinch-to-zoom | <kbd>Ctrl</kbd>+_click-and-move_
|
||||
| Pinch-to-zoom/rotate | <kbd>Ctrl</kbd>+_click-and-move_
|
||||
| Tilt (slide vertically with 2 fingers) | <kbd>Shift</kbd>+_click-and-move_
|
||||
| Drag & drop APK file | Install APK from computer
|
||||
| Drag & drop non-APK file | [Push file to device](control.md#push-file-to-device)
|
||||
|
||||
|
@ -21,6 +21,13 @@ This will create a new video device in `/dev/videoN`, where `N` is an integer
|
||||
(more [options](https://github.com/umlaeute/v4l2loopback#options) are available
|
||||
to create several devices or devices with specific IDs).
|
||||
|
||||
If you encounter problems detecting your device with Chrome/WebRTC, you can try
|
||||
`exclusive_caps` mode:
|
||||
|
||||
```
|
||||
sudo modprobe v4l2loopback exclusive_caps=1
|
||||
```
|
||||
|
||||
To list the enabled devices:
|
||||
|
||||
```bash
|
||||
|
@ -4,14 +4,14 @@
|
||||
|
||||
Download the [latest release]:
|
||||
|
||||
- [`scrcpy-win64-v2.2.zip`][direct-win64] (64-bit)
|
||||
<sub>SHA-256: `9f9da88ac4c8319dcb9bf852f2d9bba942bac663413383419cddf64eaa5685bd`</sub>
|
||||
- [`scrcpy-win32-v2.2.zip`][direct-win32] (32-bit)
|
||||
<sub>SHA-256: `cb84269fc847b8b880e320879492a1ae6c017b42175f03e199530f7a53be9d74`</sub>
|
||||
- [`scrcpy-win64-v2.3.1.zip`][direct-win64] (64-bit)
|
||||
<sub>SHA-256: `f1f78ac98214078425804e524a1bed515b9d4b8a05b78d210a4ced2b910b262d`</sub>
|
||||
- [`scrcpy-win32-v2.3.1.zip`][direct-win32] (32-bit)
|
||||
<sub>SHA-256: `5dffc2d432e9b8b5b0e16f12e71428c37c70d9124cfbe7620df0b41b7efe91ff`</sub>
|
||||
|
||||
[latest release]: https://github.com/Genymobile/scrcpy/releases/latest
|
||||
[direct-win64]: https://github.com/Genymobile/scrcpy/releases/download/v2.2/scrcpy-win64-v2.2.zip
|
||||
[direct-win32]: https://github.com/Genymobile/scrcpy/releases/download/v2.2/scrcpy-win32-v2.2.zip
|
||||
[direct-win64]: https://github.com/Genymobile/scrcpy/releases/download/v2.3.1/scrcpy-win64-v2.3.1.zip
|
||||
[direct-win32]: https://github.com/Genymobile/scrcpy/releases/download/v2.3.1/scrcpy-win32-v2.3.1.zip
|
||||
|
||||
and extract it.
|
||||
|
||||
|
@ -2,8 +2,8 @@
|
||||
set -e
|
||||
|
||||
BUILDDIR=build-auto
|
||||
PREBUILT_SERVER_URL=https://github.com/Genymobile/scrcpy/releases/download/v2.2/scrcpy-server-v2.2
|
||||
PREBUILT_SERVER_SHA256=c85c4aa84305efb69115cd497a120ebdd10258993b4cf123a8245b3d99d49874
|
||||
PREBUILT_SERVER_URL=https://github.com/Genymobile/scrcpy/releases/download/v2.3.1/scrcpy-server-v2.3.1
|
||||
PREBUILT_SERVER_SHA256=f6814822fc308a7a532f253485c9038183c6296a6c5df470a9e383b4f8e7605b
|
||||
|
||||
echo "[scrcpy] Downloading prebuilt server..."
|
||||
wget "$PREBUILT_SERVER_URL" -O scrcpy-server
|
||||
|
@ -1,5 +1,5 @@
|
||||
project('scrcpy', 'c',
|
||||
version: 'v2.2',
|
||||
version: '2.3.1',
|
||||
meson_version: '>= 0.48',
|
||||
default_options: [
|
||||
'c_std=c11',
|
||||
|
@ -7,8 +7,8 @@ android {
|
||||
applicationId "com.genymobile.scrcpy"
|
||||
minSdkVersion 21
|
||||
targetSdkVersion 34
|
||||
versionCode 200
|
||||
versionName "v2.2"
|
||||
versionCode 20301
|
||||
versionName "2.3.1"
|
||||
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
||||
}
|
||||
buildTypes {
|
||||
|
@ -12,7 +12,7 @@
|
||||
set -e
|
||||
|
||||
SCRCPY_DEBUG=false
|
||||
SCRCPY_VERSION_NAME=v2.2
|
||||
SCRCPY_VERSION_NAME=2.3.1
|
||||
|
||||
PLATFORM=${ANDROID_PLATFORM:-34}
|
||||
BUILD_TOOLS=${ANDROID_BUILD_TOOLS:-34.0.0}
|
||||
|
@ -187,5 +187,7 @@ public final class CleanUp {
|
||||
Device.setScreenPowerMode(Device.POWER_MODE_NORMAL);
|
||||
}
|
||||
}
|
||||
|
||||
System.exit(0);
|
||||
}
|
||||
}
|
||||
|
@ -45,11 +45,11 @@ public final class Device {
|
||||
void onClipboardTextChanged(String text);
|
||||
}
|
||||
|
||||
private final Size deviceSize;
|
||||
private final Rect crop;
|
||||
private int maxSize;
|
||||
private final int lockVideoOrientation;
|
||||
|
||||
private Size deviceSize;
|
||||
private ScreenInfo screenInfo;
|
||||
private RotationListener rotationListener;
|
||||
private FoldListener foldListener;
|
||||
@ -116,8 +116,8 @@ public final class Device {
|
||||
return;
|
||||
}
|
||||
|
||||
screenInfo = ScreenInfo.computeScreenInfo(displayInfo.getRotation(), displayInfo.getSize(), options.getCrop(),
|
||||
options.getMaxSize(), options.getLockVideoOrientation());
|
||||
deviceSize = displayInfo.getSize();
|
||||
screenInfo = ScreenInfo.computeScreenInfo(displayInfo.getRotation(), deviceSize, crop, maxSize, lockVideoOrientation);
|
||||
// notify
|
||||
if (foldListener != null) {
|
||||
foldListener.onFoldChanged(displayId, folded);
|
||||
|
@ -49,6 +49,7 @@ public final class Workarounds {
|
||||
}
|
||||
|
||||
public static void apply(boolean audio, boolean camera) {
|
||||
boolean mustFillConfigurationController = false;
|
||||
boolean mustFillAppInfo = false;
|
||||
boolean mustFillAppContext = false;
|
||||
|
||||
@ -85,11 +86,23 @@ public final class Workarounds {
|
||||
mustFillAppContext = true;
|
||||
}
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
||||
// On some Samsung devices, DisplayManagerGlobal.getDisplayInfoLocked() calls ActivityThread.currentActivityThread().getConfiguration(),
|
||||
// which requires a non-null ConfigurationController.
|
||||
// ConfigurationController was introduced in Android 12, so do not attempt to set it on lower versions.
|
||||
// <https://github.com/Genymobile/scrcpy/issues/4467>
|
||||
mustFillConfigurationController = true;
|
||||
}
|
||||
|
||||
if (mustFillConfigurationController) {
|
||||
// Must be call before fillAppContext() because it is necessary to get a valid system context
|
||||
fillConfigurationController();
|
||||
}
|
||||
if (mustFillAppInfo) {
|
||||
Workarounds.fillAppInfo();
|
||||
fillAppInfo();
|
||||
}
|
||||
if (mustFillAppContext) {
|
||||
Workarounds.fillAppContext();
|
||||
fillAppContext();
|
||||
}
|
||||
}
|
||||
|
||||
@ -149,6 +162,22 @@ public final class Workarounds {
|
||||
}
|
||||
}
|
||||
|
||||
private static void fillConfigurationController() {
|
||||
try {
|
||||
Class<?> configurationControllerClass = Class.forName("android.app.ConfigurationController");
|
||||
Class<?> activityThreadInternalClass = Class.forName("android.app.ActivityThreadInternal");
|
||||
Constructor<?> configurationControllerConstructor = configurationControllerClass.getDeclaredConstructor(activityThreadInternalClass);
|
||||
configurationControllerConstructor.setAccessible(true);
|
||||
Object configurationController = configurationControllerConstructor.newInstance(ACTIVITY_THREAD);
|
||||
|
||||
Field configurationControllerField = ACTIVITY_THREAD_CLASS.getDeclaredField("mConfigurationController");
|
||||
configurationControllerField.setAccessible(true);
|
||||
configurationControllerField.set(ACTIVITY_THREAD, configurationController);
|
||||
} catch (Throwable throwable) {
|
||||
Ln.d("Could not fill configuration: " + throwable.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
static Context getSystemContext() {
|
||||
try {
|
||||
Method getSystemContextMethod = ACTIVITY_THREAD_CLASS.getDeclaredMethod("getSystemContext");
|
||||
@ -256,16 +285,28 @@ public final class Workarounds {
|
||||
Method getParcelMethod = attributionSourceState.getClass().getDeclaredMethod("getParcel");
|
||||
Parcel attributionSourceParcel = (Parcel) getParcelMethod.invoke(attributionSourceState);
|
||||
|
||||
// private native int native_setup(Object audiorecordThis,
|
||||
// Object /*AudioAttributes*/ attributes,
|
||||
// int[] sampleRate, int channelMask, int channelIndexMask, int audioFormat,
|
||||
// int buffSizeInBytes, int[] sessionId, @NonNull Parcel attributionSource,
|
||||
// long nativeRecordInJavaObj, int maxSharedAudioHistoryMs);
|
||||
Method nativeSetupMethod = AudioRecord.class.getDeclaredMethod("native_setup", Object.class, Object.class, int[].class, int.class,
|
||||
int.class, int.class, int.class, int[].class, Parcel.class, long.class, int.class);
|
||||
nativeSetupMethod.setAccessible(true);
|
||||
initResult = (int) nativeSetupMethod.invoke(audioRecord, new WeakReference<AudioRecord>(audioRecord), attributes, sampleRateArray,
|
||||
channelMask, channelIndexMask, audioRecord.getAudioFormat(), bufferSizeInBytes, session, attributionSourceParcel, 0L, 0);
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
|
||||
// private native int native_setup(Object audiorecordThis,
|
||||
// Object /*AudioAttributes*/ attributes,
|
||||
// int[] sampleRate, int channelMask, int channelIndexMask, int audioFormat,
|
||||
// int buffSizeInBytes, int[] sessionId, @NonNull Parcel attributionSource,
|
||||
// long nativeRecordInJavaObj, int maxSharedAudioHistoryMs);
|
||||
Method nativeSetupMethod = AudioRecord.class.getDeclaredMethod("native_setup", Object.class, Object.class, int[].class,
|
||||
int.class, int.class, int.class, int.class, int[].class, Parcel.class, long.class, int.class);
|
||||
nativeSetupMethod.setAccessible(true);
|
||||
initResult = (int) nativeSetupMethod.invoke(audioRecord, new WeakReference<AudioRecord>(audioRecord), attributes,
|
||||
sampleRateArray, channelMask, channelIndexMask, audioRecord.getAudioFormat(), bufferSizeInBytes, session,
|
||||
attributionSourceParcel, 0L, 0);
|
||||
} else {
|
||||
// Android 14 added a new int parameter "halInputFlags"
|
||||
// <https://github.com/aosp-mirror/platform_frameworks_base/commit/f6135d75db79b1d48fad3a3b3080d37be20a2313>
|
||||
Method nativeSetupMethod = AudioRecord.class.getDeclaredMethod("native_setup", Object.class, Object.class, int[].class,
|
||||
int.class, int.class, int.class, int.class, int[].class, Parcel.class, long.class, int.class, int.class);
|
||||
nativeSetupMethod.setAccessible(true);
|
||||
initResult = (int) nativeSetupMethod.invoke(audioRecord, new WeakReference<AudioRecord>(audioRecord), attributes,
|
||||
sampleRateArray, channelMask, channelIndexMask, audioRecord.getAudioFormat(), bufferSizeInBytes, session,
|
||||
attributionSourceParcel, 0L, 0, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -41,8 +41,13 @@ public final class ClipboardManager {
|
||||
getPrimaryClipMethod = manager.getClass().getMethod("getPrimaryClip", String.class, String.class, int.class, int.class);
|
||||
getMethodVersion = 2;
|
||||
} catch (NoSuchMethodException e3) {
|
||||
getPrimaryClipMethod = manager.getClass().getMethod("getPrimaryClip", String.class, int.class, String.class);
|
||||
getMethodVersion = 3;
|
||||
try {
|
||||
getPrimaryClipMethod = manager.getClass().getMethod("getPrimaryClip", String.class, int.class, String.class);
|
||||
getMethodVersion = 3;
|
||||
} catch (NoSuchMethodException e4) {
|
||||
getPrimaryClipMethod = manager.getClass().getMethod("getPrimaryClip", String.class, String.class, int.class, int.class, boolean.class);
|
||||
getMethodVersion = 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -87,8 +92,11 @@ public final class ClipboardManager {
|
||||
return (ClipData) method.invoke(manager, FakeContext.PACKAGE_NAME, null, FakeContext.ROOT_UID);
|
||||
case 2:
|
||||
return (ClipData) method.invoke(manager, FakeContext.PACKAGE_NAME, null, FakeContext.ROOT_UID, 0);
|
||||
default:
|
||||
case 3:
|
||||
return (ClipData) method.invoke(manager, FakeContext.PACKAGE_NAME, FakeContext.ROOT_UID, null);
|
||||
default:
|
||||
// The last boolean parameter is "userOperate"
|
||||
return (ClipData) method.invoke(manager, FakeContext.PACKAGE_NAME, null, FakeContext.ROOT_UID, 0, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user