Add --screen-off-timeout

Change the Android "screen off timeout" (the idle delay before the
screen automatically turns off) and restore the initial value on
exit.

PR #5447 <https://github.com/Genymobile/scrcpy/pull/5447>
This commit is contained in:
Romain Vimont 2024-11-03 22:46:21 +01:00
parent d3db9c4065
commit eff5b4b219
11 changed files with 108 additions and 2 deletions

View File

@ -77,6 +77,7 @@ _scrcpy() {
--rotation=
-s --serial=
-S --turn-screen-off
--screen-off-timeout=
--shortcut-mod=
--start-app=
-t --show-touches

View File

@ -80,6 +80,7 @@ arguments=(
'--require-audio=[Make scrcpy fail if audio is enabled but does not work]'
{-s,--serial=}'[The device serial number \(mandatory for multiple devices only\)]:serial:($("${ADB-adb}" devices | awk '\''$2 == "device" {print $1}'\''))'
{-S,--turn-screen-off}'[Turn the device screen off immediately]'
'--screen-off-timeout=[Set the screen off timeout in seconds]'
'--shortcut-mod=[\[key1,key2+key3,...\] Specify the modifiers to use for scrcpy shortcuts]:shortcut mod:(lctrl rctrl lalt ralt lsuper rsuper)'
'--start-app=[Start an Android app]'
{-t,--show-touches}'[Show physical touches]'

View File

