Skip to content

Fix virtual display activity routing for Android desktop mode#1

Merged
lmichaelwar merged 3 commits into
masterfrom
copilot/fix-scrcpy-virtual-display-launches
Mar 14, 2026
Merged

Fix virtual display activity routing for Android desktop mode#1
lmichaelwar merged 3 commits into
masterfrom
copilot/fix-scrcpy-virtual-display-launches

Conversation

Copy link
Copy Markdown

Copilot AI commented Mar 13, 2026

Virtual displays created with --new-display on Android 16 QPR1+/17 with desktop mode enabled route activity launches to display 0 instead of the virtual display. The launcher renders correctly but tapping app icons opens them on the phone screen.

Flag changes (NewDisplayCapture.java)

  • Add VIRTUAL_DISPLAY_FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS unconditionally in the API 34+ block, ensuring the system treats the display as a full windowing environment regardless of the vdSystemDecorations option. OWN_FOCUS was already present here.

Freeform windowing mode (WindowManager.java)

  • Add setDisplayWindowingMode() using reflection to apply a WindowContainerTransaction that sets WINDOWING_MODE_FREEFORM on the virtual display's default task display area.
  • Temporarily registers a no-op DisplayAreaOrganizer for FEATURE_DEFAULT_TASK_CONTAINER to obtain the display area's WindowContainerToken, applies the transaction, then unregisters in a finally block.
  • Called from startNew() on API 34+ after virtual display creation, alongside the existing IME policy configuration.
// NewDisplayCapture.java — after virtual display creation
if (Build.VERSION.SDK_INT >= AndroidVersions.API_34_ANDROID_14) {
    ServiceManager.getWindowManager().setDisplayWindowingMode(
        virtualDisplayId, WindowManager.WINDOWING_MODE_FREEFORM);
}

All reflection failures are caught and logged as warnings — the virtual display still functions without freeform mode, just without proper desktop-mode activity routing.

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • dl.google.com
    • Triggering command: /usr/lib/jvm/temurin-17-jdk-amd64/bin/java /usr/lib/jvm/temurin-17-jdk-amd64/bin/java --add-opens=java.base/java.lang=ALL-UNNAMED --add-opens=java.base/java.lang.invoke=ALL-UNNAMED --add-opens=java.base/java.util=ALL-UNNAMED --add-opens=java.prefs/java.util.prefs=ALL-UNNAMED --add-exports=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED --add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED --add-opens=java.base/java.util=ALL-UNNAMED --add-opens=java.prefs/java.util.prefs=ALL-UNNAMED --add-opens=java.base/java.nio.charset=ALL-UNNAMED --add-opens=java.base/java.net=ALL-UNNAMED --add-opens=java.base/java.util.concurrent.atomic=ALL-UNNAMED --add-opens=java.xml/javax.xml.namespace=ALL-UNNAMED -Xmx1536m -Dfile.encoding=UTF-8 -Duser.country -Duser.language=en -Duser.variant -cp /home/REDACTED/.gradle/wrapper/dists/gradle-8.14.3-bin/cv11ve7ro1n3o1j4so8xd9n66/gradle-8.14.3/lib/gradle-daemon-main-8.14.3.jar (dns block)
  • www.puppycrawl.com
    • Triggering command: /opt/hostedtoolcache/CodeQL/2.24.2/x64/codeql/tools/linux64/java/bin/java /opt/hostedtoolcache/CodeQL/2.24.2/x64/codeql/tools/linux64/java/bin/java -jar /opt/hostedtoolcache/CodeQL/2.24.2/x64/codeql/xml/tools/xml-extractor.jar --fileList=/tmp/codeql-scratch-6269c6174ccbfd86/dbs/java/working/files-to-index16506125763911101300.list --sourceArchiveDir=/tmp/codeql-scratch-6269c6174ccbfd86/dbs/java/src --outputDir=/tmp/codeql-scratch-6269c6174ccbfd86/dbs/java/trap/java java/com/genymobile/scrcpy/control/ControlMessageReaderTest.java k/_temp/ghcca-node/node/bin/git (dns block)

If you need me to access, download, or install something from one of these locations, you can either:


💬 Send tasks to Copilot coding agent from Slack and Teams to turn conversations into code. Copilot posts an update in your thread when it's finished.

