Add an option to keep the device awake

Add an option to prevent the device to sleep:

    scrcpy --stay-awake
    scrcpy -w

The initial state is restored on exit.

Fixes #631 <https://github.com/Genymobile/scrcpy/issues/631>
This commit is contained in:
Romain Vimont 2020-05-02 01:54:48 +02:00
parent 828327365a
commit c77024314d
10 changed files with 93 additions and 15 deletions

View file

@ -396,6 +396,18 @@ The list of display ids can be retrieved by:
adb shell dumpsys display # search "mDisplayId=" in the output adb shell dumpsys display # search "mDisplayId=" in the output
``` ```
#### Stay awake
To prevent the device to sleep after some delay:
```bash
scrcpy --stay-awake
scrcpy -w
```
The initial state is restored when scrcpy is closed.
#### Turn screen off #### Turn screen off
It is possible to turn the device screen off while mirroring on start with a It is possible to turn the device screen off while mirroring on start with a
@ -410,6 +422,14 @@ Or by pressing `Ctrl`+`o` at any time.
To turn it back on, press `POWER` (or `Ctrl`+`p`). To turn it back on, press `POWER` (or `Ctrl`+`p`).
It can be useful to also prevent the device to sleep:
```bash
scrcpy --turn-screen-off --stay-awake
scrcpy -Sw
```
#### Render expired frames #### Render expired frames
By default, to minimize latency, _scrcpy_ always renders the last decoded frame By default, to minimize latency, _scrcpy_ always renders the last decoded frame

View file

@ -144,6 +144,10 @@ It only shows physical touches (not clicks from scrcpy).
.B \-v, \-\-version .B \-v, \-\-version
Print the version of scrcpy. Print the version of scrcpy.
.TP
.B \-w, \-\-stay-awake
Keep the device on while scrcpy is running.
.TP .TP
.B \-\-window\-borderless .B \-\-window\-borderless
Disable window decorations (display borderless window). Disable window decorations (display borderless window).

View file

