Skip to content

Android App — Play Store Launch Checklist

Mission: ship the Android app (AstraDial) to the Google Play Store with full call functionality working on real devices, on our own GPL-free engine.

How to read this: [x] = done and verified; [ ] = not done or not yet verified. Per the no-overclaim rule, audio/call items stay unchecked until confirmed on a real device (never the emulator — emulator audio is an artifact). Cross-refs: android-status, gpl-compliance-roadmap, mobile-app-access.

Last updated: 2026-07-10.


Phase 0 — App shell & UX (complete)

  • Login/onboarding redesign (mockup #24) + pre-login server dropdown (prod/staging/custom)
  • Contacts (org directory), Tickets, Pulse analytics tabs
  • SIM Calls Only (click-to-call + routing toggle)
  • App launcher icon (Astradial "a") + splash (#075FA7)
  • SecureStore crash self-heal (EncryptedSharedPreferences VERIFICATION_FAILED)
  • Vestigial linphone Core account purged at startup (no auth popups)
  • Old linphone UI removed from the shell (drawer locked + gear→Settings rows gone)
  • Meetings UI removed

Phase 1 — Own engine (AstraSIP + WebRTC), signaling (complete)

  • AstraEngine integrated into the app (F1) — namespace com.softphone.astradial.engine
  • Registers over WSS on staging (REGISTER→200)
  • Registers over WSS on prod (devsip:8089/ws listener enabled)
  • Call UI (mockup #37) bound to AstraEngine.onCallState (F2) — incoming/outgoing/active/ended
  • Outbound INVITE→200→ACK→Established→BYE on the wire; hold wired; in-call DTMF numpad UI
  • FGS crash on call-establish-while-backgrounded fixed (b4f4a4a84)
  • Debug builds run native x86_64 (no arm-on-x86 libsrtp translation artifact)

Phase 2 — Real-device call functionality ⚠️ THE GATE — not verified

Do all of these on the moto g34 (arm64), destination *43 (echo) or +91 9944421125 only. - [x] 2-way audio on a real device via *43 echo — CONFIRMED 2026-07-11 on the V2037 (clean-room app, own engine, zero linphone); user heard the echo. Re-verified on a CLEAN install with zero adb (00a3400): the app now requests RECORD_AUDIO itself at the tab shell (granted via the OS dialog, USER_SET), first call has clean mic init, full 2-way audio. RCA: original one-way audio was purely the missing runtime mic request — fixed. - [x] Clean-install full flow (V2037): sign in (Staging) → wss line picker → REGISTER on wss://stagesip:8089/ws → land on tabs → all 5 tabs render (reactive-signedIn fix 00a3400) → Pulse dashboard live with real staging data*43 2-way audio. GPL-free, own engine. - [ ] Ext-to-ext real call, 2-way audio - [ ] PSTN call to +91 9944421125 (adds Tata trunk + opus→alaw transcode) — 2-way audio - [ ] DTMF (RFC 2833 / dtmf_mode=rfc4733) works in-call - [ ] Mute / speaker / hold / resume work - [ ] Hangup tears down cleanly (BYE sent; no orphaned channel) - [ ] Incoming call rings over a locked/killed device (full-screen-intent notification) - [ ] Killed-app FCM wake cold-start rings (cred-restore-on-cold-process path) - [ ] Call quality acceptable on cellular (note: alaw-only, no FEC — cellular may be choppy)

Phase 2b — VoIP push registered on app open (iOS parity)

Full spec + iOS reference + 9 test cases: astradial-astracall-android/VOIP-PUSH-ON-OPEN-HANDOFF.md. Backend is shared + done (POST /users/voip-push-token + new GET /users/voip-push-status); this is the Android client flow, strictly gated on notification permission (parity with iOS). - [ ] AstradialApi.voipPushStatus(endpoint, token) → GET /users/voip-push-status (200→registered && token_matches, 404/error→null=proceed) - [ ] AstradialPush.ensureRegisteredOnOpen(promptIfNeeded) — guard SIP-registered + FCM-token present → GET-check (skip if already registered) → POST_NOTIFICATIONS gate → register; AtomicBoolean re-entrancy guard - [ ] Route triggers through the gate: onNewTokenensureRegisteredOnOpen(promptIfNeeded=false); post-login SIP-attach → ensureRegisteredOnOpen() (first-login prompt) - [ ] App-open hook (main Activity onResume / ProcessLifecycleOwner ON_START) calls it on cold launch + every foreground - [ ] POST_NOTIFICATIONS declared in manifest; runtime request via ActivityResultContracts.RequestPermission (pre-API-33 = granted by default) - [ ] Bundle id com.astradial.phone accepted by the wake gateway / token registry - [ ] On-device: run the 9 TCs in the handoff (allow/deny/already-registered/rotation/404-fallback/flap re-entrancy…) — FCM has no reliable emulator token, so real device only

Phase 3 — Mobile App Access gate (on-device)

  • Login gated to sip_port='wss' lines (picker + manual reject; 6bc29d83) — code + compile
  • On-device: only mobile-enabled lines show in the picker
  • On-device: manual entry of a non-wss user shows "This SIP user is not provisioned"
  • On-device: a wss+SIM line (e.g. ext 1003) still logs in

See gpl-compliance-roadmap. Removing the SDK is necessary but not sufficient — the app is a GPLv3 fork. - [ ] Real-device audio proven (Phase 2) — the prerequisite to start deleting liblinphone - [ ] Delete the liblinphone call code (CoreContext Core/Call bodies, ui/call/model/*, telecom) - [ ] Remove the linphone-sdk-android dependency - [ ] Phase 3 clean-room app: port our org.linphone.astradial.* + AstraEngine into astradial-astracall-android, re-namespaced com.astradial.* - [ ] Verify built APK/AAB: no liblinphone*.so, no org.linphone.core classes, no linphone-sdk - [ ] App LICENSE → proprietary; WebRTC (BSD) + Firebase (Apache-2.0) attribution in About

Phase 5 — Release engineering (Play Console)

  • Google Play Console app created (package com.astradial.phone)
  • Upload signing key configured (Play App Signing) — keystore preserved (keeps FCM token)
  • Release AAB built (bundleRelease), minify/R8 verified, no debug receivers shipped
  • Store listing: title, short + full description, screenshots (phone), feature graphic, icon
  • Privacy policy URL
  • Data safety form (mic, contacts, push token, analytics)
  • Content rating questionnaire
  • Target API level meets Play's current requirement
  • Permissions justified (RECORD_AUDIO, FGS microphone|phoneCall, USE_FULL_SCREEN_INTENT, POST_NOTIFICATIONS)

Phase 6 — QA & release rollout

  • Full P1 regression on a real device (login, tabs, contacts, tickets, SIM-only, settings)
  • Call regression matrix (Phase 2) re-run on the release build
  • Internal testing track → closed testing (a few real testers) → verify install + calls
  • Production rollout (staged %), monitor crashes (Crashlytics) + call-quality
  • Docs finalised after launch confirmed

Right now, the one blocker that gates the rest

Phase 2 — real-device 2-way audio on the own engine. Everything downstream (delete liblinphone → GPL-clean binary → Play submission) waits on hearing audio on the moto g34. Nothing is release-ready until that [x].