diff --git a/server/src/main/java/com/genymobile/scrcpy/Command.java b/server/src/main/java/com/genymobile/scrcpy/Command.java index 0ef976a66c..362504ff0c 100644 --- a/server/src/main/java/com/genymobile/scrcpy/Command.java +++ b/server/src/main/java/com/genymobile/scrcpy/Command.java @@ -30,4 +30,14 @@ public static String execReadLine(String... cmd) throws IOException, Interrupted } return result; } + + public static String execReadOutput(String... cmd) throws IOException, InterruptedException { + Process process = Runtime.getRuntime().exec(cmd); + String output = IO.toString(process.getInputStream()); + int exitCode = process.waitFor(); + if (exitCode != 0) { + throw new IOException("Command " + Arrays.toString(cmd) + " returned with value " + exitCode); + } + return output; + } } diff --git a/server/src/main/java/com/genymobile/scrcpy/IO.java b/server/src/main/java/com/genymobile/scrcpy/IO.java index 57c017dbee..6eaf0d6a24 100644 --- a/server/src/main/java/com/genymobile/scrcpy/IO.java +++ b/server/src/main/java/com/genymobile/scrcpy/IO.java @@ -6,7 +6,9 @@ import java.io.FileDescriptor; import java.io.IOException; +import java.io.InputStream; import java.nio.ByteBuffer; +import java.util.Scanner; public final class IO { private IO() { @@ -37,4 +39,13 @@ public static void writeFully(FileDescriptor fd, ByteBuffer from) throws IOExcep public static void writeFully(FileDescriptor fd, byte[] buffer, int offset, int len) throws IOException { writeFully(fd, ByteBuffer.wrap(buffer, offset, len)); } + + public static String toString(InputStream inputStream) { + StringBuilder builder = new StringBuilder(); + Scanner scanner = new Scanner(inputStream); + while (scanner.hasNextLine()) { + builder.append(scanner.nextLine()).append('\n'); + } + return builder.toString(); + } } diff --git a/server/src/main/java/com/genymobile/scrcpy/wrappers/DisplayManager.java b/server/src/main/java/com/genymobile/scrcpy/wrappers/DisplayManager.java index 3f4f897dfa..c8188dc3ff 100644 --- a/server/src/main/java/com/genymobile/scrcpy/wrappers/DisplayManager.java +++ b/server/src/main/java/com/genymobile/scrcpy/wrappers/DisplayManager.java @@ -1,8 +1,13 @@ package com.genymobile.scrcpy.wrappers; +import com.genymobile.scrcpy.Command; import com.genymobile.scrcpy.DisplayInfo; +import com.genymobile.scrcpy.Ln; import com.genymobile.scrcpy.Size; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + public final class DisplayManager { private final Object manager; // instance of hidden class android.hardware.display.DisplayManagerGlobal @@ -10,11 +15,34 @@ public DisplayManager(Object manager) { this.manager = manager; } + private DisplayInfo parseDumpsysDisplay(int displayId) { + try { + String dumpDisplay = Command.execReadOutput("dumpsys", "display"); + Pattern regex = Pattern.compile( + "^ mBaseDisplayInfo=DisplayInfo\\{\".*\", displayId " + displayId + ".+, real ([0-9]+) x ([0-9]+).+, rotation ([0-9]+).*, " + + "layerStack ([0-9]+).*"); + Matcher m = regex.matcher(dumpDisplay); + if (!m.find()) { + return null; + } + int width = Integer.parseInt(m.group(1)); + int height = Integer.parseInt(m.group(2)); + int rotation = Integer.parseInt(m.group(3)); + int layerStack = Integer.parseInt(m.group(4)); + int flags = 0; // TODO + return new DisplayInfo(displayId, new Size(width, height), rotation, layerStack, flags); + } catch (Exception e) { + Ln.e("Could not get display info from \"dumpsys display\" output", e); + return null; + } + } + public DisplayInfo getDisplayInfo(int displayId) { try { Object displayInfo = manager.getClass().getMethod("getDisplayInfo", int.class).invoke(manager, displayId); if (displayInfo == null) { - return null; + // fallback when displayInfo is null + return parseDumpsysDisplay(displayId); } Class cls = displayInfo.getClass(); // width and height already take the rotation into account