You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让第三方Android应用仅在虚拟屏幕启动而不显示于物理屏幕?

问题描述

目标

希望运行第三方Android应用,但不在物理屏幕上显示。

条件

  • 拥有完整的系统源码(AOSP)
  • 具备root权限

尝试操作

尝试创建虚拟屏幕,并请求应用在虚拟屏幕上显示(以下代码以android.uid.system身份运行)

public static android.hardware.display.VirtualDisplay createDisplay(
        Context context,
        Surface surface,
        String name,
        int height,
        int width,
        int dpi
) {
    DisplayManager displayManager = (DisplayManager) context.getSystemService(Context.DISPLAY_SERVICE);

    android.hardware.display.VirtualDisplay display = displayManager.createVirtualDisplay(
            name, width, height, dpi, surface,
            DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC |
                    DisplayManager.VIRTUAL_DISPLAY_FLAG_SECURE |
                    DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY |
                    DisplayManager.VIRTUAL_DISPLAY_FLAG_PRESENTATION |
                    DisplayManager.VIRTUAL_DISPLAY_FLAG_ROTATES_WITH_CONTENT |
                    DisplayManager.VIRTUAL_DISPLAY_FLAG_TRUSTED |
                    DisplayManager.VIRTUAL_DISPLAY_FLAG_SUPPORTS_TOUCH |
                    /*DisplayManager. VIRTUAL_DISPLAY_FLAG_OWN_FOCUS*/ 1 << 14,
    );

    return display;
}

public static void startApplication(Context context, Display display, String packageName) {
    Intent intent = context.getPackageManager().getLaunchIntentForPackage(packageName)
            .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
            .addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK);

    ActivityOptions options = ActivityOptions.makeBasic()
            .setLaunchDisplayId(display.getDisplayId());

    context.startActivity(intent, options.toBundle());
}

但应用仍会显示在物理屏幕上。


解决方案

1. 确保虚拟屏幕的Surface有效

传入的Surface如果为null或未正确初始化,系统会自动回退到物理屏幕显示。可以创建空的SurfaceTexture生成有效Surface:

// 创建空的SurfaceTexture并设置缓冲区大小
SurfaceTexture surfaceTexture = new SurfaceTexture(0);
surfaceTexture.setDefaultBufferSize(width, height);
Surface surface = new Surface(surfaceTexture);

// 使用该Surface创建虚拟屏幕
VirtualDisplay display = createDisplay(context, surface, name, height, width, dpi);

2. 调整虚拟屏幕的创建参数

  • 移除VIRTUAL_DISPLAY_FLAG_PRESENTATION:该标记针对演示类应用,可能导致系统优先选择物理屏
  • 直接使用VIRTUAL_DISPLAY_FLAG_OWN_FOCUS常量,避免硬编码1 <<14的版本兼容问题
  • 移除VIRTUAL_DISPLAY_FLAG_PUBLIC:公共虚拟屏易被系统识别为辅助显示,而非独立显示

修正后的参数配置:

int flags = DisplayManager.VIRTUAL_DISPLAY_FLAG_SECURE |
            DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY |
            DisplayManager.VIRTUAL_DISPLAY_FLAG_ROTATES_WITH_CONTENT |
            DisplayManager.VIRTUAL_DISPLAY_FLAG_TRUSTED |
            DisplayManager.VIRTUAL_DISPLAY_FLAG_SUPPORTS_TOUCH |
            DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_FOCUS;

VirtualDisplay display = displayManager.createVirtualDisplay(
        name, width, height, dpi, surface, flags
);

3. 强制将应用任务移至虚拟屏幕

若启动时的setLaunchDisplayId不生效,可在应用启动后通过ActivityManager强制迁移任务:

public static void moveAppToDisplay(Context context, String packageName, int displayId) {
    ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
    List<ActivityManager.RunningTaskInfo> tasks = am.getRunningTasks(Integer.MAX_VALUE);
    
    for (ActivityManager.RunningTaskInfo task : tasks) {
        if (task.baseActivity.getPackageName().equals(packageName)) {
            am.moveTaskToDisplay(task.id, displayId);
            break;
        }
    }
}

调用逻辑:先启动应用,延迟300-500毫秒后调用该方法(确保应用任务已创建)。

4. 系统层面修改(基于AOSP源码)

若上述方法仍无效,可修改系统源码实现强制限制:

  • 在ActivityStackSupervisor中添加逻辑,根据目标应用包名强制将其任务分配到指定虚拟屏
  • 修改DisplayManagerService,标记目标虚拟屏为该应用的专属显示

内容的提问来源于stack exchange,提问作者forDream

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 09:47:40