Ignore expected display properties changes

After initialization or an explicit display resize, a specific display
event is expected and must be ignored to avoid triggering a capture
reset.

A capture reset should occur only when the display size changes
independently, for example on app rotation.
This commit is contained in:
Romain Vimont 2026-04-19 11:40:08 +02:00
parent 3e7da96a57
commit 2151760f28
4 changed files with 86 additions and 5 deletions

View file

@ -97,8 +97,8 @@ public class DisplayMonitor {
}
}
public void setSessionDisplayProperties(DisplayProperties props) {
tracker.setCurrent(props);
public void expectChange(DisplayProperties props) {
tracker.expectChange(props);
}
private void checkDisplayPropertiesChanged() {

View file

@ -2,10 +2,33 @@ package com.genymobile.scrcpy.display;
import com.genymobile.scrcpy.util.Ln;
import java.util.ArrayList;
import java.util.List;
public final class DisplayPropertiesTracker {
private static class PendingChange {
private final DisplayProperties props;
private final long timestamp;
PendingChange(DisplayProperties props, long timestamp) {
this.props = props;
this.timestamp = timestamp;
}
}
private static final long PENDING_CACHE_DURATION = 2000; // ms
private final List<PendingChange> pending = new ArrayList<>();
private DisplayProperties props;
public synchronized void setCurrent(DisplayProperties props) {
private static long nowMs() {
return System.nanoTime() / 1000000;
}
public synchronized void expectChange(DisplayProperties props) {
long now = nowMs();
pending.add(new PendingChange(props, now));
this.props = props;
}
@ -27,6 +50,13 @@ public final class DisplayPropertiesTracker {
return true;
}
if (consumeExpectedChange(props)) {
if (Ln.isEnabled(Ln.Level.VERBOSE)) {
Ln.v(getClass().getSimpleName() + ": " + prev + " -> " + props + " (ignored)");
}
return false;
}
if (props.equals(prev)) {
if (Ln.isEnabled(Ln.Level.VERBOSE)) {
Ln.v(getClass().getSimpleName() + ": " + props + " (unchanged)");
@ -40,4 +70,55 @@ public final class DisplayPropertiesTracker {
return true;
}
private boolean consumeExpectedChange(DisplayProperties props) {
cleanExpired();
int index = getMatchingPendingIndex(props);
if (index == -1) {
return false;
}
// Remove all pending changes up to (and including) the matching one
pending.subList(0, index+1).clear();
return true;
}
private int getMatchingPendingIndex(DisplayProperties props) {
for (int i = 0; i < pending.size(); ++i) {
if (pending.get(i).props.equals(props)) {
return i;
}
}
return -1;
}
private int getFirstNonExpiredIndex() {
long now = nowMs();
for (int i = 0; i < pending.size(); ++i) {
if (pending.get(i).timestamp + PENDING_CACHE_DURATION >= now) {
return i;
}
}
return -1;
}
private void cleanExpired() {
if (pending.isEmpty()) {
return;
}
int firstNonExpiredIndex = getFirstNonExpiredIndex();
if (firstNonExpiredIndex == 0) {
// All items are fresh
return;
}
if (firstNonExpiredIndex == -1) {
// All items have expired
pending.clear();
} else {
// Remove all the items up to the first non-expired index
pending.subList(0, firstNonExpiredIndex).clear();
}
}
}

View file

@ -118,7 +118,7 @@ public class NewDisplayCapture extends SurfaceCapture {
displayRotation = 0;
// Set the current display properties to avoid an unnecessary capture reset
displayMonitor.setSessionDisplayProperties(new DisplayProperties(displaySize, displayRotation));
displayMonitor.expectChange(new DisplayProperties(displaySize, displayRotation));
} else {
DisplayInfo displayInfo = ServiceManager.getDisplayManager().getDisplayInfo(virtualDisplay.getDisplay().getDisplayId());
dpi = displayInfo.getDpi();

View file

@ -78,7 +78,7 @@ public class ScreenCapture extends SurfaceCapture {
Size displaySize = displayInfo.getSize();
int displayRotation = displayInfo.getRotation();
displayMonitor.setSessionDisplayProperties(new DisplayProperties(displaySize, displayRotation));
displayMonitor.expectChange(new DisplayProperties(displaySize, displayRotation));
if (captureOrientationLock == Orientation.Lock.LockedInitial) {
// The user requested to lock the video orientation to the current orientation