638 Commits

Author SHA1 Message Date
callebtc
363f8c5aae fix: restore background peer availability alerts 2026-07-29 15:00:13 +02:00
callebtc
889c262edc
Merge pull request #802 from permissionlesstech/codex/mesh-lab-agent-skill
Add Mesh Lab agent skill
2026-07-29 13:55:55 +02:00
callebtc
c382c17a92 mesh-lab: fail closed when evidence dir is empty
A bare `test -n` does not abort in a shell without set -e, so a failed
mktemp would let `--out ""` resolve to the repository root and write
private evidence there. Guard with an explicit exit instead.
2026-07-29 13:54:50 +02:00
callebtc
9ed5cb26da
Merge pull request #798 from permissionlesstech/codex/reproducible-builds
Enable reproducible Android builds and releases
2026-07-29 13:47:45 +02:00
callebtc
01b59a7a0c
Merge pull request #809 from permissionlesstech/voice-recording-ux
Voice recording UX: slide-to-cancel, magnetic target, refined recording pill
2026-07-29 13:02:49 +02:00
callebtc
6f60b151d0
Merge pull request #810 from permissionlesstech/codex/wear-notification-stream-fix
Fix Wear OS DM notification delivery
2026-07-29 13:02:25 +02:00
callebtc
1dae188cdf
Merge pull request #806 from permissionlesstech/codex/persistent-conversations
Persist private conversations in People
2026-07-29 13:00:57 +02:00
callebtc
6a904a1849 voice: compute cancel verdict from the final pointer coordinate - recomposed shouldCancel state could be one frame stale on a fast slide-and-lift (PR review) 2026-07-29 12:55:36 +02:00
callebtc
538701c753 wear: shorten mesh status notification 2026-07-29 12:48:12 +02:00
callebtc
c6e64b1da8 wear: fix DM notification delivery 2026-07-29 12:42:54 +02:00
callebtc
ff0578cb88
Merge pull request #808 from moehamade/fix/hotspot-wifi-direct-reliability
fix: make Wi-Fi Direct hotspot sharing reliable
2026-07-29 12:33:16 +02:00
Moe Hamade
b5fd346437 fix: test the hotspot hold under the lock that publishes Aware
The previous recheck narrowed the race without closing it. Testing
hotspotHold outside lifecycleLock left this interleaving:

  1. the recheck passes, hold not yet set
  2. holdForHotspot() sets the flag and calls stop(), which takes the
     lock, finds nothing published, and returns having stopped nothing
  3. this block takes the lock and publishes the service anyway

Aware ends up running while the hotspot believes it owns the radio,
which is the original failure.

The hold is now tested inside the same synchronized block that
publishes, so the check and the publication are one step against
stop(). Ordering holds because holdForHotspot() sets the flag before
calling stop(): either the publisher observes the flag and abandons,
or stop() observes the published service and tears it down. There is
no interleaving that leaves a service published with the hold set.

stopServices() stays outside the lock since it can block.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-29 13:27:53 +03:00
callebtc
7c67df4b30 fix: isolate canonical container workspace 2026-07-29 12:24:09 +02:00
callebtc
8eddcb15ca voice: keep pill height identical between rest and recording - constrain recording visualizer row to the text field's 22dp content height so the separator no longer shifts 2026-07-29 12:23:50 +02:00
callebtc
97026d7bbb fix: lock wear dependencies in CI 2026-07-29 12:20:48 +02:00
callebtc
56f52218ed voice: watch-quality recording UX - slide-to-cancel with magnetic X target (leans toward finger, blushes red with proximity, snaps on hover, REJECT haptic on cancel, firm click on enter/exit), release-anywhere tracking replaces button-owned release, timestamp left of waveform showing elapsed only, muted 1.5dp red outline, neutral grey recording pill with depth 2026-07-29 12:20:30 +02:00
Moe Hamade
05896f354d fix: route every hotspot failure through one teardown path
Addresses three issues from Codex review on #808.

The Wi-Fi Aware hold could be defeated by a race. startIfPossible()
does a long stretch of async work between checking the hold and
assigning the service, so holdForHotspot() landing in that window
left an in-flight start free to resurrect NAN behind the hotspot's
back, putting every P2P attempt back on BUSY. The hold is now
rechecked before committing the service, and the freshly started
service is torn down if the hotspot claimed the radio meanwhile.

Startup error paths bypassed cleanup. A web-server failure, a null
connection info, or a throw from the outer block stopped the manager
but left the Aware hold set, blocking all mesh starts until the user
happened to retry or close the screen. Worse, an error after the
server had started left it serving the APK on port 9999 -- including
after the device reconnected to an ordinary Wi-Fi network -- because
only stopHotspot() cleared it.

