How to start an Android application on a virtual screen?

478 views Asked by At

Goal

I want to run an Android app (third-party), but not show it on the physical screen.

Conditions

  • Have the complete system source code (AOSP)
  • Have root permission

Attempts

  • Try to create a virtual screen, and request the app to display on the virtual screen (the following code runs with 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());
    }

But the app will show on the real screen.


Did I miss something?

What should I do to make the specified application only appear on the virtual display, not on the physical screen?

2

There are 2 answers

1
Robbit On

It's easy, to remove your app's surface from the Output layer.

0
Devang Bhavsar On

bellow is working one.

 void startActivity(Surface mySurface){
    // Get the DisplayManager
    DisplayManager displayManager = (DisplayManager) getSystemService(Context.DISPLAY_SERVICE);
    DisplayMetrics displayMetrics = getResources().getDisplayMetrics();

    virtualDisplay = displayManager.createVirtualDisplay(
            "MyVirtualDisplay", // Name of the virtual display
            1920, 1280, // Width and height
            displayMetrics.densityDpi, // Screen density
            mySurface, // Surface for the virtual display
            DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC // Flags
    );

    // Identify the presentation display based on your criteria, e.g., display ID
    Display presentationDisplay = null;
    presentationDisplay = virtualDisplay.getDisplay();



    if (presentationDisplay != null) {
        // Create an Intent to launch the app by its package name
        String packageName = "com.mypackage.name"; // Replace with the actual package name of the app you want to open
        Intent intent = getPackageManager().getLaunchIntentForPackage(packageName);

        if (intent != null) {
            // Set the target display for the intent (presentation display)
            int displayId = virtualDisplay.getDisplay().getDisplayId();
            ActivityOptions options = ActivityOptions.makeBasic().setLaunchDisplayId(displayId);
            intent.addFlags(Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT | Intent.FLAG_ACTIVITY_NEW_TASK);

            startActivity(intent, options.toBundle());
        } else {
            // The app with the specified package name is not installed on the device
            // Handle this case accordingly
        }
    } else {
        // Presentation display not found or criteria not met
        // Handle this case accordingly
    }

}

Call from below method :

void createVirtualDisplay(){
    SurfaceView surfaceView = findViewById(R.id.my_surface_view);
    SurfaceHolder holder = surfaceView.getHolder();
    holder.addCallback(new SurfaceHolder.Callback() {
        @RequiresApi(api = Build.VERSION_CODES.O)
        @Override
        public void surfaceCreated(SurfaceHolder holder) {
            // You can use the holder.getSurface() here
            Surface mySurface = holder.getSurface();
            startActivity(mySurface);
        }

        @Override
        public void surfaceChanged(@NonNull SurfaceHolder surfaceHolder, int i, int i1, int i2) {

        }

        @Override
        public void surfaceDestroyed(@NonNull SurfaceHolder surfaceHolder) {

        }

        // Implement other callback methods
    });
}

I don't know how to apply interection on it. So better someone add more details on it.

Thanks,