diff --git a/server/src/main/java/com/genymobile/scrcpy/ScreenCapture.java b/server/src/main/java/com/genymobile/scrcpy/ScreenCapture.java index e048354a93..d6fda443d5 100644 --- a/server/src/main/java/com/genymobile/scrcpy/ScreenCapture.java +++ b/server/src/main/java/com/genymobile/scrcpy/ScreenCapture.java @@ -1,8 +1,11 @@ package com.genymobile.scrcpy; +import com.genymobile.scrcpy.wrappers.DisplayManager; import com.genymobile.scrcpy.wrappers.SurfaceControl; +import com.genymobile.scrcpy.wrappers.MediaProjectionGlobal; import android.graphics.Rect; +import android.hardware.display.VirtualDisplay; import android.os.Build; import android.os.IBinder; import android.view.Surface; @@ -11,6 +14,7 @@ public class ScreenCapture extends SurfaceCapture implements Device.RotationList private final Device device; private IBinder display; + VirtualDisplay virtualDisplay; public ScreenCapture(Device device) { this.device = device; @@ -31,12 +35,33 @@ public void start(Surface surface) { Rect unlockedVideoRect = screenInfo.getUnlockedVideoSize().toRect(); int videoRotation = screenInfo.getVideoRotation(); int layerStack = device.getLayerStack(); + Rect videoRect = screenInfo.getVideoSize().toRect(); if (display != null) { SurfaceControl.destroyDisplay(display); } - display = createDisplay(); - setDisplaySurface(display, surface, videoRotation, contentRect, unlockedVideoRect, layerStack); + try { + virtualDisplay = DisplayManager.createVirtualDisplay( + "displayManager VirtualDisplay", + videoRect.width(), + videoRect.height(), + 0, + surface); + Ln.i("Using the DisplayManager system API."); + } catch (Exception displayManagerException) { + try { + virtualDisplay = MediaProjectionGlobal.createVirtualDisplay( + "mediaProjection global", + videoRect.width(), + videoRect.height(), + 0, + surface); + Ln.i("Using the MediaProjectionGlobal system API."); + } catch (NoSuchMethodException | NullPointerException mediaProjectionGlobalException){ + display = createDisplay(); + setDisplaySurface(display, surface, videoRotation, contentRect, unlockedVideoRect, layerStack); + } + } } @Override @@ -46,6 +71,9 @@ public void release() { if (display != null) { SurfaceControl.destroyDisplay(display); } + if (virtualDisplay != null){ + virtualDisplay.release(); + } } @Override 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 17b9ae4ddb..8f6d547803 100644 --- a/server/src/main/java/com/genymobile/scrcpy/wrappers/DisplayManager.java +++ b/server/src/main/java/com/genymobile/scrcpy/wrappers/DisplayManager.java @@ -1,5 +1,8 @@ package com.genymobile.scrcpy.wrappers; +import android.hardware.display.VirtualDisplay; +import android.view.Display; +import android.view.Surface; import com.genymobile.scrcpy.Command; import com.genymobile.scrcpy.DisplayInfo; import com.genymobile.scrcpy.Ln; @@ -8,6 +11,7 @@ import android.view.Display; import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -87,6 +91,16 @@ public DisplayInfo getDisplayInfo(int displayId) { } } + public static VirtualDisplay createVirtualDisplay(String name, int width, int height, + int displayIdToMirror, Surface surface) + throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException { + java.lang.Class displayManagerClass = + java.lang.Class.forName("android.hardware.display.DisplayManager"); + return (VirtualDisplay) displayManagerClass.getMethod("createVirtualDisplay", + String.class, int.class, int.class, int.class, Surface.class) + .invoke(null, name, width, height, displayIdToMirror, surface); + } + public int[] getDisplayIds() { try { return (int[]) manager.getClass().getMethod("getDisplayIds").invoke(manager); diff --git a/server/src/main/java/com/genymobile/scrcpy/wrappers/MediaProjectionGlobal.java b/server/src/main/java/com/genymobile/scrcpy/wrappers/MediaProjectionGlobal.java new file mode 100644 index 0000000000..411fa79cfa --- /dev/null +++ b/server/src/main/java/com/genymobile/scrcpy/wrappers/MediaProjectionGlobal.java @@ -0,0 +1,67 @@ +package com.genymobile.scrcpy.wrappers; + +import android.hardware.display.VirtualDisplay; +import android.view.Surface; +import com.genymobile.scrcpy.Ln; +import java.lang.reflect.Method; +import android.os.Build; + +/** + * A wrapper for system API android.media.projection.MediaProjectionGlobal. + */ +public final class MediaProjectionGlobal { + + private static java.lang.Class MediaProjectionGlobalClass; + private static Method getInstanceMethod; + private static Method createVirtualDisplayMethod; + + static { + try { + MediaProjectionGlobalClass = java.lang.Class.forName("android.media.projection.MediaProjectionGlobal"); + } catch (ClassNotFoundException e) { + MediaProjectionGlobalClass = null; + } + } + + private static Method getGetInstanceMethod() throws NoSuchMethodException { + if (MediaProjectionGlobalClass == null) { + throw new NullPointerException("MediaProjectionGlobalClass is null"); + } + if (getInstanceMethod == null) { + getInstanceMethod = MediaProjectionGlobalClass.getMethod("getInstance"); + } + return getInstanceMethod; + } + + // String name, int width, int height, int displayIdToMirror + private static Method getCreateVirtualDisplayMethod() throws NoSuchMethodException { + if (MediaProjectionGlobalClass == null) { + throw new NullPointerException("MediaProjectionGlobalClass is null"); + } + if (createVirtualDisplayMethod == null) { + createVirtualDisplayMethod = + MediaProjectionGlobalClass.getMethod( + "createVirtualDisplay", String.class, int.class, int.class, int.class, Surface.class); + } + return createVirtualDisplayMethod; + } + + public static VirtualDisplay createVirtualDisplay( + String name, int width, int height, int displayIdToMirror, Surface surface) + throws NoSuchMethodException { + try { + Object instance = getGetInstanceMethod().invoke(null); + if (instance == null) { + Ln.e("instance == null!"); + } + return (VirtualDisplay) + getCreateVirtualDisplayMethod() + .invoke(instance, name, width, height, displayIdToMirror, surface); + } catch (ReflectiveOperationException e) { + Ln.e("Could not invoke method", e); + return null; + } + } + + private MediaProjectionGlobal() {} +}