October DealsAmazon USOctober deal check: compare before you payAmazon US: current deals, useful picks and tech finds.Check DealsPC HealthRecommendedCrashes, freezes, slowdowns? Check your PC nowSpot repairable issues before they interrupt work.Check PCOctober DealsAmazon USDeal season is back - check today's better picksAmazon US: current deals, useful picks and tech finds.See Picks×
Skip to content
Android

How to Capture Screenshots from an Android MediaProjection Foreground Service

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Direct answer: Android screen capture that continues after an activity leaves the foreground must run in a user-visible foreground service. The activity obtains fresh MediaProjection consent, starts a service declared with the mediaProjection foreground-service type, and passes the result data to that service. The service registers a projection callback, creates one virtual display connected to your own Surface-based frame pipeline, and releases everything when Android or the user stops projection.

This is not silent capture. The user approves each capture session, Android can revoke it, and createVirtualDisplay() routes frames to a Surface—it does not return a Bitmap or image file by itself.

What “background service” means on modern Android

A process that captures the screen invisibly is not the supported model. In this context, “background service” means a foreground service with a persistent user-visible notification and an active, user-approved MediaProjection session. The activity starts the consent flow; the service owns the projection while the activity is no longer visible.

Android Q (API 29) and newer require projection to run from a foreground service of type mediaProjection. Targets of Android 14 (API 34) and newer have additional ordering and permission rules. A session can end when the user stops sharing, the screen locks, another projection begins, or your process dies.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
#1 Best Overall
Android Screen Recorder
  • Android Screen Recorder

Capture flow at a glance

  1. Request a new consent Intent with MediaProjectionManager.createScreenCaptureIntent().
  2. Show the system consent UI from an Activity and check the result code.
  3. Start a foreground service using the mediaProjection type.
  4. Give the service the result code and Intent data.
  5. Inside the service, call getMediaProjection(), register MediaProjection.Callback, then create one VirtualDisplay connected to your Surface.
  6. Feed Surface frames into a separately designed image encoder/storage pipeline.
  7. On onStop(), release the display, Surface and frame resources; require fresh consent for another session.

Declare the service and permissions

Add the base foreground-service permission. If your app targets API 34 or later, add the media-projection-specific permission and type:

<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PROJECTION" />

<application ...>
    <service
        android:name=".ScreenCaptureService"
        android:exported="false"
        android:foregroundServiceType="mediaProjection" />
</application>

Do not treat these declarations as user consent. The system consent dialog is still required before every capture session.

Request consent in the Activity

Use the Activity Result API (or an equivalent result mechanism) and retain the returned result code and data only for the session you are starting. A denied result must stop the flow.

private val projectionLauncher =
    registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
        if (result.resultCode != Activity.RESULT_OK || result.data == null) {
            // User denied capture; do not start the service.
            return@registerForActivityResult
        }

        val serviceIntent = Intent(this, ScreenCaptureService::class.java).apply {
            action = ScreenCaptureService.ACTION_START
            putExtra(ScreenCaptureService.EXTRA_RESULT_CODE, result.resultCode)
            putExtra(ScreenCaptureService.EXTRA_RESULT_DATA, result.data)
        }

        ContextCompat.startForegroundService(this, serviceIntent)
    }

fun requestScreenCapture() {
    val manager = getSystemService(MediaProjectionManager::class.java)
    projectionLauncher.launch(manager.createScreenCaptureIntent())
}

On Android 14 and later, start the correctly typed foreground service before the service calls getMediaProjection(). The service should call startForeground() promptly with a notification and the media-projection service type.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Rank #2
Recordat - Screen Recorder video for Android
  • One-Tap Screen Recording: Start and stop recording instantly with a single tap.
  • High-Quality Video: Capture your screen in up to 1080p HD resolution and smooth frame rates.
  • Audio Recording: Record internal audio and microphone for complete narration or commentary.
  • Customizable Settings: Choose your preferred resolution, bitrate, and frame rate for the perfect balance of quality and file size.
  • Record with or without Audio: Flexible options for silent or narrated recordings.

Implement the foreground service lifecycle

The following skeleton shows the ordering and teardown. It intentionally leaves frame extraction and file writing behind an explicit interface: those details depend on whether you use an ImageReader, a video encoder, OpenGL, or another Surface consumer and must be threaded and sized for your workload.

class ScreenCaptureService : Service() {
    companion object {
        const val ACTION_START = "capture.START"
        const val ACTION_STOP = "capture.STOP"
        const val EXTRA_RESULT_CODE = "result_code"
        const val EXTRA_RESULT_DATA = "result_data"
    }

    private var projection: MediaProjection? = null
    private var virtualDisplay: VirtualDisplay? = null
    private var captureSurface: Surface? = null
    private var framePipeline: FramePipeline? = null

