Compare commits

..

2 commits
test ... master

Author SHA1 Message Date
54fb05837a
refine 2023-09-10 01:14:00 +08:00
85a9871082
virtual display 2023-09-08 17:51:14 +08:00
3 changed files with 34 additions and 43 deletions

View file

@ -552,9 +552,12 @@ static const struct sc_option options[] = {
.longopt_id = OPT_VIRTUAL_DISPLAY,
.longopt = "virtual-display",
.argdesc = "properties",
.optional_arg = true,
.text = "Start a new virtual display for your applications to "
"launch into. Requires Android version >= 10."
"Display size and DPI may be specified. e.g. 1920x1080dpi300"
"launch into. Requires Android version >= 10. "
"Display size and DPI may be specified. e.g. 1920x1080dpi300\n"
"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',
@ -2005,7 +2008,7 @@ parse_args_with_getopt(struct scrcpy_cli_args *args, int argc, char *argv[],
opts->su_quirk = true;
break;
case OPT_VIRTUAL_DISPLAY:
opts->virtual_display_params = optarg;
opts->virtual_display_params = optarg ?: "";
break;
default:
// getopt prints the error message on stderr

View file

@ -3,13 +3,10 @@ package com.genymobile.scrcpy;
import android.annotation.TargetApi;
import android.content.AttributionSource;
import android.content.MutableContextWrapper;
import android.content.res.Resources;
import android.os.Build;
import android.os.Process;
import android.system.Os;
import java.lang.reflect.Constructor;
public final class FakeContext extends MutableContextWrapper {
public static final String PACKAGE_NAME = Os.getuid() == 1000 ? "android" : "com.android.shell";
@ -26,17 +23,6 @@ public final class FakeContext extends MutableContextWrapper {
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
public String getPackageName() {
return PACKAGE_NAME;

View file

@ -3,6 +3,7 @@ package com.genymobile.scrcpy.wrappers;
import com.genymobile.scrcpy.Command;
import com.genymobile.scrcpy.DisplayInfo;
import com.genymobile.scrcpy.FakeContext;
import com.genymobile.scrcpy.IO;
import com.genymobile.scrcpy.Ln;
import com.genymobile.scrcpy.Size;
@ -12,7 +13,10 @@ import android.os.Build;
import android.view.Display;
import android.view.Surface;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@ -25,47 +29,45 @@ public final class DisplayManager {
public VirtualDisplay createVirtualDisplay(String displayParams) {
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_OWN_DISPLAY_GROUP = 1 << 11;
final int VIRTUAL_DISPLAY_FLAG_ALWAYS_UNLOCKED = 1 << 12;
final int VIRTUAL_DISPLAY_FLAG_TOUCH_FEEDBACK_DISABLED = 1 << 13;
try {
if (displayParams == null || displayParams.isEmpty()) displayParams = "1920x1080dpi300";
String resolution = displayParams.toLowerCase().split("dpi")[0];
String[] displayParamsArray = displayParams.split(",");
String resolution = displayParamsArray[0].toLowerCase().split("dpi")[0];
int width = Integer.parseInt(resolution.split("x")[0]);
int height = Integer.parseInt(resolution.split("x")[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);
int dpi = Integer.parseInt(displayParamsArray[0].toLowerCase().split("dpi")[1]);
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);
Surface surface = new Surface(surfaceTexture);
VirtualDisplay[] display = new VirtualDisplay[1];
display[0] = displayManager.createVirtualDisplay("test1", width, height, dpi, surface,
display[0] = displayManager.createVirtualDisplay("scrcpy", width, height, dpi, surface,
android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC
| android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR
| android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_SECURE
| VIRTUAL_DISPLAY_FLAG_TRUSTED
| VIRTUAL_DISPLAY_FLAG_ALWAYS_UNLOCKED,
new VirtualDisplay.Callback() {
@Override
public void onStopped() {
super.onStopped();
surfaceTexture.release();
surface.release();
display[0].release();
}
}, null);
// start launcher or settings activity
| VIRTUAL_DISPLAY_FLAG_ALWAYS_UNLOCKED);
Ln.i(String.format("Display: %d", display[0].getDisplay().getDisplayId()));
// start launcher
// TODO: replace shell commands with proper android framework api call
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");
//Command.exec("am", "start", "--activity-single-top", "--display", Integer.toString(display.getDisplay().getDisplayId()), "com.android.settings");
String[] cmd;
if (displayParamsArray.length == 1) {
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];
} catch (Exception e) {
throw new AssertionError(e);