diff --git a/server/src/main/java/com/genymobile/scrcpy/display/DisplayMonitor.java b/server/src/main/java/com/genymobile/scrcpy/display/DisplayMonitor.java index 31ff97d9..1ed94b11 100644 --- a/server/src/main/java/com/genymobile/scrcpy/display/DisplayMonitor.java +++ b/server/src/main/java/com/genymobile/scrcpy/display/DisplayMonitor.java @@ -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() { diff --git a/server/src/main/java/com/genymobile/scrcpy/display/DisplayPropertiesTracker.java b/server/src/main/java/com/genymobile/scrcpy/display/DisplayPropertiesTracker.java index d99c56a3..0d34c323 100644 --- a/server/src/main/java/com/genymobile/scrcpy/display/DisplayPropertiesTracker.java +++ b/server/src/main/java/com/genymobile/scrcpy/display/DisplayPropertiesTracker.java @@ -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 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(); + } + } } diff --git a/server/src/main/java/com/genymobile/scrcpy/video/NewDisplayCapture.java b/server/src/main/java/com/genymobile/scrcpy/video/NewDisplayCapture.java index e1fe0315..cee0aae2 100644 --- a/server/src/main/java/com/genymobile/scrcpy/video/NewDisplayCapture.java +++ b/server/src/main/java/com/genymobile/scrcpy/video/NewDisplayCapture.java @@ -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(); 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 5f28f868..6f8506c7 100644 --- a/server/src/main/java/com/genymobile/scrcpy/video/ScreenCapture.java +++ b/server/src/main/java/com/genymobile/scrcpy/video/ScreenCapture.java @@ -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