Compare commits

..

1 commit
master ... test

Author SHA1 Message Date
bd67110a20
test virtual display 2023-09-08 17:31:28 +08:00
3 changed files with 43 additions and 34 deletions

View file

@ -552,12 +552,9 @@ static const struct sc_option options[] = {
.longopt_id = OPT_VIRTUAL_DISPLAY, .longopt_id = OPT_VIRTUAL_DISPLAY,
.longopt = "virtual-display", .longopt = "virtual-display",
.argdesc = "properties", .argdesc = "properties",
.optional_arg = true,
.text = "Start a new virtual display for your applications to " .text = "Start a new virtual display for your applications to "
"launch into. Requires Android version >= 10." "launch into. Requires Android version >= 10."
"Display size and DPI may be specified. e.g. 1920x1080dpi300\n" "Display size and DPI may be specified. e.g. 1920x1080dpi300"
"Comma separated extra launch arguments may be passed to am start.\n"
"e.g. 1920x1080dpi300,-a,android.intent.action.MAIN,-n,com.android.settings/.applications.ManageApplications"
}, },
{ {
.shortopt = 's', .shortopt = 's',
@ -2008,7 +2005,7 @@ parse_args_with_getopt(struct scrcpy_cli_args *args, int argc, char *argv[],
opts->su_quirk = true; opts->su_quirk = true;
break; break;
case OPT_VIRTUAL_DISPLAY: case OPT_VIRTUAL_DISPLAY:
opts->virtual_display_params = optarg ?: ""; opts->virtual_display_params = optarg;
break; break;
default: default:
// getopt prints the error message on stderr // getopt prints the error message on stderr

View file

@ -3,10 +3,13 @@ package com.genymobile.scrcpy;
import android.annotation.TargetApi; import android.annotation.TargetApi;
import android.content.AttributionSource; import android.content.AttributionSource;
import android.content.MutableContextWrapper; import android.content.MutableContextWrapper;
import android.content.res.Resources;
import android.os.Build; import android.os.Build;
import android.os.Process; import android.os.Process;
import android.system.Os; import android.system.Os;
import java.lang.reflect.Constructor;
public final class FakeContext extends MutableContextWrapper { public final class FakeContext extends MutableContextWrapper {
public static final String PACKAGE_NAME = Os.getuid() == 1000 ? "android" : "com.android.shell"; public static final String PACKAGE_NAME = Os.getuid() == 1000 ? "android" : "com.android.shell";
@ -23,6 +26,17 @@ public final class FakeContext extends MutableContextWrapper {
super(null); super(null);
} }
@Override
public Resources getResources() {
try {
Constructor<?> constructor = Class.forName("android.content.res.Resources").getDeclaredConstructor();
constructor.setAccessible(true);
return (Resources) constructor.newInstance();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
@Override @Override
public String getPackageName() { public String getPackageName() {
return PACKAGE_NAME; return PACKAGE_NAME;

View file

@ -3,7 +3,6 @@ package com.genymobile.scrcpy.wrappers;
import com.genymobile.scrcpy.Command; import com.genymobile.scrcpy.Command;
import com.genymobile.scrcpy.DisplayInfo; import com.genymobile.scrcpy.DisplayInfo;
import com.genymobile.scrcpy.FakeContext; import com.genymobile.scrcpy.FakeContext;
import com.genymobile.scrcpy.IO;
import com.genymobile.scrcpy.Ln; import com.genymobile.scrcpy.Ln;
import com.genymobile.scrcpy.Size; import com.genymobile.scrcpy.Size;
@ -13,10 +12,7 @@ import android.os.Build;
import android.view.Display; import android.view.Display;
import android.view.Surface; import android.view.Surface;
import java.io.IOException;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
@ -29,45 +25,47 @@ public final class DisplayManager {
public VirtualDisplay createVirtualDisplay(String displayParams) { public VirtualDisplay createVirtualDisplay(String displayParams) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) throw new RuntimeException("requires android 10+"); if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) throw new RuntimeException("requires android 10+");
final int VIRTUAL_DISPLAY_FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD = 1 << 5;
final int VIRTUAL_DISPLAY_FLAG_SUPPORTS_TOUCH = 1 << 6;
final int VIRTUAL_DISPLAY_FLAG_ROTATES_WITH_CONTENT = 1 << 7;
final int VIRTUAL_DISPLAY_FLAG_DESTROY_CONTENT_ON_REMOVAL = 1 << 8;
final int VIRTUAL_DISPLAY_FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS = 1 << 9;
final int VIRTUAL_DISPLAY_FLAG_TRUSTED = 1 << 10; final int VIRTUAL_DISPLAY_FLAG_TRUSTED = 1 << 10;
final int VIRTUAL_DISPLAY_FLAG_OWN_DISPLAY_GROUP = 1 << 11;
final int VIRTUAL_DISPLAY_FLAG_ALWAYS_UNLOCKED = 1 << 12; final int VIRTUAL_DISPLAY_FLAG_ALWAYS_UNLOCKED = 1 << 12;
final int VIRTUAL_DISPLAY_FLAG_TOUCH_FEEDBACK_DISABLED = 1 << 13;
try { try {
if (displayParams == null || displayParams.isEmpty()) displayParams = "1920x1080dpi300"; if (displayParams == null || displayParams.isEmpty()) displayParams = "1920x1080dpi300";
String[] displayParamsArray = displayParams.split(","); String resolution = displayParams.toLowerCase().split("dpi")[0];
String resolution = displayParamsArray[0].toLowerCase().split("dpi")[0];
int width = Integer.parseInt(resolution.split("x")[0]); int width = Integer.parseInt(resolution.split("x")[0]);
int height = Integer.parseInt(resolution.split("x")[1]); int height = Integer.parseInt(resolution.split("x")[1]);
int dpi = Integer.parseInt(displayParamsArray[0].toLowerCase().split("dpi")[1]); int dpi = Integer.parseInt(displayParams.toLowerCase().split("dpi")[1]);
//MediaProjectionManager mediaProjectionManager = (MediaProjectionManager)Class.forName("android.media.projection.MediaProjectionManager").getConstructor(Class.forName("android.content.Context")).newInstance(FakeContext.get());
//Intent intent = mediaProjectionManager.createScreenCaptureIntent();
//ServiceManager.getActivityManager().startActivityAsUserWithFeature(intent);
android.hardware.display.DisplayManager displayManager = (android.hardware.display.DisplayManager)Class.forName("android.hardware.display.DisplayManager").getConstructor(Class.forName("android.content.Context")).newInstance(FakeContext.get()); android.hardware.display.DisplayManager displayManager = (android.hardware.display.DisplayManager)Class.forName("android.hardware.display.DisplayManager").getConstructor(Class.forName("android.content.Context")).newInstance(FakeContext.get());
SurfaceTexture surfaceTexture = new SurfaceTexture(false); SurfaceTexture surfaceTexture = new SurfaceTexture(false);
Surface surface = new Surface(surfaceTexture); Surface surface = new Surface(surfaceTexture);
VirtualDisplay[] display = new VirtualDisplay[1]; VirtualDisplay[] display = new VirtualDisplay[1];
display[0] = displayManager.createVirtualDisplay("scrcpy", width, height, dpi, surface, display[0] = displayManager.createVirtualDisplay("test1", width, height, dpi, surface,
android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC
| android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR | android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR
| android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_SECURE | android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_SECURE
| VIRTUAL_DISPLAY_FLAG_TRUSTED | VIRTUAL_DISPLAY_FLAG_TRUSTED
| VIRTUAL_DISPLAY_FLAG_ALWAYS_UNLOCKED); | VIRTUAL_DISPLAY_FLAG_ALWAYS_UNLOCKED,
Ln.i(String.format("Display: %d", display[0].getDisplay().getDisplayId())); new VirtualDisplay.Callback() {
// start launcher @Override
public void onStopped() {
super.onStopped();
surfaceTexture.release();
surface.release();
display[0].release();
}
}, null);
// start launcher or settings activity
// TODO: replace shell commands with proper android framework api call // TODO: replace shell commands with proper android framework api call
String[] cmd; Command.exec("am", "start", "--user", "0", "--display", Integer.toString(display[0].getDisplay().getDisplayId()), "-a", "android.intent.action.MAIN", "-c", "android.intent.category.HOME", "-c", "android.intent.category.DEFAULT");
if (displayParamsArray.length == 1) { //Command.exec("am", "start", "--activity-single-top", "--display", Integer.toString(display.getDisplay().getDisplayId()), "com.android.settings");
cmd = new String[]{"am", "start", "--user", "0", "--display", Integer.toString(display[0].getDisplay().getDisplayId()), "-a", "android.intent.action.MAIN", "-c", "android.intent.category.HOME", "-c", "android.intent.category.DEFAULT"};
}
else {
ArrayList<String> command = new ArrayList<>(Arrays.asList("am", "start", "--display", Integer.toString(display[0].getDisplay().getDisplayId())));
command.addAll(Arrays.asList(Arrays.copyOfRange(displayParamsArray, 1, displayParamsArray.length)));
cmd = command.toArray(new String[0]);
}
Process process = Runtime.getRuntime().exec(cmd);
String output = IO.toString(process.getInputStream());
String error = IO.toString(process.getErrorStream());
int exitCode = process.waitFor();
if (exitCode != 0) {
throw new IOException("Command " + Arrays.toString(cmd) + " returned with value " + exitCode);
}
Ln.i(String.format("stdout: %s\nstderr: %s", output.trim(), error.trim()));
return display[0]; return display[0];
} catch (Exception e) { } catch (Exception e) {
throw new AssertionError(e); throw new AssertionError(e);