13 Commits

Author SHA1 Message Date
f0a4fd18cd Wear UI: intercept system back so Messages/Conversation/Accounts pop within app
Add BackHandler in WearApp: back from thread: -> messages, messages/accounts
-> dialer. At the root dialer route the handler is disabled so back finishes
the Activity normally. Fixes back-from-Messages dropping to the clock face.
2026-08-21 04:09:41 +01:00
100ee241a2 Wear SIP: plaintext SIP MESSAGE (RFC 3428) send/receive + inbox UI
- Native: add message_send() JNI (Api.message_send) and wire the
  existing message_listen receive callback (message_handler) to forward
  inbound MESSAGEs to WearBaresipService.messageEvent.
- Kotlin: WearBaresipServiceHelper.sendMessage (normalizes peer ->
  sip:peer@mail.txt3.net), MessageStore (JSON file persistence, no extra
  deps), messageEvent stores + posts a CATEGORY_MESSAGE notification.
- UI: MessagesScreen (conversation list) + ConversationScreen (thread +
  send field), reached via a new 'Messages' button on the dialer.
- README roadmap: mark SIP MESSAGE done; reword encryption plan to
  asymmetric E2E over SIP MESSAGE with NFC key exchange (OMEMO is
  XMPP-only and does not apply to SIP).

Verified: builds, app starts, registers over TLS, no crash. Live
two-endpoint exchange still to be tested with a real peer.
2026-08-21 03:48:21 +01:00
0f883c9847 Wear SIP: switch transport to TLS:5062 (verify disabled, mTLS pending)
- accounts: outbound transport=tls on port 5062.
- config.static: tls_verify no + tls_selfsigned yes (server cert is an
  expired Asterisk Private CA; verification disabled for now; mTLS client
  cert support planned but not yet enabled).
- Registration over TLS verified working on Galaxy Watch (Android 16).

Note: TLS transport is independent of the self-managed incoming-call UI
path (verified earlier over UDP), so lock-screen answer/decline + audio
carry over unchanged.
2026-08-21 03:22:04 +01:00
a31d6a693c Wear SIP: incoming call UI over lock screen via self-managed telecom
- Launch InCallActivity from WearConnectionService.onCreateIncomingConnection
  (self-managed telecom context) instead of a background FGS startActivity.
  This is the only path Android permits to show UI over a secure lock screen
  / from the background (BAL exemption); a plain FGS startActivity is blocked.
- Register a SELF_MANAGED PhoneAccount (CAPABILITY_SELF_MANAGED only; a
  self-managed account must not also be CALL_PROVIDER) and hand inbound calls
  to TelecomManager.addNewIncomingCall.
- Answer/Decline routed from the system self-managed Connection back to the
  native stack via WearBaresipServiceHelper (deferred ua_answer/ua_hangup).
- Add dedicated InCallActivity (setShowWhenLocked/turnScreenOn) hosting the
  InCallScreen; MainActivity no longer owns the call UI.
- Switch SIP transport to UDP:5761 (matches server); keep sipnat=outbound +
  natpinhole for NAT traversal.
- Remove dead phoneCall FGS upgrade/downgrade (needed DIALER role; the
  self-managed launch path replaces it).

Verified on Galaxy Watch (Android 16, SDK 36): inbound call rings + shows
InCallActivity over the lock screen (pattern lock on) with working two-way
audio; activity dismisses cleanly on hangup.
2026-08-21 03:15:22 +01:00
899e778e49 Wear SIP: stable inbound calls (ring/answer/hangup) + README
- NAT-survival account settings (sipnat=outbound;natpinhole=yes) so INVITE
  replies are not dropped (was going straight to voicemail).
- Native event_handler emits 'incoming call' (BEVENT_SIPSESS_CONN) carrying
  the SIP msg pointer and 'call incoming' (BEVENT_CALL_INCOMING) carrying the
  real struct call*; passes ua/call as separate jlong args (no lossy string
  parse). uaEvent(String, Long, Long) signature updated.
- Answer flow: ua_accept on 'incoming call' (caller hears ringing) then
  ua_answer deferred to the baresip main loop via a one-shot timer
  (ua_answer_async) so the UI-thread Answer tap does not crash in sip_treplyf.
- FGS started from Application.onCreate (decoupled from Activity) holding
  WifiLock + WakeLock so SIP survives screen-off / task removal.
- Ring: vibration + screen wake + high-priority full-screen-intent
  notification; stopRinging() on established/closed + 30s watchdog so the
  ring never loops forever on remote hang-up.
- Lock-screen presentation: manifest showWhenLocked/turnScreenOn +
  USE_FULL_SCREEN_INTENT permission + InCallScreen launch. (Still unreliable
  when fully asleep + backgrounded — tracked in README.)
- wear/README.md: project overview, how answering works, build/install,
  known gaps, and roadmap (SIP MESSAGE, contacts, start-at-boot, UI).

Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-21 01:58:56 +01:00
300bdcc810 Wear SIP: revert to TCP registration (fixes INVITE retransmit timeout)
The UDP switch made the watch register over UDP while Asterisk had
cached a TCP Contact (transport=tcp). Asterisk sent the INVITE over
TCP but got no SIP response (not even 100 Trying) -> 6.4s
retransmission timeout -> immediate voicemail.