@ -137,6 +137,9 @@ scrcpy_print_usage(const char *arg0) {
" -v, --version\n" " -v, --version\n"
" Print the version of scrcpy.\n" " Print the version of scrcpy.\n"
"\n" "\n"
" -w, --stay-awake\n"
" Keep the device on while scrcpy is running.\n"
"\n"
" --window-borderless\n" " --window-borderless\n"
" Disable window decorations (display borderless window).\n" " Disable window decorations (display borderless window).\n"
"\n" "\n"
@ -497,6 +500,7 @@ scrcpy_parse_args(struct scrcpy_cli_args *args, int argc, char *argv[]) {
{"rotation", required_argument, NULL, OPT_ROTATION}, {"rotation", required_argument, NULL, OPT_ROTATION},
{"serial", required_argument, NULL, 's'}, {"serial", required_argument, NULL, 's'},
{"show-touches", no_argument, NULL, 't'}, {"show-touches", no_argument, NULL, 't'},
{"stay-awake", no_argument, NULL, 'w'},
{"turn-screen-off", no_argument, NULL, 'S'}, {"turn-screen-off", no_argument, NULL, 'S'},
{"version", no_argument, NULL, 'v'}, {"version", no_argument, NULL, 'v'},
{"window-title", required_argument, NULL, OPT_WINDOW_TITLE}, {"window-title", required_argument, NULL, OPT_WINDOW_TITLE},
@ -514,7 +518,7 @@ scrcpy_parse_args(struct scrcpy_cli_args *args, int argc, char *argv[]) {
optind = 0; // reset to start from the first argument in tests optind = 0; // reset to start from the first argument in tests
int c; int c;
while ((c = getopt_long(argc, argv, "b:c:fF:hm:nNp:r:s:StTv", long_options, while ((c = getopt_long(argc, argv, "b:c:fF:hm:nNp:r:s:StTvw", long_options,
NULL)) != -1) { NULL)) != -1) {
switch (c) { switch (c) {
case 'b': case 'b':
@ -594,6 +598,9 @@ scrcpy_parse_args(struct scrcpy_cli_args *args, int argc, char *argv[]) {
case 'v': case 'v':
args->version = true; args->version = true;
break; break;
case 'w':
opts->stay_awake = true;
break;
case OPT_RENDER_EXPIRED_FRAMES: case OPT_RENDER_EXPIRED_FRAMES:
opts->render_expired_frames = true; opts->render_expired_frames = true;
break; break;
@ -676,5 +683,10 @@ scrcpy_parse_args(struct scrcpy_cli_args *args, int argc, char *argv[]) {
return false; return false;
} }
if (!opts->control && opts->stay_awake) {
LOGE("Could not request to stay awake if control is disabled");
return false;
}
return true; return true;
} }

View file

@ -278,6 +278,7 @@ scrcpy(const struct scrcpy_options *options) {
.control = options->control, .control = options->control,
.display_id = options->display_id, .display_id = options->display_id,
.show_touches = options->show_touches, .show_touches = options->show_touches,
.stay_awake = options->stay_awake,
}; };
if (!server_start(&server, options->serial, &params)) { if (!server_start(&server, options->serial, &params)) {
return false; return false;

View file

@ -38,6 +38,7 @@ struct scrcpy_options {
bool prefer_text; bool prefer_text;
bool window_borderless; bool window_borderless;
bool mipmaps; bool mipmaps;
bool stay_awake;
}; };
#define SCRCPY_OPTIONS_DEFAULT { \ #define SCRCPY_OPTIONS_DEFAULT { \
@ -72,6 +73,7 @@ struct scrcpy_options {
.prefer_text = false, \ .prefer_text = false, \
.window_borderless = false, \ .window_borderless = false, \
.mipmaps = true, \ .mipmaps = true, \
.stay_awake = false, \
} }
bool bool

View file

@ -269,6 +269,7 @@ execute_server(struct server *server, const struct server_params *params) {
params->control ? "true" : "false", params->control ? "true" : "false",
display_id_string, display_id_string,
params->show_touches ? "true" : "false", params->show_touches ? "true" : "false",
params->stay_awake ? "true" : "false",
}; };
#ifdef SERVER_DEBUGGER #ifdef SERVER_DEBUGGER
LOGI("Server debugger waiting for a client on device port " LOGI("Server debugger waiting for a client on device port "

View file

@ -52,6 +52,7 @@ struct server_params {
bool control; bool control;
uint16_t display_id; uint16_t display_id;
bool show_touches; bool show_touches;
bool stay_awake;
}; };
// init default values // init default values

View file

@ -19,18 +19,18 @@ public final class CleanUp {
// not instantiable // not instantiable
} }
public static void configure(boolean disableShowTouches) throws IOException { public static void configure(boolean disableShowTouches, int restoreStayOn) throws IOException {
boolean needProcess = disableShowTouches; boolean needProcess = disableShowTouches || restoreStayOn != -1;
if (needProcess) { if (needProcess) {
startProcess(disableShowTouches); startProcess(disableShowTouches, restoreStayOn);
} 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(boolean disableShowTouches) throws IOException { private static void startProcess(boolean disableShowTouches, int restoreStayOn) throws IOException {
String[] cmd = {"app_process", "/", CleanUp.class.getName(), String.valueOf(disableShowTouches)}; String[] cmd = {"app_process", "/", CleanUp.class.getName(), String.valueOf(disableShowTouches), String.valueOf(restoreStayOn)};
ProcessBuilder builder = new ProcessBuilder(cmd); ProcessBuilder builder = new ProcessBuilder(cmd);
builder.environment().put("CLASSPATH", SERVER_PATH); builder.environment().put("CLASSPATH", SERVER_PATH);
@ -58,12 +58,19 @@ public final class CleanUp {
Ln.i("Cleaning up"); Ln.i("Cleaning up");
boolean disableShowTouches = Boolean.parseBoolean(args[0]); boolean disableShowTouches = Boolean.parseBoolean(args[0]);
int restoreStayOn = Integer.parseInt(args[1]);
if (disableShowTouches) { if (disableShowTouches || restoreStayOn != -1) {
ServiceManager serviceManager = new ServiceManager(); ServiceManager serviceManager = new ServiceManager();
try (ContentProvider settings = serviceManager.getActivityManager().createSettingsProvider()) { try (ContentProvider settings = serviceManager.getActivityManager().createSettingsProvider()) {
Ln.i("Disabling \"show touches\""); if (disableShowTouches) {
settings.putValue(ContentProvider.TABLE_SYSTEM, "show_touches", "0"); Ln.i("Disabling \"show touches\"");
settings.putValue(ContentProvider.TABLE_SYSTEM, "show_touches", "0");
}
if (restoreStayOn != -1) {
Ln.i("Restoring \"stay awake\"");
settings.putValue(ContentProvider.TABLE_GLOBAL, "stay_on_while_plugged_in", String.valueOf(restoreStayOn));
}
} }
} }
} }

View file

@ -13,6 +13,7 @@ public class Options {
private boolean control; private boolean control;
private int displayId; private int displayId;
private boolean showTouches; private boolean showTouches;
private boolean stayAwake;
public int getMaxSize() { public int getMaxSize() {
return maxSize; return maxSize;
@ -93,4 +94,12 @@ public class Options {
public void setShowTouches(boolean showTouches) { public void setShowTouches(boolean showTouches) {
this.showTouches = showTouches; this.showTouches = showTouches;
} }
public boolean getStayAwake() {
return stayAwake;
}
public void setStayAwake(boolean stayAwake) {
this.stayAwake = stayAwake;
}
} }

View file

@ -4,6 +4,7 @@ import com.genymobile.scrcpy.wrappers.ContentProvider;
import android.graphics.Rect; import android.graphics.Rect;
import android.media.MediaCodec; import android.media.MediaCodec;
import android.os.BatteryManager;
import android.os.Build; import android.os.Build;
import java.io.IOException; import java.io.IOException;
@ -20,15 +21,32 @@ public final class Server {
final Device device = new Device(options); final Device device = new Device(options);
boolean mustDisableShowTouchesOnCleanUp = false; boolean mustDisableShowTouchesOnCleanUp = false;
if (options.getShowTouches()) { int restoreStayOn = -1;
if (options.getShowTouches() || options.getStayAwake()) {
try (ContentProvider settings = device.createSettingsProvider()) { try (ContentProvider settings = device.createSettingsProvider()) {
String oldValue = settings.getAndPutValue(ContentProvider.TABLE_SYSTEM, "show_touches", "1"); if (options.getShowTouches()) {
// If "show touches" was disabled, it must be disabled back on clean up String oldValue = settings.getAndPutValue(ContentProvider.TABLE_SYSTEM, "show_touches", "1");
mustDisableShowTouchesOnCleanUp = !"1".equals(oldValue); // If "show touches" was disabled, it must be disabled back on clean up
mustDisableShowTouchesOnCleanUp = !"1".equals(oldValue);
}
if (options.getStayAwake()) {
int stayOn = BatteryManager.BATTERY_PLUGGED_AC | BatteryManager.BATTERY_PLUGGED_USB | BatteryManager.BATTERY_PLUGGED_WIRELESS;
String oldValue = settings.getAndPutValue(ContentProvider.TABLE_GLOBAL, "stay_on_while_plugged_in", String.valueOf(stayOn));
try {
restoreStayOn = Integer.parseInt(oldValue);
if (restoreStayOn == stayOn) {
// No need to restore
restoreStayOn = -1;
}
} catch (NumberFormatException e) {
restoreStayOn = 0;
}
}
} }
} }
CleanUp.configure(mustDisableShowTouchesOnCleanUp); CleanUp.configure(mustDisableShowTouchesOnCleanUp, restoreStayOn);
boolean tunnelForward = options.isTunnelForward(); boolean tunnelForward = options.isTunnelForward();
try (DesktopConnection connection = DesktopConnection.open(device, tunnelForward)) { try (DesktopConnection connection = DesktopConnection.open(device, tunnelForward)) {
@ -91,7 +109,7 @@ public final class Server {
"The server version (" + BuildConfig.VERSION_NAME + ") does not match the client " + "(" + clientVersion + ")"); "The server version (" + BuildConfig.VERSION_NAME + ") does not match the client " + "(" + clientVersion + ")");
} }
final int expectedParameters = 11; final int expectedParameters = 12;
if (args.length != expectedParameters) { if (args.length != expectedParameters) {
throw new IllegalArgumentException("Expecting " + expectedParameters + " parameters"); throw new IllegalArgumentException("Expecting " + expectedParameters + " parameters");
} }
@ -129,6 +147,9 @@ public final class Server {
boolean showTouches = Boolean.parseBoolean(args[10]); boolean showTouches = Boolean.parseBoolean(args[10]);
options.setShowTouches(showTouches); options.setShowTouches(showTouches);
boolean stayAwake = Boolean.parseBoolean(args[11]);
options.setStayAwake(stayAwake);
return options; return options;
} }