How to Test File Sharing on Android (Complete Guide)

File sharing is a core user flow in many Android apps—social media, productivity, messaging, and file‑manager utilities all rely on the ability to send or receive documents, images, audio, or video. W

March 06, 2026 · 15 min read · How-To Guides

Why File Sharing Matters on Android

File sharing is a core user flow in many Android apps—social media, productivity, messaging, and file‑manager utilities all rely on the ability to send or receive documents, images, audio, or video. When this flow breaks, users encounter silent failures, corrupted attachments, or security leaks that erode trust and can lead to compliance issues. Because sharing touches multiple system components (Intents, ContentProviders, permissions, storage scopes, and UI widgets), a defect can appear only under specific device configurations, OS versions, or user personas. A thorough test strategy therefore needs to cover functional correctness, error handling, accessibility, security, and performance across a matrix of conditions.

Core Mechanisms Behind Android File Sharing

Understanding the underlying APIs helps you design tests that hit the right entry points and observe the correct side‑effects.

Intents and the ShareSheet

The most common path uses ACTION_SEND or ACTION_SEND_MULTIPLE with an Intent. The system resolves the intent to a chooser (ShareSheet) that presents target activities capable of handling the supplied MIME type. The sender supplies either a Uri (content:// or file://) or raw data via EXTRA_STREAM. Receivers read the Uri using a ContentResolver.

ContentProvider and FileProvider

Apps that expose files for sharing typically implement a ContentProvider. For files stored in internal storage, FileProvider generates a content Uri that grants temporary read/write permission via FLAG_GRANT_READ_URI_PERMISSION. Mis‑configured providers are a frequent source of FileUriExposedException on Android 7.0+ and of permission denial on scoped storage (Android 10+).

Direct Share Targets

Starting with Android 6.0, apps can publish ChooserTargetService implementations to appear as high‑priority icons in the ShareSheet. Testing direct share requires verifying that the service returns correct ChooserTarget objects and that the resulting activity handles the intent correctly.

Alternative Transfer Mechanisms

Bluetooth (ACTION_SEND with Bluetooth share), NFC (ACTION_NDEF_DISCOVERED), Wi‑Fi Direct, and proprietary SDKs (e.g., Google Drive API) also use the same Intent contract but may add extra extras or require specific permissions.

Understanding these mechanisms lets you map each test case to the exact API layer that should be exercised.

Test Matrix for File Sharing

Below is a comprehensive matrix that you can paste into a test‑management tool. Each row defines a unique scenario, the steps to trigger it, the expected observable outcome, and a priority (P0 = blocking, P1 = high, P2 = medium).

IDCategoryDescriptionStepsExpected ResultPriority
FS‑01Happy PathShare a single image via implicit intent1. Open app, select image 2. Tap Share button 3. Choose a target app (e.g., Gmail) 4. Verify image attachedImage appears in target app, no crash, correct MIME (image/jpeg)P0
FS‑02Happy PathShare multiple files (PDF + video)Same as FS‑01 but select two items, use ACTION_SEND_MULTIPLEBoth files attached, correct URIs, no data lossP0
FS‑03Error PathShare with unsupported MIME typeAttempt to share a .xyz file (unregistered MIME)ShareSheet shows “No apps can perform this action” or fallback to “Save to device”P1
FS‑04Error PathShare when storage permission deniedRevoke READ_EXTERNAL_STORAGE (Android 9‑) or MANAGE_EXTERNAL_STORAGE (Android 13‑) before shareShare fails gracefully, toast or snackbar informs user, no crashP1
FS‑05Error PathShare to target that crashes on intent receiptInstall a buggy target app that throws NullPointerException on getIntent()ShareSheet still shows target; after selection, target crashes but sender remains responsive (ANR not propagated)P1
FS‑06Edge CaseShare large file (>100 MB)Select a 150 MB video, share via GmailFile attaches, upload progresses, no OOM in sender; if size exceeds provider limit, appropriate error shownP1
FS‑07Edge CaseShare via content Uri with temporary permissionUse FileProvider to share a file from internal storageTarget can read file; after share completes, permission is revoked (verify via adb shell content query --uri content://...)P1
FS‑08Edge CaseShare from scoped storage (Android 10+)Save file to app‑specific external folder, share using ContentResolver.openOutputStreamTarget receives Uri with correct permissions; file accessible despite scoped storage restrictionsP1
FS‑09Edge CaseShare while device is in Doze modeForce Doze (adb shell dumpsys deviceidle force-idle), then shareShare initiates; background upload may be delayed but sender UI stays responsiveP2
FS‑10AccessibilityShare button has proper content descriptionInspect Share button with TalkBack enabledButton announces “Share, button” and is reachable via swipe navigationP1
FS‑11AccessibilityShareSheet navigable via keyboard/dpadConnect USB keyboard, navigate ShareSheet with arrow keysFocus moves between items, Enter selects targetP2
FS‑12Security/PrivacyNo leakage of file path in logsShare a file, capture logcat (adb logcat)No absolute file path appears in Intent extras or debug outputP1
FS‑13Security/PrivacyGranting only necessary URI permissionsShare via FileProvider, check that FLAG_GRANT_READ_URI_PERMISSION is set, not WRITE unless neededTarget can read but cannot modify sender’s fileP1
FS‑14Security/PrivacyPreventing tap‑jacking on ShareSheetOverlay a transparent view while ShareSheet is visible; verify that taps still go to ShareSheet itemsOverlay does not intercept ShareSheet touchesP2
FS‑15PerformanceShare UI latency < 200 msMeasure time from Share button tap to ShareSheet appearance using SystraceLatency under threshold on mid‑tier device (e.g., Pixel 4a)P2
FS‑16LocalizationShareSheet labels respect localeSet device locale to ja-JP, share, verify Japanese text in chooserAll UI strings translated correctlyP2
FS‑17ConcurrencyShare same file while another share is in progressStart first share to Gmail, before completion start second share to WhatsAppBoth shares proceed independently; no corruption or crashesP2
FS‑18InterruptionShare interrupted by incoming callInitiate share, receive voice call, hang up, verify share resumes or fails cleanlyShare either completes after call or shows appropriate error; app stays stableP2
FS‑19Backup/RestoreShare after app restored from backupBackup app data via ADB, uninstall, reinstall, restore data, attempt shareShare works with previously saved files (URIs remain valid)P2
FS‑20Instant AppShare from instant app versionLaunch instant app, trigger shareShareSheet appears, target receives Uri with appropriate temporary permissionsP2

*How to use the table*:

Manual Testing Approach

Manual testing remains valuable for exploratory checks, especially when validating UI flow, accessibility, and subtle error handling that automated scripts may miss.

Device and Environment Setup

  1. Hardware matrix – Include at least one device per major API level (28, 29, 30, 31, 33) and one OEM with heavy customization (e.g., Samsung One UI, Xiaomi MIUI).
  2. System state – Clear app data (adb shell pm clear ) before each test series to avoid stale permissions.
  3. Tooling – Have adb, uiautomatorviewer, and Systrace ready. Enable Developer Options → Show touches, Pointer location, and Stay awake.

Step‑by‑Step Procedure for a Typical Share Flow

  1. Launch the app and navigate to the content to be shared (e.g., a photo gallery).
  2. Activate the Share action – tap the Share icon or long‑press → Share.
  3. Observe the ShareSheet – confirm that it appears within 200 ms, lists expected targets, and shows correct MIME type labels.
  4. Select a target – choose an app capable of handling the MIME type (e.g., Gmail for image/*).
  5. Validate data transfer – in the target app, confirm that the attached file opens correctly, matches the original checksum (md5sum or sha256sum).
  6. Check permission lifecycle – after the target finishes, run adb shell content query --uri content:/// --projection "_display_name" to see if the Uri still grants read access (it should not).
  7. Repeat for error cases – deny storage permission via Settings → Apps → → Permissions, then repeat steps 2‑5 and verify graceful failure UI.
  8. Accessibility check – turn on TalkBack, navigate to the Share button using swipe gestures, ensure it announces correctly and is operable.
  9. Log capture – run adb logcat -v time > share_log.txt before starting the test; after completion, grep for the package name to spot unexpected exceptions or security warnings.

Documentation and Bug Reporting

Automated Testing Approaches

Automation provides repeatability and scalability. Below are the main frameworks suited for Android file‑sharing validation, with concrete code snippets.

Espresso for UI‑Level ShareSheet Validation

Espresso runs on the AndroidJUnitRunner and synchronizes with the UI thread. Use IntentMatchers to capture the share intent and validate its extras.


@RunWith(AndroidJUnit4::class)
class ShareFlowTest {

    @Test
    fun shareSingleImage_attachesCorrectUri() {
        // Arrange
        val context = ApplicationProvider.getApplicationContext<Context>()
        val testImage = File(context.filesDir, "test.jpg")
        FileOutputStream(testImage).use { it.write(testBitmapToBytes()) }

        // Act – click share button
        onView(withId(R.id.btn_share)).perform(click())

        // Assert – ShareSheet appears
        intended(hasAction(Intent.ACTION_SEND))
        intended(hasExtra(Intent.EXTRA_STREAM, uriWithPermission(testImage)))

        // Simulate picking a target (e.g., a mock target activity)
        intended(hasComponent(MockShareTarget::class.java.name))
    }

    private fun uriWithPermission(file: File): Matcher<Uri> {
        return object : TypeSafeMatcher<Uri>() {
            override fun matchesSafely(uri: Uri?): Boolean {
                return uri != null && uri.toString().startsWith("content://")
            }

            override fun describeTo(description: Description) {
                description.appendText("content Uri with temporary permission")
            }
        }
    }
}

*Key points*:

UI Automator for Cross‑App ShareSheet Interaction

When you need to interact with the ShareSheet itself (which resides in the system UI), UI Automator is the right choice.


@RunWith(AndroidJUnit4.class)
public class ShareSheetUiAutomatorTest {

    private UiDevice device;

    @Before
    public void setUp() {
        device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
    }

    @Test
    public void shareViaGmail_success() throws Exception {
        // Launch the app under test
        Context ctx = InstrumentationRegistry.getInstrumentation().getTargetContext();
        Intent launchIntent = ctx.getPackageManager()
                .getLaunchIntentForPackage(ctx.getPackageName());
        launchIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
        ctx.startActivity(launchIntent);

        // Wait for share button and click
        UiObject shareBtn = device.findObject(new UiSelector()
                .resourceId("com.example.app:id/btn_share"));
        shareBtn.clickWait();

        // Wait for ShareSheet to appear
        UiObject chooser = device.findObject(new UiSelector()
                .className("android.widget.FrameLayout")
                .descriptionContains("Share"));
        chooser.waitForExists(5000);

        // Select Gmail from the list
        UiObject gmailItem = device.findObject(new UiSelector()
                .text("Gmail"));
        gmailItem.clickAndWaitForNewWindow();

        // Verify that Gmail composer shows attachment
        UiObject attachment = device.findObject(new UiSelector()
                .descriptionContains("test.jpg"));
        assertTrue(attachment.waitForExists(5000));
    }
}

*Why UI Automator?*

Appium for Hybrid or Web‑View Sharing

If your app contains a WebView that triggers a share (e.g., a “Share link” button), Appium can drive both native and web contexts.


@Test
public void shareLinkFromWebView() {
    driver.findElement(By.id("open_webview_btn")).click();
    // Switch to WebView context
    Set<String> contexts = driver.getContextHandles();
    for (String ctx : contexts) {
        if (ctx.contains("WEBVIEW")) {
            driver.context(ctx);
            break;
        }
    }

    // Click share link inside page
    driver.findElement(By.id("share-link")).click();

    // Return to native context to handle ShareSheet
    driver.context("NATIVE_APP");
    new WebDriverWait(driver, 20)
            .until(ExpectedConditions.elementToBeClickable(
                    By.xpath("//android.widget.TextView[@text='Gmail']")));

    driver to choose Gmail)
    driver.findElement(By.xpath("//android.widget.TextView[@text='Gmail']")).click();

    // Validate in Gmail (native)
    Assert.assertTrue(driver.findElement(By.id("subject")).getText()
            .contains("Shared link"));
}

*Note*: Appium requires the Android SDK platform‑tools and the chromedriver matching the device’s Chrome version.

Autonomous Exploration with SUSA

SUSA can be pointed at an APK or a web URL and will exercise the share flow using a variety of user personas (curious, impatient, adversarial, etc.) without any test scripts.


# Install the agent
pip install susatest-agent

# Run a session on a local APK
susatest run \
    --app ./MyApp.apk \
    --device emulator-5554 \
    --personas curious impatient adversarial \
    --output ./susa_report.json \
    --timeout 15m

During the run, SUSA automatically:

Because SUSA explores without pre‑defined scripts, it often discovers issues such as:

These findings complement the deterministic checks covered by Espresso/UI Automator.

Tooling and Infrastructure

A robust file‑sharing test suite relies on a combination of command‑line utilities, Gradle plugins, and cloud device farms.

ADB Commands for Permission and State Manipulation


# Revoke runtime permission (pre‑Android 13)
adb shell pm revoke com.example.app android.permission.READ_EXTERNAL_STORAGE

# Grant temporary URI permission manually (for verification)
adb shell pm grant com.example.app android.permission.FLAG_GRANT_READ_URI_PERMISSION

# Force Doze mode
adb shell dumpsys deviceidle force-idle
adb shell dumpsys deviceidle unforce

# Simulate low storage
adb shell sm set-virtual-disk true

Gradle Test Orchestration

Add the following to app/build.gradle to run UI Automator tests on a device farm via Firebase Test Lab:


android {
    ...
    testOptions {
        unitTests {
            includeAndroidResources = true
        }
    }
}

dependencies {
    androidTestImplementation 'androidx.test:runner:1.5.2'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
    androidTestImplementation 'androidx.test.uiautomator:uiautomator:2.2.0'
}

Then execute:


./gradlew connectedAndroidTest -Pandroid.testInstrumentationRunnerArguments.clearPackageData=true

Cloud Device Farms

When testing matrix items like FS‑06 (large file) or FS‑09 (Doze), use a service such as Firebase Test Lab or AWS Device Farm to run the same test suite across dozens of device/API combos in parallel. Upload your APK and test suite, specify a matrix of models, and retrieve a consolidated HTML report with screenshots and logs.

Continuous Integration Integration

Edge Cases That Only Show Up in Production

Even with exhaustive lab testing, certain conditions surface only after real‑world usage. Below are the most common production‑only pitfalls for file sharing, along with detection strategies.

Scoped Storage Migration Issues

On Android 10+, apps targeting API 29+ must use scoped storage. If a legacy code path still attempts to share a file:// Uri, the receiver gets a FileUriExposedException.

Detection: Enable StrictMode.VmPolicy.Builder().detectLeakedSqlLiteObjects().penaltyLog() and watch logcat for StrictMode warnings when sharing.

Permission Revocation During Background Share

Android 12 introduced one‑time permissions; if the user denies a permission while a share is in progress (e.g., via the permission dialog that appears because the target app requests a dangerous permission), the sender may lose the Uri grant mid‑transfer.

Detection: Use a MonkeyRunner script that randomly toggles permissions while a share is active, then verify that the sender either pauses gracefully or shows a clear error.

Work Profile and Managed Configurations

When the app is installed in a work profile, the share intent may be resolved to a personal‑profile target, causing data leakage or policy violation.

Detection: Provision a device with a work profile (adb shell cmd device-provisioner create-managed-user), install the app in the work profile, and attempt to share to a personal‑profile app (e.g., personal Gmail). Verify that the share is blocked or that a work‑only warning appears.

Instant App Context Limits

Instant apps have a restricted sandbox; they cannot request MANAGE_EXTERNAL_STORAGE and must rely on FileProvider. If you attempt to share a file from the app’s internal cache without using FileProvider, the share fails silently.

Detection: Run the instant app bundle via adb shell am start -W -a android.intent.action.MAIN -c android.intent.category.LAUNCHER -n com.example.app/.MainActivity --user 0 --ez instant_app true and attempt a share; monitor for SecurityException.

OEM‑Specific ShareSheet Modifications

Some manufacturers replace the default ShareSheet with a custom UI that may not forward certain Intent extras (e.g., stripping EXTRA_TITLE).

Detection: Test on at least one device per major OEM (Samsung, Xiaomi, OPPO, Vivo) and compare the received Intent extras in the target app. Use adb logcat to log Intent#getExtras() on the receiver side.

Background Location and Microphone Permissions Interfering with Share

If your app requests location or microphone permissions and the share flow triggers a system UI that also needs those permissions (e.g., sharing to a recorder app), a permission conflict can cause the ShareSheet to be dismissed.

Detection: Enable both location and microphone permissions, start a share to a voice‑memo app, then revoke one permission mid‑share via Settings and observe the outcome.

Battery Optimization Whitelisting

Devices with aggressive battery savers may place your app in a restricted bucket, preventing it from starting background services needed to finish a share after the UI returns.

Detection: Add the app to the “Optimize battery usage” exemption list, then disable it, run a share that relies on a background upload service (e.g., to Google Drive), and verify whether the upload completes or stalls.

Multi‑User and Guest Sessions

On tablets or secondary users, the app’s data directory is isolated. Sharing a file that was created under the primary user while logged in as a guest results in a Uri that points to a non‑existent location for the guest.

Detection: Create a second user (adb shell pm create-user guest), switch to it (adb shell am switch-user ), install the app, and attempt to share a file that was previously saved under the primary user. Expect a clear “File not found” message.

Network‑Dependent Share Targets (e.g., Cloud Services)

When sharing to a service that requires network (Drive, Dropbox), a flaky connection can cause the sender to believe the share succeeded while the target never receives the file.

Detection: Use adb shell emulator -netdelay 2000 -netloss 10 to emulate latency and packet loss, then verify that the sender shows an appropriate retry or error UI rather than a false success toast.

Short Checklist for File‑Sharing Validation

Copy this list into your test plan; tick each item before signing off a release.

Closing Takeaways

File sharing on Android is deceptively simple: a few lines of Intent code hide a tangled web of permissions, storage scopes, UI dialogs, and cross‑app contracts. A solid testing strategy therefore needs to combine deterministic checks (Espresso, UI Automator, Appium) with exploratory, persona‑driven techniques that surface the hidden paths real users travel.

By exercising the matrix above—happy paths, error conditions, edge cases, accessibility, security, and performance—you will catch the majority of defects that manifest in the wild. Leverage ADB for permission and state manipulation, use cloud device farms for version and OEM coverage, and integrate autonomous tools like SUSA into your nightly pipeline to catch regressions that static scripts never consider.

When every share action results in the correct file arriving intact, with the user informed of any problem and never exposed to a crash or privacy leak, you have achieved the reliability users expect from a modern Android application.

---

*This guide is intentionally detailed to serve as a reference you can keep bookmarked. Apply the matrix, adapt the snippets to your codebase, and iterate as new Android releases shift the behavior of Intents, scoped storage, and UI components.*

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