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
.
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];
ActivityResultLauncherstartMediaProjection = 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
.
User consent
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 fromcreateScreenCaptureIntent()
togetMediaProjection()
more than once - Calls
createVirtualDisplay()
more than once on the sameMediaProjection
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 projectionSurface
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.
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.