    private val projectionCallback = object : MediaProjection.Callback() {
        override fun onStop() {
            // Android or the user revoked the session.
            releaseCapture()
            stopSelf()
        }
    }

    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
        when (intent?.action) {
            ACTION_START -> startCapture(intent)
            ACTION_STOP -> {
                releaseCapture()
                stopSelf()
            }
        }
        return START_NOT_STICKY
    }

    private fun startCapture(intent: Intent) {
        val notification = buildCaptureNotification()
        if (Build.VERSION.SDK_INT >= 29) {
            startForeground(
                1001,
                notification,
                ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PROJECTION
            )
        } else {
            startForeground(1001, notification)
        }

        val resultCode = intent.getIntExtra(EXTRA_RESULT_CODE, Activity.RESULT_CANCELED)
        val resultData = intent.getParcelableExtra<Intent>(EXTRA_RESULT_DATA)
            ?: return stopSelf()

        val manager = getSystemService(MediaProjectionManager::class.java)
        projection = manager.getMediaProjection(resultCode, resultData)
        projection?.registerCallback(projectionCallback, Handler(Looper.getMainLooper()))

        // Choose dimensions and create a Surface consumed by your frame pipeline.
        val metrics = resources.displayMetrics
        val width = metrics.widthPixels
        val height = metrics.heightPixels
        val density = metrics.densityDpi
        framePipeline = FramePipeline(width, height).also { it.start() }
        captureSurface = framePipeline!!.surface

        virtualDisplay = projection?.createVirtualDisplay(
            "ScreenCapture",
            width,
            height,
            density,
            DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR,
            captureSurface,
            null,
            null
        )
    }

    private fun releaseCapture() {
        virtualDisplay?.release()
        virtualDisplay = null
        framePipeline?.stop()
        framePipeline = null
        captureSurface?.release()
        captureSurface = null
        projection?.unregisterCallback(projectionCallback)
        projection?.stop()
        projection = null
    }

    override fun onBind(intent: Intent?) : IBinder? = null
    override fun onDestroy() {
        releaseCapture()
        super.onDestroy()
    }
}

The callback must be registered before createVirtualDisplay(). Without registration, display creation can fail with IllegalStateException. A stopped projection cannot create another virtual display.

Turn the Surface stream into a screenshot

MediaProjection supplies authorization and display plumbing. It does not hand you a still image. Your Surface consumer must acquire frames, convert or encode them, and persist the result. Common designs include an ImageReader Surface for CPU-readable frames or a hardware/video pipeline for repeated captures. Whichever design you choose, define ownership and threading clearly:

  • Close each acquired image and release buffers promptly.
  • Keep the producer and consumer dimensions identical, including row stride and pixel format handling.
  • Do not block the projection callback or main thread while encoding or writing files.
  • Bound queues so a slow disk or encoder cannot exhaust memory.
  • Store output in app-private or user-selected storage according to your app’s sharing requirements.

The official projection guidance establishes the session and Surface lifecycle, not one universal still-image extraction recipe. Verify the current API and resource details for your chosen frame reader before shipping.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Rank #3
Screen Recorder : best Screen Recorder with audio
  • ⭐⭐ Read and follow this App institutions ⭐⭐
  • ⭐ Open app slide bar section ⭐.
  • ⭐ Click settings option ⭐.
  • ⭐ We first option see -
  • Audio Configuration ⭐.

Full display versus a selected app window

Scope Privacy boundary Initial dimensions Resize handling
Full device display Everything the user shares, subject to Android’s capture rules Use maximum display bounds for initial sizing Resize the existing display and Surface on configuration changes
User-selected app window Only the window selected in the system dialog Unknown until selection completes Handle onCapturedContentResize(), then resize the existing display and Surface

Android 14 introduced user selection of a single app window. Do not assume its dimensions equal the physical display. For rotation, window changes, or other configuration changes, call VirtualDisplay.resize() and update its Surface rather than creating a second display.

Android 14 session rules

  • Each createVirtualDisplay() call defines a capture session.
  • For apps targeting API 34 or later, one MediaProjection instance can be used for only one such call.
  • The consent result and Intent cannot be reused to obtain multiple projection instances; reuse can produce SecurityException.
  • The user must grant consent before each capture session.

If capture stops, release all resources and run the Activity consent flow again. Do not try to revive a stopped projection by creating another display from the same token.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Troubleshooting

SecurityException from getMediaProjection()

Check that the user approved this session, the service is already running as a media-projection foreground service, and you are not reusing old result data or a projection instance on an API 34-targeting app.

IllegalStateException from display creation

