From 92ae7de2892bb9d7eadfe6c860ab03351b2f13ed Mon Sep 17 00:00:00 2001 From: Romain Vimont Date: Wed, 15 Apr 2026 19:40:17 +0200 Subject: [PATCH] Extract display properties tracker `DisplayMonitor` listens for system display events. Move the event-handling logic into a separate class (`DisplayPropertiesTracker`), as it will become more complex in the following commit. --- .../scrcpy/display/DisplayMonitor.java | 54 ++++++------------- .../display/DisplayPropertiesTracker.java | 43 +++++++++++++++ 2 files changed, 59 insertions(+), 38 deletions(-) create mode 100644 server/src/main/java/com/genymobile/scrcpy/display/DisplayPropertiesTracker.java 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 5a31fff5..31ff97d9 100644 --- a/server/src/main/java/com/genymobile/scrcpy/display/DisplayMonitor.java +++ b/server/src/main/java/com/genymobile/scrcpy/display/DisplayMonitor.java @@ -25,6 +25,8 @@ public class DisplayMonitor { // So use the default method only before Android 14. private static final boolean USE_DEFAULT_METHOD = Build.VERSION.SDK_INT < AndroidVersions.API_34_ANDROID_14; + private final DisplayPropertiesTracker tracker = new DisplayPropertiesTracker(); + private DisplayManager.DisplayListenerHandle displayListenerHandle; private HandlerThread handlerThread; @@ -32,8 +34,6 @@ public class DisplayMonitor { private int displayId = Device.DISPLAY_ID_NONE; - private DisplayProperties props; - private Listener listener; public void start(int displayId, Listener listener) { @@ -48,15 +48,16 @@ public class DisplayMonitor { handlerThread = new HandlerThread("DisplayListener"); handlerThread.start(); Handler handler = new Handler(handlerThread.getLooper()); - displayListenerHandle = ServiceManager.getDisplayManager().registerDisplayListener(eventDisplayId -> { - if (Ln.isEnabled(Ln.Level.VERBOSE)) { - Ln.v("DisplayMonitor: onDisplayChanged(" + eventDisplayId + ")"); - } + displayListenerHandle = ServiceManager.getDisplayManager().registerDisplayListener( + eventDisplayId -> { + if (Ln.isEnabled(Ln.Level.VERBOSE)) { + Ln.v("DisplayMonitor: onDisplayChanged(" + eventDisplayId + ")"); + } - if (eventDisplayId == displayId) { - checkDisplayPropertiesChanged(); - } - }, handler); + if (eventDisplayId == displayId) { + checkDisplayPropertiesChanged(); + } + }, handler); } else { displayWindowListener = new DisplayWindowListener() { @Override @@ -96,39 +97,16 @@ public class DisplayMonitor { } } - private synchronized DisplayProperties getAndSetDisplayProperties(DisplayProperties props) { - DisplayProperties oldProps = this.props; - this.props = props; - return oldProps; - } - - public synchronized void setSessionDisplayProperties(DisplayProperties props) { - this.props = props; + public void setSessionDisplayProperties(DisplayProperties props) { + tracker.setCurrent(props); } private void checkDisplayPropertiesChanged() { DisplayInfo di = ServiceManager.getDisplayManager().getDisplayInfo(displayId); - if (di == null) { - Ln.w("DisplayInfo for " + displayId + " cannot be retrieved"); - // We can't compare with the current properties, so reset unconditionally - DisplayProperties oldProps = getAndSetDisplayProperties(null); // exchange with synchronization - if (Ln.isEnabled(Ln.Level.VERBOSE)) { - Ln.v("DisplayMonitor: requestReset(): " + oldProps + " -> (unknown)"); - } + DisplayProperties props = di != null ? new DisplayProperties(di.getSize(), di.getRotation()) : null; + boolean trigger = tracker.onDisplayPropertiesChanged(props); + if (trigger) { listener.onDisplayPropertiesChanged(); - } else { - DisplayProperties newProps = new DisplayProperties(di.getSize(), di.getRotation()); - - DisplayProperties oldProps = getAndSetDisplayProperties(newProps); // exchange with synchronization - if (!newProps.equals(oldProps)) { - // Reset only if the properties are different - if (Ln.isEnabled(Ln.Level.VERBOSE)) { - Ln.v("DisplayMonitor: requestReset(): " + oldProps + " -> " + newProps); - } - listener.onDisplayPropertiesChanged(); - } else if (Ln.isEnabled(Ln.Level.VERBOSE)) { - Ln.v("DisplayMonitor: DisplayProperties not changed (" + newProps + "): do not requestReset()"); - } } } } diff --git a/server/src/main/java/com/genymobile/scrcpy/display/DisplayPropertiesTracker.java b/server/src/main/java/com/genymobile/scrcpy/display/DisplayPropertiesTracker.java new file mode 100644 index 00000000..c7d782a2 --- /dev/null +++ b/server/src/main/java/com/genymobile/scrcpy/display/DisplayPropertiesTracker.java @@ -0,0 +1,43 @@ +package com.genymobile.scrcpy.display; + +import com.genymobile.scrcpy.util.Ln; + +public final class DisplayPropertiesTracker { + private DisplayProperties props; + + public synchronized void setCurrent(DisplayProperties props) { + this.props = props; + } + + /** + * Set the current display properties, and indicate whether the capture must be reset. + * + * @param props the current display properties + * @return {@code true} if the capture must be reset + */ + public synchronized boolean onDisplayPropertiesChanged(DisplayProperties props) { + DisplayProperties prev = this.props; + this.props = props; + + if (props == null) { + // The display properties have changed, but are unknown, a resize event must be triggered + if (Ln.isEnabled(Ln.Level.VERBOSE)) { + Ln.v(getClass().getSimpleName() + ": " + prev + " -> (unknown)"); + } + return true; + } + + if (props.equals(prev)) { + if (Ln.isEnabled(Ln.Level.VERBOSE)) { + Ln.v(getClass().getSimpleName() + ": " + props + "(unchanged)"); + } + return false; + } + + if (Ln.isEnabled(Ln.Level.VERBOSE)) { + Ln.v(getClass().getSimpleName() + ": " + prev + " -> " + props); + } + + return true; + } +}