How to Test Video Calls on Android (Complete Guide)
Video calling is no longer a niche feature; it is a core interaction for telehealth, remote work, education, and social apps. On Android the complexity multiplies because the platform exposes a hetero
Why Video Call Testing Demands Special Attention on Android
Video calling is no longer a niche feature; it is a core interaction for telehealth, remote work, education, and social apps. On Android the complexity multiplies because the platform exposes a heterogeneous set of hardware capabilities, permission models, and background‑process behaviors. A defect that survives unit tests can surface as a dropped call, garbled audio, or a privacy leak when a real user experiences fluctuating network conditions, receives an incoming SMS, or switches to battery‑saver mode.
Testing video calls therefore requires a blend of functional verification, media‑path validation, and system‑level stress testing. The following guide walks through a complete methodology: from a concrete test matrix to manual steps, automated scripts, and finally how autonomous, persona‑driven exploration can surface issues that scripted tests never consider.
---
Common Failure Modes Seen in Production
Understanding what typically goes wrong helps prioritize test effort. The table below aggregates failure categories observed across multiple Android video‑call apps in the wild.
| Category | Typical Symptom | Root Cause (Android‑specific) | Detection Technique |
|---|---|---|---|
| Permission handling | Call fails to start, black screen | Missing CAMERA, RECORD_AUDIO, or READ_PHONE_STATE at runtime; permission denied after a system update | Runtime permission dialog checks, adb shell pm grant |
| Audio‑video sync drift | Lip‑sync error > 150 ms | Improper use of AudioTrack/AudioRecord timestamps, or reliance on MediaCodec without configuring KEY_OUTPUT_DELAY | Frame‑timestamp comparison, MediaRecorder API probes |
| Network volatility | Freeze, pixelation, call drop | Wi‑Fi to cellular handoff, captive portal, VPN, or aggressive Doze mode throttling | Network simulation (tc, netem), ConnectivityManager callbacks |
| Background interference | Audio muted, video paused when another app grabs mic/camera | Another foreground service holds audio focus (AudioManager.AUDIOFOCUS_GAIN_TRANSIENT) or camera is opened by a different process | AudioManager focus listeners, camera state polling |
| UI glitches under rotation/multi‑window | Controls disappear, layout overlaps | Failure to handle Configuration changes, or using fixed‑dimension SurfaceView without adapting to new window size | onConfigurationChanged verification, UI Automator screenshots |
| Accessibility barriers | TalkBack cannot announce call state, missing labels | Custom views without contentDescription, or reliance on touch‑only gestures | Accessibility scanner, TalkBack navigation |
| Security/privacy leaks | Call metadata exposed in logs, screen capture allowed | Over‑verbose Log.d, missing FLAG_SECURE on window, or insufficient encryption of signaling | Logcat inspection, adb shell dumpsys window windows flag check |
| Resource exhaustion | ANR, OOM kill during long call | Heavy bitmap processing, failure to release MediaCodec buffers, or unbounded growth of signaling queues | adb shell dumpsys meminfo, Systrace for main‑thread stalls |
Each of these rows informs a specific test case; the next section consolidates them into a usable matrix.
---
Comprehensive Test Matrix
The matrix below organizes test scenarios by dimension (functional, error, edge, accessibility, security) and indicates the recommended verification method. Use it as a checklist when building test suites.
| Dimension | Test ID | Scenario | Preconditions | Steps | Expected Outcome | Automation Hint |
|---|---|---|---|---|---|---|
| Happy Path | HP‑1 | Two‑party call initiation and teardown | App installed, granted CAMERA & AUDIO, device on stable Wi‑Fi | 1. User A taps “Start Call” → 2. User B accepts → 3. Verify video/audio streams → 4. Either party ends call | Both ends see each other's video, hear audio, call ends cleanly, resources released | Espresso + IdlingResource for signaling; MediaProjection to capture frames |
| Happy Path | HP‑2 | Call with screen share enabled | Same as HP‑1, plus screen‑share permission granted | 1. Start call → 2. Activate screen share → 3. Share a scrolling list → 4. Stop share | Remote participant sees exact screen content, no lag > 200 ms, local UI unchanged | Use VirtualDisplay via MediaProjection; compare bitmap hash |
| Error Path | EP‑1 | Missing camera permission at runtime | Permission denied via adb shell pm revoke | 1. Launch call flow → 2. Observe permission rationale | App shows rationale dialog, does not crash, call button disabled | UI Automator to verify dialog text, Espresso to assert button state |
| Error Path | EP‑2 | Audio focus loss due to music app | Background music app playing, requests AUDIOFOCUS_GAIN | 1. Start call → 2. Launch music app → 3. Observe audio behavior | Call audio lowers (ducking) or pauses per app policy, recovers after focus returns | AudioManager focus listener; verify volume via MediaRecorder |
| Error Path | EP‑3 | Signaling server returns 500 | Mock server configured to error on /join | 1. Attempt call → 2. Handle error | App shows retry toast, does not leak socket, cleans up MediaCodec | MockWebServer + Espresso idling for network idle |
| Edge Case | EC‑1 | Network latency spike (300 ms) + jitter | Use tc qdisc add dev wlan0 root netem delay 300ms 100ms distribution normal | 1. Start call → 2. Monitor for freeze → 3. Verify recovery after latency returns to normal | Video may freeze briefly (< 2 s), audio may buffer, call recovers without crash | adb shell dumpsys media.audio_flinger for buffer stats |
| Edge Case | EC‑2 | Incoming voice call interrupts video call | Device has carrier SIM, enable call waiting | 1. Start video call → 2. Receive incoming voice call → 3. Accept/reject → 4. Return to video call | Video call pauses/resumes correctly, mic/camera released/grabbed appropriately, no deadlock | TelephonyManager state broadcast receiver test |
| Edge Case | EC‑3 | Battery saver / extreme low power | Enable Battery Saver, set battery level to 5 % via adb shell dumpsys battery set level 5 | 1. Start call → 2. Observe for throttling | Frame rate may drop, but call remains stable; no ANR | Systrace to capture CPU freq scaling |
| Edge Case | EC‑4 | Picture‑in‑picture (PiP) mode activated | App supports PiP, user presses home during call | 1. Start call → 2. Swipe up to home → 3. Verify PiP window | Video continues in small window, controls accessible, audio unchanged | UI Automator to assert PiP window presence, MediaProjection to capture |
| Accessibility | AC‑1 | TalkBack navigation of call controls | TalkBack enabled, focus starts on call screen | 1. Swipe left/right → 2. Hear description of each button | Every interactive element has a meaningful contentDescription, state changes announced | Accessibility Test Framework (ATF) or androidx.test.espresso.accessibility |
| Accessibility | AC‑2 | High contrast / font scaling | Set Settings → Accessibility → Font size → Largest, enable high contrast | 1. Verify layout does not clip text, buttons remain tappable | All text scales, touch targets ≥ 48 dp | UI Automator screenshot comparison |
| Security/Privacy | SE‑1 | Screen capture prevention | Call screen marked with FLAG_SECURE | 1. Attempt screenshot via power+vol down → 2. Check result | Screenshot is black, no video frame leaked | adb shell screencap validation |
| Security/Privacy | SE‑2 | Signaling encryption verification | Enable network capture (Wireshark) on device | 1. Place call → 2. Inspect packets | Signaling payload (SDP, ICE) is TLS‑encrypted, no plaintext credentials | adb shell tcpdump or HttpLoggingInterceptor level BODY |
| Security/Privacy | SE‑3 | Permission re‑grant after device reboot | Reboot device, check persisted permissions | 1. Reboot → 2. Launch app → 3. Attempt call | Permissions remain granted, no re‑prompt unless explicitly revoked | adb shell pm list permissions -g -d |
*Tip:* When constructing automated suites, group tests by dimension and run them in parallel on a device farm to keep total execution time manageable.
---
Manual Testing – Step‑by‑Step Walkthrough
Even with automation, a disciplined manual pass catches nuances that scripts gloss over. Follow this procedure on a physical device (or a well‑configured emulator) before committing to CI.
- Device Preparation
- Enable Developer Options → USB debugging.
- Set
adb shell settings put global window_animation_scale 0.0and similarly for transition and animator scales to eliminate animation noise. - Clear app data (
adb shell pm clear com.example.videocall) to start from a clean state. - Grant required permissions via
adb shell pm grant com.example.videocall android.permission.CAMERAandandroid.permission.RECORD_AUDIO.
- Baseline Happy Path
- Launch the app, navigate to the call screen.
- Tap “Start Call” with a second device (or a test user account) ready to accept.
- Observe:
- Both video feeds appear within 2 seconds.
- Audio levels move in sync with speech (use a speaker and watch the waveform in the UI if available).
- No overlay or toast appears indicating permission issues.
- End the call from either side and verify that the UI returns to the idle state, camera preview stops, and microphone icon disappears.
- Permission Flow
- Revoke camera permission (
adb shell pm revoke com.example.videocall android.permission.CAMERA). - Attempt to start a call.
- Verify that a rationale dialog appears, the call button stays disabled, and the app does not crash.
- Re‑grant permission and repeat the happy path to confirm recovery.
- Audio Focus Ducking Test
- Start a music player (e.g., YouTube) and begin playback.
- Initiate the video call.
- Confirm that the music volume lowers (or pauses) as per the app’s audio focus request.
- End the call and ensure music resumes at its original level.
- Network Stress
- Connect the device to a Wi‑Fi network routed through a Linux box running
tc. - Apply
tc qdisc add dev wlan0 root netem delay 200ms 50ms distribution normal loss 2%. - Place a call and note any freezing, pixelation, or audio dropouts.
- Remove the netem rule and verify the call recovers without manual intervention.
- Interrupt Handling
- While in a call, trigger an incoming voice call (using a second SIM or a VoIP app).
- Accept the voice call; the video call should pause, releasing camera/mic.
- End the voice call and verify the video call resumes with both streams restored.
- Repeat with an incoming SMS notification that heads‑up displays; ensure the video UI does not get obscured.
- Orientation & Multi‑Window
- Start a call in portrait.
- Rotate to landscape; verify that video feeds rotate correctly and UI elements remain accessible.
- Drag the app into split‑screen mode with another app (e.g., Chrome).
- Confirm that the video continues, the preview does not stretch, and touch targets remain usable.
- Exit multi‑window and return to full screen; ensure no UI corruption.
- Picture‑in‑Picture
- With an active call, press Home.
- Confirm the video shrinks to a PiP window that remains interactive (tap to expand).
- Drag the PiP window to different screen corners; ensure it does not get stuck under the system bar.
- Return to the app via the PiP window; verify full‑screen call restores correctly.
- Accessibility Check
- Enable TalkBack.
- Navigate through the call screen using swipe gestures.
- Listen for descriptive labels on each button (e.g., “Mute microphone, toggle”).
- Change font size to largest and verify that no text is clipped and touch targets stay ≥ 48 dp.
- Security & Privacy Spot‑Check
- Attempt a screenshot while in a call; verify the result is black (indicating
FLAG_SECURE). - Start a packet capture (
adb shell tcpdump -i wlan0 -s 0 -w /sdcard/call.pcap) and place a brief call. - Inspect the capture with Wireshark; confirm that signaling traffic uses TLS and that no raw audio/video payloads are visible (they should be encrypted via SRTP).
- Reboot the device, relaunch the app, and confirm that previously granted permissions are still present without a re‑prompt.
If any step fails, log the exact device model, Android version, and the precise state (e.g., network condition, battery level). This information is invaluable for reproducing the issue later in an automated test or bug report.
---
Automated Approaches – Tooling and Sample Code
1. UI‑Level Testing with Espresso + Idling Resources
Espresso excels at verifying UI state and synchronizing with asynchronous operations (signaling, media preparation). The following snippet demonstrates a happy‑path test that waits for the remote video surface to appear.
@RunWith(AndroidJUnit4::class)
class VideoCallTest {
private lateinit var activityScenario: ActivityScenario<MainActivity>
@Before
fun setUp() {
activityScenario = ActivityScenario.launch(MainActivity::class.java)
// Grant permissions programmatically for the test
ShellUtils.grantPermission(
InstrumentationRegistry.getInstrumentation().targetContext,
Manifest.permission.CAMERA,
Manifest.permission.RECORD_AUDIO
)
}
@Test
fun happyPathCallEstablishesVideo() {
// Tap start call button
onView(withId(R.id.btn_start_call)).perform(click())
// Idling resource that waits until signaling reports CALL_CONNECTED
val callConnectedIdling = object : IdlingResource {
override fun getName() = "CallConnectedIdling"
private var callback: IdlingResource.ResourceCallback? = null
override fun isIdleNow(): Boolean {
val isConnected = CallManager.getInstance().isConnected()
if (isConnected) callback?.onTransitionToIdle()
return isConnected
}
override fun registerIdleTransitionCallback(callback: IdlingResource.ResourceCallback) {
this.callback = callback
}
}
IdlingRegistry.getInstance().register(callConnectedIdling)
// Wait for remote SurfaceView to appear (indicating video decode)
onView(withId(R.id.remote_surface))
.check(matches(isDisplayed()))
.check(matches(withEffectiveVisibility(View.VISIBLE)))
// End call and verify cleanup
onView(withId(R.id.btn_end_call)).perform(click())
onView(withId(R.id.btn_start_call)).check(matches(isDisplayed()))
IdlingRegistry.getInstance().unregister(callConnectedIdling)
}
}
Key points
- Use a custom
IdlingResourcethat polls the signaling layer for connection state. - Verify both local and remote
SurfaceViewvisibility; you can also capture a frame viaMediaProjectionand compare against a known bitmap to ensure decoding succeeded. - After the call ends, assert that UI elements return to their idle state and that no stray
SurfaceViewremains leaked (you can checkActivity.getWindow().getDecorView().findViewsWithTextfor leftover views).
2. Media Path Validation with Camera2 Test Source
To confirm that the app actually sends frames from the camera (and not a static image), replace the physical camera with a test source that generates a moving pattern. The Android CTS provides android.hardware.camera2.test which can be used via adb shell am instrument.
# Install the camera test source APK (part of platform-tools)
adb install -r /path/to/CameraTestSource.apk
# Grant the test app permission to use the test source
adb shell appops set com.example.videocall CAMERA ignore
# Launch the test source service (it creates a virtual camera)
adb shell am startservice -n com.android.camera2.testsource/.CameraTestSourceService
# Run your Espresso test; the virtual camera will feed a rotating color bar pattern
In your test, after confirming the remote surface is visible, grab a frame using ImageReader attached to the local preview Surface. Compute the average hue; if it matches the expected pattern (e.g., rotating through red‑green‑blue), you know the camera pipeline is active.
3. Audio Path Verification with AudioRecord and Playback
A simple way to ensure audio is being captured and rendered is to record a short snippet from the microphone, play it back through the speaker, and compare the waveform to a known test tone.
private fun captureAndValidateAudio(durationMs: Long = 2000): Boolean {
val sampleRate = 44100
val bufferSize = AudioRecord.getMinBufferSize(sampleRate,
AudioFormat.CHANNEL_IN_MONO,
AudioFormat.ENCODING_PCM_16BIT)
val recorder = AudioRecord(
MediaRecorder.AudioSource.MIC,
sampleRate,
AudioFormat.CHANNEL_IN_MONO,
AudioFormat.ENCODING_PCM_16BIT,
bufferSize
)
recorder.startRecording()
val samples = ShortArray(bufferSize / 2)
val start = SystemClock.uptimeMillis()
val collected = mutableListOf<Short>()
while (SystemClock.uptimeMillis() - start < durationMs) {
val read = recorder.read(samples, 0, samples.size)
if (read > 0) collected.addAll(samples.copyOfRange(0, read))
}
recorder.stop()
recorder.release()
// Simple energy test: ensure RMS > threshold (indicates non‑silence)
val sum = collected.map { it.toDouble() * it }.sum()
val rms = Math.sqrt(sum / collected.size)
return rms > 100.0 // empirical threshold; adjust per device
}
Call this function before and after the call starts; a significant increase in RMS confirms the mic is live. For the speaker path, you can use AudioTrack to play a known tone and verify with the same recorder on a second device or using a loopback cable.
4. Network Condition Simulation
While tc works on rooted devices or emulators with elevated privileges, you can also use the Android NetworkCapabilities API to inject latency and loss via TrafficShaper (API 29+). Example:
val trafficShader = ConnectivityManager.getTrafficShaper()
val config = TrafficShaper.Config.Builder()
.setDelayMs(300)
.setLossPercentage(2)
.build()
trafficShader.apply(config)
Wrap this in a @Before/@After JUnit rule to apply the condition only for the duration of a test.
5. Cross‑Device Synchronization with UiAutomator
For true two‑party validation, launch the same test on a second device and coordinate via a socket or ADB forwarding. A minimal example:
Device A (caller)
adb -A forward tcp:5555 tcp:5555
adb -A shell am instrument -w -e action start_call -e peer_port 5555 com.example.test/androidx.test.runner.AndroidJUnitRunner
Device B (callee)
adb -B forward tcp:5555 tcp:5555
adb -B shell am instrument -w -e action accept_call -e peer_port 5555 com.example.test/androidx.test.runner.AndroidJUnitRunner
Each test side opens a socket on the forwarded port, exchanges a simple JSON signal ({type: "offer"} or {type: "answer"}), and then proceeds with the UI steps. This approach eliminates reliance on a real signaling server for UI verification while still exercising the full client‑side call flow.
6. Automated Accessibility Scanning
Integrate the androidx.test.espresso.accessibility library:
@Test
fun accessibilityCheck() {
AccessibilityChecks.enable()
onView(withId(R.id.call_screen)).check(matches(isDisplayed()))
}
This will run a series of heuristics (touch target size, contrast, content descriptions) and fail the test if any violation is found, giving you immediate feedback in CI.
---
Autonomous, Persona‑Driven Exploration – Where Scripts Miss Bugs
Traditional automated tests follow predetermined paths; they excel at regressions but often ignore the myriad ways real users interact with an app. Autonomous exploration platforms (e.g., SUSA) simulate distinct personas—each with its own behavior model—to stress the application in ways a script writer might not anticipate.
How Personas Work
| Persona | Core Traits | Typical Interaction Patterns |
|---|---|---|
| Curious | Explores every visible element, taps repeatedly, long presses | Opens settings, tries hidden gestures, rotates device frequently |
| Impatient | Rapid taps, minimal waiting, aborts if UI does not respond within 1 s | Spams call button, cancels mid‑dial, force‑closes app |
| Novice | Prefers large, labeled buttons, avoids icons without text, reads tooltips | Starts with help screen, follows on‑boarding prompts, rarely uses shortcuts |
| Adversarial | Attempts to break invariants: sends malformed input, rotates while dialog is open, denies permissions repeatedly | Toggles camera off mid‑call, spam back button, forces network loss via airplane mode |
| Elderly | Slower interaction, larger tap targets needed, prefers voice commands | Uses accessibility scale, relies on TalkBack, avoids multi‑touch gestures |
| Accessibility | Relies on screen reader, high contrast, switch control | Navigates via directional pad, expects all actions to be announced |
| Power User | Uses shortcuts, expects quick settings, multitasks heavily | Splits screen, uses picture‑in‑picture, triggers quick tiles (flashlight, DND) |
| Battery‑Saver Conscious | Frequently checks battery, enables power‑saving modes mid‑task | Starts call, then toggles Battery Saver, observes impact |
Each persona is driven by a stochastic state machine that decides the next action based on the current UI hierarchy, sensor readings (battery, network), and a configurable “aggressiveness” factor. The engine records every visited screen, every action taken, and any anomaly (crash, ANR, unhandled exception, permission denial, accessibility violation).
Why This Finds Issues Scripts Overlook
- Permission Race Conditions – A script may grant permissions once at startup; an adversarial persona might repeatedly deny and re‑grant the camera permission while a call is in progress, exposing a race where the app tries to reconnect the camera after a denial and crashes.
- Gesture Conflicts – The curious persona may discover a hidden long‑press on the video preview that triggers a debug overlay; if the overlay incorrectly captures touch events, the call controls become unresponsive—a scenario rarely captured in a linear test script.
- Multitasking Interference – A power‑user persona often puts the app in split‑screen while simultaneously launching a CPU‑heavy game. The resulting thermal throttling can cause the video encoder to drop frames, leading to noticeable drift that only appears under sustained load.
- Network Fluctuation Patterns – Rather than a fixed latency, the adversarial persona can enable airplane mode for 200 ms, disable it, then repeat, simulating a flaky Wi‑Fi hand‑off. This can reveal bugs in ICE restart logic where the app fails to renew candidates.
- Accessibility Overlaps – When TalkBack is enabled, some custom views lose their
contentDescriptionafter a configuration change. An accessibility‑focused persona that repeatedly rotates the device while the screen reader is active will catch this regression, whereas a script that tests rotation only once may miss it.
- Battery‑Saver Induced Frame Drops – The battery‑saver conscious persona will trigger Power Save mid‑call, causing the system to lower the CPU frequency. If the app does not adapt its encoder bitrate, the video may become blocky. Scripts that keep the device plugged in will not see this.
Integrating Persona Exploration into Your Workflow
- Run a baseline persona suite nightly on a device farm (e.g., Firebase Test Lab) to collect a set of discovered anomalies.
- Triangulate findings: any crash or ANR flagged by the persona run should be added as a unit test or Espresso test to prevent regression.
- Feed the discovered flows back into SUSA’s learning engine: the platform remembers which screens lead to dead ends (e.g., a settings page that never returns to the call UI) and prioritizes them in subsequent runs, increasing efficiency over time.
- Combine with manual spot checks: after a persona run highlights a suspicious area (e.g., “camera permission denied during call”), perform a focused manual test to validate the user impact and gather logs for debugging.
While SUSA is one implementation of this idea, the core principle—varying user behavior models to expose hidden interaction bugs—can be adopted with open‑source tools like adb monkey combined with custom scripts, or with frameworks such as AndroidX Test’s ActivityScenario combined with random decision generators.
---
Edge Cases That Surface Only in Production
Even the most exhaustive test matrix can miss conditions that arise from the real‑world device ecosystem. Below is a curated list of production‑only triggers, why they matter, and how you can approximate them in a lab.
| Production Trigger | Why It Breaks Calls | Lab Approximation |
|---|---|---|
| Carrier‑Specific VoLTE/ViLTE Hand‑off | Switching between LTE voice and video causes the system to tear down and rebuild the media stack; some apps forget to release the old AudioTrack. | Use adb shell svc data disable and adb shell svc data enable rapidly while on a call, or use a network simulator that mimics LTE bearer changes. |
| VPN or Proxy with Split Tunneling | Traffic may be routed through a tunnel that blocks UDP ports needed for media, forcing fallback to TCP and increasing latency. | Configure the device’s VPN settings to point to a local openvpn instance that drops UDP 50000‑60000. |
| Captive Portal Interception | Public Wi‑Fi redirects HTTP(S) to a login page; if the app does not detect the portal, signaling times out. | Run a local hotspot with hostapd that serves a redirect page for the first HTTP request, then allow traffic after manual auth. |
| Do Not Disturb (DND) Priority Mode | Incoming call notifications may be suppressed, causing the user to miss an incoming video call request. | Enable DND via adb shell cmd notification set_interruption_filter 2 and place a second call from another device. |
| Nearby Share / Quick Share Interference | These services also request microphone access for audio notes; simultaneous access can cause the audio route to switch unexpectedly. | Launch Nearby Share audio note recording while a video call is active and observe audio glitches. |
| External USB Audio/Video Accessories | Plugging in a USB webcam or headset mid‑call may trigger a route change; some apps do not handle AudioDeviceCallback. | Use a USB‑OTG adapter with a webcam, call adb shell am broadcast -a android.media.ACTION_AUDIO_BECOMING_NOISY to simulate unplug, then plug again. |
| System UI Themes (Dark Mode, High Contrast) | Custom views that hard‑code background colors become invisible or lose contrast. | Enable forced dark mode via adb shell cmd ui mode night yes and run the accessibility check. |
| Background Location Services | Some OEMs aggressively kill background services when location is in use; if your signaling relies on a background keep‑alive, the call may drop after a few minutes. | Start a location request in another app, then observe if your signaling socket receives a keep‑alive timeout. |
| Thermal Throttling from Gaming | Sustained GPU load raises temperature, causing the encoder to drop bitrate or switch to software fallback, increasing CPU usage and leading to jank. | Run a GPU stress test (e.g., glmark2) in background while maintaining a call; monitor adb shell dumpsys thermalservice. |
| Multiple Simultaneous Calls (VoIP + Cellular) | Receiving a cellular call while a VoIP call is active can cause audio routing conflicts; the system may give priority to the cellular stream, muting VoIP audio. | Initiate a VoIP call, then trigger an incoming cellular call via adb shell telecom service call +1234567890. |
| SIM Switch Dual‑Active Devices | On dual‑SIM phones, switching the default data SIM mid‑call can cause a momentary loss of IP connectivity. | Use adb shell telephony sim select-slot 1 then 2 repeatedly during a call. |
| Enterprise Device Owners (MDM) Policies | MDM may enforce disabled camera or microphone; the app must gracefully degrade rather than crash. | Install a test DPC (Device Policy Controller) that sets setCameraDisabled(true) and launch the call. |
To capture these, augment your test matrix with environmental variation steps: toggle a setting, plug/unplug a peripheral, or inject a system broadcast before or during the call. Automate the toggles via adb shell commands within a @Rule that resets the state after each test.
---
Concise Checklist for Engineers
| ✅ Item | Description |
|---|---|
| Permissions | Verify runtime grant/denial flows for CAMERA, RECORD_AUDIO, PHONE_STATE; ensure rationale dialogs appear and app does not crash. |
| Happy‑Path Media | Confirm both local and remote video render within 2 s, audio levels move with speech, and call terminates cleanly (resources released). |
| Error Handling | Test missing permissions, signaling failures (500/timeout), network loss, and audio focus loss; assert graceful UI and no leaked objects. |
| Edge Cases | Simulate latency/jitter, incoming voice/SMS calls, battery saver, orientation changes, split‑screen, PiP, and device rotation while TalkBack is on. |
| Accessibility | Run AccessibilityChecks.enable(); manually navigate with TalkBack; verify content descriptions, touch target size ≥ 48 dp, and contrast ratios ≥ 4.5:1. |
| Security | Ensure window flag FLAG_SECURE is set; confirm signaling is TLS‑encrypted; verify no screen capture leakage; check permissions persist after reboot. |
| Network Stress | Use tc/netem or TrafficShaper to inject delay, jitter, loss; confirm call recovers without crash after conditions normalize. |
| Interruption Handling | Validate behavior when an incoming cellular call, SMS heads‑up, or notification shade appears during a call. |
| Multitasking | Test split‑screen, picture‑in‑picture, and background CPU/GPU load; ensure no deadlock or excessive frame drop. |
| Cleanup | After each test scenario, assert that MediaRecorder, AudioRecord, Camera, and SurfaceView objects are released; inspect adb shell dumpsys media.audio_flinger for orphaned tracks. |
| Logging & Metrics | Capture Logcat for unexpected warnings, record frame‑timestamps via MediaCodec getOutputBuffers(), and log battery/temperature for correlation analysis. |
Run this checklist on a representative matrix of devices (different SoCs, Android versions, OEM skins) before marking a feature as release‑
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