Compare commits

..

1 Commits

Author SHA1 Message Date
Romain Vimont
01199084ad quickfix secure flag DONOTMERGE 2021-04-26 08:17:25 +02:00
12 changed files with 106 additions and 273 deletions

View File

@@ -186,7 +186,7 @@ Enable "show touches" on start, restore the initial value on exit.
It only shows physical touches (not clicks from scrcpy). It only shows physical touches (not clicks from scrcpy).
.TP .TP
.BI "\-\-v4l2-sink " /dev/videoN .BI "\-\-v4l2_sink " /dev/videoN
Output to v4l2loopback device. Output to v4l2loopback device.
It requires to lock the video orientation (see --lock-video-orientation). It requires to lock the video orientation (see --lock-video-orientation).

View File

@@ -177,7 +177,7 @@ scrcpy_print_usage(const char *arg0) {
" It only shows physical touches (not clicks from scrcpy).\n" " It only shows physical touches (not clicks from scrcpy).\n"
"\n" "\n"
#ifdef HAVE_V4L2 #ifdef HAVE_V4L2
" --v4l2-sink /dev/videoN\n" " --v4l2_sink /dev/videoN\n"
" Output to v4l2loopback device.\n" " Output to v4l2loopback device.\n"
" It requires to lock the video orientation (see\n" " It requires to lock the video orientation (see\n"
" --lock-video-orientation).\n" " --lock-video-orientation).\n"
@@ -726,7 +726,7 @@ scrcpy_parse_args(struct scrcpy_cli_args *args, int argc, char *argv[]) {
{"stay-awake", no_argument, NULL, 'w'}, {"stay-awake", no_argument, NULL, 'w'},
{"turn-screen-off", no_argument, NULL, 'S'}, {"turn-screen-off", no_argument, NULL, 'S'},
#ifdef HAVE_V4L2 #ifdef HAVE_V4L2
{"v4l2-sink", required_argument, NULL, OPT_V4L2_SINK}, {"v4l2_sink", required_argument, NULL, OPT_V4L2_SINK},
#endif #endif
{"verbosity", required_argument, NULL, 'V'}, {"verbosity", required_argument, NULL, 'V'},
{"version", no_argument, NULL, 'v'}, {"version", no_argument, NULL, 'v'},
@@ -926,7 +926,7 @@ scrcpy_parse_args(struct scrcpy_cli_args *args, int argc, char *argv[]) {
#ifdef HAVE_V4L2 #ifdef HAVE_V4L2
if (!opts->display && !opts->record_filename && !opts->v4l2_device) { if (!opts->display && !opts->record_filename && !opts->v4l2_device) {
LOGE("-N/--no-display requires either screen recording (-r/--record)" LOGE("-N/--no-display requires either screen recording (-r/--record)"
" or sink to v4l2loopback device (--v4l2-sink)"); " or sink to v4l2loopback device (--v4l2_sink)");
return false; return false;
} }

View File

@@ -111,8 +111,6 @@ decoder_push(struct decoder *decoder, const AVPacket *packet) {
// A frame lost should not make the whole pipeline fail. The error, if // A frame lost should not make the whole pipeline fail. The error, if
// any, is already logged. // any, is already logged.
(void) ok; (void) ok;
av_frame_unref(decoder->frame);
} else if (ret != AVERROR(EAGAIN)) { } else if (ret != AVERROR(EAGAIN)) {
LOGE("Could not receive video frame: %d", ret); LOGE("Could not receive video frame: %d", ret);
return false; return false;

View File

@@ -243,6 +243,10 @@ av_log_callback(void *avcl, int level, const char *fmt, va_list vl) {
bool bool
scrcpy(const struct scrcpy_options *options) { scrcpy(const struct scrcpy_options *options) {
if (!server_init(&server)) {
return false;
}
bool ret = false; bool ret = false;
bool server_started = false; bool server_started = false;
@@ -259,7 +263,6 @@ scrcpy(const struct scrcpy_options *options) {
bool record = !!options->record_filename; bool record = !!options->record_filename;
struct server_params params = { struct server_params params = {
.serial = options->serial,
.log_level = options->log_level, .log_level = options->log_level,
.crop = options->crop, .crop = options->crop,
.port_range = options->port_range, .port_range = options->port_range,
@@ -276,12 +279,7 @@ scrcpy(const struct scrcpy_options *options) {
.force_adb_forward = options->force_adb_forward, .force_adb_forward = options->force_adb_forward,
.power_off_on_close = options->power_off_on_close, .power_off_on_close = options->power_off_on_close,
}; };
if (!server_start(&server, options->serial, &params)) {
if (!server_init(&server, &params)) {
return false;
}
if (!server_start(&server)) {
goto end; goto end;
} }
@@ -313,7 +311,7 @@ scrcpy(const struct scrcpy_options *options) {
fps_counter_initialized = true; fps_counter_initialized = true;
if (options->control) { if (options->control) {
if (!file_handler_init(&file_handler, options->serial, if (!file_handler_init(&file_handler, server.serial,
options->push_target)) { options->push_target)) {
goto end; goto end;
} }

View File

@@ -128,10 +128,9 @@ disable_tunnel_forward(const char *serial, uint16_t local_port) {
static bool static bool
disable_tunnel(struct server *server) { disable_tunnel(struct server *server) {
if (server->tunnel_forward) { if (server->tunnel_forward) {
return disable_tunnel_forward(server->params.serial, return disable_tunnel_forward(server->serial, server->local_port);
server->local_port);
} }
return disable_tunnel_reverse(server->params.serial); return disable_tunnel_reverse(server->serial);
} }
static socket_t static socket_t
@@ -145,7 +144,7 @@ enable_tunnel_reverse_any_port(struct server *server,
struct sc_port_range port_range) { struct sc_port_range port_range) {
uint16_t port = port_range.first; uint16_t port = port_range.first;
for (;;) { for (;;) {
if (!enable_tunnel_reverse(server->params.serial, port)) { if (!enable_tunnel_reverse(server->serial, port)) {
// the command itself failed, it will fail on any port // the command itself failed, it will fail on any port
return false; return false;
} }
@@ -164,7 +163,7 @@ enable_tunnel_reverse_any_port(struct server *server,
} }
// failure, disable tunnel and try another port // failure, disable tunnel and try another port
if (!disable_tunnel_reverse(server->params.serial)) { if (!disable_tunnel_reverse(server->serial)) {
LOGW("Could not remove reverse tunnel on port %" PRIu16, port); LOGW("Could not remove reverse tunnel on port %" PRIu16, port);
} }
@@ -192,7 +191,7 @@ enable_tunnel_forward_any_port(struct server *server,
server->tunnel_forward = true; server->tunnel_forward = true;
uint16_t port = port_range.first; uint16_t port = port_range.first;
for (;;) { for (;;) {
if (enable_tunnel_forward(server->params.serial, port)) { if (enable_tunnel_forward(server->serial, port)) {
// success // success
server->local_port = port; server->local_port = port;
return true; return true;
@@ -307,7 +306,7 @@ execute_server(struct server *server, const struct server_params *params) {
// Port: 5005 // Port: 5005
// Then click on "Debug" // Then click on "Debug"
#endif #endif
return adb_execute(server->params.serial, cmd, ARRAY_LEN(cmd)); return adb_execute(server->serial, cmd, sizeof(cmd) / sizeof(cmd[0]));
} }
static socket_t static socket_t
@@ -353,75 +352,21 @@ close_socket(socket_t socket) {
} }
} }
static void
server_params_destroy(struct server_params *params) {
// The server stores a copy of the params provided by the user
free((char *) params->crop);
free((char *) params->codec_options);
free((char *) params->encoder_name);
}
static bool
server_params_copy(struct server_params *dst, const struct server_params *src) {
// params reference user-allocated memory, so we must copy them to handle
// them from a separate thread
*dst = *src;
dst->crop = NULL;
dst->codec_options = NULL;
dst->encoder_name = NULL;
if (src->crop) {
dst->crop = strdup(src->crop);
if (!dst->crop) {
goto error;
}
}
if (src->codec_options) {
dst->codec_options = strdup(src->codec_options);
if (!dst->codec_options) {
goto error;
}
}
if (src->encoder_name) {
dst->encoder_name = strdup(src->encoder_name);
if (!dst->encoder_name) {
goto error;
}
}
return true;
error:
server_params_destroy(dst);
return false;
};
bool bool
server_init(struct server *server, const struct server_params *params) { server_init(struct server *server) {
if (!server_params_copy(&server->params, params)) { server->serial = NULL;
LOGE("Could not copy server params");
return false;
}
server->process = PROCESS_NONE; server->process = PROCESS_NONE;
atomic_flag_clear_explicit(&server->server_socket_closed, atomic_flag_clear_explicit(&server->server_socket_closed,
memory_order_relaxed); memory_order_relaxed);
bool ok = sc_mutex_init(&server->mutex); bool ok = sc_mutex_init(&server->mutex);
if (!ok) { if (!ok) {
server_params_destroy(&server->params);
return false; return false;
} }
ok = sc_cond_init(&server->process_terminated_cond); ok = sc_cond_init(&server->process_terminated_cond);
if (!ok) { if (!ok) {
sc_mutex_destroy(&server->mutex); sc_mutex_destroy(&server->mutex);
server_params_destroy(&server->params);
return false; return false;
} }
@@ -461,41 +406,31 @@ run_wait_server(void *data) {
return 0; return 0;
} }
static int bool
run_server(void *data) { server_start(struct server *server, const char *serial,
struct server *server = data; const struct server_params *params) {
if (serial) {
server->serial = strdup(serial);
if (!server->serial) {
return false;
}
}
const struct server_params *params = &server->params; if (!push_server(serial)) {
const struct server_callbacks *cbs = &server->cbs; goto error1;
void *userdata = server->userdata;
if (!push_server(params->serial)) {
cbs->on_connection_failed(server);
goto end;
} }
if (!enable_tunnel_any_port(server, params->port_range, if (!enable_tunnel_any_port(server, params->port_range,
params->force_adb_forward)) { params->force_adb_forward)) {
cbs->on_connection_failed(server); goto error1;
goto end;
} }
// server will connect to our server socket // server will connect to our server socket
server->process = execute_server(server, params); server->process = execute_server(server, params);
if (server->process == PROCESS_NONE) { if (server->process == PROCESS_NONE) {
cbs->on_connection_failed(server); goto error2;
goto end;
} }
process_wait(server->process, false); // ignore exit code
end:
return 0;
}
bool
server_start(struct server *server) {
// If the server process dies before connecting to the server socket, then // If the server process dies before connecting to the server socket, then
// the client will be stuck forever on accept(). To avoid the problem, we // the client will be stuck forever on accept(). To avoid the problem, we
// must be able to wake up the accept() call when the server dies. To keep // must be able to wake up the accept() call when the server dies. To keep
@@ -507,14 +442,14 @@ server_start(struct server *server) {
if (!ok) { if (!ok) {
process_terminate(server->process); process_terminate(server->process);
process_wait(server->process, true); // ignore exit code process_wait(server->process, true); // ignore exit code
goto error; goto error2;
} }
server->tunnel_enabled = true; server->tunnel_enabled = true;
return true; return true;
error: error2:
if (!server->tunnel_forward) { if (!server->tunnel_forward) {
bool was_closed = bool was_closed =
atomic_flag_test_and_set(&server->server_socket_closed); atomic_flag_test_and_set(&server->server_socket_closed);
@@ -524,7 +459,8 @@ error:
close_socket(server->server_socket); close_socket(server->server_socket);
} }
disable_tunnel(server); disable_tunnel(server);
error1:
free(server->serial);
return false; return false;
} }
@@ -622,5 +558,4 @@ server_destroy(struct server *server) {
free(server->serial); free(server->serial);
sc_cond_destroy(&server->process_terminated_cond); sc_cond_destroy(&server->process_terminated_cond);
sc_mutex_destroy(&server->mutex); sc_mutex_destroy(&server->mutex);
server_params_destroy(&server->params);
} }

View File

@@ -13,25 +13,6 @@
#include "util/net.h" #include "util/net.h"
#include "util/thread.h" #include "util/thread.h"
struct server_params {
enum sc_log_level log_level;
const char *serial;
const char *crop;
const char *codec_options;
const char *encoder_name;
struct sc_port_range port_range;
uint16_t max_size;
uint32_t bit_rate;
uint16_t max_fps;
int8_t lock_video_orientation;
bool control;
uint32_t display_id;
bool show_touches;
bool stay_awake;
bool force_adb_forward;
bool power_off_on_close;
};
struct server { struct server {
char *serial; char *serial;
process_t process; process_t process;
@@ -48,29 +29,34 @@ struct server {
uint16_t local_port; // selected from port_range uint16_t local_port; // selected from port_range
bool tunnel_enabled; bool tunnel_enabled;
bool tunnel_forward; // use "adb forward" instead of "adb reverse" bool tunnel_forward; // use "adb forward" instead of "adb reverse"
// The internal allocated strings are copies owned by the server
struct server_params params;
const struct server_callbacks *cbs;
void *userdata;
}; };
struct server_callbacks { struct server_params {
void (*on_connection_failed)(struct server *server); enum sc_log_level log_level;
void (*on_connected)(struct server *server, const char *name, const char *crop;
struct size size, void *userdata); const char *codec_options;
void (*on_disconnected)(struct server *server, void *userdata); const char *encoder_name;
struct sc_port_range port_range;
uint16_t max_size;
uint32_t bit_rate;
uint16_t max_fps;
int8_t lock_video_orientation;
bool control;
uint32_t display_id;
bool show_touches;
bool stay_awake;
bool force_adb_forward;
bool power_off_on_close;
}; };
// init server fields // init default values
bool bool
server_init(struct server *server, const struct server_params *params); server_init(struct server *server);
// push, enable tunnel et start the server // push, enable tunnel et start the server
bool bool
server_start(struct server *server, const struct server_callbacks *cbs, server_start(struct server *server, const char *serial,
void *userdata); const struct server_params *params);
// block until the communication with the server is established // block until the communication with the server is established
bool bool

View File

@@ -92,11 +92,11 @@ encode_and_write_frame(struct sc_v4l2_sink *vs, const AVFrame *frame) {
// A packet was received // A packet was received
bool ok = write_packet(vs, packet); bool ok = write_packet(vs, packet);
av_packet_unref(packet);
if (!ok) { if (!ok) {
LOGW("Could not send packet to v4l2 sink"); LOGW("Could not send packet to v4l2 sink");
return false; return false;
} }
av_packet_unref(packet);
} else if (ret != AVERROR(EAGAIN)) { } else if (ret != AVERROR(EAGAIN)) {
LOGE("Could not receive v4l2 video packet: %d", ret); LOGE("Could not receive v4l2 video packet: %d", ret);
return false; return false;
@@ -125,7 +125,6 @@ run_v4l2_sink(void *data) {
video_buffer_consume(&vs->vb, vs->frame); video_buffer_consume(&vs->vb, vs->frame);
bool ok = encode_and_write_frame(vs, vs->frame); bool ok = encode_and_write_frame(vs, vs->frame);
av_frame_unref(vs->frame);
if (!ok) { if (!ok) {
LOGE("Could not send frame to v4l2 sink"); LOGE("Could not send frame to v4l2 sink");
break; break;

View File

@@ -3,10 +3,6 @@ package com.genymobile.scrcpy;
import com.genymobile.scrcpy.wrappers.ContentProvider; import com.genymobile.scrcpy.wrappers.ContentProvider;
import com.genymobile.scrcpy.wrappers.ServiceManager; import com.genymobile.scrcpy.wrappers.ServiceManager;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.Base64;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
@@ -19,123 +15,25 @@ public final class CleanUp {
public static final String SERVER_PATH = "/data/local/tmp/scrcpy-server.jar"; 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
public static class Config implements Parcelable {
public static final Creator<Config> CREATOR = new Creator<Config>() {
@Override
public Config createFromParcel(Parcel in) {
return new Config(in);
}
@Override
public Config[] newArray(int size) {
return new Config[size];
}
};
private static final int FLAG_DISABLE_SHOW_TOUCHES = 1;
private static final int FLAG_RESTORE_NORMAL_POWER_MODE = 2;
private static final int FLAG_POWER_OFF_SCREEN = 4;
private int displayId;
// Restore the value (between 0 and 7), -1 to not restore
// <https://developer.android.com/reference/android/provider/Settings.Global#STAY_ON_WHILE_PLUGGED_IN>
private int restoreStayOn = -1;
private boolean disableShowTouches;
private boolean restoreNormalPowerMode;
private boolean powerOffScreen;
public Config() {
// Default constructor, the fields are initialized by CleanUp.configure()
}
protected Config(Parcel in) {
displayId = in.readInt();
restoreStayOn = in.readInt();
byte options = in.readByte();
disableShowTouches = (options & FLAG_DISABLE_SHOW_TOUCHES) != 0;
restoreNormalPowerMode = (options & FLAG_RESTORE_NORMAL_POWER_MODE) != 0;
powerOffScreen = (options & FLAG_POWER_OFF_SCREEN) != 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(displayId);
dest.writeInt(restoreStayOn);
byte options = 0;
if (disableShowTouches) {
options |= FLAG_DISABLE_SHOW_TOUCHES;
}
if (restoreNormalPowerMode) {
options |= FLAG_RESTORE_NORMAL_POWER_MODE;
}
if (powerOffScreen) {
options |= FLAG_POWER_OFF_SCREEN;
}
dest.writeByte(options);
}
private boolean hasWork() {
return disableShowTouches || restoreStayOn != -1 || restoreNormalPowerMode || powerOffScreen;
}
@Override
public int describeContents() {
return 0;
}
byte[] serialize() {
Parcel parcel = Parcel.obtain();
writeToParcel(parcel, 0);
byte[] bytes = parcel.marshall();
parcel.recycle();
return bytes;
}
static Config deserialize(byte[] bytes) {
Parcel parcel = Parcel.obtain();
parcel.unmarshall(bytes, 0, bytes.length);
parcel.setDataPosition(0);
return CREATOR.createFromParcel(parcel);
}
static Config fromBase64(String base64) {
byte[] bytes = Base64.decode(base64, Base64.NO_WRAP);
return deserialize(bytes);
}
String toBase64() {
byte[] bytes = serialize();
return Base64.encodeToString(bytes, Base64.NO_WRAP);
}
}
private CleanUp() { private CleanUp() {
// not instantiable // not instantiable
} }
public static void configure(int displayId, int restoreStayOn, boolean disableShowTouches, boolean restoreNormalPowerMode, boolean powerOffScreen) public static void configure(boolean disableShowTouches, int restoreStayOn, boolean restoreNormalPowerMode, boolean powerOffScreen, int displayId)
throws IOException { throws IOException {
Config config = new Config(); boolean needProcess = disableShowTouches || restoreStayOn != -1 || restoreNormalPowerMode || powerOffScreen;
config.displayId = displayId; if (needProcess) {
config.disableShowTouches = disableShowTouches; startProcess(disableShowTouches, restoreStayOn, restoreNormalPowerMode, powerOffScreen, displayId);
config.restoreStayOn = restoreStayOn;
config.restoreNormalPowerMode = restoreNormalPowerMode;
config.powerOffScreen = powerOffScreen;
if (config.hasWork()) {
startProcess(config);
} else { } else {
// There is no additional clean up to do when scrcpy dies // There is no additional clean up to do when scrcpy dies
unlinkSelf(); unlinkSelf();
} }
} }
private static void startProcess(Config config) throws IOException { private static void startProcess(boolean disableShowTouches, int restoreStayOn, boolean restoreNormalPowerMode, boolean powerOffScreen,
String[] cmd = {"app_process", "/", CleanUp.class.getName(), config.toBase64()}; int displayId) throws IOException {
String[] cmd = {"app_process", "/", CleanUp.class.getName(), String.valueOf(disableShowTouches), String.valueOf(
restoreStayOn), String.valueOf(restoreNormalPowerMode), String.valueOf(powerOffScreen), String.valueOf(displayId)};
ProcessBuilder builder = new ProcessBuilder(cmd); ProcessBuilder builder = new ProcessBuilder(cmd);
builder.environment().put("CLASSPATH", SERVER_PATH); builder.environment().put("CLASSPATH", SERVER_PATH);
@@ -162,27 +60,31 @@ public final class CleanUp {
Ln.i("Cleaning up"); Ln.i("Cleaning up");
Config config = Config.fromBase64(args[0]); boolean disableShowTouches = Boolean.parseBoolean(args[0]);
int restoreStayOn = Integer.parseInt(args[1]);
boolean restoreNormalPowerMode = Boolean.parseBoolean(args[2]);
boolean powerOffScreen = Boolean.parseBoolean(args[3]);
int displayId = Integer.parseInt(args[4]);
if (config.disableShowTouches || config.restoreStayOn != -1) { if (disableShowTouches || restoreStayOn != -1) {
ServiceManager serviceManager = new ServiceManager(); ServiceManager serviceManager = new ServiceManager();
try (ContentProvider settings = serviceManager.getActivityManager().createSettingsProvider()) { try (ContentProvider settings = serviceManager.getActivityManager().createSettingsProvider()) {
if (config.disableShowTouches) { if (disableShowTouches) {
Ln.i("Disabling \"show touches\""); Ln.i("Disabling \"show touches\"");
settings.putValue(ContentProvider.TABLE_SYSTEM, "show_touches", "0"); settings.putValue(ContentProvider.TABLE_SYSTEM, "show_touches", "0");
} }
if (config.restoreStayOn != -1) { if (restoreStayOn != -1) {
Ln.i("Restoring \"stay awake\""); Ln.i("Restoring \"stay awake\"");
settings.putValue(ContentProvider.TABLE_GLOBAL, "stay_on_while_plugged_in", String.valueOf(config.restoreStayOn)); settings.putValue(ContentProvider.TABLE_GLOBAL, "stay_on_while_plugged_in", String.valueOf(restoreStayOn));
} }
} }
} }
if (Device.isScreenOn()) { if (Device.isScreenOn()) {
if (config.powerOffScreen) { if (powerOffScreen) {
Ln.i("Power off screen"); Ln.i("Power off screen");
Device.powerOffScreen(config.displayId); Device.powerOffScreen(displayId);
} else if (config.restoreNormalPowerMode) { } else if (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);
} }

View File

@@ -55,7 +55,7 @@ public class Controller {
public void control() throws IOException { public void control() throws IOException {
// on start, power on the device // on start, power on the device
if (!Device.isScreenOn()) { if (!Device.isScreenOn()) {
device.pressReleaseKeycode(KeyEvent.KEYCODE_POWER); device.injectKeycode(KeyEvent.KEYCODE_POWER);
// dirty hack // dirty hack
// After POWER is injected, the device is powered on asynchronously. // After POWER is injected, the device is powered on asynchronously.
@@ -273,7 +273,7 @@ public class Controller {
if (keepPowerModeOff) { if (keepPowerModeOff) {
schedulePowerModeOff(); schedulePowerModeOff();
} }
return device.pressReleaseKeycode(KeyEvent.KEYCODE_POWER); return device.injectKeycode(KeyEvent.KEYCODE_POWER);
} }
private boolean setClipboard(String text, boolean paste) { private boolean setClipboard(String text, boolean paste) {
@@ -284,7 +284,7 @@ public class Controller {
// On Android >= 7, also press the PASTE key if requested // On Android >= 7, also press the PASTE key if requested
if (paste && Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && device.supportsInputEvents()) { if (paste && Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && device.supportsInputEvents()) {
device.pressReleaseKeycode(KeyEvent.KEYCODE_PASTE); device.injectKeycode(KeyEvent.KEYCODE_PASTE);
} }
return ok; return ok;

View File

@@ -164,39 +164,54 @@ public final class Device {
return supportsInputEvents; return supportsInputEvents;
} }
public static boolean injectEvent(InputEvent inputEvent, int displayId) { public static boolean injectEvent(InputEvent inputEvent, int mode, int displayId) {
if (!supportsInputEvents(displayId)) { if (!supportsInputEvents(displayId)) {
throw new AssertionError("Could not inject input event if !supportsInputEvents()"); return false;
} }
if (displayId != 0 && !InputManager.setDisplayId(inputEvent, displayId)) { if (displayId != 0 && !InputManager.setDisplayId(inputEvent, displayId)) {
return false; return false;
} }
return SERVICE_MANAGER.getInputManager().injectInputEvent(inputEvent, InputManager.INJECT_INPUT_EVENT_MODE_ASYNC); return SERVICE_MANAGER.getInputManager().injectInputEvent(inputEvent, mode);
}
public boolean injectEvent(InputEvent inputEvent, int mode) {
if (!supportsInputEvents()) {
throw new AssertionError("Could not inject input event if !supportsInputEvents()");
}
return injectEvent(inputEvent, mode, displayId);
}
public static boolean injectEventOnDisplay(InputEvent event, int displayId) {
return injectEvent(event, InputManager.INJECT_INPUT_EVENT_MODE_ASYNC, displayId);
} }
public boolean injectEvent(InputEvent event) { public boolean injectEvent(InputEvent event) {
return injectEvent(event, displayId); return injectEvent(event, InputManager.INJECT_INPUT_EVENT_MODE_ASYNC);
} }
public static boolean injectKeyEvent(int action, int keyCode, int repeat, int metaState, int displayId) { public static boolean injectKeyEvent(int action, int keyCode, int repeat, int metaState, int displayId) {
long now = SystemClock.uptimeMillis(); long now = SystemClock.uptimeMillis();
KeyEvent event = new KeyEvent(now, now, action, keyCode, repeat, metaState, KeyCharacterMap.VIRTUAL_KEYBOARD, 0, 0, KeyEvent event = new KeyEvent(now, now, action, keyCode, repeat, metaState, KeyCharacterMap.VIRTUAL_KEYBOARD, 0, 0,
InputDevice.SOURCE_KEYBOARD); InputDevice.SOURCE_KEYBOARD);
return injectEvent(event, displayId); return injectEventOnDisplay(event, displayId);
} }
public boolean injectKeyEvent(int action, int keyCode, int repeat, int metaState) { public boolean injectKeyEvent(int action, int keyCode, int repeat, int metaState) {
return injectKeyEvent(action, keyCode, repeat, metaState, displayId); long now = SystemClock.uptimeMillis();
KeyEvent event = new KeyEvent(now, now, action, keyCode, repeat, metaState, KeyCharacterMap.VIRTUAL_KEYBOARD, 0, 0,
InputDevice.SOURCE_KEYBOARD);
return injectEvent(event);
} }
public static boolean pressReleaseKeycode(int keyCode, int displayId) { public static boolean injectKeycode(int keyCode, int displayId) {
return injectKeyEvent(KeyEvent.ACTION_DOWN, keyCode, 0, 0, displayId) && injectKeyEvent(KeyEvent.ACTION_UP, keyCode, 0, 0, displayId); return injectKeyEvent(KeyEvent.ACTION_DOWN, keyCode, 0, 0, displayId) && injectKeyEvent(KeyEvent.ACTION_UP, keyCode, 0, 0, displayId);
} }
public boolean pressReleaseKeycode(int keyCode) { public boolean injectKeycode(int keyCode) {
return pressReleaseKeycode(keyCode, displayId); return injectKeyEvent(KeyEvent.ACTION_DOWN, keyCode, 0, 0) && injectKeyEvent(KeyEvent.ACTION_UP, keyCode, 0, 0);
} }
public static boolean isScreenOn() { public static boolean isScreenOn() {
@@ -272,7 +287,7 @@ public final class Device {
if (!isScreenOn()) { if (!isScreenOn()) {
return true; return true;
} }
return pressReleaseKeycode(KeyEvent.KEYCODE_POWER, displayId); return injectKeycode(KeyEvent.KEYCODE_POWER, displayId);
} }
/** /**

View File

@@ -225,7 +225,7 @@ public class ScreenEncoder implements Device.RotationListener {
} }
private static IBinder createDisplay() { private static IBinder createDisplay() {
return SurfaceControl.createDisplay("scrcpy", true); return SurfaceControl.createDisplay("scrcpy", false);
} }
private static void configure(MediaCodec codec, MediaFormat format) { private static void configure(MediaCodec codec, MediaFormat format) {

View File

@@ -50,7 +50,7 @@ public final class Server {
} }
} }
CleanUp.configure(options.getDisplayId(), restoreStayOn, mustDisableShowTouchesOnCleanUp, true, options.getPowerOffScreenOnClose()); CleanUp.configure(mustDisableShowTouchesOnCleanUp, restoreStayOn, true, options.getPowerOffScreenOnClose(), options.getDisplayId());
boolean tunnelForward = options.isTunnelForward(); boolean tunnelForward = options.isTunnelForward();