Copilot AI and others added 2 commits March 13, 2026 20:58
…ay desktop mode

- Add VIRTUAL_DISPLAY_FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS unconditionally
  for API 34+ alongside OWN_FOCUS to ensure desktop mode compatibility
- Add WindowContainerTransaction-based setDisplayWindowingMode() to
  WindowManager using reflection to set WINDOWING_MODE_FREEFORM on the
  virtual display's default task area after creation
- Call setDisplayWindowingMode after virtual display creation on API 34+

Co-authored-by: lmichaelwar <[email protected]>
Copilot AI changed the title [WIP] Fix routing of activity launches for virtual displays Fix virtual display activity routing for Android desktop mode Mar 13, 2026
Copilot AI requested a review from lmichaelwar March 13, 2026 21:02
@lmichaelwar lmichaelwar marked this pull request as ready for review March 14, 2026 01:21
Copilot AI review requested due to automatic review settings March 14, 2026 01:21
@lmichaelwar lmichaelwar merged commit 8142f96 into master Mar 14, 2026
2 checks passed
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes app/activity launch routing for --new-display virtual displays on Android 16 QPR1+/17 when desktop mode is enabled by ensuring the virtual display is treated as a proper “desktop-like” environment (system decorations + freeform windowing mode).

Changes:

  • Always add VIRTUAL_DISPLAY_FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS on API 34+ for new virtual displays.
  • Add WindowManager#setDisplayWindowingMode() (reflection-based) to apply a WindowContainerTransaction setting WINDOWING_MODE_FREEFORM on the virtual display’s default task area.
  • Invoke setDisplayWindowingMode() after virtual display creation on API 34+.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.

File Description
server/src/main/java/com/genymobile/scrcpy/wrappers/WindowManager.java Adds reflection logic to set freeform windowing mode on a display via Window Organizer APIs.
server/src/main/java/com/genymobile/scrcpy/video/NewDisplayCapture.java Adjusts virtual display flags for API 34+ and calls the new windowing-mode setter after creation.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +291 to +304
// Get the IWindowOrganizerController
Class<?> serviceManagerClass = Class.forName("android.os.ServiceManager");
Method getServiceMethod = serviceManagerClass.getDeclaredMethod("getService", String.class);
IBinder wocBinder = (IBinder) getServiceMethod.invoke(null, "window_organizer");
if (wocBinder == null) {
Ln.w("window_organizer service not available");
return;
}

Class<?> iWocStubClass = Class.forName("android.window.IWindowOrganizerController$Stub");
Object windowOrganizerController = iWocStubClass.getDeclaredMethod("asInterface", IBinder.class).invoke(null, wocBinder);

// Get the IDisplayAreaOrganizerController
daoController = windowOrganizerController.getClass().getMethod("getDisplayAreaOrganizerController").invoke(windowOrganizerController);
Comment on lines +306 to +316
// Create a no-op IDisplayAreaOrganizer proxy for registration; callbacks are ignored since we unregister immediately
Class<?> idaoClass = Class.forName("android.window.IDisplayAreaOrganizer");
organizerProxy = Proxy.newProxyInstance(
ClassLoader.getSystemClassLoader(),
new Class[]{idaoClass},
(proxy, method, args) -> {
if ("asBinder".equals(method.getName())) {
return organizerBinder;
}
return null;
}
Comment on lines +191 to +192
| VIRTUAL_DISPLAY_FLAG_DEVICE_DISPLAY_GROUP
| VIRTUAL_DISPLAY_FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS;
@lmichaelwar
Copy link
Copy Markdown
Owner

@copilot apply changes based on the comments in this thread

Copilot AI added a commit that referenced this pull request Mar 14, 2026
… Binder descriptor, respect vdSystemDecorations flag

1. WindowManager.java: Replace manual reflection for window_organizer service
   with ServiceManager.getService() to avoid duplicating reflection logic.
2. WindowManager.java: Attach correct AIDL interface descriptor to the
   organizer Binder and override onTransact to safely handle callbacks.
3. NewDisplayCapture.java: Remove unconditional SHOULD_SHOW_SYSTEM_DECORATIONS
   from API 34+ block so --no-vd-system-decorations remains effective.

Co-authored-by: lmichaelwar <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants