0

I have an Android screen recording app. In my app the user can start a screen recording directly in the app, as well as via a button in a notification (bound to a foreground service).

To start a recording I retrieve the intent for creating media projections via the screen recording system dialog: startActivityForResult(activity, mediaProjectionManager.createScreenCaptureIntent(), requestId)

This intent is later used to create a MediaProjection, which is again used to acquire a VirtualDisplay for the screen recording.

In order to avoid having to start a screen recording system dialog every time the user starts a recording via the notification from my foreground service, I save the original Intent for creating media projections in the service and then simply reuse that Intent. This worked fine up to Android 14 (API 34).

During my testing with the Android 14 Preview I found out that this does not seem to be possible anymore. According to the exception thrown it is not allowed anymore to retrieve a MediaProjection with the same Intent OR create multiple virtual displays with the same MediaProjection.

FATAL EXCEPTION: main
Process: com.recording.app.staging, PID: 19029
                 java.lang.SecurityException: Don't re-use the resultData to retrieve the same projection instance, and don't use a token that has timed out. Don't take multiple captures by invoking MediaProjection#createVirtualDisplay multiple times on the same instance.
                    at android.os.Parcel.createExceptionOrNull(Parcel.java:3057)
                    at android.os.Parcel.createException(Parcel.java:3041)
                    at android.os.Parcel.readException(Parcel.java:3024)
                    at android.os.Parcel.readException(Parcel.java:2966)
                    at android.hardware.display.IDisplayManager$Stub$Proxy.createVirtualDisplay(IDisplayManager.java:1425)
                    at android.hardware.display.DisplayManagerGlobal.createVirtualDisplay(DisplayManagerGlobal.java:643)
                    at android.hardware.display.DisplayManager.createVirtualDisplay(DisplayManager.java:1134)
                    at android.media.projection.MediaProjection.createVirtualDisplay(MediaProjection.java:247)
                    at android.media.projection.MediaProjection.createVirtualDisplay(MediaProjection.java:216)
                    at com.recording.app.model.service.recording.resource.MediaProjectionResource.createVirtualDisplay(MediaProjectionResource.kt:39)
                 Caused by: android.os.RemoteException: Remote stack trace:
                    at com.android.server.media.projection.MediaProjectionManagerService$MediaProjection.isValid(MediaProjectionManagerService.java:1081)
                    at com.android.server.display.DisplayManagerService.createVirtualDisplayInternal(DisplayManagerService.java:1447)
                    at com.android.server.display.DisplayManagerService.-$$Nest$mcreateVirtualDisplayInternal(DisplayManagerService.java:0)
                    at com.android.server.display.DisplayManagerService$BinderService.createVirtualDisplay(DisplayManagerService.java:3706)
                    at android.hardware.display.IDisplayManager$Stub.onTransact(IDisplayManager.java:730)com.android.server.media.projection.MediaProjectionManagerService$MediaProjection.isValid(MediaProjectionManagerService.java:1081)

...

Is there still a way to allow my users to only grant the screen recording permission once and then to directly start a recording (as long as my service was not killed)?

Maybe it is possible to keep and reuse a single VirtualDisplay, but that also does not seem like a good solution because the display would mirror the real display even if there was no recording going on, wasting resources.

If that does not work, my only remaining option is to always ask the user for permission. But I am also unsure whether that works when the user has opened a different app and only wants to start the recording via notification.

Did I miss something? Any insights are greatly appreciated!

Update

After some more testing:

  • Reusing the same Intent to retrieve multiple MediaProjections is not possible
  • Reusing a single MediaProjection instance to get multiple VirtualDisplays also seems impossible
  • It is possible to reuse a single VirtualDisplay instance to do multiple recordings, but seems hacky

Outcome

It is possible to do multiple recordings with a single VirtualDisplay by always updating the target surface using

virtualDispaly.surface = newRecordingSurface

However, this seems hacky and not intended because the system UI will show that the app is recording the screen as long as the VirtualDisplay is active. So even if my app is not "really" capturing the screen (because no target surface is set for the VirtualDisplay) the system UI still shows like it is.

This would look very concerning for a user and the user can also just stop the screen capture at which point the VirtualDisplay seems to be broken. Therefore, I decided to remove the functionality, to start a recording from my foreground service, until I find a better option.

jhain
  • 1
  • 1

0 Answers0