Media projection

The android.media.projection APIs introduced in Android 5 (API level 21) enable you to capture the contents of a device display as a media stream that you can play back, record, or cast to other devices, such as TVs.

Android 14 (API level 34) introduces app screen sharing, which enables users to share a single app window instead of the entire device screen regardless of windowing mode. App screen sharing excludes the status bar, navigation bar, notifications, and other system UI elements from the shared display—even when app screen sharing is used to capture an app in full screen. Only the contents of the selected app are shared.

App screen sharing ensures user privacy, increases user productivity, and enhances multitasking by enabling users to run multiple apps but restrict content sharing to just a single app.

Three display representations

A media projection captures the contents of a device display or app window and then projects the captured image to a virtual display that renders the image on a Surface.

Real device display projected onto virtual display. Contents of
              virtual display written to application-provided `Surface`.
Figure 1. Real device screen or app window projected onto virtual display. Virtual display written to application-provided Surface.

The application provides the Surface by means of a MediaRecorder, SurfaceTexture, or ImageReader, which consumes the contents of the captured display and enables you to manage images rendered on the Surface in real time. You can save the images as a recording or cast them to a TV or other device.

Real display

Begin a media projection session by obtaining a token that grants your app the ability to capture the contents of the device display or app window. The token is represented by an instance of the MediaProjection class.

Use the getMediaProjection() method of the MediaProjectionManager system service to create a MediaProjection instance when you start a new activity. Start the activity with an intent from the createScreenCaptureIntent() method to specify a screen capture operation:

Kotlin

val mediaProjectionManager = getSystemService(MediaProjectionManager::class.java)
var mediaProjection : MediaProjection
val startMediaProjection = registerForActivityResult( StartActivityForResult() ) { result -> if (result.resultCode == RESULT_OK) { mediaProjection = mediaProjectionManager .getMediaProjection(result.resultCode, result.data!!) } }
startMediaProjection.launch(mediaProjectionManager.createScreenCaptureIntent())

Java

final MediaProjectionManager mediaProjectionManager =
    getSystemService(MediaProjectionManager.class);
final MediaProjection[] mediaProjection = new MediaProjection[1];
ActivityResultLauncher startMediaProjection = registerForActivityResult( new StartActivityForResult(), result -> { if (result.getResultCode() == Activity.RESULT_OK) { mediaProjection[0] = mediaProjectionManager .getMediaProjection(result.getResultCode(), result.getData()); } } );
startMediaProjection.launch(mediaProjectionManager.createScreenCaptureIntent());

Virtual display

The centerpiece of a media projection is the virtual display, which you create by calling createVirtualDisplay() on a MediaProjection instance:

Kotlin

virtualDisplay = mediaProjection.createVirtualDisplay(
                     "ScreenCapture",
                     width,
                     height,
                     screenDensity,
                     DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR,
                     surface,
                     null, null)

Java

virtualDisplay = mediaProjection.createVirtualDisplay(
                     "ScreenCapture",
                     width,
                     height,
                     screenDensity,
                     DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR,
                     surface,
                     null, null);

The width and height parameters specify the dimensions of the virtual display. To obtain values for width and height, use the WindowMetrics APIs introduced in Android 11 (API level 30). (For details, see the Media projection size section.)

Surface

Size the media projection surface to produce output in the appropriate resolution. Make the surface large (low resolution) for screen casting to TVs or computer monitors and small (high resolution) for device display recording.

As of Android 12L (API level 32), when rendering captured content on the surface, the system scales the content uniformly, maintaining the aspect ratio, so that both dimensions of the content (width and height) are equal to or less than the corresponding dimensions of the surface. The captured content is then centered on the surface.

The Android 12L scaling approach improves screen casting to televisions and other large displays by maximizing the size of the surface image while ensuring the proper aspect ratio.

Foreground service permission

If your app targets Android 14 or higher, the app manifest must include a permission declaration for the mediaProjection foreground service type:

<manifest ...>
    <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
    <uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PROJECTION" />
    <application ...>
        <service
            android:name=".MyMediaProjectionService"
            android:foregroundServiceType="mediaProjection"
            android:exported="false">
        </service>
    </application>
</manifest>

Start the media projection service with a call to startForeground().

If you don't specify the foreground service type in the call, the type defaults to a bitwise integer of the foreground service types defined in the manifest. If the manifest doesn't specify any service types, the system throws MissingForegroundServiceTypeException.

Your app must request user consent before each media projection session. A session is a single call to createVirtualDisplay(). A MediaProjection token must be used only once to make the call.

On Android 14 or higher, the createVirtualDisplay() method throws a SecurityException if your app does either of the following:

  • Passes an Intent instance returned from createScreenCaptureIntent() to getMediaProjection() more than once
  • Calls createVirtualDisplay() more than once on the same MediaProjection instance

Media projection size

A media projection can capture the entire device display or an app window regardless of windowing mode.