Revert to TCP so the watch's registration matches Asterisk's cached
contact. With nat=yes now set, the TCP Contact is made public
(78.141.29.181:<port>), so the INVITE arrives over the persistent TCP
socket and baresip's response reaches Asterisk, letting the call ring
the full configured window instead of timing out.
2026-08-20 23:19:39 +01:00
34661f4ca6 Wear SIP: stop handing incoming calls to system telecom (fixes 2s drop)
The experiment of calling TelecomManager.addNewIncomingCall() for our
COMPANION PhoneAccount caused Samsung Wear's telecom stack to auto-reject
the incoming WearConnection within ~2s; its onReject() then hung up the
native baresip call, so Asterisk dropped to voicemail immediately instead
of ringing for the configured 25s.

Remove the handoff from the 'call incoming' path. The in-app InCallScreen
+ full-screen-intent notification remain the alert UI. The native call now
stays alive and rings for the full window (verified: no more 2s reject +
re-register cycle).
2026-08-20 23:12:23 +01:00
c88bee33d8 Wear SIP: register over UDP (NAT-friendly Contact)
Switch outbound transport from tcp to udp. With Asterisk peer
nat=yes, Asterisk now sends the INVITE to the public source address
(78.141.29.181:<port>) instead of the watch's private Contact, so
incoming calls traverse the NAT and reach the watch.

Verified: external incoming calls now arrive (uaEvent: incoming call
from external caller logged on the watch).
2026-08-20 23:03:15 +01:00
106ef4ed9d Wear SIP: switch account to 01273961147 + NAT-survival settings
- Account line now uses 01273961147 (same credential).
- sipnat=outbound + natpinhole=yes + regint=60 keep the NAT
  mapping/keep-alive fresh so Asterisk's INVITE (sent to the public
  Contact) reaches the watch behind NAT.

Note: sipnat=outbound is ineffective here because the outbound proxy
is the server itself (no edge STUN to learn the watch's public NAT
IP); the actual NAT fix is Asterisk-side (nat=force_rport,comedia on
the peer), which makes Asterisk target the public source address.
2026-08-20 22:40:59 +01:00
bd5b5efa3b Wear SIP: incoming-call alert (full-screen intent + screen wake + vibrate)
- High-importance (IMPORTANCE_MAX) call channel; on incoming call post a
  PRIORITY_MAX / CATEGORY_CALL notification with a full-screen intent that
  launches the InCallScreen over the watch face.
- MainActivity: setShowWhenLocked/setTurnScreenOn + FLAG_SHOW_WHEN_LOCKED
  so the in-call UI presents over the dimmed screen / keyguard.
- Request POST_NOTIFICATIONS at runtime (API 33+ silently drops
  notifications without it) alongside RECORD_AUDIO.
- Vibration ring pattern + wake-lock on incoming call; dismiss the
  heads-up when the call closes.

Note: on Samsung Galaxy Watch the watch notification manager blocks
alerting for apps not in its allowed-notifications list; the device
setting (Settings > Notifications > App notifications > Baresip Wear)
must be enabled for the heads-up to fire. Foreground/app-open case
verified working (call answered, audio -> onboard speaker).
2026-08-20 22:25:42 +01:00
15e266cb43 Wear SIP: audio routing, stock-style dialer, DTMF, incoming-call handling, telecom scaffold
- AudioRouteManager: route to onboard speaker when no BT headset is
  connected, BT SCO when one is; set MODE_IN_COMMUNICATION + focus.
- aaudio: build with AAUDIO_PERFORMANCE_MODE_NONE so Android routing
  (speakerphone) is honoured instead of being bypassed by low-latency.
- DialerScreen: restyled to a stock-dialer layout (large number display,
  3x4 keypad with sub-letters, green call FAB, backspace, recent chips).
- InCallScreen: added DTMF keypad (sendDigit) for voicemail/IVR.
- WearBaresipService: on incoming call, wake screen + vibrate + bring
  activity to foreground so Answer/Decline is visible.
- Fixed dial normalization (bare extension -> full SIP URI with domain)
  and the uap parse in uaEvent so defaultUap is set and calls connect.
- config.static: load g711/opus codecs to resolve 488 Not Acceptable Here.
- Telecom scaffold (experiment): PhoneAccount + ConnectionService handed
  incoming calls via addNewIncomingCall to test stock Wear dialer pickup.
- Submodule libbaresip-android rebuilt with g711/opus/aaudio changes.

Verified: assembleDebug green, installs and registers on Galaxy Watch,
incoming call event fires and is handled without crashing.
2026-08-20 22:06:15 +01:00
a849d98b5e Wear UI: dialer, in-call, debug accounts, baresip: provisioning
- Wear Compose dialer with recent calls and in-call answer/decline/hangup/mute
- Debug accounts screen (scrollable ScalingLazyColumn) for manual SIP config
- baresip:// provisioning intent mirroring phone app (RSA/AES bundle decrypt)
- Physical button (STEM_1/BACK) returns from Accounts via onKeyDown
- Native event handler now emits uap/callp for incoming/registration events
- Writes accounts/auth files in baresip format; verified REGISTER attempt on watch
2026-08-19 04:05:40 +01:00
9f94e72b1e Add Wear OS SIP client module running baresip NDK stack
- New :wear application module (Wear Compose, minSdk 30)
- Second JNI lib 'wearbaresip' reusing distribution static libs
- Watch-side service initializes baresip via full init path
  (libre_init -> conf_configure -> baresip_init -> ua_init)
- FGS started from MainActivity foreground state with mic type
  only (phoneCall requires default-dialer, rejected on watch)
- Runtime-verified: builds, installs, native lib loads and SIP
  stack starts on armeabi-v7a Wear OS device
2026-08-19 03:22:05 +01:00