nwrkbiz / android-xserver

Maintaining the original project to make it work again with new Android versions.
MIT License
173 stars 20 forks source link

XServer in foreground may restart after the device was unlocked #35

Open Hagb opened 1 year ago

Hagb commented 1 year ago

In some configuration, the phone hides the navigation bar in unlocking GUI, and shows the navigation again after unlocked.

If XServer is in foreground, it will trigger the ScreenView.onSizeChanged event twice. (My device is OnePlus 6 with LineageOS 19.1, in which unlocking by fingerprint triggers it, but unlocking by pattern doesn't trigger it because the navigation bar recovers in the pattern interface. Unlocking by swiping may also trigger the event.)

https://github.com/nwrkbiz/android-xserver/blob/51e907880d4295ee3c381a593c738ca365c066fb/library/src/main/java/au/com/darkside/xserver/ScreenView.java#L655

The first one is triggered by hiding the navigation (size is expanded), and the second one is triggered by the recovering the navigation (size is reduced). There are all triggered after the phone was unlocked, and the second is triggered a very short time after the first one is triggered.

It causes the XServer to "restart".

One possible workaround is to delay the "restart", and stop the "restart" after the size recovers the original value in a short time:

diff --git a/library/src/main/java/au/com/darkside/xserver/ScreenView.java b/library/src/main/java/au/com/darkside/xserver/ScreenView.java
index 423462a..af2de29 100644
--- a/library/src/main/java/au/com/darkside/xserver/ScreenView.java
+++ b/library/src/main/java/au/com/darkside/xserver/ScreenView.java
@@ -642,6 +642,11 @@ public class ScreenView extends View {
         }
     }

+    protected Handler resizeDelayer = new Handler();
+    protected boolean waitingForResize = false;
+    protected int widthBeforeResize;
+    protected int heightBeforeResize;
+
     /**
      * Called when the size changes.
      * Create the root window.
@@ -655,6 +660,29 @@ public class ScreenView extends View {
     protected void onSizeChanged(int width, int height, int oldWidth, int oldHeight) {
         super.onSizeChanged(width, height, oldWidth, oldHeight);

+        if (!_xServer.isStarted()) {
+            onRealSizeChanged(width, height, oldWidth, oldHeight);
+            return;
+        }
+
+        if (!waitingForResize) {
+            widthBeforeResize = oldWidth;
+            heightBeforeResize = oldHeight;
+        }
+        waitingForResize = true;
+        resizeDelayer.removeCallbacksAndMessages(null);
+        resizeDelayer.postDelayed(new Runnable() {
+            @Override
+            public void run() {
+                waitingForResize = false;
+                if (width != widthBeforeResize || height != heightBeforeResize) {
+                    onRealSizeChanged(width, height, widthBeforeResize, heightBeforeResize);
+                }
+            }
+        }, 500); // threshold in ms
+    }
+
+    protected void onRealSizeChanged(int width, int height, int oldWidth, int oldHeight){
         _rootWindow = new Window(_rootId, _xServer, null, this, null, 0, 0, width, height, 0, false, true);
         _sharedClipboardWindow = new Window(_xServer.nextFreeResourceId()+1, _xServer, null, this, _rootWindow, -1, -1, 1, 1, 0, true, false); // hidden window managing android <-> xServer clipboard
         _sharedClipboardWindow.setIsServerWindow(true); // flag as functional server only window (there is a urgent need to introduce interfaces..)
@@ -711,6 +739,7 @@ public class ScreenView extends View {
         _xServer.start();
     }

+
     /**
      * Move the pointer on the screen.
      *
diff --git a/library/src/main/java/au/com/darkside/xserver/XServer.java b/library/src/main/java/au/com/darkside/xserver/XServer.java
index 046c8f8..6aa3dcf 100644
--- a/library/src/main/java/au/com/darkside/xserver/XServer.java
+++ b/library/src/main/java/au/com/darkside/xserver/XServer.java
@@ -132,6 +132,10 @@ public class XServer {
         _onStartListener = l;
     }

+    public boolean isStarted(){
+        return _acceptThread != null;
+    }
+
     /**
      * Start the thread that listens on the socket.
      * Also start the window manager if one is specified.

Also related to #26.

nwrkbiz commented 1 year ago

Can you provide a pull request? I will merge this then.

Hagb commented 1 year ago

Can you provide a pull request? I will merge this then.

Yes. But I doubt whether this workaround is reliable enough

It does work on my device, but I don't know whether the hardcoded threshold (500 ms in my code) is good, which may depend on the performance and status of device.

Too large threshold leads to obvious delay when the size is actually changed, while too small threshold make XServer restart when the device is unlocked. (At first, I tried 200 ms, but sometimes it doesn't work for the threshold was not large enough.)

I consider adding an option for custom threshold in the menu.

It would be better to find a way that doesn't depend on the performance of device. (But I failed to find that.)