Both follow from the same gap: cleanup lived at the call sites rather
than in one place. All failures now go through failWith(), which
shares teardown() with stopHotspot() and releases the server, the
manager and the hold together.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-29 13:09:04 +03:00
callebtc
dcb77dc6b1 Merge remote-tracking branch 'origin/main' into codex/reproducible-builds 2026-07-29 12:08:12 +02:00
Moe Hamade
41544a6840 fix: make Wi-Fi Direct hotspot sharing reliable
Starting the APK-sharing hotspot failed intermittently with
"Failed to create hotspot: BUSY", sometimes for minutes, then
succeeded for no apparent reason. Two distinct causes, both
confirmed against a Pixel 9a via dumpsys and HAL logs.

1. Wi-Fi Aware holds the radio. The mesh's NAN interface and
   Wi-Fi Direct's P2P interface cannot coexist on common chipsets:

     HalDevMgr: bestIfaceCreationProposal is null, requestIface=P2P,
                existingIface=[name=wlan0 type=STA, name=aware_nmi0 type=NAN]
     WifiP2pNative: Failed to create P2p iface

   The P2P state machine then stays in P2pDisabledState and answers
   every createGroup with BUSY, while still broadcasting
   WIFI_P2P_STATE_ENABLED. Whether sharing worked came down to
   whether Aware happened to be attached, which is what made it look
   random. WifiAwareController now releases Aware for the duration of
   the hotspot and blocks restarts until it finishes.

2. Orphaned groups. A P2P group outlives the process that created
   it, so a crash or swipe-away while hosting leaves one behind, and
   the framework answers BUSY for as long as it exists. Startup now
   removes a stale group first, but only one it can show is ours --
   Wi-Fi Direct is shared with Cast, Android Auto and Quick Share.
   Ownership is the group name we recorded creating, with the SSID
   prefix as a fallback for orphans from older builds.

Also fixed while tracing these:

- Channel leak: initialize() ran on every retry attempt and the
  channel was never closed, leaving a binder registration with
  WifiP2pService per attempt. Observed climbing to 7 stale clients.
  It is now initialised once and closed after removeGroup replies.
- BUSY is the framework's catch-all reply, so retrying was futile
  for permanent causes and too impatient for real contention.
  Retries now back off 1s/2s/4s/8s and only for genuinely transient
  failures; P2P being off fails immediately with a message that says
  so rather than 15 seconds ending in "busy".
- Turning Wi-Fi off mid-session left the UI showing an active
  hotspot forever; it now aborts cleanly.