@ -106,6 +106,7 @@ enum {
OPT_NEW_DISPLAY,
OPT_LIST_APPS,
OPT_START_APP,
OPT_SCREEN_OFF_TIMEOUT,
};
struct sc_option {
@ -793,6 +794,13 @@ static const struct sc_option options[] = {
.longopt = "turn-screen-off",
.text = "Turn the device screen off immediately.",
},
{
.longopt_id = OPT_SCREEN_OFF_TIMEOUT,
.longopt = "screen-off-timeout",
.argdesc = "seconds",
.text = "Set the screen off timeout while scrcpy is running (restore "
"the initial value on exit).",
},
{
.longopt_id = OPT_SHORTCUT_MOD,
.longopt = "shortcut-mod",
@ -2155,6 +2163,20 @@ parse_time_limit(const char *s, sc_tick *tick) {
return true;
}
static bool
parse_screen_off_timeout(const char *s, sc_tick *tick) {
long value;
// value in seconds, but must fit in 31 bits in milliseconds
bool ok = parse_integer_arg(s, &value, false, 0, 0x7FFFFFFF / 1000,
"screen off timeout");
if (!ok) {
return false;
}
*tick = SC_TICK_FROM_SEC(value);
return true;
}
static bool
parse_pause_on_exit(const char *s, enum sc_pause_on_exit *pause_on_exit) {
if (!s || !strcmp(s, "true")) {
@ -2730,6 +2752,12 @@ parse_args_with_getopt(struct scrcpy_cli_args *args, int argc, char *argv[],
case OPT_START_APP:
opts->start_app = optarg;
break;
case OPT_SCREEN_OFF_TIMEOUT:
if (!parse_screen_off_timeout(optarg,
&opts->screen_off_timeout)) {
return false;
}
break;
default:
// getopt prints the error message on stderr
return false;

View File

@ -62,6 +62,7 @@ const struct scrcpy_options scrcpy_options_default = {
.audio_buffer = -1, // depends on the audio format,
.audio_output_buffer = SC_TICK_FROM_MS(5),
.time_limit = 0,
.screen_off_timeout = -1,
#ifdef HAVE_V4L2
.v4l2_device = NULL,
.v4l2_buffer = 0,

View File

@ -265,6 +265,7 @@ struct scrcpy_options {
sc_tick audio_buffer;
sc_tick audio_output_buffer;
sc_tick time_limit;
sc_tick screen_off_timeout;
#ifdef HAVE_V4L2
const char *v4l2_device;
sc_tick v4l2_buffer;

View File

@ -428,6 +428,7 @@ scrcpy(struct scrcpy_options *options) {
.video_bit_rate = options->video_bit_rate,
.audio_bit_rate = options->audio_bit_rate,
.max_fps = options->max_fps,
.screen_off_timeout = options->screen_off_timeout,
.lock_video_orientation = options->lock_video_orientation,
.control = options->control,
.display_id = options->display_id,

View File

@ -320,6 +320,11 @@ execute_server(struct sc_server *server,
if (params->stay_awake) {
ADD_PARAM("stay_awake=true");
}
if (params->screen_off_timeout != -1) {
assert(params->screen_off_timeout >= 0);
uint64_t ms = SC_TICK_TO_MS(params->screen_off_timeout);
ADD_PARAM("screen_off_timeout=%" PRIu64, ms);
}
if (params->video_codec_options) {
VALIDATE_STRING(params->video_codec_options);
ADD_PARAM("video_codec_options=%s", params->video_codec_options);

View File

@ -45,6 +45,7 @@ struct sc_server_params {
uint32_t video_bit_rate;
uint32_t audio_bit_rate;
const char *max_fps; // float to be parsed by the server
sc_tick screen_off_timeout;
int8_t lock_video_orientation;
bool control;
uint32_t display_id;

View File

@ -71,6 +71,31 @@ adb shell cmd display power-on 0
```
## Screen off timeout
The Android screen automatically turns off after some delay.
To change this delay while scrcpy is running:
```bash
scrcpy --screen-off-timeout=300 # 300 seconds (5 minutes)
```
The initial value is restored on exit.
It is possible to change this setting manually:
```bash
# get the current screen_off_timeout value
adb shell settings get system screen_off_timeout
# set a new value (in milliseconds)
adb shell settings put system screen_off_timeout 30000
```
Note that the Android value is in milliseconds, but the scrcpy command line
argument is in seconds.
## Show touches
For presentations, it may be useful to show physical touches (on the physical

View File

@ -73,10 +73,29 @@ public final class CleanUp {
}
}
int restoreScreenOffTimeout = -1;
int screenOffTimeout = options.getScreenOffTimeout();
if (screenOffTimeout != -1) {
try {
String oldValue = Settings.getAndPutValue(Settings.TABLE_SYSTEM, "screen_off_timeout", String.valueOf(screenOffTimeout));
try {
int currentScreenOffTimeout = Integer.parseInt(oldValue);
// Restore only if the current value is different
if (currentScreenOffTimeout != screenOffTimeout) {
restoreScreenOffTimeout = currentScreenOffTimeout;
}
} catch (NumberFormatException e) {
// ignore
}
} catch (SettingsException e) {
Ln.e("Could not change \"screen_off_timeout\"", e);
}
}
boolean powerOffScreen = options.getPowerOffScreenOnClose();
try {
run(displayId, restoreStayOn, disableShowTouches, powerOffScreen);
run(displayId, restoreStayOn, disableShowTouches, powerOffScreen, restoreScreenOffTimeout);
} catch (InterruptedException e) {
// ignore
} catch (IOException e) {
@ -84,7 +103,8 @@ public final class CleanUp {
}
}
private void run(int displayId, int restoreStayOn, boolean disableShowTouches, boolean powerOffScreen) throws IOException, InterruptedException {
private void run(int displayId, int restoreStayOn, boolean disableShowTouches, boolean powerOffScreen, int restoreScreenOffTimeout)
throws IOException, InterruptedException {
String[] cmd = {
"app_process",
"/",
@ -93,6 +113,7 @@ public final class CleanUp {
String.valueOf(restoreStayOn),
String.valueOf(disableShowTouches),
String.valueOf(powerOffScreen),
String.valueOf(restoreScreenOffTimeout),
};
ProcessBuilder builder = new ProcessBuilder(cmd);
@ -139,6 +160,7 @@ public final class CleanUp {
int restoreStayOn = Integer.parseInt(args[1]);
boolean disableShowTouches = Boolean.parseBoolean(args[2]);
boolean powerOffScreen = Boolean.parseBoolean(args[3]);
int restoreScreenOffTimeout = Integer.parseInt(args[4]);
// Dynamic option
boolean restoreDisplayPower = false;
@ -175,6 +197,15 @@ public final class CleanUp {
}
}
if (restoreScreenOffTimeout != -1) {
Ln.i("Restoring \"screen off timeout\"");
try {
Settings.putValue(Settings.TABLE_SYSTEM, "screen_off_timeout", String.valueOf(restoreScreenOffTimeout));
} catch (SettingsException e) {
Ln.e("Could not restore \"screen_off_timeout\"", e);
}
}
if (displayId != Device.DISPLAY_ID_NONE && Device.isScreenOn(displayId)) {
if (powerOffScreen) {
Ln.i("Power off screen");

View File

@ -45,6 +45,7 @@ public class Options {
private boolean cameraHighSpeed;
private boolean showTouches;
private boolean stayAwake;
private int screenOffTimeout = -1;
private List<CodecOption> videoCodecOptions;
private List<CodecOption> audioCodecOptions;
@ -174,6 +175,10 @@ public class Options {
return stayAwake;
}
public int getScreenOffTimeout() {
return screenOffTimeout;
}
public List<CodecOption> getVideoCodecOptions() {
return videoCodecOptions;
}
@ -363,6 +368,12 @@ public class Options {
case "stay_awake":
options.stayAwake = Boolean.parseBoolean(value);
break;
case "screen_off_timeout":
options.screenOffTimeout = Integer.parseInt(value);
if (options.screenOffTimeout < -1) {
throw new IllegalArgumentException("Invalid screen off timeout: " + options.screenOffTimeout);
}
break;
case "video_codec_options":
options.videoCodecOptions = CodecOption.parse(value);
break;