On this page
Enforcing edge-to-edge layouts on Android represents one of the most significant visual architecture shifts since the introduction of Material Design. With Android 15 making edge-to-edge display mandatory for applications targeting API level 35, mobile engineering teams can no longer treat system bar insets as an optional cosmetic polish. When apps draw behind the translucent status bar, camera cutouts, and the gesture navigation bar, interactive buttons, bottom navigation bars, and text fields frequently collide with system UI elements. Traditional unit tests and synthetic Robolectric harnesses cannot accurately render hardware display cutouts, physical gesture pill exclusion zones, or IME keyboard animations. Integrating Claude Code with ScreenSync MCP provides developers with an autonomous, physical-device testing loop that inspects real WindowInsetsCompat handling, verifies layout node tree bounds against system bars, and catches visual regressions without rooting the device or compromising security boundaries.
Key Takeaways
- Android 15 enforces edge-to-edge rendering by default for apps targeting API level 35, rendering legacy system bar background flags obsolete and requiring explicit insets handling.
- Layout regressions commonly manifest as floating action buttons trapped beneath gesture navigation bars or form inputs obscured behind the software keyboard (IME).
- Synthetic unit test doubles and Robolectric harnesses lack physical display cutouts, hardware sensor notches, and vendor-specific gesture exclusion zones.
- ScreenSync MCP provides 226 Model Context Protocol tools, enabling Claude Code to query live Android accessibility trees (
get_ui_hierarchy) and capture low-latency screen buffers via native MediaProjection without root access. - Touch interactions, hardware keyboard simulation, and window orientation changes execute over ADB from the desktop hub over USB or wireless debugging.
- Production-grade insets testing requires evaluating
WindowInsetsCompat.Type.systemBars(),displayCutout(), andime()across physical devices to prevent layout clipping and touch target obstruction.
The Android 15 Edge-to-Edge Mandate: Architectural Reality and Breaking Changes
The transition to edge-to-edge displays fundamentally alters how the Android window manager measures, lays out, and renders view hierarchies. Prior to Android 15, applications could opt into edge-to-edge rendering by calling WindowCompat.setDecorFitsSystemWindows(window, false) or setting specific window flags. Android 15 deprecates this opt-in behavior and enforces edge-to-edge rendering for all apps targeting API 35, forcing application view hierarchies to span the entire physical display from corner to corner.
Direct Answer: What Edge-to-Edge Enforcement Means for Android Apps
Android 15 edge-to-edge enforcement means applications draw beneath the status bar, display cutouts, and navigation bar by default. System bars become transparent or translucent, and the window manager no longer fits views within system boundaries automatically. Developers must explicitly apply padding or margins using WindowInsetsCompat or Jetpack Compose WindowInsets to keep interactive elements within visible, touchable screen areas.
The Evolution from DecorFitsSystemWindows to Mandatory Insets
Historically, Android developers relied on android:fitsSystemWindows="true" in XML layouts or called WindowCompat.setDecorFitsSystemWindows(window, true) to instruct the operating system to automatically inject padding matching the status bar and navigation bar heights. This legacy approach created numerous subtle bugs, particularly when activities contained complex nested view hierarchies, scrolling containers, or custom bottom sheets.
Under the Android 15 architecture, setDecorFitsSystemWindows(window, true) is deprecated and ignored for apps targeting API 35. The framework window manager dispatches window insets directly down the view hierarchy. If a ViewGroup or Composable fails to consume or apply these insets, UI elements collide with system bars. For example, a BottomNavigationView or NavigationBar placed at the bottom of the screen without WindowInsetsCompat.Type.navigationBars() padding renders directly beneath the Android gesture navigation pill, making navigation tabs unresponsive or misdirected when users attempt to swipe home.
Display Cutouts, Pinholes, and Waterfalls
Edge-to-edge enforcement is further complicated by physical device hardware variability. Android hardware encompasses a vast spectrum of physical form factors:
- Camera Pinholes and Notches: Centered, offset left, or corner camera punch-holes require explicit
displayCutout()handling so that action bar titles or toolbar navigation icons do not collide with the camera lens. - Gesture Navigation Bars vs Three-Button Navigation: Devices configured with gesture navigation present a thin horizontal indicator bar (typically 16-24dp high), whereas devices configured with classic three-button navigation reserve a rigid 48dp bottom bar. Applications must dynamically adapt their bottom padding depending on user system preferences.
- Waterfall and Curved Displays: Displays with steep curved edges introduce side cutouts and touch exclusion zones where edge taps must be disregarded or inset inward to prevent accidental palm triggers.
The following table contrasts legacy window management against the mandatory Android 15 edge-to-edge architecture:
| Architectural Property | Legacy Android (API < 35 Opt-In) | Android 15 Mandatory (API 35+) |
|---|---|---|
| Default Window Fitting | Window fits inside system bars by default | Views draw behind all system bars by default |
setDecorFitsSystemWindows |
Controls whether app fits inside system bars | Deprecated and ignored; edge-to-edge is mandatory |
| System Bar Colors | Solid colors, dark scrims, or light/dark icons | Fully transparent or translucent system bars |
| Status Bar Collision Risk | Low (OS padded content automatically) | High (toolbars collide with status icons and clock) |
| Navigation Bar Collision Risk | Low (content stopped above navigation bar) | High (FABs and bottom bars trapped under gesture pill) |
| Display Cutout Handling | Default letterboxing or optional cutout mode | Mandatory cutout insets handling for landscape and portrait |
| IME Keyboard Insets | windowSoftInputMode="adjustResize" worked globally |
Requires explicit WindowInsetsCompat.Type.ime() consumption |
| Verification Strategy | Static layout preview or simple JVM mocks | Real device node hierarchy and visual frame inspection |
The Testing Challenge: Why Synthetic Mocks and Emulators Miss Insets Bugs
Validating edge-to-edge layouts represents a notorious blind spot in automated mobile quality assurance. Synthetic unit test runners, headless CI emulators, and traditional UI test frameworks like Espresso frequently pass test suites while the physical app exhibits severe visual overlapping in production.
Direct Answer: Why Emulators Miss Insets Regressions
Emulators and synthetic mocks fail to capture edge-to-edge bugs because generic AVD images often lack vendor-specific camera cutout geometries, OEM gesture navigation bar heights, and realistic soft keyboard rendering engines. Furthermore, headless test runners evaluate view models and layout attributes without verifying physical pixel collisions, allowing obscured buttons and clipped typography to pass assertions undetected.
The Limits of Robolectric and JVM-Based Layout Tests
Robolectric executes Android framework code directly on the Java Virtual Machine (JVM). While Robolectric allows developers to instantiate Activities and inflate layouts at blazing speeds, its shadow window manager does not execute the actual SurfaceFlinger graphics pipeline or hardware-accelerated Skia rendering engine.
When a layout inflates in a Robolectric test, View.getRootWindowInsets() often returns null or provides synthetic default insets that do not mirror real physical displays. A button with android:layout_marginBottom="0dp" sitting at coordinate y = 2340 on a 2400-pixel vertical screen passes all synthetic Robolectric assertions, even though on a physical Samsung Galaxy or Google Pixel, that exact button is completely covered by the navigation bar and unusable by human fingers.
Espresso and UiAutomator Coordinate Blind Spots
Traditional instrumentation frameworks like Espresso and UiAutomator interact with Android views through programmatic references (onView(withId(R.id.submit_button))). While Espresso can verify that a view is marked VISIBLE in the view hierarchy, it does not assess whether the view's interactive bounding box overlaps with system window insets:
- False-Positive Visibility: Espresso's
matches(isDisplayed())assertion only checks that at least 90% of the view's area is visible within its parent layout. If the bottom 10% of a critical CTA button overlaps the gesture navigation bar, Espresso declares the test green even though users attempting to tap the button trigger the Android home gesture instead. - Missing Cutout Bounds: Emulators booted in CI pipelines frequently run standard 1080x1920 configurations without simulated display cutouts. When the same build runs on a device with a deep camera notch, text in the top app bar is clipped directly behind the physical camera module.
- IME Animation Desynchronization: Testing keyboard transitions with Espresso often relies on static delays. Espresso cannot easily assert whether a floating action button smoothly animates upward as the keyboard opens or whether the button snaps beneath the keyboard during layout reflow.
By connecting Claude Code for Android app testing on a real device through ScreenSync MCP, developers overcome these limitations by evaluating the live physical display, inspecting the true accessibility hierarchy, and validating interactive touch targets under real hardware constraints.
| Quality Dimension | Robolectric (JVM Unit Test) | Headless CI Emulator (Espresso) | Claude Code + ScreenSync MCP |
|---|---|---|---|
| Execution Environment | Desktop JVM | Virtualized Android AVD | Physical Android Hardware (Android 7.0+) |
| System Bar Insets | Mocked synthetic insets or null | Generic AVD insets; missing OEM tweaks | Live hardware system bar dimensions |
| Display Cutouts | Not supported | Simulated via developer options only | Real physical camera punch-holes and notches |
| Touch Target Assertion | None (pure programmatic invocation) | Coarse clickability; blind to OS bar overlap | Precise node coordinate and bounds analysis |
| Visual Frame Analysis | No display output | Static screenshot capture (high latency) | Sub-100ms MediaProjection frame streaming |
| IME Keyboard Dynamics | Synthetic text injection; no soft IME | Slow emulator software keyboard render | Real physical IME popup and insets animation |
| OEM Navigation Modes | Fixed default navigation | Standard AVD gesture or 3-button | Real One UI, Pixel, and MIUI navigation skins |
| CI/CD Automation | Fast unit test phase | Brittle, resource-heavy VM setup | Autonomous CLI agent execution via MCP |
Production Kotlin Architecture for Resilient WindowInsets Handling
To build an Android application that gracefully conforms to edge-to-edge requirements across both legacy Android releases and Android 15, developers must implement robust window insets consumption. Below are production-ready Kotlin architectures for both traditional Android Views and modern Jetpack Compose applications.
Production Android Views Implementation with WindowInsetsCompat
In Android Views, you must attach an OnApplyWindowInsetsListener to root containers and individual scrolling views to ensure insets are consumed hierarchically without causing double-padding bugs:
package com.example.app.ui.layout
import android.os.Build
import android.os.Bundle
import android.view.View
import android.view.ViewGroup
import androidx.appcompat.app.AppCompatActivity
import androidx.core.graphics.Insets
import androidx.core.view.ViewCompat
import androidx.core.view.WindowCompat
import androidx.core.view.WindowInsetsCompat
import androidx.core.view.updateLayoutParams
import androidx.core.view.updatePadding
import com.example.app.databinding.ActivityMainBinding
class EdgeToEdgeActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
// Configure the window for edge-to-edge rendering
WindowCompat.setDecorFitsSystemWindows(window, false)
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
setupSystemBarInsets()
setupKeyboardInsets()
}
private fun setupSystemBarInsets() {
// Apply insets listener to the app bar to handle status bar and display cutout
ViewCompat.setOnApplyWindowInsetsListener(binding.appBarLayout) { view, windowInsets ->
val insets = windowInsets.getInsets(
WindowInsetsCompat.Type.statusBars() or WindowInsetsCompat.Type.displayCutout()
)
// Apply top padding to avoid status bar and camera notch overlap
view.updatePadding(top = insets.top)
windowInsets
}
// Apply bottom padding to the bottom navigation bar or content container
ViewCompat.setOnApplyWindowInsetsListener(binding.bottomNavigation) { view, windowInsets ->
val insets = windowInsets.getInsets(WindowInsetsCompat.Type.navigationBars())
// Apply bottom padding to raise navigation tabs above the gesture bar
view.updatePadding(bottom = insets.bottom)
windowInsets
}
// Apply margins to Floating Action Button so it hovers above navigation bar
ViewCompat.setOnApplyWindowInsetsListener(binding.floatingActionButton) { view, windowInsets ->
val insets = windowInsets.getInsets(WindowInsetsCompat.Type.navigationBars())
view.updateLayoutParams<ViewGroup.MarginLayoutParams> {
bottomMargin = insets.bottom + 16 // 16dp base margin + nav bar height
}
windowInsets
}
}
private fun setupKeyboardInsets() {
// Animate content upward when the software keyboard (IME) opens
ViewCompat.setOnApplyWindowInsetsListener(binding.rootContainer) { view, windowInsets ->
val imeInsets = windowInsets.getInsets(WindowInsetsCompat.Type.ime())
val navInsets = windowInsets.getInsets(WindowInsetsCompat.Type.navigationBars())
// The keyboard already covers the navigation bar, so take the maximum
val bottomPadding = maxOf(imeInsets.bottom, navInsets.bottom)
view.updatePadding(bottom = bottomPadding)
windowInsets
}
}
}
Production Jetpack Compose Implementation with Safe Insets
In Jetpack Compose, the runtime provides built-in WindowInsets handling via modifiers. For a detailed exploration of composable testing, review our dedicated guide on testing Jetpack Compose apps with Claude Code and MCP. Below is a resilient Compose layout structure:
package com.example.app.ui.compose
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.asPaddingValues
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.imePadding
import androidx.compose.foundation.layout.navigationBarsPadding
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.safeDrawing
import androidx.compose.foundation.layout.statusBarsPadding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.FloatingActionButton
import androidx.compose.material3.Icon
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun EdgeToEdgeScreen() {
Scaffold(
contentWindowInsets = WindowInsets.safeDrawing,
topBar = {
TopAppBar(
title = { Text("Edge-to-Edge Verification") },
// Automatically respects statusBars and displayCutout insets
windowInsets = WindowInsets.safeDrawing
)
},
floatingActionButton = {
FloatingActionButton(
onClick = { /* Action */ },
// Automatically insets above navigation bars and software keyboards
modifier = Modifier
.navigationBarsPadding()
.imePadding()
) {
Text("+")
}
}
) { innerPadding ->
LazyColumn(
modifier = Modifier
.fillMaxSize()
.padding(innerPadding)
.imePadding()
) {
items(50) { index ->
Text(
text = "Scrollable Content Item #$index",
modifier = Modifier.padding(16.dp)
)
}
}
}
}
Setting Up Claude Code and ScreenSync MCP for Insets Verification
Connecting Claude Code to physical Android hardware provides an interactive Model Context Protocol pipeline that unifies real-time screen perception with deterministic device controls.
Direct Answer: How ScreenSync MCP Connects Claude Code to Android Devices
ScreenSync MCP runs as a local Node.js hub that implements the Model Context Protocol over stdio for AI clients like Claude Code, Claude Desktop, and Cursor. Android screen frames stream across the local Wi-Fi network from the phone to the desktop hub on HTTP port 3000 via native MediaProjection without root access or ADB, while control tools like taps, swipes, and text entry execute through ADB over USB or wireless debugging.
Hub Architecture and Dual-Pathway Execution
ScreenSync MCP is engineered specifically for physical Android devices running Android 7.0 or later. It operates through two distinct technical pathways:
- Screen Capture Pathway: Uses Android's native
MediaProjectionAPI. When the developer taps "Start now" on the device's system projection dialog at the start of a session, the app streams display frame buffers directly across the local LAN to the desktop hub on HTTP port 3000. This capture pipeline requires no root access and zero ADB permissions, maintaining a median latency of approximately 94 ms on local Wi-Fi networks in our tests. - Device Control Pathway: Action tools (
control_tap,control_swipe,control_type,control_launch_app) execute through standard Android Debug Bridge (ADB) commands routed by the desktop hub over USB or wireless debugging.
To set up the desktop hub, ensure Node.js 18+ is installed on your development workstation (Windows, macOS, or Linux). Download and extract the hub archive, then start the server using the platform startup script:
# On Linux or macOS
./start-hub.sh
# On Windows PowerShell or Command Prompt
.\start-hub.bat
The hub initializes on local port 3000 and generates a connection QR code. Install the free ScreenSync MCP application from Google Play (com.screensync.mcp), grant the MediaProjection screen capture consent prompt, and scan the QR code to pair the phone and hub over your local Wi-Fi network.
Next, register ScreenSync MCP as an active stdio server inside Claude Code:
# Register ScreenSync MCP inside Claude Code CLI
claude mcp add screensync node "C:/tools/screensync/screensync-hub.js"
Verify that Claude Code connects successfully by running /mcp in the CLI. The agent will show ScreenSync MCP active with its 226 available tools: 29 phone and desktop tools (12 control_* action tools, 3 os_* system tools, and 14 capture and hub tools like get_latest_screenshot, get_ui_hierarchy, and get_logcat), alongside 197 web_* browser tools powered by the Chrome/Edge extension. For complete configuration options, consult the official ScreenSync MCP setup guide.
{
"mcpServers": {
"screensync": {
"command": "node",
"args": ["C:/tools/screensync/screensync-hub.js"],
"env": {
"SCREEN_SYNC_TOKEN": "your_secure_bearer_token_here"
}
}
}
}
This configuration also integrates with Claude Desktop by placing the block above into claude_desktop_config.json via Settings > Developer.
Step-by-Step QA Playbook: Autonomous Edge-to-Edge and Insets Testing
With Claude Code connected to your physical Android device via ScreenSync MCP, you can automate comprehensive edge-to-edge layout audits. Claude Code inspects view hierarchies, calculates coordinate overlaps against system bars, and exercises dynamic IME transitions.
Step 1: Launch Application and Extract Screen Window Geometry
Instruct Claude Code to launch the target application and extract the physical display dimensions alongside the system bar boundaries:
Launch com.example.app on the connected Android device. Retrieve the current UI hierarchy using get_ui_hierarchy and capture the screen state with get_latest_screenshot. Identify the status bar height, navigation bar height, and screen dimensions.
Claude Code calls control_launch_app followed by get_ui_hierarchy:
{
"name": "control_launch_app",
"arguments": {
"package": "com.example.app",
"activity": ".ui.layout.EdgeToEdgeActivity"
}
}
The agent queries the node tree. Unlike computer vision models that guess pixel boundaries from static images, ScreenSync MCP returns exact structural view bounds ([left,top][right,bottom]), view IDs, and clickable properties. To understand why node hierarchies outperform raw vision, explore our architectural analysis on how AI agents use Android UI trees not screenshots.
Step 2: Validate Status Bar and Display Cutout Clearance
Direct Claude Code to verify that header toolbars, back buttons, and title text are not clipped by the top status bar or camera notch:
Inspect the top app bar element in the UI hierarchy. Calculate the bottom bound of the status bar (top insets) and assert that the top bound of all interactive header buttons is strictly greater than or equal to the status bar height.
Claude Code examines the bounds of binding.appBarLayout and its child views:
- Screen dimensions:
1080 x 2400 - Status bar height:
88px(approx 32dp on high-density screen) - Back button bounds:
[16, 104][112, 200] - Assertion: Since
top = 104px > 88px, the back button is completely clear of the status bar.
If a developer failed to add updatePadding(top = insets.top), the back button bounds would report [16, 16][112, 112], which overlaps the status bar between 16px and 88px. Claude Code flags this as a critical insets collision defect.
Step 3: Validate Bottom Navigation and Gesture Pill Clearance
Instruct Claude Code to check that bottom navigation items or floating action buttons (FABs) maintain adequate clearance from the bottom gesture navigation bar:
Inspect the bottom navigation bar and the Floating Action Button. Retrieve the bottom insets representing the gesture navigation bar. Assert that the touchable bounding boxes of all navigation items sit above the navigation bar exclusion zone.
Claude Code parses the navigation bar node:
- Screen vertical limit:
2400px - Gesture bar insets:
64px(bottom zone from2336pxto2400px) - Navigation item touch bounds:
[0, 2192][1080, 2336] - Assertion: Navigation item bounds terminate at
2336px, perfectly flush with the top of the gesture navigation bar. The gesture pill has a clear visual background while touch targets remain fully unobstructed.
Step 4: Exercise Software Keyboard (IME) Insets Transitions
One of the most common edge-to-edge regressions occurs when focusing an EditText field. The soft keyboard animates into view, but the input field or its submit button remains trapped behind the keyboard.
Prompt Claude Code to test this flow:
Tap the comment input field at the bottom of the screen using control_tap. Wait 500ms for the keyboard to animate. Call get_ui_hierarchy to assert that the input field and its submit button shifted upward and remain completely visible above the keyboard insets.
Claude Code dispatches control_tap to the input field coordinates, then calls get_ui_hierarchy to assert that the container's bottom padding adjusted to match the IME insets:
{
"name": "control_tap",
"arguments": {
"x": 300,
"y": 2250
}
}
The agent verifies that the input field's new bounding box is [32, 1280][880, 1392], positioning it securely above the software keyboard's top boundary at 1400px. For related input automation techniques, read our guide on testing Android runtime permissions with Claude Code and MCP.
Deep Dive: Edge Case Testing Across Screen Orientations and Foldables
Testing edge-to-edge layouts on a single portrait phone does not guarantee stability in diverse mobile environments. Android applications must gracefully handle dynamic screen rotations, foldable posture changes, and split-screen multi-window modes.
1. Landscape Orientation and Dual Cutout Shifts
When users rotate an Android phone into landscape mode, the status bar relocates or shrinks, while the display cutout (camera hole) shifts to the left or right side of the screen.
Using ScreenSync MCP, Claude Code can trigger screen rotation via ADB:
adb shell settings put system user_rotation 1
In landscape mode (2400 x 1080):
- The camera cutout now creates a horizontal cutout on the left or right edge (e.g., width
136px). - Claude Code queries
get_ui_hierarchyto confirm that horizontal padding (WindowInsetsCompat.Type.displayCutout()) was applied to prevent content from slipping behind the camera hole. - After validation, Claude Code resets the rotation to portrait (
user_rotation 0).
To explore specialized layout testing on foldables, dual-screen devices, and tablet form factors, see our comprehensive guide on testing Android foldables and adaptive layouts with Claude Code and MCP.
2. Multi-Window and Split-Screen Insets Redistribution
When an application enters split-screen mode, the window manager redistributes system insets:
- The top application receives the status bar insets but zero bottom navigation bar insets.
- The bottom application receives the navigation bar insets but zero status bar insets.
- Both applications receive custom divider insets.
Claude Code triggers split-screen mode via ADB input commands, queries get_ui_hierarchy for each window, and validates that neither application applies phantom status bar padding when running in the lower split window.
3. Gesture Bar vs 3-Button Navigation Toggle
OEMs like Samsung, Xiaomi, and Google allow users to toggle between gesture navigation and 3-button navigation.
Claude Code can toggle navigation modes in test environments:
# Enable 3-button navigation via overlay
adb shell cmd overlay enable com.android.internal.systemui.navbar.threebutton
# Enable gesture navigation via overlay
adb shell cmd overlay enable com.android.internal.systemui.navbar.gestural
Claude Code validates that your application dynamically re-evaluates WindowInsetsCompat.Type.navigationBars() and scales its bottom padding from 24dp (gesture bar) to 48dp (3-button bar) without requiring an activity recreation.
Security, Token Authentication, and Local Network Privacy
Automating physical Android devices with AI coding agents in professional development environments requires strict compliance with enterprise security and data privacy standards.
Local LAN Streaming Isolation
ScreenSync MCP strictly confines real-time screen streaming to the developer's local area network. When the Android application transmits display frame buffers via the native MediaProjection API, packets flow directly across the local Wi-Fi router or USB tether to the desktop hub running on HTTP port 3000. Display buffers and video frames are never transmitted to EpsolDev cloud servers. An optional Google Drive upload fallback exists within the Android app settings, but it is disabled by default.
Model Context Protocol Bearer Token Governance
All communication between the Android app, desktop hub, and AI coding agents is authenticated using a secure bearer token (SCREEN_SYNC_TOKEN). This prevents unauthorized machines on corporate Wi-Fi subnets from discovering the hub, capturing screen streams, or injecting unauthorized ADB commands.
Model Provider Data Boundaries
Developers should understand precisely when mobile display data leaves the local machine. Video streams processed by the local ScreenSync MCP hub remain on your workstation. However, when Claude Code or any connected AI model executes get_latest_screenshot, that individual visual frame is encoded as a JPEG and sent to Anthropic's model API endpoint for visual inference.
When testing enterprise applications handling sensitive data, developers should utilize mock data fixtures or test accounts to avoid rendering real personal identifiable information (PII), customer credentials, or production payment cards on screen. To explore comprehensive device control capabilities, review our complete Android MCP tool documentation.
Pre-Testing Checklist for Android Edge-to-Edge Quality Assurance
Before launching an automated edge-to-edge verification session with Claude Code and ScreenSync MCP, ensure your test environment satisfies the following prerequisites:
- Target SDK Level: Confirm your application targets Android 15 (compileSdkVersion 35, targetSdkVersion 35) to enforce mandatory edge-to-edge behavior.
- Physical Device Operating System: Ensure the connected physical device runs Android 7.0 (API level 24) or later.
- ScreenSync Android App: Install version 2.5.7 from Google Play (
com.screensync.mcp) and grant the MediaProjection consent prompt upon launch. - Desktop Hub Environment: Verify Node.js 18+ is available on the workstation and start hub version 1.14.4 via
start-hub.batorstart-hub.shon port 3000. - ADB Connectivity: Ensure the physical device is authorized for USB debugging or wireless debugging (
adb devicesconfirms authorized status). - Claude Code Registration: Confirm that
claude mcp add screensync node "/path/to/hub/screensync-hub.js"is configured and active. - WindowCompat Configuration: Verify that
WindowCompat.setDecorFitsSystemWindows(window, false)is declared in your base activity. - Insets Consumption: Verify that scrolling containers and bottom navigation bars register
OnApplyWindowInsetsListeneror ComposeWindowInsets.safeDrawing.
Conclusion
The Android 15 edge-to-edge mandate marks a permanent evolution toward immersive, borderless mobile application design. However, delivering flawless edge-to-edge user experiences demands verification tools capable of inspecting physical hardware insets, display cutouts, and dynamic keyboard animations. By bridging Claude Code with physical devices through ScreenSync MCP, engineering teams can autonomously audit view hierarchies, calculate exact insets clearances, and eliminate visual regressions before production releases.
ScreenSync MCP provides the ScreenSync MCP Android app, ScreenSync MCP desktop hub, and ScreenSync MCP browser extension to mobile engineers worldwide. To explore comprehensive device control capabilities, consult the complete Android MCP tool reference, learn more about the overall ScreenSync MCP architecture, or explore our complete Android MCP server guide.
Ready to automate your Android testing workflows on real hardware? Download the free app on ScreenSync MCP on Google Play and follow the ScreenSync MCP setup guide to connect your AI agent today.
Next steps
Questions, answered
Can Claude Code test Android 15 edge-to-edge layout enforcement on real devices?
Yes, Claude Code connects to the local ScreenSync MCP hub over stdio to test Android 15 edge-to-edge layouts on physical devices running Android 7.0 or later. The agent queries get_ui_hierarchy to inspect exact node bounds against system bar insets and captures display buffers via native MediaProjection without requiring root access.
What is the difference between WindowInsetsCompat and legacy fitsSystemWindows?
Legacy fitsSystemWindows automatically added padding to view containers to keep them within system windows. WindowInsetsCompat dispatches insets hierarchically, allowing views to draw behind transparent system bars while developers selectively consume statusBars, navigationBars, displayCutout, or ime insets to preserve interactive touch targets and prevent clipping.
Why do synthetic unit tests like Robolectric fail to catch edge-to-edge bugs?
Robolectric executes on the JVM without running Android's SurfaceFlinger compositor or hardware rendering pipeline. View.getRootWindowInsets often returns null or synthetic defaults that omit physical camera notches, OEM navigation bar heights, and live keyboard animations, allowing views that collide with system bars on physical hardware to pass unit tests.
Does testing edge-to-edge layouts with ScreenSync MCP require root or ADB?
Screen capture requires no root and no ADB, streaming display frames across your local network via Android's native MediaProjection API following user consent. Device control tools like tapping buttons, swiping lists, or invoking the software keyboard execute through Android Debug Bridge (ADB) over USB or wireless debugging.
How do AI agents detect UI overlap behind system bars without pixel guessing?
Rather than guessing coordinates from raw pixels, Claude Code calls get_ui_hierarchy via ScreenSync MCP to inspect the structural accessibility node tree. The agent compares each view's bounding box against known status bar and gesture navigation insets, deterministically detecting whether a button is trapped beneath the navigation bar.
How does ScreenSync MCP verify IME soft keyboard insets transitions?
Claude Code uses control_tap to focus an EditText, triggering the physical soft keyboard. The agent then calls get_ui_hierarchy to verify that the container consumed WindowInsetsCompat.Type.ime() padding and that input fields, action buttons, and cancel controls animate cleanly above the keyboard without being obscured.
Can Claude Code test edge-to-edge layouts across landscape and split-screen modes?
Yes, Claude Code dispatches ADB shell commands through ScreenSync MCP to rotate the device orientation or trigger multi-window split-screen modes. The agent re-queries get_ui_hierarchy to verify that camera cutout insets adapt horizontally and that split-screen windows receive correct partitioned system insets without phantom top padding.
Are application frames or test code sent to EpsolDev cloud servers during MCP QA?
No, visual frame buffers stream strictly across your local Wi-Fi network between the physical Android phone and your local desktop hub on port 3000. Frames never reach EpsolDev servers. When Claude Code executes get_latest_screenshot, only that specific frame is sent to Anthropic's model API for visual reasoning.




