comments fix, move layerStack field to Device class, prevent sending input event to wrong display

This commit is contained in:
evigurskiy 2020-03-23 12:35:47 +03:00
commit 2ea23b7fa2
8 changed files with 43 additions and 26 deletions

View file

@ -60,7 +60,7 @@ scrcpy_print_usage(const char *arg0) {
" -n, --no-control\n" " -n, --no-control\n"
" Disable device control (mirror the device in read-only).\n" " Disable device control (mirror the device in read-only).\n"
"\n" "\n"
" -d, --display\n" " --display\n"
" Specify the display id to mirror, default 0\n" " Specify the display id to mirror, default 0\n"
"\n" "\n"
" -N, --no-display\n" " -N, --no-display\n"
@ -413,6 +413,7 @@ guess_record_format(const char *filename) {
#define OPT_WINDOW_BORDERLESS 1011 #define OPT_WINDOW_BORDERLESS 1011
#define OPT_MAX_FPS 1012 #define OPT_MAX_FPS 1012
#define OPT_LOCK_VIDEO_ORIENTATION 1013 #define OPT_LOCK_VIDEO_ORIENTATION 1013
#define OPT_DISPLAY_ID 1014
bool bool
scrcpy_parse_args(struct scrcpy_cli_args *args, int argc, char *argv[]) { scrcpy_parse_args(struct scrcpy_cli_args *args, int argc, char *argv[]) {
@ -446,6 +447,7 @@ scrcpy_parse_args(struct scrcpy_cli_args *args, int argc, char *argv[]) {
{"window-height", required_argument, NULL, OPT_WINDOW_HEIGHT}, {"window-height", required_argument, NULL, OPT_WINDOW_HEIGHT},
{"window-borderless", no_argument, NULL, {"window-borderless", no_argument, NULL,
OPT_WINDOW_BORDERLESS}, OPT_WINDOW_BORDERLESS},
{"display", required_argument, NULL, OPT_DISPLAY_ID},
{NULL, 0, NULL, 0 }, {NULL, 0, NULL, 0 },
}; };
@ -454,7 +456,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:nNpd:r:s:StTv", long_options, while ((c = getopt_long(argc, argv, "b:c:fF:hm:nNp:r:s:StTv", long_options,
NULL)) != -1) { NULL)) != -1) {
switch (c) { switch (c) {
case 'b': case 'b':
@ -508,7 +510,7 @@ scrcpy_parse_args(struct scrcpy_cli_args *args, int argc, char *argv[]) {
return false; return false;
} }
break; break;
case 'd': case OPT_DISPLAY_ID:
if (!parse_display_id(optarg, &opts->display_id)) { if (!parse_display_id(optarg, &opts->display_id)) {
return false; return false;
} }

View file

@ -23,13 +23,26 @@ public final class Device {
private final ServiceManager serviceManager = new ServiceManager(); private final ServiceManager serviceManager = new ServiceManager();
private final DisplayInfo displayInfo;
private ScreenInfo screenInfo; private ScreenInfo screenInfo;
private RotationListener rotationListener; private RotationListener rotationListener;
/**
* The surface flinger layer stack associated with this logical display.
*/
private final int layerStack;
/**
* Logical display identifier.
*/
private final int displayId;
private final boolean isPresentationDisplay;
public Device(Options options) { public Device(Options options) {
DisplayInfo displayInfo = serviceManager.getDisplayManager().getDisplayInfo(); DisplayInfo displayInfo = serviceManager.getDisplayManager().getDisplayInfo(options.getDisplayId());
screenInfo = ScreenInfo.computeScreenInfo(displayInfo, options.getCrop(), options.getMaxSize(), options.getLockedVideoOrientation()); screenInfo = ScreenInfo.computeScreenInfo(displayInfo, options.getCrop(), options.getMaxSize(), options.getLockedVideoOrientation());
layerStack = displayInfo.getLayerStack();
displayId = displayInfo.getDisplayId();
isPresentationDisplay = displayInfo.isPresentation();
registerRotationWatcher(new IRotationWatcher.Stub() { registerRotationWatcher(new IRotationWatcher.Stub() {
@Override @Override
public void onRotationChanged(int rotation) throws RemoteException { public void onRotationChanged(int rotation) throws RemoteException {
@ -47,7 +60,7 @@ public final class Device {
Ln.w("Display doesn't have FLAG_SUPPORTS_PROTECTED_BUFFERS flag, mirroring can be restricted"); Ln.w("Display doesn't have FLAG_SUPPORTS_PROTECTED_BUFFERS flag, mirroring can be restricted");
} }
if (!isSupportInputEvents()) { if (!isSupportInputEvents()) {
Ln.w("Input events for display with flag FLAG_PRESENTATION, can be supported since API 29"); Ln.w("Sorry, can't support input events for displays with FLAG_PRESENTATION flag for devices with API lower then 29");
} }
} }
@ -55,6 +68,10 @@ public final class Device {
return screenInfo; return screenInfo;
} }
public int getLayerStack() {
return layerStack;
}
public Point getPhysicalPoint(Position position) { public Point getPhysicalPoint(Position position) {
// it hides the field on purpose, to read it with a lock // it hides the field on purpose, to read it with a lock
@SuppressWarnings("checkstyle:HiddenField") @SuppressWarnings("checkstyle:HiddenField")
@ -86,7 +103,8 @@ public final class Device {
public boolean injectInputEvent(InputEvent inputEvent, int mode) { public boolean injectInputEvent(InputEvent inputEvent, int mode) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q){ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q){
InputManager.setDisplayId(inputEvent, displayInfo.getDisplayId()); if (!InputManager.setDisplayId(inputEvent, displayId))
return false;
} }
@ -101,7 +119,7 @@ public final class Device {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q)
return true; return true;
else else
return !displayInfo.isPresentation(); return !isPresentationDisplay;
} }
public void registerRotationWatcher(IRotationWatcher rotationWatcher) { public void registerRotationWatcher(IRotationWatcher rotationWatcher) {

View file

@ -7,12 +7,10 @@ public final class DisplayInfo {
private final int layerStack; private final int layerStack;
private final int flags; private final int flags;
public static final int DEFAULT_DISPLAY = 0x00000000; public static final int FLAG_SUPPORTS_PROTECTED_BUFFERS = 0x00000001;
public static final int FLAG_PRESENTATION = 0x00000008; public static final int FLAG_PRESENTATION = 0x00000008;
public static final int FLAG_SUPPORTS_PROTECTED_BUFFERS = 0x00000001;
public DisplayInfo(int displayId, Size size, int rotation, int layerStack, int flags) { public DisplayInfo(int displayId, Size size, int rotation, int layerStack, int flags) {
this.displayId = displayId; this.displayId = displayId;
this.size = size; this.size = size;
@ -38,11 +36,11 @@ public final class DisplayInfo {
} }
public boolean isPresentation() { public boolean isPresentation() {
return (flags & FLAG_PRESENTATION) == FLAG_PRESENTATION; return (flags & FLAG_PRESENTATION) != 0;
} }
public boolean isSupportProtectedBuffers() { public boolean isSupportProtectedBuffers() {
return (flags & FLAG_SUPPORTS_PROTECTED_BUFFERS) == FLAG_SUPPORTS_PROTECTED_BUFFERS; return (flags & FLAG_SUPPORTS_PROTECTED_BUFFERS) != 0;
} }
} }

View file

@ -74,7 +74,7 @@ public class ScreenEncoder implements Device.RotationListener {
setSize(format, videoRect.width(), videoRect.height()); setSize(format, videoRect.width(), videoRect.height());
configure(codec, format); configure(codec, format);
Surface surface = codec.createInputSurface(); Surface surface = codec.createInputSurface();
setDisplaySurface(display, surface, videoRotation, contentRect, unlockedVideoRect); setDisplaySurface(display, surface, videoRotation, contentRect, unlockedVideoRect, device.getLayerStack());
codec.start(); codec.start();
try { try {
alive = encode(codec, fd); alive = encode(codec, fd);

View file

@ -14,7 +14,6 @@ public final class ScreenInfo {
* However, it does not include the locked video orientation. * However, it does not include the locked video orientation.
*/ */
private final Size unlockedVideoSize; private final Size unlockedVideoSize;
private final int layerStack;
/** /**
* Device rotation, related to the natural device orientation (0, 1, 2 or 3) * Device rotation, related to the natural device orientation (0, 1, 2 or 3)
@ -31,7 +30,6 @@ public final class ScreenInfo {
this.unlockedVideoSize = unlockedVideoSize; this.unlockedVideoSize = unlockedVideoSize;
this.deviceRotation = deviceRotation; this.deviceRotation = deviceRotation;
this.lockedVideoOrientation = lockedVideoOrientation; this.lockedVideoOrientation = lockedVideoOrientation;
this.layerStack = layerStack;
} }
public Rect getContentRect() { public Rect getContentRect() {

View file

@ -80,8 +80,8 @@ 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 + ")");
} }
if (args.length != 9) { if (args.length != 10) {
throw new IllegalArgumentException("Expecting 9 parameters"); throw new IllegalArgumentException("Expecting 10 parameters");
} }
Options options = new Options(); Options options = new Options();
@ -111,7 +111,7 @@ public final class Server {
boolean control = Boolean.parseBoolean(args[8]); boolean control = Boolean.parseBoolean(args[8]);
options.setControl(control); options.setControl(control);
int displayId = Integer.parseInt(args[8]); int displayId = Integer.parseInt(args[9]);
options.setDisplayId(displayId); options.setDisplayId(displayId);
return options; return options;

View file

@ -3,7 +3,6 @@ package com.genymobile.scrcpy.wrappers;
import android.os.IInterface; import android.os.IInterface;
import com.genymobile.scrcpy.DisplayInfo; import com.genymobile.scrcpy.DisplayInfo;
import com.genymobile.scrcpy.Ln;
import com.genymobile.scrcpy.Size; import com.genymobile.scrcpy.Size;
public final class DisplayManager { public final class DisplayManager {
@ -16,6 +15,7 @@ public final class DisplayManager {
public DisplayInfo getDisplayInfo(int displayId) { public DisplayInfo getDisplayInfo(int displayId) {
try { try {
Object displayInfo = manager.getClass().getMethod("getDisplayInfo", int.class).invoke(manager, displayId); Object displayInfo = manager.getClass().getMethod("getDisplayInfo", int.class).invoke(manager, displayId);
if (displayInfo == null) throw new IllegalArgumentException(suggestFixMessage(displayId, getDisplayIds()));
Class<?> cls = displayInfo.getClass(); Class<?> cls = displayInfo.getClass();
// width and height already take the rotation into account // width and height already take the rotation into account
int width = cls.getDeclaredField("logicalWidth").getInt(displayInfo); int width = cls.getDeclaredField("logicalWidth").getInt(displayInfo);
@ -25,7 +25,6 @@ public final class DisplayManager {
int flags = cls.getDeclaredField("flags").getInt(displayInfo); int flags = cls.getDeclaredField("flags").getInt(displayInfo);
return new DisplayInfo(displayId, new Size(width, height), rotation, layerStack, flags); return new DisplayInfo(displayId, new Size(width, height), rotation, layerStack, flags);
} catch (Exception e) { } catch (Exception e) {
if (e instanceof NullPointerException) suggestFix(displayId, getDisplayIds());
throw new AssertionError(e); throw new AssertionError(e);
} }
} }
@ -38,17 +37,17 @@ public final class DisplayManager {
} }
} }
private void suggestFix(int displayId, int[] displayIds) { private String suggestFixMessage(int displayId, int[] displayIds) {
if (displayIds == null || displayIds.length == 0) if (displayIds == null || displayIds.length == 0)
return; return null;
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
sb.append("Failed to get displayId=[") sb.append("Failed to get displayId=[")
.append(displayId) .append(displayId)
.append("]\nTry to user one of these available display ids:\n"); .append("]\nTry to use one of these available display ids:\n");
for (int id : displayIds) { for (int id : displayIds) {
sb.append("scrcpy --display ").append(id).append("\n"); sb.append("scrcpy --display ").append(id).append("\n");
} }
Ln.e(sb.toString()); return sb.toString();
} }
} }

View file

@ -38,11 +38,13 @@ public final class InputManager {
} }
} }
public static void setDisplayId(InputEvent inputEvent, int displayId) { public static boolean setDisplayId(InputEvent inputEvent, int displayId) {
try { try {
inputEvent.getClass().getMethod("setDisplayId", int.class).invoke(inputEvent, displayId); inputEvent.getClass().getMethod("setDisplayId", int.class).invoke(inputEvent, displayId);
return true;
} catch (InvocationTargetException | IllegalAccessException | NoSuchMethodException e) { } catch (InvocationTargetException | IllegalAccessException | NoSuchMethodException e) {
Ln.e("Could not invoke method", e); Ln.e("Could not invoke method", e);
return false;
} }
} }
} }