Compare commits
3 Commits
master
...
display_ca
Author | SHA1 | Date | |
---|---|---|---|
|
7a86156503 | ||
|
1b5d88368a | ||
|
daba00a819 |
@ -318,14 +318,14 @@ Disable video and audio playback on the computer (equivalent to \fB\-\-no\-video
|
|||||||
|
|
||||||
.TP
|
.TP
|
||||||
\fB\-\-new\-display\fR[=[\fIwidth\fRx\fIheight\fR][/\fIdpi\fR]]
|
\fB\-\-new\-display\fR[=[\fIwidth\fRx\fIheight\fR][/\fIdpi\fR]]
|
||||||
Create a new display with the specified resolution and density. If not provided, they default to the main display dimensions and DPI, and \fB\-\-max\-size\fR is considered.
|
Create a new display with the specified resolution and density. If not provided, they default to the main display dimensions and DPI.
|
||||||
|
|
||||||
Examples:
|
Examples:
|
||||||
|
|
||||||
\-\-new\-display=1920x1080
|
\-\-new\-display=1920x1080
|
||||||
\-\-new\-display=1920x1080/420
|
\-\-new\-display=1920x1080/420 # force 420 dpi
|
||||||
|
\-\-new\-display=1920x1080@24 # 24 fps (Android >= 14)
|
||||||
\-\-new\-display # main display size and density
|
\-\-new\-display # main display size and density
|
||||||
\-\-new\-display -m1920 # scaled to fit a max size of 1920
|
|
||||||
\-\-new\-display=/240 # main display size and 240 dpi
|
\-\-new\-display=/240 # main display size and 240 dpi
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
|
@ -586,16 +586,18 @@ static const struct sc_option options[] = {
|
|||||||
{
|
{
|
||||||
.longopt_id = OPT_NEW_DISPLAY,
|
.longopt_id = OPT_NEW_DISPLAY,
|
||||||
.longopt = "new-display",
|
.longopt = "new-display",
|
||||||
.argdesc = "[<width>x<height>][/<dpi>]",
|
.argdesc = "[<width>x<height>][/<dpi>][@<fps>]",
|
||||||
.optional_arg = true,
|
.optional_arg = true,
|
||||||
.text = "Create a new display with the specified resolution and "
|
.text = "Create a new display with the specified resolution and "
|
||||||
"density. If not provided, they default to the main display "
|
"density. If not provided, they default to the main display "
|
||||||
"dimensions and DPI, and --max-size is considered.\n"
|
"dimensions and DPI.\n"
|
||||||
|
"From Android 14, it is also possible to request a frame rate. "
|
||||||
|
"If not provided, it defaults to 60 fps.\n"
|
||||||
"Examples:\n"
|
"Examples:\n"
|
||||||
" --new-display=1920x1080\n"
|
" --new-display=1920x1080\n"
|
||||||
" --new-display=1920x1080/420 # force 420 dpi\n"
|
" --new-display=1920x1080/420 # force 420 dpi\n"
|
||||||
|
" --new-display=1920x1080@24 # 24 fps (Android >= 14)\n"
|
||||||
" --new-display # main display size and density\n"
|
" --new-display # main display size and density\n"
|
||||||
" --new-display -m1920 # scaled to fit a max size of 1920\n"
|
|
||||||
" --new-display=/240 # main display size and 240 dpi",
|
" --new-display=/240 # main display size and 240 dpi",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -2891,13 +2893,6 @@ parse_args_with_getopt(struct scrcpy_cli_args *args, int argc, char *argv[],
|
|||||||
LOGE("--new-display is incompatible with --no-video");
|
LOGE("--new-display is incompatible with --no-video");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (opts->max_size && opts->new_display[0] != '\0'
|
|
||||||
&& opts->new_display[0] != '/') {
|
|
||||||
// An explicit size is defined (not "" nor "/<dpi>")
|
|
||||||
LOGE("Cannot specify both --new-display size and -m/--max-size");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (otg) {
|
if (otg) {
|
||||||
|
@ -193,9 +193,9 @@ phone, landscape for a tablet).
|
|||||||
|
|
||||||
Cropping is performed before `--capture-orientation` and `--angle`.
|
Cropping is performed before `--capture-orientation` and `--angle`.
|
||||||
|
|
||||||
For screen mirroring, `--max-size` is applied after cropping. For camera and
|
For display mirroring, `--max-size` is applied after cropping. For camera,
|
||||||
virtual display mirroring, `--max-size` is applied first (because it selects the
|
`--max-size` is applied first (because it selects the source size rather than
|
||||||
source size rather than resizing it).
|
resizing the content).
|
||||||
|
|
||||||
|
|
||||||
## Display
|
## Display
|
||||||
|
@ -7,8 +7,8 @@ To mirror a new virtual display instead of the device screen:
|
|||||||
```bash
|
```bash
|
||||||
scrcpy --new-display=1920x1080
|
scrcpy --new-display=1920x1080
|
||||||
scrcpy --new-display=1920x1080/420 # force 420 dpi
|
scrcpy --new-display=1920x1080/420 # force 420 dpi
|
||||||
|
scrcpy --new-display=1920x1080@24 # 24 fps (Android >= 14)
|
||||||
scrcpy --new-display # use the main display size and density
|
scrcpy --new-display # use the main display size and density
|
||||||
scrcpy --new-display -m1920 # ... scaled to fit a max size of 1920
|
|
||||||
scrcpy --new-display=/240 # use the main display size and 240 dpi
|
scrcpy --new-display=/240 # use the main display size and 240 dpi
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -566,36 +566,68 @@ public class Options {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static NewDisplay parseNewDisplay(String newDisplay) {
|
static NewDisplay parseNewDisplay(String newDisplay) {
|
||||||
// Possible inputs:
|
// Input in the form "[<width>x<height>][/<dpi>][@<fps>]" (each [] block is optional)
|
||||||
// - "" (empty string)
|
// For convenience, the order of dpi and fps does not matter.
|
||||||
// - "<width>x<height>/<dpi>"
|
|
||||||
// - "<width>x<height>"
|
|
||||||
// - "/<dpi>"
|
|
||||||
if (newDisplay.isEmpty()) {
|
if (newDisplay.isEmpty()) {
|
||||||
return new NewDisplay();
|
return new NewDisplay();
|
||||||
}
|
}
|
||||||
|
|
||||||
String[] tokens = newDisplay.split("/");
|
String sizeString = null;
|
||||||
|
String dpiString = null;
|
||||||
|
String fpsString = null;
|
||||||
|
|
||||||
Size size;
|
String s = newDisplay;
|
||||||
if (!tokens[0].isEmpty()) {
|
while (true) {
|
||||||
size = parseSize(tokens[0]);
|
int slashIndex = s.indexOf('/');
|
||||||
} else {
|
int atIndex = s.indexOf('@');
|
||||||
size = null;
|
int lastSepIndex = Math.max(slashIndex, atIndex);
|
||||||
}
|
if (lastSepIndex == -1) {
|
||||||
|
if (!s.isEmpty()) {
|
||||||
int dpi;
|
sizeString = s;
|
||||||
if (tokens.length >= 2) {
|
}
|
||||||
dpi = Integer.parseInt(tokens[1]);
|
break;
|
||||||
if (dpi <= 0) {
|
} else {
|
||||||
throw new IllegalArgumentException("Invalid non-positive dpi: " + tokens[1]);
|
char lastSep = newDisplay.charAt(lastSepIndex);
|
||||||
|
if (lastSep == '@') {
|
||||||
|
if (fpsString != null) {
|
||||||
|
throw new IllegalArgumentException("Invalid new display format: '@' may not appear twice");
|
||||||
|
}
|
||||||
|
fpsString = s.substring(lastSepIndex + 1);
|
||||||
|
} else {
|
||||||
|
assert lastSep == '/';
|
||||||
|
if (dpiString != null) {
|
||||||
|
throw new IllegalArgumentException("Invalid new display format: '/' may not appear twice");
|
||||||
|
}
|
||||||
|
dpiString = s.substring(lastSepIndex + 1);
|
||||||
|
}
|
||||||
|
s = s.substring(0, lastSepIndex);
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
dpi = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return new NewDisplay(size, dpi);
|
Size size = null;
|
||||||
|
int dpi = 0;
|
||||||
|
float fps = 0;
|
||||||
|
|
||||||
|
if (sizeString != null) {
|
||||||
|
size = parseSize(sizeString);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dpiString != null) {
|
||||||
|
dpi = Integer.parseInt(dpiString);
|
||||||
|
if (dpi <= 0) {
|
||||||
|
throw new IllegalArgumentException("Invalid non-positive dpi: " + dpiString);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fpsString != null) {
|
||||||
|
fps = Float.parseFloat(fpsString);
|
||||||
|
if (fps < 0) {
|
||||||
|
throw new IllegalArgumentException("Invalid negative fps: " + fpsString);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new NewDisplay(size, dpi, fps);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Pair<Orientation.Lock, Orientation> parseCaptureOrientation(String value) {
|
private static Pair<Orientation.Lock, Orientation> parseCaptureOrientation(String value) {
|
||||||
|
@ -3,14 +3,16 @@ package com.genymobile.scrcpy.device;
|
|||||||
public final class NewDisplay {
|
public final class NewDisplay {
|
||||||
private Size size;
|
private Size size;
|
||||||
private int dpi;
|
private int dpi;
|
||||||
|
private float fps;
|
||||||
|
|
||||||
public NewDisplay() {
|
public NewDisplay() {
|
||||||
// Auto size and dpi
|
// Auto size, dpi and fps
|
||||||
}
|
}
|
||||||
|
|
||||||
public NewDisplay(Size size, int dpi) {
|
public NewDisplay(Size size, int dpi, float fps) {
|
||||||
this.size = size;
|
this.size = size;
|
||||||
this.dpi = dpi;
|
this.dpi = dpi;
|
||||||
|
this.fps = fps;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Size getSize() {
|
public Size getSize() {
|
||||||
@ -21,6 +23,10 @@ public final class NewDisplay {
|
|||||||
return dpi;
|
return dpi;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public float getFps() {
|
||||||
|
return fps;
|
||||||
|
}
|
||||||
|
|
||||||
public boolean hasExplicitSize() {
|
public boolean hasExplicitSize() {
|
||||||
return size != null;
|
return size != null;
|
||||||
}
|
}
|
||||||
@ -28,4 +34,8 @@ public final class NewDisplay {
|
|||||||
public boolean hasExplicitDpi() {
|
public boolean hasExplicitDpi() {
|
||||||
return dpi != 0;
|
return dpi != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean hasExplicitFps() {
|
||||||
|
return fps != 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -60,7 +60,7 @@ public final class Size {
|
|||||||
* @return The current size rounded.
|
* @return The current size rounded.
|
||||||
*/
|
*/
|
||||||
public Size round8() {
|
public Size round8() {
|
||||||
if ((width & 7) == 0 && (height & 7) == 0) {
|
if (isMultipleOf8()) {
|
||||||
// Already a multiple of 8
|
// Already a multiple of 8
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@ -80,6 +80,10 @@ public final class Size {
|
|||||||
return new Size(w, h);
|
return new Size(w, h);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isMultipleOf8() {
|
||||||
|
return (width & 7) == 0 && (height & 7) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
public Rect toRect() {
|
public Rect toRect() {
|
||||||
return new Rect(0, 0, width, height);
|
return new Rect(0, 0, width, height);
|
||||||
}
|
}
|
||||||
|
@ -14,8 +14,10 @@ import com.genymobile.scrcpy.util.AffineMatrix;
|
|||||||
import com.genymobile.scrcpy.util.Ln;
|
import com.genymobile.scrcpy.util.Ln;
|
||||||
import com.genymobile.scrcpy.wrappers.ServiceManager;
|
import com.genymobile.scrcpy.wrappers.ServiceManager;
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint;
|
||||||
import android.graphics.Rect;
|
import android.graphics.Rect;
|
||||||
import android.hardware.display.VirtualDisplay;
|
import android.hardware.display.VirtualDisplay;
|
||||||
|
import android.hardware.display.VirtualDisplayConfig;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.view.Surface;
|
import android.view.Surface;
|
||||||
|
|
||||||
@ -48,7 +50,7 @@ public class NewDisplayCapture extends SurfaceCapture {
|
|||||||
|
|
||||||
private Size mainDisplaySize;
|
private Size mainDisplaySize;
|
||||||
private int mainDisplayDpi;
|
private int mainDisplayDpi;
|
||||||
private int maxSize; // only used if newDisplay.getSize() != null
|
private int maxSize;
|
||||||
private final Rect crop;
|
private final Rect crop;
|
||||||
private final boolean captureOrientationLocked;
|
private final boolean captureOrientationLocked;
|
||||||
private final Orientation captureOrientation;
|
private final Orientation captureOrientation;
|
||||||
@ -101,7 +103,7 @@ public class NewDisplayCapture extends SurfaceCapture {
|
|||||||
int displayRotation;
|
int displayRotation;
|
||||||
if (virtualDisplay == null) {
|
if (virtualDisplay == null) {
|
||||||
if (!newDisplay.hasExplicitSize()) {
|
if (!newDisplay.hasExplicitSize()) {
|
||||||
displaySize = mainDisplaySize.limit(maxSize).round8();
|
displaySize = mainDisplaySize;
|
||||||
}
|
}
|
||||||
if (!newDisplay.hasExplicitDpi()) {
|
if (!newDisplay.hasExplicitDpi()) {
|
||||||
dpi = scaleDpi(mainDisplaySize, mainDisplayDpi, displaySize);
|
dpi = scaleDpi(mainDisplaySize, mainDisplayDpi, displaySize);
|
||||||
@ -128,10 +130,19 @@ public class NewDisplayCapture extends SurfaceCapture {
|
|||||||
filter.addOrientation(displayRotation, captureOrientationLocked, captureOrientation);
|
filter.addOrientation(displayRotation, captureOrientationLocked, captureOrientation);
|
||||||
filter.addAngle(angle);
|
filter.addAngle(angle);
|
||||||
|
|
||||||
|
Size filteredSize = filter.getOutputSize();
|
||||||
|
if (!filteredSize.isMultipleOf8() || (maxSize != 0 && filteredSize.getMax() > maxSize)) {
|
||||||
|
if (maxSize != 0) {
|
||||||
|
filteredSize = filteredSize.limit(maxSize);
|
||||||
|
}
|
||||||
|
filteredSize = filteredSize.round8();
|
||||||
|
filter.addResize(filteredSize);
|
||||||
|
}
|
||||||
|
|
||||||
eventTransform = filter.getInverseTransform();
|
eventTransform = filter.getInverseTransform();
|
||||||
|
|
||||||
// DisplayInfo gives the oriented size (so videoSize includes the display rotation)
|
// DisplayInfo gives the oriented size (so videoSize includes the display rotation)
|
||||||
videoSize = filter.getOutputSize().limit(maxSize).round8();
|
videoSize = filter.getOutputSize();
|
||||||
|
|
||||||
// But the virtual display video always remains in the origin orientation (the video itself is not rotated, so it must rotated manually).
|
// But the virtual display video always remains in the origin orientation (the video itself is not rotated, so it must rotated manually).
|
||||||
// This additional display rotation must not be included in the input events transform (the expected coordinates are already in the
|
// This additional display rotation must not be included in the input events transform (the expected coordinates are already in the
|
||||||
@ -152,6 +163,7 @@ public class NewDisplayCapture extends SurfaceCapture {
|
|||||||
displayTransform = AffineMatrix.multiplyAll(displayRotationMatrix, eventTransform);
|
displayTransform = AffineMatrix.multiplyAll(displayRotationMatrix, eventTransform);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressLint("WrongConstant")
|
||||||
public void startNew(Surface surface) {
|
public void startNew(Surface surface) {
|
||||||
int virtualDisplayId;
|
int virtualDisplayId;
|
||||||
try {
|
try {
|
||||||
@ -173,10 +185,30 @@ public class NewDisplayCapture extends SurfaceCapture {
|
|||||||
| VIRTUAL_DISPLAY_FLAG_DEVICE_DISPLAY_GROUP;
|
| VIRTUAL_DISPLAY_FLAG_DEVICE_DISPLAY_GROUP;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
virtualDisplay = ServiceManager.getDisplayManager()
|
|
||||||
.createNewVirtualDisplay("scrcpy", displaySize.getWidth(), displaySize.getHeight(), dpi, surface, flags);
|
// Since Android 14, it is possible to request a display frame rate:
|
||||||
|
// <https://android.googlesource.com/platform/frameworks/base/+/6c57176e9a2882eff03c5b3f3cccfd988d38488d>
|
||||||
|
// It defaults to 60 fps:
|
||||||
|
// <https://android.googlesource.com/platform/frameworks/base/+/6c57176e9a2882eff03c5b3f3cccfd988d38488d/services/core/java/com/android/server/display/VirtualDisplayAdapter.java#562>
|
||||||
|
float fps = newDisplay.getFps();
|
||||||
|
if (fps > 0) {
|
||||||
|
if (Build.VERSION.SDK_INT >= AndroidVersions.API_34_ANDROID_14) {
|
||||||
|
VirtualDisplayConfig.Builder builder = new VirtualDisplayConfig.Builder(
|
||||||
|
"scrcpy", displaySize.getWidth(), displaySize.getHeight(), dpi);
|
||||||
|
builder.setFlags(flags);
|
||||||
|
builder.setSurface(surface);
|
||||||
|
builder.setRequestedRefreshRate(fps);
|
||||||
|
virtualDisplay = ServiceManager.getDisplayManager().createNewVirtualDisplay(builder.build());
|
||||||
|
} else {
|
||||||
|
throw new UnsupportedOperationException("Setting the virtual display frame rate (@" + fps + ") requires Android >= 14");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
virtualDisplay = ServiceManager.getDisplayManager()
|
||||||
|
.createNewVirtualDisplay("scrcpy", displaySize.getWidth(), displaySize.getHeight(), dpi, surface, flags);
|
||||||
|
}
|
||||||
virtualDisplayId = virtualDisplay.getDisplay().getDisplayId();
|
virtualDisplayId = virtualDisplay.getDisplay().getDisplayId();
|
||||||
Ln.i("New display: " + displaySize.getWidth() + "x" + displaySize.getHeight() + "/" + dpi + " (id=" + virtualDisplayId + ")");
|
String fpsString = fps > 0 ? "@" + fps : "";
|
||||||
|
Ln.i("New display: " + displaySize.getWidth() + "x" + displaySize.getHeight() + "/" + dpi + fpsString + " (id=" + virtualDisplayId + ")");
|
||||||
|
|
||||||
displaySizeMonitor.start(virtualDisplayId, this::invalidate);
|
displaySizeMonitor.start(virtualDisplayId, this::invalidate);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
@ -231,11 +263,6 @@ public class NewDisplayCapture extends SurfaceCapture {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized boolean setMaxSize(int newMaxSize) {
|
public synchronized boolean setMaxSize(int newMaxSize) {
|
||||||
if (newDisplay.hasExplicitSize()) {
|
|
||||||
// Cannot retry with a different size if the display size was explicitly provided
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
maxSize = newMaxSize;
|
maxSize = newMaxSize;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -103,4 +103,17 @@ public class VideoFilter {
|
|||||||
double ccwAngle = -cwAngle;
|
double ccwAngle = -cwAngle;
|
||||||
transform = AffineMatrix.rotate(ccwAngle).withAspectRatio(size).fromCenter().multiply(transform);
|
transform = AffineMatrix.rotate(ccwAngle).withAspectRatio(size).fromCenter().multiply(transform);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void addResize(Size targetSize) {
|
||||||
|
if (size.equals(targetSize)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (transform == null) {
|
||||||
|
// The requested scaling is performed by the viewport (by changing the output size), but the OpenGL filter must still run, even if
|
||||||
|
// resizing is not performed by the shader. So transform MUST NOT be null.
|
||||||
|
transform = AffineMatrix.IDENTITY;
|
||||||
|
}
|
||||||
|
size = targetSize;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,6 +11,7 @@ import android.annotation.SuppressLint;
|
|||||||
import android.annotation.TargetApi;
|
import android.annotation.TargetApi;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.hardware.display.VirtualDisplay;
|
import android.hardware.display.VirtualDisplay;
|
||||||
|
import android.hardware.display.VirtualDisplayConfig;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.view.Display;
|
import android.view.Display;
|
||||||
import android.view.Surface;
|
import android.view.Surface;
|
||||||
@ -46,6 +47,7 @@ public final class DisplayManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private final Object manager; // instance of hidden class android.hardware.display.DisplayManagerGlobal
|
private final Object manager; // instance of hidden class android.hardware.display.DisplayManagerGlobal
|
||||||
|
private android.hardware.display.DisplayManager displayManager;
|
||||||
private Method createVirtualDisplayMethod;
|
private Method createVirtualDisplayMethod;
|
||||||
private Method requestDisplayPowerMethod;
|
private Method requestDisplayPowerMethod;
|
||||||
|
|
||||||
@ -151,17 +153,31 @@ public final class DisplayManager {
|
|||||||
return createVirtualDisplayMethod;
|
return createVirtualDisplayMethod;
|
||||||
}
|
}
|
||||||
|
|
||||||
public VirtualDisplay createVirtualDisplay(String name, int width, int height, int displayIdToMirror, Surface surface) throws Exception {
|
public VirtualDisplay createVirtualDisplay(String name, int width, int height, int displayIdToMirror, Surface surface)
|
||||||
|
throws ReflectiveOperationException {
|
||||||
Method method = getCreateVirtualDisplayMethod();
|
Method method = getCreateVirtualDisplayMethod();
|
||||||
return (VirtualDisplay) method.invoke(null, name, width, height, displayIdToMirror, surface);
|
return (VirtualDisplay) method.invoke(null, name, width, height, displayIdToMirror, surface);
|
||||||
}
|
}
|
||||||
|
|
||||||
public VirtualDisplay createNewVirtualDisplay(String name, int width, int height, int dpi, Surface surface, int flags) throws Exception {
|
private android.hardware.display.DisplayManager getAndroidDisplayManager() throws ReflectiveOperationException {
|
||||||
Constructor<android.hardware.display.DisplayManager> ctor = android.hardware.display.DisplayManager.class.getDeclaredConstructor(
|
if (displayManager == null) {
|
||||||
Context.class);
|
Constructor<android.hardware.display.DisplayManager> ctor = android.hardware.display.DisplayManager.class.getDeclaredConstructor(
|
||||||
ctor.setAccessible(true);
|
Context.class);
|
||||||
android.hardware.display.DisplayManager dm = ctor.newInstance(FakeContext.get());
|
ctor.setAccessible(true);
|
||||||
return dm.createVirtualDisplay(name, width, height, dpi, surface, flags);
|
displayManager = ctor.newInstance(FakeContext.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
return displayManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
public VirtualDisplay createNewVirtualDisplay(String name, int width, int height, int dpi, Surface surface, int flags)
|
||||||
|
throws ReflectiveOperationException {
|
||||||
|
return getAndroidDisplayManager().createVirtualDisplay(name, width, height, dpi, surface, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TargetApi(AndroidVersions.API_34_ANDROID_14)
|
||||||
|
public VirtualDisplay createNewVirtualDisplay(VirtualDisplayConfig config) throws ReflectiveOperationException {
|
||||||
|
return getAndroidDisplayManager().createVirtualDisplay(config);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Method getRequestDisplayPowerMethod() throws NoSuchMethodException {
|
private Method getRequestDisplayPowerMethod() throws NoSuchMethodException {
|
||||||
|
120
server/src/test/java/com/genymobile/scrcpy/OptionsTest.java
Normal file
120
server/src/test/java/com/genymobile/scrcpy/OptionsTest.java
Normal file
@ -0,0 +1,120 @@
|
|||||||
|
package com.genymobile.scrcpy;
|
||||||
|
|
||||||
|
import com.genymobile.scrcpy.device.NewDisplay;
|
||||||
|
import com.genymobile.scrcpy.device.Size;
|
||||||
|
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
public class OptionsTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testParseNewDisplayEmpty() {
|
||||||
|
NewDisplay newDisplay = Options.parseNewDisplay("");
|
||||||
|
Assert.assertFalse(newDisplay.hasExplicitSize());
|
||||||
|
Assert.assertFalse(newDisplay.hasExplicitDpi());
|
||||||
|
Assert.assertFalse(newDisplay.hasExplicitFps());
|
||||||
|
Assert.assertNull(newDisplay.getSize());
|
||||||
|
Assert.assertEquals(0, newDisplay.getDpi());
|
||||||
|
Assert.assertEquals(0, newDisplay.getFps(), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testParseNewDisplaySizeOnly() {
|
||||||
|
NewDisplay newDisplay = Options.parseNewDisplay("1920x1080");
|
||||||
|
Assert.assertTrue(newDisplay.hasExplicitSize());
|
||||||
|
Assert.assertFalse(newDisplay.hasExplicitDpi());
|
||||||
|
Assert.assertFalse(newDisplay.hasExplicitFps());
|
||||||
|
Assert.assertEquals(new Size(1920, 1080), newDisplay.getSize());
|
||||||
|
Assert.assertEquals(0, newDisplay.getDpi());
|
||||||
|
Assert.assertEquals(0, newDisplay.getFps(), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testParseNewDisplayDpiOnly() {
|
||||||
|
NewDisplay newDisplay = Options.parseNewDisplay("/240");
|
||||||
|
Assert.assertFalse(newDisplay.hasExplicitSize());
|
||||||
|
Assert.assertTrue(newDisplay.hasExplicitDpi());
|
||||||
|
Assert.assertFalse(newDisplay.hasExplicitFps());
|
||||||
|
Assert.assertNull(newDisplay.getSize());
|
||||||
|
Assert.assertEquals(240, newDisplay.getDpi());
|
||||||
|
Assert.assertEquals(0, newDisplay.getFps(), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testParseNewDisplayFpsOnly() {
|
||||||
|
NewDisplay newDisplay = Options.parseNewDisplay("@30");
|
||||||
|
Assert.assertFalse(newDisplay.hasExplicitSize());
|
||||||
|
Assert.assertFalse(newDisplay.hasExplicitDpi());
|
||||||
|
Assert.assertTrue(newDisplay.hasExplicitFps());
|
||||||
|
Assert.assertNull(newDisplay.getSize());
|
||||||
|
Assert.assertEquals(0, newDisplay.getDpi());
|
||||||
|
Assert.assertEquals(30, newDisplay.getFps(), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testParseNewDisplaySizeAndDpi() {
|
||||||
|
NewDisplay newDisplay = Options.parseNewDisplay("1920x1080/240");
|
||||||
|
Assert.assertTrue(newDisplay.hasExplicitSize());
|
||||||
|
Assert.assertTrue(newDisplay.hasExplicitDpi());
|
||||||
|
Assert.assertFalse(newDisplay.hasExplicitFps());
|
||||||
|
Assert.assertEquals(new Size(1920, 1080), newDisplay.getSize());
|
||||||
|
Assert.assertEquals(240, newDisplay.getDpi());
|
||||||
|
Assert.assertEquals(0, newDisplay.getFps(), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testParseNewDisplaySizeAndFps() {
|
||||||
|
NewDisplay newDisplay = Options.parseNewDisplay("1920x1080@30");
|
||||||
|
Assert.assertTrue(newDisplay.hasExplicitSize());
|
||||||
|
Assert.assertFalse(newDisplay.hasExplicitDpi());
|
||||||
|
Assert.assertTrue(newDisplay.hasExplicitFps());
|
||||||
|
Assert.assertEquals(new Size(1920, 1080), newDisplay.getSize());
|
||||||
|
Assert.assertEquals(0, newDisplay.getDpi());
|
||||||
|
Assert.assertEquals(30, newDisplay.getFps(), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testParseNewDisplaySizeAndDpiAndFps() {
|
||||||
|
NewDisplay newDisplay = Options.parseNewDisplay("1920x1080/240@30");
|
||||||
|
Assert.assertTrue(newDisplay.hasExplicitSize());
|
||||||
|
Assert.assertTrue(newDisplay.hasExplicitDpi());
|
||||||
|
Assert.assertTrue(newDisplay.hasExplicitFps());
|
||||||
|
Assert.assertEquals(new Size(1920, 1080), newDisplay.getSize());
|
||||||
|
Assert.assertEquals(240, newDisplay.getDpi());
|
||||||
|
Assert.assertEquals(30, newDisplay.getFps(), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testParseNewDisplaySizeAndFpsAndDpi() {
|
||||||
|
NewDisplay newDisplay = Options.parseNewDisplay("1920x1080@30/240");
|
||||||
|
Assert.assertTrue(newDisplay.hasExplicitSize());
|
||||||
|
Assert.assertTrue(newDisplay.hasExplicitDpi());
|
||||||
|
Assert.assertTrue(newDisplay.hasExplicitFps());
|
||||||
|
Assert.assertEquals(new Size(1920, 1080), newDisplay.getSize());
|
||||||
|
Assert.assertEquals(240, newDisplay.getDpi());
|
||||||
|
Assert.assertEquals(30, newDisplay.getFps(), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testParseNewDisplayDpiAndFps() {
|
||||||
|
NewDisplay newDisplay = Options.parseNewDisplay("/240@30");
|
||||||
|
Assert.assertFalse(newDisplay.hasExplicitSize());
|
||||||
|
Assert.assertTrue(newDisplay.hasExplicitDpi());
|
||||||
|
Assert.assertTrue(newDisplay.hasExplicitFps());
|
||||||
|
Assert.assertNull(newDisplay.getSize());
|
||||||
|
Assert.assertEquals(240, newDisplay.getDpi());
|
||||||
|
Assert.assertEquals(30, newDisplay.getFps(), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testParseNewDisplayFpsAndDpi() {
|
||||||
|
NewDisplay newDisplay = Options.parseNewDisplay("@30/240");
|
||||||
|
Assert.assertFalse(newDisplay.hasExplicitSize());
|
||||||
|
Assert.assertTrue(newDisplay.hasExplicitDpi());
|
||||||
|
Assert.assertTrue(newDisplay.hasExplicitFps());
|
||||||
|
Assert.assertNull(newDisplay.getSize());
|
||||||
|
Assert.assertEquals(240, newDisplay.getDpi());
|
||||||
|
Assert.assertEquals(30, newDisplay.getFps(), 0);
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user