Astradial Android — Native UI Specification (Samsung One UI)¶
Goal: a user who picks up the app must believe it is the Samsung Galaxy Phone app. This page is the screen-by-screen contract. The canonical reference is the stock Samsung Phone / Contacts app on the founder's Galaxy device (One UI 6/7) — when this text and the device disagree, the device wins.
Hard rule: native One UI, no cross-platform UI
The UI is native Android — Kotlin + XML layouts / Material Components themed to One UI (same toolkit Linphone already uses; no Compose rewrite required, no Flutter, no React Native). The acceptance bar is Samsung One UI, not stock Pixel/Material You. The three Figma kits referenced below are Material-3 component sources — re-theme them to One UI, don't ship them as-is.
This is the Android counterpart to the iOS UI Spec; the strategy (Linphone engine, native dialer skin) is identical — see Overview. The engine and platform plumbing come from linphone-android (Kotlin, MVVM, XML layouts + data binding, package org.linphone); we keep the view-models and replace the views.
Design references¶
- Primary: stock Samsung Phone, Contacts, and Dialer (One UI) on the founder's Galaxy.
- Figma component kits (re-themed to One UI): Material 3 dialer/contacts kit, Material 3 design file, Material 3 Messaging app.
Design-system ground rules¶
These apply to every screen. They are what makes the app feel like One UI; correct layouts with these wrong still read as fake.
| Aspect | Rule |
|---|---|
| Toolkit | Android Views + data binding + Material Components for Android, themed to One UI. No custom-drawn lookalikes where a platform/Material control exists. |
| One UI layout law | Top half = title/empty "viewing area", bottom half = controls (one-handed reach). One UI uses a large collapsing CollapsingToolbarLayout/AppBarLayout header that shrinks on scroll; primary actions sit low. Match this — it is the single most recognisable One UI trait. |
| Typography | System sans-serif. On Galaxy hardware the system font is SamsungOne/SamsungSharpSans, so using system text styles gives One UI typography for free — never bundle a lookalike font, never hard-code sizes. |
| Icons | Material Symbols / the One UI line-icon style (rounded, medium weight). No Linphone iconography survives. |
| Colors | One UI tokens via theme attributes (?attr/colorPrimary, ?attr/colorSurface, ?android:attr/colorBackground)—never hard-code hex. Dynamic color (Material You / One UI palette) on Android 12+; system green for the call FAB, system red for missed/decline. Dark mode automatic via -night resources. |
| Bottom navigation | One UI BottomNavigationView (replaces Linphone's bottom_nav_bar.xml). Large touch targets, label under icon, One UI selected-pill. |
| Lists | One UI rounded list cells / MaterialCardView grouping where stock does; large headers; section index where stock Contacts shows the A–Z rail. |
| Ripples & motion | System ripple + One UI's spring/over-scroll (EdgeEffect) defaults. No custom transition curves. |
| Haptics | One UI keypad haptics: HapticFeedbackConstants on digit press + system keypad tone (match stock dialer). |
| Accessibility | TalkBack labels on every control, large-font/Dynamic-type support — stock One UI supports these, so must we. |
Tabs¶
OSS dialer (public repo) ships the three pure-dialer tabs; the private overlay adds the two MD tabs (see Overview → clean split and MD Analytics). Full app, in One UI bottom-nav order:
Keypad · Recents · Contacts · Analytics¹ · Tickets¹ (¹ private overlay)
Replaces Linphone's MainActivity bottom-nav set (Contacts / Calls / Conversations / Meetings). Conversations & Meetings are removed from the UI for v1 (engine support stays).
Tab — Keypad (dialer)¶
Linphone source: ui/main/history/fragment/StartCallFragment.kt + NumpadModel.kt + StartCallViewModel.kt, layouts start_call_fragment.xml / call_numpad_* (note: Linphone already draws a squircle numpad — shape_squircle_numpad_background.xml — which is close to One UI; restyle, don't rebuild from scratch). Keep the VM, replace the layout.
One UI keypad, top → bottom: 1. SIP-line/identity chip (top): selected outbound account; tap → account picker bottom sheet. Shown even with one line (match stock dual-SIM chip). 2. Number display: large, centred, shrinks as it grows; matched-contact / "Add to contacts" hint below; backspace appears once non-empty. 3. Numpad grid: 4×3 One UI squircle keys; digit large, letters small below (ABC…); long-press 0 → +; One UI press haptic + DTMF tone. 4. Green call FAB centred below the grid; empty-number tap recalls the last dialled number (stock behaviour).
Function mapping: digits feed liblinphone's outgoing-address builder; during a call the same pad sends DTMF (RFC 4733).
Tab — Recents (call logs)¶
Linphone source: ui/main/history/fragment/HistoryListFragment.kt + HistoryListViewModel.kt + HistoryListAdapter.kt. Keep VM/adapter data, replace the row + header layouts.
- Large One UI header
Recents, collapsing on scroll; search affordance. - All / Missed filter (One UI segmented/tab strip).
- Rows: avatar (photo / initials / generic), name or number bold (missed in red), secondary line = direction glyph (in/out/missed) + SIP-line badge
- number label; right = relative time + info chevron → call detail. Consecutive same-party calls collapse with a
(N)count. - Swipe / long-press: delete one, clear all, call back.
Data source: liblinphone CallLog history (core.callLogs); missed filter = missed/declined/aborted statuses.
Tab — Contacts¶
Linphone source: ui/main/contacts/fragment/ContactsListFragment.kt + ContactsListViewModel.kt + ContactViewModel.kt + adapters.
Org directory, NOT device contacts (matches the shipped iOS app)
Like the iOS app, the Contacts tab shows the Astradial org Users & Extensions directory, not the device address book — so we drop the READ_CONTACTS permission (see security audit). Linphone's ContactsManager (ContactsContract bridge) is kept only to render SIP Friends; the device-contacts read path is disabled.
- Large One UI header
Contacts, collapsing; search bar with the One UI look;+for a new entry where applicable. - A–Z sticky sections + index rail on the right edge (One UI style).
- Rows: initials/photo avatar + name; tap → One UI contact detail with the action row (call / message / video — non-call actions may hand off to system apps); numbers tap-to-call via liblinphone.
In-call screen¶
Use the Android Telecom ConnectionService path Linphone already wires (core/CoreInCallService.kt, androidx.telecom, MANAGE_OWN_CALLS, USE_FULL_SCREEN_INTENT). On a Galaxy this surfaces Samsung's own system in-call UI / full-screen incoming-call screen — the strongest "native" signal, the One UI equivalent of iOS CallKit. The in-app call screen (ui/call/CallActivity.kt, restyled) must mirror the One UI call layout: large name/number top, timer, the One UI button grid (mute, keypad, speaker, add call, hold, video-slot→hidden/transfer), red end-call bottom-centre, with the in-call numpad as a One UI bottom sheet (call_numpad_bottom_sheet.xml).
What we deliberately discard from Linphone's UI¶
Linphone 6's branding (orange theme, its assistant/onboarding, sidebar/drawer DrawerMenuFragment, chat & meetings styling, its tab structure) is entirely replaced. Keep the view-model ↔ core wiring where convenient; no Linphone visual element survives into Astradial builds — app icon, splash, colours, layouts, fonts, the assistant onboarding. Provisioning is Astradial QR scan + manual SIP entry only (the OSS dialer ships authless; Firebase sign-in is the private overlay).
Acceptance test for "100% native One UI"¶
Side-by-side with the stock Samsung Phone app on the same Galaxy:
- Same bottom-nav tabs, icons, order, selected-pill look.
- One UI header collapse + bottom-weighted controls match (the one-handed law) on every screen.
- Keypad squircle geometry, letter labels, spacing, call-FAB size, press haptic + tone indistinguishable.
- Recents rows: same two-line structure, direction glyphs, badges, timestamp wording, info affordance.
- Contacts: same search, A–Z rail, section headers, contact-detail action row.
- Dark mode, largest font scale, and TalkBack all behave like One UI.
- Incoming call raises the Samsung system call screen (Telecom), not a custom one.
- A failed item is a bug, not a nice-to-have.