Initial size

With full-screen media projection, your app must determine the size of the device screen. In app screen sharing, your app won't be able to determine the size of the captured display until the user has selected the capture region. So, the initial size of any media projection is the size of the device screen.

Use the platform WindowManager getMaximumWindowMetrics() method to return a WindowMetrics object for the device screen even if the media projection host app is in multi‑window mode, occupying only part of the display.

For compatibility down to API level 14, use the WindowMetricsCalculator computeMaximumWindowMetrics() method from the Jetpack WindowManager library.

Call the WindowMetrics getBounds() method to get the width and height of the device display.

Size changes

The size of the media projection can change when the device is rotated or the user selects an app window as the capture region in app screen sharing. The media projection might be letterboxed if the captured content is a different size than the maximum window metrics obtained when the media projection was set up.

To ensure the media projection precisely aligns with the size of the captured content for any captured region and across device rotations, use the onCapturedContentResize() callback to resize the capture. (For more information, see the Customization section, which follows).

Customization

Your app can customize the media projection user experience with the following MediaProjection.Callback APIs:

  • onCapturedContentVisibilityChanged(): Enables the host app (the app that started the media projection) to show or hide the shared content.

    Use this callback to customize your app's UI based on whether the captured region is visible to the user. For example, if your app is visible to the user and is displaying the captured content within the app's UI, and the captured app is also visible to the user (as indicated through this callback), the user sees the same content twice. Use the callback to update your app's UI to hide the captured content and free up layout space in your app for other content.

  • onCapturedContentResize(): Enables the host app to change the size of the media projection on the virtual display and media projection Surface based on the size of the captured display region.

    Triggered whenever the captured content—a single app window or full device display—changes size (because of device rotation or the captured app entering a different windowing mode). Use this API to resize both the virtual display and surface to ensure the aspect ratio matches the captured content and the capture is not letterboxed.

Resource recovery

Your app should register the MediaProjection onStop() callback to be informed when the media projection session is stopped and becomes invalid. When the session is stopped, your app should release the resources that it holds, such as the virtual display and projection surface. A stopped media projection session can no longer create a new virtual display, even if your app has not previously created a virtual display for that media projection.

The system invokes the callback when the media projection terminates. This termination can happen for several reasons, such as:

  • the user stops the session using the app's UI or the system's media projection status bar chip
  • the screen is being locked
  • another media projection session starts
  • the app process is killed

If your app doesn't register the callback, any call to createVirtualDisplay() throws IllegalStateException.

Opt out

Android 14 or higher enables app screen sharing by default. Each media projection session gives users the option of sharing an app window or the entire display.

Your app can opt out of app screen sharing by calling the createScreenCaptureIntent(MediaProjectionConfig) method with a MediaProjectionConfig argument returned from a call to createConfigForDefaultDisplay().

A call to createScreenCaptureIntent(MediaProjectionConfig) with a MediaProjectionConfig argument returned from a call to createConfigForUserChoice() is the same as the default behavior, that is, a call to createScreenCaptureIntent().

Resizable apps

Always make your media projection apps resizable (resizeableActivity="true"). Resizable apps support device configuration changes and multi‑window mode (see Multi-window support).

If your app is not resizable, it must query the display bounds from a window context and use getMaximumWindowMetrics() to retrieve the WindowMetrics of the maximum display area available to the app :

Kotlin

val windowContext = context.createWindowContext(context.display!!,
      WindowManager.LayoutParams.TYPE_APPLICATION, null)
val projectionMetrics = windowContext.getSystemService(WindowManager::class.java)
      .maximumWindowMetrics

Java

Context windowContext = context.createWindowContext(context.getDisplay(),
      WindowManager.LayoutParams.TYPE_APPLICATION, null);
WindowMetrics projectionMetrics = windowContext.getSystemService(WindowManager.class)
      .getMaximumWindowMetrics();

Status bar chip and auto stop

Screen projection exploits expose private user data such as financial information because users don't realize their device screen is being shared.

Android 15 (API level 35) and higher display a status bar chip that is large and prominent to alert users to any in‑progress screen projection. Users can tap the chip to stop their screen from being shared, cast, or recorded. Also, screen projection automatically stops when the device screen is locked.

Figure 2. Status bar chip for screen sharing, casting, and recording.

Test the availability of the media projection status bar chip by starting screen sharing, casting, or recording. The chip should appear in the status bar.

To ensure your app releases resources and updates its UI when screen projection is stopped by user interaction with the status bar chip or by lock screen activation, do the following:

  • Create an instance of MediaProjection.Callback.

  • Implement the callback onStop() method. The method is called when screen projection stops. Release any resources your app is holding and update the app UI as needed.

To test the callback, tap the status bar chip or lock the device screen to stop screen projection. Verify that the onStop() method is called and your app responds as intended.

Additional resources

For more information about media projection, see Capture video and audio playback.