Designs and audits native Android interfaces. Use when reviewing Compose layout, typography, color, motion, or adaptive patterns on a verified emulator build.
Installs into .claude/skills of the current project.
Are you the author of Software Android Design?
Add the live security badge to your README. It updates with every re-scan.
[](https://www.skillsdirectory.com/skills/vasilyu1983-software-android-design)
---
name: software-android-design
description: "Designs and audits native Android interfaces. Use when reviewing Compose layout, typography, color, motion, or adaptive patterns on a verified emulator build."
compatibility: Portable core. Works on Claude Code and Codex.
version: "1.2"
last_validated: 2026-07-11
---
# Native Android Design
Use this skill for visual design decisions and design-focused audits in native Android apps. Prefer it when the user needs Material 3 aligned screen structure, current Android-native visual defaults, or a screenshot-to-fix loop after a fresh verified build/install/launch. If the request is really about greenfield scaffolding, Gradle build loops, module selection, or broader Android implementation workflow, route to `software-mobile` and return here once the question becomes visual structure or design quality.
## Quick Reference
| Design concern | Default | Notes |
|---------------|---------|-------|
| Type | `MaterialTheme.typography` | Display → Headline → Title → Body → Label scale |
| Color | `MaterialTheme.colorScheme` | primary, secondary, tertiary, surface, error, and `on*` variants |
| Shape | `MaterialTheme.shapes` | ExtraSmall→ExtraLarge; `RoundedCornerShape` |
| Dynamic color | `dynamicDarkColorScheme` / `dynamicLightColorScheme` | Android 12+; static seed palette on older APIs |
| Bottom nav | `NavigationBar` 3–5 destinations | `NavigationRail` from medium through extra-large width (the `NavigationSuiteScaffold` default), expanded rail (not drawer) under M3 Expressive |
| Top bar | `TopAppBar` / `MediumTopAppBar` / `LargeTopAppBar` / `CenterAlignedTopAppBar` | Choose by headline presence; collapsing variants for rich headers |
| Cards | `ElevatedCard` hero, `Card` primary, `OutlinedCard` secondary | Optional team hierarchy; use theme surface/elevation defaults |
| Adaptive layouts | `ListDetailPaneScaffold`, `SupportingPaneScaffold`, `NavigationSuiteScaffold` | Feed grids for homogeneous content |
| Detail views | Sheet for a focused task; destination or detail pane for deep content | Preserve context and back behavior |
| Motion | Container transforms, `AnimatedVisibility`, `animateContentSize`, `spring()` | M3 Expressive defaults |
| Edge-to-edge | `enableEdgeToEdge()` + `windowInsetsPadding` | Mandatory, non-optional for targetSdk 36+ (`windowOptOutEdgeToEdgeEnforcement` removed) |
| Predictive back | Navigation and Material component defaults | Custom `PredictiveBackHandler` only for custom gesture-driven behavior |
| Press feedback | Standard clickable Material component or `Modifier.clickable` | Default indication provides feedback; custom scale motion is optional |
| Chip groups | `FlowRow` | Use when spatial context matters; avoid horizontal scroll for finite sets |
| Peer view switch | `SegmentedButton` or `TabRow` | Reduces navigation depth vs. separate screens |
| Touch targets | ≥ 48dp on all interactive elements | Platform minimum |
| Token discipline | No magic numbers in screen files | Tokenize spacing, elevation, shape, color |
## Defaults
- Start from Material 3; select Expressive when it fits the app's design system and task density.
- Treat Compose Material 3 as the modern native baseline for navigation, surfaces, typography, color, shape, and motion.
- Enable dynamic color on Android 12+ and provide a well-tuned static seed palette as fallback.
- Prefer `MaterialTheme.typography`, `MaterialTheme.colorScheme`, `MaterialTheme.shapes`, and standard containers before custom styling.
- Keep navigation familiar: adaptive bar/rail for peer sections, the app's navigation host for drill-down, sheets for focused tasks.
- Use emulator screenshot-driven verification after the screenshot is tied to the current build. Preserve app data unless stale state or signing mismatch actually requires a reset.
## Platform Currency
Look these up each session; never hard-code them in advice or generated code:
- **Current Android release and API level**: check [developer.android.com/about/versions](https://developer.android.com/about/versions) before calling any version "current" or "latest".
- **Google Play target API policy**: the required target API level and its deadline move roughly once a year. Check [developer.android.com/google/play/requirements/target-sdk](https://developer.android.com/google/play/requirements/target-sdk) rather than hardcoding a number.
- **Material 3 Expressive**: check the installed artifact and [release notes](https://developer.android.com/jetpack/androidx/releases/compose-material3) for each API's availability and annotation. Release channel and opt-in status are separate: `Material3ExpressiveApi` does not require opt-in; `ExperimentalMaterial3ExpressiveApi` does.
- **Compose BOM**: look up the current stable BOM at [developer.android.com/develop/ui/compose/bom/bom-mapping](https://developer.android.com/develop/ui/compose/bom/bom-mapping) rather than pinning an exact version in generated code.
- **Predictive back** is default for apps targeting API 36+ on Android 16+ devices; `onBackPressed()` and `KEYCODE_BACK` are no longer dispatched at that target. Prefer supported navigation/component handling; custom interception can disable system animations.
- **Edge-to-edge** is fully mandatory, not just default-on: `windowOptOutEdgeToEdgeEnforcement` is deprecated and has no effect once targetSdk reaches 36. Any recommendation that relies on opting out of edge-to-edge is stale.
## Runtime Proof Gate
- Do not trust screenshots until the installed package and visible screen are tied to the current build and variant.
- Start with `adb install -r` so saved state and the exact repro survive. Clear data or uninstall only after capturing the current state and proving stale state, schema incompatibility, or a signing mismatch.
- If install or launch is failing, stop design iteration and fix runtime truth before continuing.
- Use ADB and Gradle from the command line when Android Studio is not available.
## Core Workflow
1. Define the screen's primary job and the one or two pieces of content that must win first attention.
2. Choose the Material structure first: `NavigationBar`, `NavigationRail`, `Scaffold`, `TopAppBar`, `ModalBottomSheet`, `ListDetailPaneScaffold`, or adaptive scaffold.
3. Apply typography, spacing, and color using Material tokens before inventing a custom scale.
4. Use `currentWindowAdaptiveInfo(supportLargeAndXLargeWidth = true)` and `isWidthAtLeastBreakpoint(...)`; verify compact, medium, expanded, and Large/Extra-large for desktop or connected-display targets. Load [material-layout-spacing.md](references/material-layout-spacing.md#layout-adaptivity) for ordered checks, height constraints, and hinge handling.
5. Verify with emulator: build, preserve repro state, replace-install, launch, capture screenshot, inspect, fix, repeat. Clear data only when state is the variable under test.
Before accepting a visual change, capture the affected screen in populated, loading, empty, error, and disabled/permission states that the feature can reach. Cross those states with the smallest device/configuration set that can expose the risk: compact + expanded width for adaptive changes, 200% font scale for text/layout changes, light + dark for color/material changes, and TalkBack focus order for semantic changes. A single polished happy-path screenshot is presentation evidence, not state coverage.
## Design Craft Checklist
Before writing or reviewing screen code, check these patterns from [references/design-craft-patterns.md](references/design-craft-patterns.md):
1. **Token discipline**: Every spacing, elevation, shape, color, and repeated typography value traces to a named token. No magic numbers in screen files. If a `TextStyle(fontSize = N.sp, fontWeight = W)` pattern appears 3+ times, extract it to a typography token or use the Material type scale.
2. **Data containment**: Values live in Cards, `ListItem` rows, or grid cells with visual boundaries, not floating in unbounded Column space.
3. **Visual anchoring**: Data labels include Material icons (18-20dp). Categorized lists use colored dot indicators (6dp Canvas circles) for instant visual grouping.
4. **Card hierarchy**: Use a distinct hero treatment when the task needs it; `ElevatedCard`/`Card`/`OutlinedCard` is a team default, not a platform-required hierarchy. Keep shape/elevation values in theme tokens.
5. **Data visualization**: Use `Canvas` for custom charts (radar, rings, gauges), animated score rings with `Animatable`, and gradient score bars. See [references/android-component-patterns.md](references/android-component-patterns.md#canvas-visualizations).
6. **Interactive polish**: Apply `AnimatedVisibility` for entrance reveals, `animateContentSize` for expanding sections, `spring()` for natural motion, container transforms for navigation transitions, and press feedback via `Indication` or `InteractionSource` on all tappable surfaces.
7. **Elevation and tonal surfaces**: Use `tonalElevation` for surface layering rather than drop shadows alone. Material 3 uses tonal color overlays to express elevation — `Surface(tonalElevation = N.dp)` shifts surface color automatically.
8. **Localization readiness** (strings, plurals and pipeline are owned by [software-localisation](../software-localisation/SKILL.md)): All user-facing strings go through `strings.xml`, including short labels. Test longer translations, Arabic RTL, and CJK locales for overflow and mirroring.
9. **Competitor awareness**: Check competitor patterns before inventing novel solutions. Borrow containment and anchoring patterns, not brand identities.
10. **Adaptive layout**: Verify reflow and navigation chrome against window width, height, and posture; a tablet in split-screen can have compact width.
11. **Accessibility**: All touch targets >= 48dp. All decorative images have `contentDescription = null`. All meaningful images and icons have descriptive `contentDescription`. Use `semantics { }` to merge related elements for TalkBack and provide custom actions.
12. **Shape consistency**: Use `MaterialTheme.shapes` scale (ExtraSmall through ExtraLarge) rather than ad-hoc `RoundedCornerShape` values. Keep shape language consistent across Cards, Buttons, Chips, and Sheets.
## Design Review Loop
- Prefer Android Studio Layout Inspector for hierarchy and bounds inspection when a project is runnable.
- If Layout Inspector is unavailable, use ADB screencap + uiautomator dump as fallback for screenshots and hierarchy XML.
- Prefer side-by-side before/after screenshots over verbal "looks better" claims.
- Ask for evidence of font scaling (100%, 130%, 200%), dark/light theme, and `WindowSizeClass` behavior when a change touches layout or hierarchy.
See:
- [references/ai-design-review-android.md](references/ai-design-review-android.md)
- [references/android-studio-design-loop.md](references/android-studio-design-loop.md)
- [scripts/capture-screenshot.sh](scripts/capture-screenshot.sh)
- [scripts/layout-inspector.sh](scripts/layout-inspector.sh)
## Expert Judgment
Decisions a senior Android design reviewer makes that go beyond checklist compliance:
### Compose vs. Views
Default to Compose for any new screen or greenfield module — it is the modern native baseline and this skill assumes it. Views still legitimately win in narrower cases:
- **Large existing View/XML codebases** where a full rewrite is not funded — interop via `ComposeView`/`AndroidView` at the screen boundary, migrate incrementally, do not force a big-bang rewrite for a design fix.
- **Performance-critical custom rendering** with `SurfaceView`/`TextureView` (camera preview, video, some game-like canvases) — Compose's `AndroidView` interop works but adds indirection; a thin View layer can still be simpler when the surface needs precise frame-timing control.
- **Heavy `RecyclerView` with complex diffing/animations already tuned** — `LazyColumn` is capable, but do not force a rewrite of a well-optimized, stable RecyclerView adapter purely for "modernization" without a design or velocity reason.
- Flag it as a smell, not a rule, when a team defaults to Views for a brand-new screen — ask why, since Compose Material 3 is the better-supported path for adaptive layouts, dynamic color, and Material 3 Expressive.
### Design-System Governance
- A token system only pays off if it is enforced, not just documented. If screen files still contain 3+ repeated raw `TextStyle`/`Color(0xFF...)`/`dp` literals, the design system has a governance gap, not a discipline gap — recommend a lint rule (e.g., Compose lint check or custom detekt rule) over a style-guide reminder.
- When a design system diverges from Material 3 defaults (custom shape scale, custom type ramp), require the divergence to be named and centralized in one theme file — never let ad-hoc per-screen overrides recreate "shadow tokens."
- Treat Material 3 Expressive adoption as a system-wide decision, not a per-screen one: mixing baseline M3 shapes/motion with Expressive shapes/motion in the same app reads as visually inconsistent. Pick one posture per app (or per clearly-scoped surface) and document why.
- Keep baseline M3 for dense productivity surfaces when larger shapes or prominent motion obscure comparison or reduce usable space. Retain an established brand system when migration provides no user benefit; reduce decorative motion for motion-sensitive users. This is a design judgment, not a Google prohibition on Expressive.
### Navigation and Predictive Back
- For new Compose navigation that needs multi-pane scenes, consider Navigation 3 `NavDisplay`; preserve a working Navigation Compose `NavHost` for a scoped visual fix. Navigation 3 uses scene strategies to render one or more entries, so test pane changes during window resizing. Load [android-component-patterns.md](references/android-component-patterns.md#navigation-3-and-predictive-back) when choosing scene transitions.
- Design back as a preview of the actual destination: test completion and cancellation from both swipe edges, including sheet dismissal and search exit. Prefer navigation/Material handling; use custom progress-driven handling only when the default cannot express the interaction, and preserve state when the gesture is cancelled.
### Platform Convention vs. Brand Identity
- Keep interaction models (navigation placement, back behavior, sheet vs. dialog choice, gesture conventions) aligned with platform convention even when a brand wants to differentiate — users' muscle memory for Android navigation is a usability asset, not a constraint to design around.
- Spend brand differentiation budget on what users actually perceive as "your app": color, shape language, motion character, illustration, voice/tone in copy. These can diverge from stock Material without confusing users.
- When a brand team pushes a fully custom navigation paradigm (e.g., no back button, custom bottom bar behavior) purely for differentiation, push back with the platform-convention cost: broken predictive-back expectations, broken TalkBack navigation order, and accessibility-services friction, all for a gain that is rarely measurable in retention.
### Foldable and Large-Screen Failure Modes
Common mistakes that pass phone-only review but fail on foldables/tablets:
- **Fixed single-pane layout stretched to expanded width** — constrain reading width or switch panes at `isWidthAtLeastBreakpoint(WindowSizeClass.WIDTH_DP_EXPANDED_LOWER_BOUND)`; make a separate Large/Extra-large choice when extra space supports another pane.
- **Not handling the fold seam / hinge** — content or interactive elements landing exactly on the hinge on a foldable's tabletop or book posture. Use `WindowInfoTracker`/`FoldingFeature` to detect the hinge and avoid placing critical controls there.
- **Navigation chrome selected by device label** — `NavigationSuiteScaffold` uses a bar for compact width, compact height, or tabletop posture; otherwise it uses a rail. A tablet can still need the bar in a constrained window.
- **Orientation/resizability assumptions baked into layout code** — assuming portrait-only or a fixed activity size breaks multi-window and free-form resizing. At targetSdk 36 (Android 16), on displays with the smallest width ≥600dp, the system ignores `screenOrientation`, `resizableActivity`, `min/maxAspectRatio`, and `setRequestedOrientation()` (games are exempt via `appCategory`); a temporary opt-out (`PROPERTY_COMPAT_ALLOW_RESTRICTED_RESIZABILITY`) stops working at targetSdk 37. Verify behavior with the emulator's resizable/foldable device profiles, not just a fixed Pixel phone skin, and check Play's adaptive app quality tiers — verify current thresholds at [developer.android.com/docs/quality-guidelines/adaptive-app-quality](https://developer.android.com/docs/quality-guidelines/adaptive-app-quality).
- **Testing only at compact and expanded, skipping medium** — the foldable inner-display and small-tablet band (600-839dp) is where two-column layouts most often look cramped or where a rail/nav choice is wrong; do not skip it as "close enough" to either neighbor.
## Route Elsewhere
- Use [../software-mobile/SKILL.md](../software-mobile/SKILL.md) for platform selection, cross-platform decisions, or general Android architecture and implementation strategy.
- Use [../qa-testing-android/SKILL.md](../qa-testing-android/SKILL.md) for Espresso, UI Automator, Compose testing, device matrix planning, or screenshot diff testing.
- Use [../software-ui-ux-design/SKILL.md](../software-ui-ux-design/SKILL.md) for generic product UX patterns that are not Android-specific.
- Use [../software-accessibility/SKILL.md](../software-accessibility/SKILL.md) for broader accessibility remediation beyond Android-native visual design defaults.
## Navigation
### References
- [references/design-craft-patterns.md](references/design-craft-patterns.md) — token discipline, data containment, visual anchoring, dark theme, competitor analysis, and common anti-patterns
- [references/material-layout-spacing.md](references/material-layout-spacing.md) — 8dp grid, edge-to-edge, spacing discipline, adaptive layouts, and dashboard density
- [references/material-typography-color.md](references/material-typography-color.md) — Material type scale, dynamic color, tonal palettes, custom fonts, contrast, and accessibility
- [references/android-component-patterns.md](references/android-component-patterns.md) — NavigationBar/Rail/Drawer, TopAppBar, Scaffold, Cards, Chips, Canvas visualizations, and interactive animations
- [references/android-dashboard-design.md](references/android-dashboard-design.md) — overview-screen hierarchy, data display patterns, card hierarchy, and content-heavy dashboard heuristics
- [references/ai-design-review-android.md](references/ai-design-review-android.md) — screenshot prompts, review checklists (structure, token audit, containment, anchoring), and proof expectations
- [references/android-studio-design-loop.md](references/android-studio-design-loop.md) — current Android Studio and emulator verification flow
- [data/sources.json](data/sources.json) — primary sources and freshness-check targets
### Scripts
These are optional helpers for a proven-build design loop. If the app cannot be built, installed, or launched cleanly, fix the build before staying in this skill.
- [scripts/_android_common.sh](scripts/_android_common.sh) — shared helpers for ADB, emulator, and AVD resolution
- [scripts/bootstrap-emulator.sh](scripts/bootstrap-emulator.sh) — create and boot an AVD for design iteration
- [scripts/build-android.sh](scripts/build-android.sh) — compile-only Gradle build wrapper
- [scripts/run-android.sh](scripts/run-android.sh) — build, install, and launch for iterative design work (`--uninstall-first` is an escalation, not the default)
- [scripts/capture-screenshot.sh](scripts/capture-screenshot.sh) — save an emulator screenshot for review loops
- [scripts/layout-inspector.sh](scripts/layout-inspector.sh) — dump UI hierarchy via uiautomator for structure review
- [scripts/test_run_android.py](scripts/test_run_android.py) — offline launcher regressions; run with `python3`, using mocked ADB/Gradle
## Anti-Patterns
- Do not invent custom chrome before checking whether standard Material 3 structure already solves the hierarchy problem.
- Do not hardcode `Color(0xFF...)` values in Composables — use `MaterialTheme.colorScheme` roles so light, dark, and dynamic color adapt automatically.
- Do not use fixed `sp` sizes outside the Material type scale without justification — prefer `MaterialTheme.typography` roles.
- Do not rely on elevation shadows alone for depth — Material 3 uses `tonalElevation` (tonal color shift) as the primary depth signal; shadows are supplementary.
- Do not wrap `Box(Modifier.clickable { })` without providing a ripple `Indication` — it produces a dead-feeling tap with no visual response.
- Do not use `ModalBottomSheet` as the sole navigation mechanism — it is for secondary detail, not primary app structure.
- Do not skip `WindowInsets` consumption after calling `enableEdgeToEdge()` — content will render behind system bars.
- Do not place an unbounded-height `LazyColumn` inside a vertical-scrolling parent; it throws during measurement. Prefer one mixed-item `LazyColumn`. A bounded-height child or different-axis scroller is valid; see [Google's nesting examples](https://developer.android.com/develop/ui/compose/lists#avoid-nesting-scrollable).
- Test fixed card heights at 200% font scale; prefer content-driven height. A minimum height can still grow with content.
- Do not use `pointerInput` with `detectTapGestures` for simple click handling — use `Modifier.clickable` which provides accessibility semantics, ripple, and focus handling for free.
- Do not treat dashboard heuristics such as card count or density as Google rules.
- Do not hardcode `Color.White` or `Color.Black` for text or surfaces — use `MaterialTheme.colorScheme.onSurface`, `onSurfaceVariant`, or `outline` roles.
- Do not skip `contentDescription` on meaningful icons and images — TalkBack users get no information from undescribed elements.
- Do not use `fillMaxWidth()` on every element without considering medium and expanded `WindowSizeClass` — content stretches to unreadable line lengths on tablets.
- Do not dismiss `ModalBottomSheet` and present a new one in the same frame — set state to hidden first, then present the new sheet after recomposition.
- Do not put temporal controls (sliders, scrubbers) inside bottom sheets — they belong in the main layout where they stay visible during visualization interaction.
- Do not start Canvas `animatableProgress` at `0f` for data-driven views — data may load after composition, leaving the Canvas empty. Start at `1f` or trigger animation on data change.
- Do not use `LazyVerticalGrid` with `GridCells.Fixed(3)` on compact phones for content that needs readable text — two columns or a single column with weight-based rows works better. Reserve `Fixed(3)` for icon-sized cells or compact stat grids.
- Do not use `Modifier.background()` with a rounded shape without also applying `.clip()` to the same shape — child content will bleed past the rounded corners. Use `Surface(shape = ...)` instead, which clips automatically.
- Do not use `rememberSaveable` for large data objects or lists — it serializes to `Bundle` which has a strict 1MB transaction limit. Use a `ViewModel` for screen-level data state; use `rememberSaveable` only for primitive UI state (selected tab index, scroll position, sheet expanded boolean).
- For Strong Skipping and visualization state/recomposition, load [android-native's state guidance](../software-android-native/references/compose-state-concurrency.md).
## Verification Gate
Before concluding a design recommendation or audit, confirm all of the following:
- [ ] Recommendation maps to standard Material 3 structure; custom patterns justified in comments
- [ ] Screenshot/emulator state from a freshly installed and launched build (not a stale install)
- [ ] Typography uses `MaterialTheme.typography` roles, not ad-hoc `TextStyle(fontSize = N.sp)`
- [ ] Color uses `MaterialTheme.colorScheme` roles; contrast verified in both light and dark themes, with dynamic color on and off
- [ ] All interactive elements have touch targets ≥ 48dp
- [ ] Adaptive layout verified on compact, medium, expanded, and Large/Extra-large when targeting desktop/connected displays
- [ ] Edge-to-edge: `enableEdgeToEdge()` called and all content uses `windowInsetsPadding` or equivalent — not an opt-out (`windowOptOutEdgeToEdgeEnforcement` has no effect at targetSdk 36+)
- [ ] Back preview reaches the intended destination, handles cancellation, and preserves sheet/search behavior using supported APIs
- [ ] Dashboard/density guidance labeled as a team heuristic, not a Google platform rule
- [ ] Expressive APIs checked against installed dependencies; required opt-ins and release channel recorded separately
Use [Platform Currency](#platform-currency) and [data/sources.json](data/sources.json) for platform/dependency decisions; consult the installed artifact's API reference before changing components.
## Learnings Loop
When prior decisions or pitfalls are relevant, consult `learnings.consolidated.md` if present; use `learnings.md` only for needed history or as the available fallback. Otherwise skip both.
After applying it, if you encountered a pattern worth remembering, a mistake worth preventing, or a domain fact that surprised you, append one dated bullet to `learnings.md` via `agents-skills-feedback-loop/scripts/append_learning.py`. Do not modify `SKILL.md` itself.