From 7024d38199206e1a4e7c02e2c9016e856de4a3c0 Mon Sep 17 00:00:00 2001 From: Romain Vimont Date: Sat, 12 Oct 2024 09:23:31 +0200 Subject: [PATCH] Send PositionMapper to Controller directly When a new capture starts, send a new PositionMapper to the Controller without using the global Device as an intermediate. Now all Device methods are static. PR #5370 --- .../java/com/genymobile/scrcpy/Server.java | 10 +++--- .../genymobile/scrcpy/control/Controller.java | 32 +++++++++++++++---- .../com/genymobile/scrcpy/device/Device.java | 20 ++---------- .../scrcpy/video/ScreenCapture.java | 14 ++++---- .../scrcpy/video/VirtualDisplayListener.java | 7 ++++ 5 files changed, 45 insertions(+), 38 deletions(-) create mode 100644 server/src/main/java/com/genymobile/scrcpy/video/VirtualDisplayListener.java diff --git a/server/src/main/java/com/genymobile/scrcpy/Server.java b/server/src/main/java/com/genymobile/scrcpy/Server.java index 0b60dbdc..91e7ce6c 100644 --- a/server/src/main/java/com/genymobile/scrcpy/Server.java +++ b/server/src/main/java/com/genymobile/scrcpy/Server.java @@ -139,9 +139,6 @@ public final class Server { boolean video = options.getVideo(); boolean audio = options.getAudio(); boolean sendDummyByte = options.getSendDummyByte(); - boolean camera = video && options.getVideoSource() == VideoSource.CAMERA; - - final Device device = camera ? null : new Device(); Workarounds.apply(); @@ -153,10 +150,11 @@ public final class Server { connection.sendDeviceMeta(Device.getDeviceName()); } + Controller controller = null; + if (control) { ControlChannel controlChannel = connection.getControlChannel(); - Controller controller = new Controller( - device, options.getDisplayId(), controlChannel, cleanUp, options.getClipboardAutosync(), options.getPowerOn()); + controller = new Controller(options.getDisplayId(), controlChannel, cleanUp, options.getClipboardAutosync(), options.getPowerOn()); asyncProcessors.add(controller); } @@ -186,7 +184,7 @@ public final class Server { options.getSendFrameMeta()); SurfaceCapture surfaceCapture; if (options.getVideoSource() == VideoSource.DISPLAY) { - surfaceCapture = new ScreenCapture(device, options.getDisplayId(), options.getMaxSize(), options.getCrop(), + surfaceCapture = new ScreenCapture(controller, options.getDisplayId(), options.getMaxSize(), options.getCrop(), options.getLockVideoOrientation()); } else { surfaceCapture = new CameraCapture(options.getCameraId(), options.getCameraFacing(), options.getCameraSize(), diff --git a/server/src/main/java/com/genymobile/scrcpy/control/Controller.java b/server/src/main/java/com/genymobile/scrcpy/control/Controller.java index e6463563..ac870f27 100644 --- a/server/src/main/java/com/genymobile/scrcpy/control/Controller.java +++ b/server/src/main/java/com/genymobile/scrcpy/control/Controller.java @@ -7,6 +7,7 @@ import com.genymobile.scrcpy.device.Device; import com.genymobile.scrcpy.device.Point; import com.genymobile.scrcpy.device.Position; import com.genymobile.scrcpy.util.Ln; +import com.genymobile.scrcpy.video.VirtualDisplayListener; import com.genymobile.scrcpy.wrappers.ClipboardManager; import com.genymobile.scrcpy.wrappers.InputManager; import com.genymobile.scrcpy.wrappers.ServiceManager; @@ -26,8 +27,9 @@ import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicReference; -public class Controller implements AsyncProcessor { +public class Controller implements AsyncProcessor, VirtualDisplayListener { private static final int DEFAULT_DEVICE_ID = 0; @@ -40,7 +42,6 @@ public class Controller implements AsyncProcessor { private UhidManager uhidManager; - private final Device device; private final int displayId; private final boolean supportsInputEvents; private final ControlChannel controlChannel; @@ -53,6 +54,8 @@ public class Controller implements AsyncProcessor { private final AtomicBoolean isSettingClipboard = new AtomicBoolean(); + private final AtomicReference positionMapper = new AtomicReference<>(); + private long lastTouchDown; private final PointersState pointersState = new PointersState(); private final MotionEvent.PointerProperties[] pointerProperties = new MotionEvent.PointerProperties[PointersState.MAX_POINTERS]; @@ -60,8 +63,7 @@ public class Controller implements AsyncProcessor { private boolean keepPowerModeOff; - public Controller(Device device, int displayId, ControlChannel controlChannel, CleanUp cleanUp, boolean clipboardAutosync, boolean powerOn) { - this.device = device; + public Controller(int displayId, ControlChannel controlChannel, CleanUp cleanUp, boolean clipboardAutosync, boolean powerOn) { this.displayId = displayId; this.controlChannel = controlChannel; this.cleanUp = cleanUp; @@ -99,6 +101,11 @@ public class Controller implements AsyncProcessor { } } + @Override + public void onNewVirtualDisplay(PositionMapper positionMapper) { + this.positionMapper.set(positionMapper); + } + private UhidManager getUhidManager() { if (uhidManager == null) { uhidManager = new UhidManager(sender); @@ -299,7 +306,7 @@ public class Controller implements AsyncProcessor { private boolean injectTouch(int action, long pointerId, Position position, float pressure, int actionButton, int buttons) { long now = SystemClock.uptimeMillis(); - Point point = device.getPhysicalPoint(position); + Point point = getPhysicalPoint(position); if (point == null) { Ln.w("Ignore touch event, it was generated for a different device size"); return false; @@ -407,9 +414,9 @@ public class Controller implements AsyncProcessor { private boolean injectScroll(Position position, float hScroll, float vScroll, int buttons) { long now = SystemClock.uptimeMillis(); - Point point = device.getPhysicalPoint(position); + Point point = getPhysicalPoint(position); if (point == null) { - // ignore event + Ln.w("Ignore scroll event, it was generated for a different device size"); return false; } @@ -427,6 +434,17 @@ public class Controller implements AsyncProcessor { return injectEvent(event, Device.INJECT_MODE_ASYNC); } + private Point getPhysicalPoint(Position position) { + // it hides the field on purpose, to read it with atomic access + @SuppressWarnings("checkstyle:HiddenField") + PositionMapper positionMapper = this.positionMapper.get(); + if (positionMapper == null) { + return null; + } + + return positionMapper.map(position); + } + /** * Schedule a call to set power mode to off after a small delay. */ diff --git a/server/src/main/java/com/genymobile/scrcpy/device/Device.java b/server/src/main/java/com/genymobile/scrcpy/device/Device.java index 0977a2b7..35266d0e 100644 --- a/server/src/main/java/com/genymobile/scrcpy/device/Device.java +++ b/server/src/main/java/com/genymobile/scrcpy/device/Device.java @@ -1,7 +1,6 @@ package com.genymobile.scrcpy.device; import com.genymobile.scrcpy.AndroidVersions; -import com.genymobile.scrcpy.control.PositionMapper; import com.genymobile.scrcpy.util.Ln; import com.genymobile.scrcpy.wrappers.ClipboardManager; import com.genymobile.scrcpy.wrappers.DisplayControl; @@ -18,8 +17,6 @@ import android.view.InputEvent; import android.view.KeyCharacterMap; import android.view.KeyEvent; -import java.util.concurrent.atomic.AtomicReference; - public final class Device { public static final int POWER_MODE_OFF = SurfaceControl.POWER_MODE_OFF; @@ -32,17 +29,8 @@ public final class Device { public static final int LOCK_VIDEO_ORIENTATION_UNLOCKED = -1; public static final int LOCK_VIDEO_ORIENTATION_INITIAL = -2; - private final AtomicReference positionMapper = new AtomicReference<>(); // set by the ScreenCapture instance - - public Point getPhysicalPoint(Position position) { - // it hides the field on purpose, to read it with atomic access - @SuppressWarnings("checkstyle:HiddenField") - PositionMapper positionMapper = this.positionMapper.get(); - if (positionMapper == null) { - return null; - } - - return positionMapper.map(position); + private Device() { + // not instantiable } public static String getDeviceName() { @@ -54,10 +42,6 @@ public final class Device { return displayId == 0 || Build.VERSION.SDK_INT >= AndroidVersions.API_29_ANDROID_10; } - public void setPositionMapper(PositionMapper positionMapper) { - this.positionMapper.set(positionMapper); - } - public static boolean injectEvent(InputEvent inputEvent, int displayId, int injectMode) { if (!supportsInputEvents(displayId)) { throw new AssertionError("Could not inject input event if !supportsInputEvents()"); diff --git a/server/src/main/java/com/genymobile/scrcpy/video/ScreenCapture.java b/server/src/main/java/com/genymobile/scrcpy/video/ScreenCapture.java index 066c9ae4..95faaf39 100644 --- a/server/src/main/java/com/genymobile/scrcpy/video/ScreenCapture.java +++ b/server/src/main/java/com/genymobile/scrcpy/video/ScreenCapture.java @@ -3,7 +3,6 @@ package com.genymobile.scrcpy.video; import com.genymobile.scrcpy.AndroidVersions; import com.genymobile.scrcpy.control.PositionMapper; import com.genymobile.scrcpy.device.ConfigurationException; -import com.genymobile.scrcpy.device.Device; import com.genymobile.scrcpy.device.DisplayInfo; import com.genymobile.scrcpy.device.Size; import com.genymobile.scrcpy.util.Ln; @@ -21,8 +20,7 @@ import android.view.Surface; public class ScreenCapture extends SurfaceCapture { - private final Device device; - + private final VirtualDisplayListener vdListener; private final int displayId; private int maxSize; private final Rect crop; @@ -37,8 +35,8 @@ public class ScreenCapture extends SurfaceCapture { private IRotationWatcher rotationWatcher; private IDisplayFoldListener displayFoldListener; - public ScreenCapture(Device device, int displayId, int maxSize, Rect crop, int lockVideoOrientation) { - this.device = device; + public ScreenCapture(VirtualDisplayListener vdListener, int displayId, int maxSize, Rect crop, int lockVideoOrientation) { + this.vdListener = vdListener; this.displayId = displayId; this.maxSize = maxSize; this.crop = crop; @@ -133,8 +131,10 @@ public class ScreenCapture extends SurfaceCapture { } } - PositionMapper positionMapper = PositionMapper.from(screenInfo); - device.setPositionMapper(positionMapper); + if (vdListener != null) { + PositionMapper positionMapper = PositionMapper.from(screenInfo); + vdListener.onNewVirtualDisplay(positionMapper); + } } @Override diff --git a/server/src/main/java/com/genymobile/scrcpy/video/VirtualDisplayListener.java b/server/src/main/java/com/genymobile/scrcpy/video/VirtualDisplayListener.java new file mode 100644 index 00000000..d978361e --- /dev/null +++ b/server/src/main/java/com/genymobile/scrcpy/video/VirtualDisplayListener.java @@ -0,0 +1,7 @@ +package com.genymobile.scrcpy.video; + +import com.genymobile.scrcpy.control.PositionMapper; + +public interface VirtualDisplayListener { + void onNewVirtualDisplay(PositionMapper positionMapper); +}