How to Test Screen Sharing on Android (Complete Guide)

Screen sharing is a core feature for collaboration apps, remote support tools, live‑streaming platforms, and any software that lets a user broadcast what is on their display. On Android the feature re

January 09, 2026 · 17 min read · How-To Guides

Why Screen Sharing Matters on Android

Screen sharing is a core feature for collaboration apps, remote support tools, live‑streaming platforms, and any software that lets a user broadcast what is on their display. On Android the feature relies on the MediaProjection API, which grants such as video‑conferencing, tele‑health, or field‑service, a broken share can halt a meeting, expose private data, or cause a crash that leads to poor ratings and churn. Because the feature touches several system layers—UI rendering, permission model, media codecs, and network transport—defects are often subtle and only surface under specific device states or user interactions. Understanding where things can go wrong helps you build a test strategy that catches regressions before they reach users.

Common Failure Modes in Production

When screen sharing goes awry in the wild, the symptoms usually fall into one of these buckets:

Failure CategoryTypical SymptomRoot Cause (Android‑specific)
Permission denialShare button does nothing or shows a toast “Permission denied”Missing android.permission.SYSTEM_ALERT_WINDOW or android.permission.FOREGROUND_SERVICE; MediaProjection not granted via result callback
Black or frozen videoRemote participants see a static frame or a black screenSurface not released, SurfaceTexture not updated, or hardware encoder stuck due to insufficient buffer allocation
Audio‑video driftAudio continues while video freezes or lagsMismatched timestamps between MediaCodec output and audio track; improper use of ImageReader vs AudioRecord
Overlay interferenceShare UI appears but is obscured by system dialogs or other appsMissing TYPE_APPLICATION_OVERLAY flag, or another app with higher window‑type priority covering the preview
Security leakageSensitive content appears in the share despite FLAG_SECUREApp forgets to call setSecure(true) on the window or uses a non‑secure Surface for capture
Crash / ANRApp stops responding when sharing starts or stopsLong‑running work on the main thread (e.g., blocking ImageReader.acquireLatestImage()), or failure to release the MediaProjection token on onStop
Resource leakDevice gets hot, battery drains quickly after a share sessionMediaCodec or ImageReader not released, leading to orphaned buffers and continuous GPU usage
Compatibility breakShare works on Pixel but fails on Samsung/OnePlusOEM‑specific restrictions on MediaProjection, custom power‑saving policies, or altered WindowManager behavior

Each of these categories can be reproduced in a test lab if you know which knobs to turn. The next section lays out a matrix that captures the dimensions you need to exercise.

Test Matrix for Screen Sharing

The following table maps test dimensions (rows) against scenarios (columns). Mark a cell with when the scenario should be exercised for that dimension, and leave it blank when it is not applicable. Use this matrix to generate both manual test scripts and automated test cases.

Dimension \ ScenarioHappy‑Path Share StartShare Stop Mid‑SessionPermission DeniedBlack Screen InjectionOverlap with System AlertLow‑Bandwidth NetworkPicture‑in‑Picture (PiP) ModeMulti‑Window (Split‑Screen)Accessibility Service ActiveDevice Administrator PolicyFLAG_SECURE WindowBattery‑Saver Mode
Functional correctness
Performance & latency
Security & privacy
Accessibility (WCAG)
Stability (crash/ANR)
Resource management
Compatibility (OEM)
Regression (post‑update)

How to read the matrix

You can turn each checked cell into a concrete test case. The next two sections show how to execute them manually and then how to automate the repetitive parts.

Manual Testing Approach

