Added adaptive virtual display that adjusts to window size

This commit is contained in:
Tinura Dinith 2026-03-05 02:15:28 +05:30
parent 3fcc177da5
commit 52709d60ba
12 changed files with 308 additions and 8 deletions

View file

@ -25,6 +25,7 @@ public final class ControlMessage {
public static final int TYPE_OPEN_HARD_KEYBOARD_SETTINGS = 15;
public static final int TYPE_START_APP = 16;
public static final int TYPE_RESET_VIDEO = 17;
public static final int TYPE_SET_DISPLAY_SIZE = 18;
public static final long SEQUENCE_INVALID = 0;
@ -53,6 +54,9 @@ public final class ControlMessage {
private boolean on;
private int vendorId;
private int productId;
private int displayWidth;
private int displayHeight;
private int displayDpi;
private ControlMessage() {
}
@ -166,6 +170,15 @@ public final class ControlMessage {
return msg;
}
public static ControlMessage createSetDisplaySize(int width, int height, int dpi) {
ControlMessage msg = new ControlMessage();
msg.type = TYPE_SET_DISPLAY_SIZE;
msg.displayWidth = width;
msg.displayHeight = height;
msg.displayDpi = dpi;
return msg;
}
public int getType() {
return type;
}
@ -249,4 +262,16 @@ public final class ControlMessage {
public int getProductId() {
return productId;
}
public int getDisplayWidth() {
return displayWidth;
}
public int getDisplayHeight() {
return displayHeight;
}
public int getDisplayDpi() {
return displayDpi;
}
}

View file

@ -48,6 +48,8 @@ public class ControlMessageReader {
case ControlMessage.TYPE_OPEN_HARD_KEYBOARD_SETTINGS:
case ControlMessage.TYPE_RESET_VIDEO:
return ControlMessage.createEmpty(type);
case ControlMessage.TYPE_SET_DISPLAY_SIZE:
return parseSetDisplaySize();
case ControlMessage.TYPE_UHID_CREATE:
return parseUhidCreate();
case ControlMessage.TYPE_UHID_INPUT:
@ -141,6 +143,13 @@ public class ControlMessageReader {
return ControlMessage.createSetDisplayPower(on);
}
private ControlMessage parseSetDisplaySize() throws IOException {
int width = dis.readUnsignedShort();
int height = dis.readUnsignedShort();
int dpi = dis.readUnsignedShort();
return ControlMessage.createSetDisplaySize(width, height, dpi);
}
private ControlMessage parseUhidCreate() throws IOException {
int id = dis.readUnsignedShort();
int vendorId = dis.readUnsignedShort();

View file

@ -96,6 +96,9 @@ public class Controller implements AsyncProcessor, VirtualDisplayListener {
private final MotionEvent.PointerCoords[] pointerCoords = new MotionEvent.PointerCoords[PointersState.MAX_POINTERS];
private boolean keepDisplayPowerOff;
private String lastStartedAppPackage;
private boolean lastStartedAppForceStop;
private boolean pendingRelaunchOnResize;
// Used for resetting video encoding on RESET_VIDEO message
private SurfaceCapture surfaceCapture;
@ -146,6 +149,11 @@ public class Controller implements AsyncProcessor, VirtualDisplayListener {
displayDataAvailable.notify();
}
}
if (pendingRelaunchOnResize && lastStartedAppPackage != null) {
pendingRelaunchOnResize = false;
Ln.i("Relaunching app \"" + lastStartedAppPackage + "\" on resized display " + virtualDisplayId + "...");
Device.startApp(lastStartedAppPackage, virtualDisplayId, lastStartedAppForceStop);
}
}
public void setSurfaceCapture(SurfaceCapture surfaceCapture) {
@ -331,6 +339,9 @@ public class Controller implements AsyncProcessor, VirtualDisplayListener {
case ControlMessage.TYPE_RESET_VIDEO:
resetVideo();
break;
case ControlMessage.TYPE_SET_DISPLAY_SIZE:
setDisplaySize(msg.getDisplayWidth(), msg.getDisplayHeight(), msg.getDisplayDpi());
break;
default:
// do nothing
}
@ -691,6 +702,8 @@ public class Controller implements AsyncProcessor, VirtualDisplayListener {
Ln.i("Starting app \"" + app.getName() + "\" [" + app.getPackageName() + "] on display " + startAppDisplayId + "...");
Device.startApp(app.getPackageName(), startAppDisplayId, forceStopBeforeStart);
lastStartedAppPackage = app.getPackageName();
lastStartedAppForceStop = forceStopBeforeStart;
}
private int getStartAppDisplayId() {
@ -754,4 +767,18 @@ public class Controller implements AsyncProcessor, VirtualDisplayListener {
surfaceCapture.requestInvalidate();
}
}
private void setDisplaySize(int width, int height, int dpi) {
if (surfaceCapture instanceof com.genymobile.scrcpy.video.NewDisplayCapture) {
com.genymobile.scrcpy.video.NewDisplayCapture nd =
(com.genymobile.scrcpy.video.NewDisplayCapture) surfaceCapture;
Ln.i("Resize virtual display to " + width + "x" + height + "/" + dpi);
if (lastStartedAppPackage != null) {
pendingRelaunchOnResize = true;
}
nd.setDisplaySize(width, height, dpi);
} else {
Ln.w("Display resize ignored: not a virtual display capture");
}
}
}

View file

@ -64,6 +64,9 @@ public class NewDisplayCapture extends SurfaceCapture {
private Size physicalSize; // the physical size of the display (without rotation)
private int dpi;
private Size requestedDisplaySize;
private int requestedDpi;
private boolean hasRequestedSize;
public NewDisplayCapture(VirtualDisplayListener vdListener, Options options) {
this.vdListener = vdListener;
@ -105,11 +108,20 @@ public class NewDisplayCapture extends SurfaceCapture {
public void prepare() {
int displayRotation;
if (virtualDisplay == null) {
if (!newDisplay.hasExplicitSize()) {
displaySize = mainDisplaySize;
}
if (!newDisplay.hasExplicitDpi()) {
dpi = scaleDpi(mainDisplaySize, mainDisplayDpi, displaySize);
if (hasRequestedSize && requestedDisplaySize != null) {
displaySize = requestedDisplaySize;
if (requestedDpi != 0) {
dpi = requestedDpi;
} else {
dpi = scaleDpi(mainDisplaySize, mainDisplayDpi, displaySize);
}
} else {
if (!newDisplay.hasExplicitSize()) {
displaySize = mainDisplaySize;
}
if (!newDisplay.hasExplicitDpi()) {
dpi = scaleDpi(mainDisplaySize, mainDisplayDpi, displaySize);
}
}
videoSize = displaySize;
@ -266,4 +278,33 @@ public class NewDisplayCapture extends SurfaceCapture {
public void requestInvalidate() {
invalidate();
}
public synchronized void setDisplaySize(int width, int height, int dpi) {
if (width <= 0 || height <= 0) {
return;
}
requestedDisplaySize = new Size(width, height);
requestedDpi = dpi;
hasRequestedSize = true;
if (virtualDisplay != null) {
int newDpi = dpi;
if (newDpi == 0) {
newDpi = scaleDpi(mainDisplaySize, mainDisplayDpi, requestedDisplaySize);
}
try {
virtualDisplay.resize(width, height, newDpi);
displaySizeMonitor.setSessionDisplaySize(requestedDisplaySize);
Ln.i("Virtual display resized in-place to " + width + "x" + height + "/" + newDpi);
} catch (Exception e) {
Ln.w("Virtual display resize failed, fallback to recreate", e);
displaySizeMonitor.stopAndRelease();
virtualDisplay.release();
virtualDisplay = null;
}
}
invalidate();
}
}