Register MediaProjection.Callback first. Also verify that the projection has not already been stopped and that you create only one virtual display for that session.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Rank #4
Screen recorder - Record screen video for Android
  • - Record screen without root, unlimited screen recording time.
  • - The screen recorder feature is compatible and runs well on all kinds of Android phones such as Samsung, LG, Oppo, Xiaomi, Huawei, etc.
  • - Videos recorded by the application have low capacity and high resolution.
  • - Manage recorded videos: add, edit, delete, share videos recorded with the application.
  • - Useful video editing features Crop video: Cut the part from a video into a new video, Join video: Combine multiple videos into 1 video.

Black, frozen, or empty output

Confirm that a live Surface is attached, the frame consumer is running, and its dimensions match the virtual display. Check that acquired frames are closed and that your encoder or image conversion is not blocking the producer.

Capture ends when the Activity closes

Move projection ownership and frame processing into the foreground service. The Activity should only request consent, pass the result, and provide controls to stop the session.

Wrong size after rotation or window selection

Handle resize callbacks and configuration changes. Resize the existing VirtualDisplay and replace or resize the Surface; do not call createVirtualDisplay() again.

No capture after screen lock or another sharing session

This is an expected revocation path. Release resources in onStop(), notify the user, and require a new consent flow.

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Best Value
RecMe Free Screen Recorder
  • High quality recording to movie
  • No root required
  • Audio recording
  • Camera and controls overlay
  • Free

Performance, reliability, and privacy checklist

  • Use a foreground notification that explains the active capture.
  • Capture only the scope the user selected and stop promptly when they revoke it.
  • Choose the smallest practical dimensions and frame rate for your output.
  • Move image conversion, compression, and file I/O off the main thread.
  • Handle process death and service recreation as a new session; do not assume the old token remains valid.
  • Test rotation, multi-window mode, app-window selection, screen lock, another projection, denied consent, and low-memory conditions.

Or skip the browser setup

If your actual requirement is a screenshot of a web page rather than the Android device display, ScreenshotNeo avoids MediaProjection entirely. One request returns a PNG, JPEG, WebP, or PDF; cookie and consent banners, newsletter popups, and chat widgets are removed before capture. Bot checks, blank pages, failed loads, timeouts, and cache hits are not billed, and response headers identify the page verdict and billing status.

See the ScreenshotNeo API documentation for all options. This cURL example captures a page as WebP:

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp

Equivalent Python:

import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"}, timeout=90)
open("shot.webp", "wb").write(r.content)

Equivalent Node.js:

const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);

ScreenshotNeo also offers an MCP server with take_screenshot, get_page_info, and capture_pdf for Claude, Cursor, and other MCP clients. The Free plan includes 1,000 screenshots per month with no card; paid plans start at $5 for 3,000. Start with a free ScreenshotNeo account.

Frequently Asked Questions

Can MediaProjection capture without showing a notification?

No. Supported background operation requires a user-visible foreground service and an active consent grant.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Can I reuse one consent result for several screenshots?

For API 34-targeting apps, treat each capture session as one consent and one virtual-display call; request consent again after the session ends.

Does createVirtualDisplay() return a Bitmap?

No. It sends display content to your Surface. Frame acquisition, encoding, and storage are separate application code.

What should happen when onStop() fires?

Release the virtual display, Surface, frame resources, and projection, then require fresh consent before starting again.

Quick Recap

Bestseller No. 1
Android Screen Recorder
Android Screen Recorder
Android Screen Recorder
$6.99
Bestseller No. 2
Recordat - Screen Recorder video for Android
Recordat - Screen Recorder video for Android
One-Tap Screen Recording: Start and stop recording instantly with a single tap.; Record with or without Audio: Flexible options for silent or narrated recordings.
Bestseller No. 3
Screen Recorder : best Screen Recorder with audio
Screen Recorder : best Screen Recorder with audio
⭐⭐ Read and follow this App institutions ⭐⭐; ⭐ Open app slide bar section ⭐.; ⭐ Click settings option ⭐.
Bestseller No. 4
Screen recorder - Record screen video for Android
Screen recorder - Record screen video for Android
- Record screen without root, unlimited screen recording time.; - Videos recorded by the application have low capacity and high resolution.
$3.00
Bestseller No. 5
RecMe Free Screen Recorder
RecMe Free Screen Recorder
High quality recording to movie; No root required; Audio recording; Camera and controls overlay

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Leave a Reply

Your email address will not be published. Required fields are marked *

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Read next

Recommended PC Tool
Recommended PC Tool
Crashes, No Sound, or Screen Glitches?Free driver scan
Windows Errors? Fix Them Before They SpreadFree repair scan

Two free Windows tools

One Free Minute Could Fix That PC

Before you go - each of these free tools takes about a minute and tackles what quietly slows a Windows PC down.

Special offer. View Outbyte info, uninstall instructions, EULA, and Privacy Policy.