Setup

  1. Device preparation – Use a physical device (API 21+). Disable battery optimizations for the test app (Settings > Apps > [YourApp] > Battery > Unrestricted). Enable Developer options → Stay awake while charging to prevent the screen from turning off mid‑test.
  2. Instrumentation – Install adb version ≥ 1.0.40. Grant the app the android.permission.SYSTEM_ALERT_WINDOW via adb shell pm grant your.package.name android.permission.SYSTEM_ALERT_WINDOW.
  3. Log capture – Start adb logcat -v threadtime > screenshare.log & to collect timestamps, exceptions, and MediaProjection callbacks.
  4. Remote viewer – Set up a simple receiver (e.g., ffplay -framerate 30 -i udp://@:5000?overrun_nonfatal=1) to view the streamed frames, or use the companion app’s preview if it exists.
  5. Baseline – Run a happy‑path share for 30 seconds and note the average frame‑rate (target ≥ 24 fps) and end‑to‑end latency (measure with a timestamp overlay).

Step‑by‑Step Test Cases

#ScenarioActionsExpected Observation
1Happy‑path startTap “Share Screen” → grant MediaProjection via system dialog → confirm preview appearsPreview shows live UI, no black frames, audio continues if applicable
2Share stop mid‑sessionWhile sharing, press Back or tap “Stop Share”Preview stops, MediaProjection token released, no leftover Surface in logcat
3Permission deniedDeny the system MediaProjection dialogApp shows a toast/error, no preview, onResult returns RESULT_CANCELED
4Black screen injectionUse adb shell service call media_projection 1 i32 0 to simulate a null resultApp handles null data gracefully, does not crash, shows error UI
5Overlap with system alertTrigger a system alert (e.g., incoming call) while sharingShare preview is paused or hidden; after call ends, sharing resumes without glitch
6Low‑bandwidth networkConnect device to a Wi‑Fi network throttled to 500 kbps (via tc on a router)Video quality degrades gracefully, no freeze, audio stays in sync
7Picture‑in‑PictureWhile sharing, swipe up to home → app enters PiPSharing continues in the small PiP window, UI scales correctly
8Multi‑window (split‑screen)Drag the app to top/bottom half, open another app in the other halfShare continues, preview respects the allocated window size
9Accessibility service activeEnable TalkBack, start sharingTalkBack still reads UI elements; share preview does not interfere with focus order
10Device administrator policySet a policy that disables screen capture (DevicePolicyManager.setScreenCaptureDisabled(true))Share request is immediately denied, appropriate error shown
11FLAG_SECURE windowOpen a Dialog with getWindow().setSecure(true) before starting shareContent inside the dialog appears black in the shared stream, but rest of UI is visible
12Battery‑saver modeEnable Battery Saver, start shareShare works but may drop frame‑rate; verify that the app respects the power‑save hint (lower encoder bitrate)

During each step, watch logcat for:

Record the outcome in a spreadsheet; any deviation from the expected observation flags a defect.

Observations and Logging

Manual testing is invaluable for catching UX‑specific glitches (e.g., a button that becomes unreachable when the share preview overlays it). However, repeating the matrix on every build is tedious. The next section shows how to automate the repeatable parts while retaining the ability to explore edge cases that scripts often miss.

Automated Testing Strategies

Using Espresso/UIAutomator for Interaction Flows

Espresso excels at verifying UI state before and after a share action. UIAutomator can cross‑app boundaries, which is useful for granting the MediaProjection permission via the system dialog.


// ShareScreenTest.kt
@RunWith(AndroidJUnit4::class)
class ShareScreenTest {

    @get:Rule
    val activityRule = ActivityTestRule(MainActivity::class.java)

    @Test
    fun happyPathShareStartAndStop() {
        // Click share button
        onView(withId(R.id.btn_share)).perform(click())

        // Grant permission via UIAutomator (system dialog)
        val uiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
        val allowButton = uiDevice.findObject(By.text("Allow"))
        assertTrue("Allow button not found", allowButton.exists())
        allowButton.click()

        // Verify preview SurfaceView appears
        onView(withId(R.id.preview_surface)).check(matches(isDisplayed()))

        // Simulate stopping share
        onView(withId(R.id.btn_stop)).perform(click())
        onView(withId(R.id.preview_surface)).check(matches(not(isDisplayed())))

        // Ensure MediaProjection callback fired
        val activity = activityRule.activity
        assertFalse("Projection still active", activity.isProjectionActive())
    }
}

What this covers

Direct MediaProjection API Unit Tests

You can unit‑test the core capture logic without launching a full UI by using a mock ImageReader and a CountDownLatch to verify that frames are produced.


// MediaCaptureTest.java
@Test
public void testFrameProduction() throws Exception {
    final CountDownLatch latch = new CountDownLatch(1);
    final AtomicLong lastTimestamp = new AtomicLong(-1);

    ImageReader reader = ImageReader.newInstance(
        1080, 1920, ImageFormat.YUV_420_888, 2, new Handler(Looper.getMainLooper()));
    reader.setOnImageAvailableListener(reader1AvailableListener(reader1 -> {
        Image img = reader1.acquireLatestImage();
        long ts = img.getTimestamp();
        assertTrue("Timestamp went backwards", ts > lastTimestamp.get());
        lastTimestamp.set(ts);
        img.close();
        latch.countDown();
    }, null);

    // Simulate a projection that feeds the reader
    MediaProjection projection = createMockProjection(reader.getSurface());
    projection.start(); // hypothetical method that begins feeding frames

    boolean success = latch.await(5, TimeUnit.SECONDS);
    assertTrue("No frames received within timeout", success);
    reader.close();
    projection.stop();
}

The test asserts that timestamps strictly increase, catching encoder stalls or buffer reuse bugs.

ADB‑Based Stress Scripts

For long‑running stability checks, a simple Bash loop can start/stop sharing many times while monitoring logcat for crashes.


#!/usr/bin/env bash
PACKAGE=com.example.screenshare
ITERATIONS=200
LOG=adb_stress.log

echo "Starting stress test – $ITERATIONS iterations" > $LOG
for ((i=1; i<=ITERATIONS; i++)); do
    echo "Iteration $i" >> $LOG
    # Launch share via a hidden activity or a shortcut
    adb shell am start -n $PACKAGE/.ShareLauncherActivity >> $LOG 2>&1
    sleep 2   # allow share to start
    # Stop share
    adb shell am broadcast -a com.example.STOP_SHARE >> $LOG 2>&1
    sleep 1
    # Check for any crash or ANR since last iteration
    adb logcat -d -b crash >> $LOG 2>&1
    adb logcat -d -b system >> $LOG 2>&1
done
echo "Stress test finished" >> $LOG

You can extend the script to vary network conditions (adb shell cmd netpolicy set ...) or toggle battery‑saver between iterations.

Leveraging SUSA for Autonomous, Persona‑Driven Exploration

SUSA explores an app without pre‑written scripts by simulating distinct user personas. When you point SUSA at your screen‑sharing feature, it will:

  1. Curious persona – Tap every visible element, long‑press on the preview, try to drag the share UI off‑screen.
  2. Impatient persona – Rapidly toggle the share button, spam the stop action, and attempt to start a second share while the first is still initializing.
  3. Novice persona – Follow system prompts literally, often denying permission the first time, then granting after a toast appears.
  4. Adversarial persona – Inject malicious intents (e.g., broadcast android.media.projection.action.START with a crafted Intent) to see if the app mishandles unsolicited projection tokens.
  5. Elderly persona – Use larger font sizes and slower interaction timing; verify that UI elements remain reachable.
  6. Accessibility persona – Enable TalkBack and Switch Control, then attempt to start a share via accessibility shortcuts.
  7. Power‑user persona – Open developer options, force GPU rendering, enable “Don’t keep activities”, and observe if the share survives activity recreation.

Susa’s cross‑session memory means that after a first run it remembers which screens led to dead ends (e.g., a permission denial that crashes the app) and avoids repeating fruitless paths, focusing instead on novel combinations like “share while in PiP with TalkBack enabled and battery‑saver on”. The output includes a concise PASS/FAIL matrix for each user flow (login → share → stop) and a list of discovered issues such as:

These are precisely the scenarios that hand‑written automated tests often overlook because they combine multiple system states that are difficult to anticipate in isolation. By running SUSA on each PR, you get a safety net that complements your deterministic Espresso/UIAutomator suite.

Choosing the Right Tool for Each Matrix Cell

Test DimensionBest Fit ToolReason
Permission flow & UI stateEspresso + UIAutomatorPrecise assertion on view visibility and system dialog handling
Frame‑rate & timestamp validationJUnit + mocked ImageReaderAllows deterministic checking of MediaCodec output without UI
Long‑running stability / stressBash/ADB loopEasy to repeat hundreds of cycles and capture crash logs
Battery‑saver, network throttling, PiP, multi‑windowADB shell commands (cmd, wm) combined with UIAutomator for navigation
Accessibility & font scalingUIAutomator with UiObject2.setText() and accessibility service enabled
Adversarial / unexpected intentsSUSA (persona‑driven) or custom adb am broadcast fuzzing
Regression after code changeCombination of the above, stored as CI jobs; Susa provides a baseline “smoke” set that expands over time

By aligning each matrix cell with the most efficient technique, you keep test execution time low while still achieving high coverage.

Edge Cases That Appear Only in Production

Even the most exhaustive lab matrix can miss conditions that arise only when the app runs in the wild. Below are the most common production‑only pitfalls for screen sharing on Android, along with concrete ways to surface them in a test environment.

1. Network Variability Beyond Simple Throttling

Production networks exhibit bursty loss, jitter, and occasional reconnects. A steady 500 kbps pipe does not capture the effect of a sudden drop to 50 kbps for 2 seconds followed by a spike to 5 Mbps. To emulate this:


# Using tc netem on a Linux router or on the device if rooted
adb shell su -c "tc qdisc add dev wlan0 root netem loss 10% delay 100ms distribution normal"
# Simulate a burst
adb shell su -c "tc qdisc change dev wlan0 root netem loss 30% delay 300ms"
sleep 5
adb shell su -c "tc qdisc change dev wlan0 root netem loss 0% delay 0ms"

Observe whether the encoder adapts its bitrate, whether the app drops frames gracefully, and whether the MediaCodec recovers without dropping the Surface.

2. Multi‑Window and Picture‑in‑Picture Interactions

Some OEMs treat the preview Surface as a normal window; others assign it a higher z‑order when the app is in PiP. Test the following sequence on a device with split‑screen support:

  1. Launch the app in the left half of split‑screen.
  2. Start screen sharing.
  3. Drag the divider to make the app’s width less than 360 dp (the minimum width for many UI elements).
  4. Verify that the preview does not get clipped and that touch events still reach the share controls.

On certain Samsung devices, the system may automatically pause the projection when the app becomes invisible; ensure your MediaProjectionCallback#onStop handler re‑requests a new projection if the user returns to the app.

3. Manufacturer‑Specific MediaProjection Restrictions

Xiaomi’s MIUI, Huawei’s EMUI, and OnePlus’s OxygenOS sometimes require an additional android.permission.READ_EXTERNAL_STORAGE for the projection to work, or they impose a background execution limit that kills the service after a few minutes. To test:

The fix often involves moving the capture work to a foreground service with a persistent notification.

4. Overlay Permission Conflicts

If your app also uses a custom overlay (e.g., a floating chat head), the system may grant the overlay permission but deny the MediaProjection request because both request SYSTEM_ALERT_WINDOW. Some devices treat the first granted permission as the winner, causing the second to silently fail. Test by:

  1. Granting overlay permission via settings.
  2. Starting the share flow.
  3. Checking adb logcat | grep MediaProjection for PermissionDenialException.

If you see a denial, restructure your app to request the projection *before* showing any overlay, or merge both functionalities into a single window with the appropriate flags.

5. Accessibility Service Interference

Services like TalkBack or Switch Control can capture touch events and deliver them with added latency. When a user enables these services, the share UI might become unresponsive because the accessibility service intercepts the tap before it reaches your view. To validate:

If the press is lost, consider exposing an alternative activation method (e.g., a voice command or a persistent notification action) that bypasses the touch layer.

6. FLAG_SECURE and Secure Surface Conflicts

Some apps deliberately mark certain windows as secure (e.g., payment dialogs). If you attempt to share the entire screen while a secure window is present, the projection will black out that region. A subtle bug occurs when the app *temporarily* marks its own window as secure (perhaps to protect a credential field) and then forgets to clear the flag before starting the share. The result is a partially blacked‑out stream that users may not notice until they see missing UI elements. Test by:


// In your test
activity.window.addFlags(WindowManager.LayoutParams.FLAG_SECURE)
activity.shareScreen() // should still show non-secure parts
activity.window.clearFlags(WindowManager.LayoutParams.FLAG_SECURE)

Check the captured frames (you can save them via ImageReader to disk) for any unexpected black rectangles.

7. Battery‑Saver and Thermal Throttling

When the device reaches a high temperature, the system may clamp the CPU frequency and also lower the maximum bitrate allowed for video encoders. This can cause the encoder to drop frames or produce low‑quality output without raising an error. To simulate:


adb shell cmd power set-power-save true   # enable battery saver
adb shell svc wifi disable               # force CPU to work harder (optional)
# Run a CPU‑intensive benchmark in background to raise temperature
adb shell "yes > /dev/null &"

After a few minutes, inspect the encoder’s output format (MediaFormat.getInteger(MediaFormat.KEY_BIT_RATE)) and compare it to the requested bitrate. A significant reduction indicates the system is throttling; ensure your app adapts gracefully (e.g., by lowering resolution or notifying the user of reduced quality).

Checklist for Screen Sharing Release

Before you tag a release as “screen sharing ready”, run through this concise checklist. Each item can be verified with a combination of the manual steps, automated tests, and SUSA runs described above.

✅ ItemHow to Verify
Permission flow handles both grant and denialEspresso/UIAutomator test + manual denial
Preview Surface appears and is updated at ≥ 24 fpsFrame‑rate check via MediaCodec timestamps
Audio‑video sync stays < 40 ms driftInsert audio tone + visual flash, measure offset
Share stops cleanly on Back, system navigation, or incoming callVerify MediaProjectionCallback#onStop fires, no leaked Surface
No black‑screen regions when FLAG_SECURE windows are presentSecure window test, inspect saved frames
Overlay apps (chat heads, floating widgets) do not block share UILaunch overlay, attempt share, check for permission denial
Accessibility services (TalkBack, Switch Control) still functionalEnable service, navigate UI, start share
Multi‑window and PiP modes keep share alive and visibleSplit‑screen + PiP tests, check preview bounds
Battery‑saver and thermal throttling do not crash the appEnable saver, run heat‑generating load, observe bitrate adaptation
OEM‑specific quirks (MIUI, EMUI, OxygenOS) are handledTest on at least one device per OEM family, watch for process kills
No resource leaks after repeated start/stop cyclesRun ADB stress loop (≥ 50 iterations), check dumpsys media.projection and meminfo
Security: no leakage of secure content via projectionAttempt to share while a secure dialog is up, confirm blacked‑out region only
User‑facing error messages are clear and actionableManual denial scenarios, verify toast/snackbar text
Regression: all previously passing scenarios still pass after code changeRun full matrix + Susa baseline on CI

If any item fails, treat it as a blocker and fix before promoting the build.

Takeaways

Screen sharing on Android is deceptively simple to start but notoriously hard to keep reliable across the fragmented ecosystem. The feature sits at the intersection of permissions, window management, media codecs, and power policy, which means that a single overlooked flag—like forgetting to clear FLAG_SECURE or neglecting to request the overlay permission before the projection—can produce a black screen, a crash, or a silent data leak.

A disciplined testing strategy combines three layers:

  1. Deterministic UI tests (Espresso/UIAutomator) that guard the happy path and the most common error flows.
  2. Targeted unit and integration tests that validate the MediaProjection contract—frame timestamps, Surface lifecycle, and encoder bitrate adjustments.
  3. Exploratory, persona‑driven runs (via SUSA or similar autonomous agents) that surface the surprising combinations of states—like “impatient user toggling share while TalkBack is active and the device is in battery‑saver mode”—that scripted tests rarely consider.

By exercising the matrix dimensions in both manual and automated forms, and by continuously feeding the results back into your development loop, you can catch the majority of defects before they reach users. Remember to treat each device family as a separate variable; a pass on a Pixel does not guarantee a pass on a Xiaomi Mi or a Samsung Galaxy.

Finally, treat screen sharing not as a static feature but as a living contract with the OS. Whenever you update your target SDK, add a new permission, or change the way you handle windows, re‑run the full matrix and let Susa’s cross‑session memory guide you toward the next hidden bug. When the contract holds, your users get a seamless, trustworthy way to share what they see—exactly what collaboration apps need to thrive.

Test Your App Autonomously

Upload your APK or URL. SUSA explores like 10 real users — finds bugs, accessibility violations, and security issues. No scripts.

Try SUSA Free