Retry and startup decisions are extracted into HotspotStartupPolicy,
which has no Android dependencies and is covered by 13 unit tests.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-29 12:54:01 +03:00
callebtc
bf87a80617 Honor private message admission during panic 2026-07-29 11:00:24 +02:00
callebtc
c8153c0d18 Keep Wear shared state compatible 2026-07-29 03:57:28 +02:00
callebtc
e4f0713121 Merge remote-tracking branch 'origin/main' into codex/persistent-conversations 2026-07-29 03:53:34 +02:00
callebtc
c5ff1ca59a Complete persistent conversation lifecycle 2026-07-29 03:53:29 +02:00
callebtc
d3f01f27c6 persistent 2026-07-29 03:41:24 +02:00
callebtc
7fad2f2202 persist 2026-07-29 03:41:16 +02:00
callebtc
5edc9f7d85 docs: add maintainer release runbook 2026-07-29 03:05:01 +02:00
callebtc
3b53b9bdcc
Merge pull request #805 from permissionlesstech/wear-os-1
Wear OS app: standalone bitchat client for Pixel Watch
2026-07-29 03:02:46 +02:00
callebtc
e4ad09830b wear: address PR review - (1) DM send no longer echoes 'Sent' pre-handshake: session-gated echo stays 'Sending' and retries for 15s after initiating Noise handshake; (2) minSdk 33 (Wear OS 4): API 30 lacks the S+ Bluetooth permissions and would require location for scan, which the app refuses; (3) recreate BluetoothConnectionManager when !isReusable() so stop->start cycles don't leave a zombie mesh 2026-07-29 02:54:11 +02:00
callebtc
120cc8e901 docs: wear screenshots for PR - onboarding, chat, people, voice notes, recording overlay 2026-07-29 02:39:29 +02:00
callebtc
9998e7ae3f wear: fluid magnetic slide-to-cancel - cancel button leans toward the approaching finger and blushes green-to-red continuously with proximity (finger-driven), soft springy scale bloom on activation; rotation wobble removed 2026-07-29 02:28:07 +02:00
callebtc
18831c20fa wear: slide-to-cancel voice recording - global finger tracking while recording, mic button morphs into red cancel target on approach (tick haptic in/out, double-click reject on cancel), release anywhere sends; PTT release no longer owned by the small mic button; haptics: knock on record start/incoming message, click on stop/send, tick on text send 2026-07-29 02:22:40 +02:00
callebtc
2e3f7bf827 voice improvments 2026-07-29 02:12:55 +02:00
callebtc
b3b478be10 wear: copy polish - compact notification-permission and nickname-edit descriptions, sentence-case labels across all screens (buttons, placeholders, empty states, prompts) 2026-07-29 02:07:08 +02:00
callebtc
da5650ceb4 fix: keep release signing local 2026-07-29 02:06:43 +02:00
callebtc
c1e6204686 wear: rename from People screen - 'you' row first opens nickname editor; nickname field auto-focuses with cursor at end, IME Done only closes keyboard for review, confirm button is the single commit path, trim while typing 2026-07-29 02:04:09 +02:00
callebtc
86a04bc8a2 wear: chat header fits round screen with unread (title yields to people+mail icons with counts, whole header taps to People); People screen: capitalized title, Noise lock icon instead of 'noise ✓' text, RSSI removed, unread senders float to top with mail icon + count 2026-07-29 01:43:04 +02:00
callebtc
28261af55c wear: add DM notifications and refresh launcher assets 2026-07-29 01:23:17 +02:00
callebtc
2e8f6ffc35 wear: shrink header to dense form on scroll-up instead of hiding it - overlay-only size animation, list geometry untouched 2026-07-29 01:08:11 +02:00
callebtc
92f60bd02f wear: simplify chat scrolling to the classic messenger pattern - constant list padding with header/action bar as floating overlays driven by one scroll-direction state; removes the animated bottom clearance and in-layout header resizing that shifted content mid-gesture 2026-07-29 01:04:44 +02:00
callebtc
f5915c4c31
Merge pull request #804 from permissionlesstech/codex/fix-private-media-contact-routing
Fix private media sending from contact conversations
2026-07-29 00:54:47 +02:00
callebtc
80342a74e8 wear: fix dock/undock flapping when scrolling up from bottom - undocking collapsed the 48dp bottom clearance which clamped scroll back to the end and re-docked in a loop; buttons now toggle on a fast 12dp overlay-only channel while the geometry-changing docked state requires 60dp of upward scroll (> 48dp padding delta) 2026-07-29 00:52:07 +02:00
callebtc
c7720d3847 Fix private media routing for contact conversations 2026-07-29 00:43:39 +02:00
callebtc
8f4c937e92 wear: fix action bar disappearing at bottom - replace fragile distance-to-last-item geometry (dead-zoned by expanded padding, skewed by edge-scaling) with scroll-intent logic: canScrollForward=false always docks + shows buttons, any downward scroll reveals them, upward scroll hides 2026-07-29 00:32:45 +02:00
callebtc
c06fa67ccc wear: fix header size flip-flopping - drive header from the debounced dockedAtNewest state instead of raw per-frame layout geometry; header is full-size at the newest, compacts when browsing history 2026-07-28 22:24:35 +02:00
callebtc
156a5f3218 wear: perf - debug-signed R8 release build for on-device testing, Gson keep rules, cache time formatter, memoize file chip stat 2026-07-28 22:16:32 +02:00
callebtc
fb93d2d85f wear: TransformingLazyColumn chat lists - native center-scaling/rotary/scrollbar, exact scroll-to-end autoscroll, Arrangement.Bottom anchoring, consolidated ChatScaffold 2026-07-28 22:06:51 +02:00
callebtc
d4aa9b1644 wear: fix padding oscillation with hysteresis (expand <40, collapse >120) - padding delta can no longer retrigger itself 2026-07-28 21:40:51 +02:00
callebtc
f64338a3b8 wear: dynamic bottom padding - last message clears floating buttons at newest, text flows behind them when scrolled up 2026-07-28 21:38:15 +02:00
callebtc
5e937fa816 wear: action buttons float over chat text instead of reserving space; empty-state lifted clear of buttons 2026-07-28 21:34:14 +02:00
callebtc
5797ee18c0 wear: fix inverted scroll direction and restore scrollbar - normal top-down scrollable bottom-anchored via Box alignment, ScreenScaffold scroll indicator, standard rotaryScrollable defaults 2026-07-28 21:30:08 +02:00