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.
This commit is contained in:
Romain Vimont 2024-10-12 09:23:31 +02:00
parent 699c5c7efb
commit 49cf48614e
5 changed files with 45 additions and 38 deletions

View File

@ -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(),

View File

@ -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> 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;
@ -100,6 +102,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);
@ -300,7 +307,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;
@ -408,9 +415,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;
}
@ -428,6 +435,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 from the atomic once
@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.
*/

View File

@ -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> positionMapper = new AtomicReference<>(); // set by the ScreenCapture instance
public Point getPhysicalPoint(Position position) {
// it hides the field on purpose, to read it from the atomic once
@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() {
@ -53,10 +41,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()");

View File

@ -2,7 +2,6 @@ package com.genymobile.scrcpy.video;
import com.genymobile.scrcpy.AndroidVersions;
import com.genymobile.scrcpy.control.PositionMapper;
import com.genymobile.scrcpy.device.Device;
import com.genymobile.scrcpy.device.DisplayInfo;
import com.genymobile.scrcpy.device.Size;
import com.genymobile.scrcpy.util.Ln;
@ -20,8 +19,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;
@ -36,8 +34,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;
@ -124,8 +122,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

View File

@ -0,0 +1,7 @@
package com.genymobile.scrcpy.video;
import com.genymobile.scrcpy.control.PositionMapper;
public interface VirtualDisplayListener {
void onNewVirtualDisplay(PositionMapper positionMapper);
}