feat(service): CDM presence — restart MeshService when the radio reappears (Phase 2) - #6479
Draft
jamesarich wants to merge 1 commit into
Draft
feat(service): CDM presence — restart MeshService when the radio reappears (Phase 2)#6479jamesarich wants to merge 1 commit into
jamesarich wants to merge 1 commit into
Conversation
Contributor
|
Important Review skippedDraft detected. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
jamesarich
force-pushed
the
feat/cdm-presence-phase2-3
branch
from
July 27, 2026 23:30
0c4bb19 to
0c29a24
Compare
…pears (Phase 2) Phase 2 of CDM adoption: MeshCompanionDeviceService, a system-bound CompanionDeviceService, receives presence events for the associated radio (String callbacks on 31-32, AssociationInfo on 33-35, DevicePresenceEvent on 36+). A device-appeared event for the selected radio starts MeshService with the new CompanionDevicePresent trigger; the orchestrator reconnects to the persisted address on its own — no scan involved, the transport builds its Peripheral straight from the MAC. CompanionPresenceCoordinator keeps observation registered for exactly the selected, associated radio and re-asserts it on every process start. Device-disappeared events are deliberately unhandled: presence-driven teardown (Phase 3) waits until field data shows appeared-events are trustworthy across OEMs — a torn-down service that never restarts is strictly worse than today's idle one. - Manifest: REQUEST_OBSERVE_COMPANION_DEVICE_PRESENCE + exported service behind BIND_COMPANION_DEVICE_SERVICE. - CompanionAssociationRepository: start/stopObservingPresence with the 31-35 String vs 36+ ObservingDevicePresenceRequest fork, plus macForAssociationId for the event-based callback. - Tests: presence policy matrix, coordinator reconciliation (recording fake), repository forks under Robolectric (String-overload shadow only exists from sdk 33), new trigger through the ForegroundStartPolicy matrix, StateFlow added to KoinVerify known types. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
jamesarich
force-pushed
the
feat/cdm-association-phase1
branch
from
August 1, 2026 15:24
d9efb64 to
b5cae14
Compare
jamesarich
force-pushed
the
feat/cdm-presence-phase2-3
branch
from
August 1, 2026 15:24
0c29a24 to
40d5302
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
Stacked on #6477 (Phase 1: associations). An association legalizes background starts, but nothing produces one when the radio comes back into range with the app backgrounded or dead. Companion Device Manager presence closes that gap: the system binds our
CompanionDeviceService— reviving the process if necessary — when the associated radio's BLE presence changes, and we restartMeshServiceso it reconnects on its own. This is the "it just reconnects, like a smartwatch" behavior, and CDM is the only sanctioned mechanism for it.🌟 What changed
MeshCompanionDeviceService: adapts all three callback generations (String 31–32,AssociationInfo33–35,DevicePresenceEvent36+ — API shapes verified against the SDK 37 jar) onto pure decisions inCompanionPresencePolicy. A device-appeared event for the selected radio startsMeshServicewith the newCompanionDevicePresenttrigger;MeshServiceOrchestrator.start()then reconnects to the persisted address — no scan step, the transport builds its KablePeripheralstraight from the MAC. Events for other (older) associated radios are ignored, and appeared events never fight a live connection.CompanionPresenceCoordinatorkeeps presence observation registered for exactly one radio — the selected BLE device while it holds an association — retiring registrations on selection change/disassociation, and re-asserting on every process start (registration does not reliably survive reboots). Eagerly started fromMeshUtilApplication.onCreateper the repo's eager-init pattern.CompanionDevicePresentflows through the existingappInForeground || hasCompanionAssociationgate (the trigger implies an association by construction); the caller's try/catch still lets the OS verify the claim.REQUEST_OBSERVE_COMPANION_DEVICE_PRESENCE(normal-level, API 31) + the service exported behind the platform-signatureBIND_COMPANION_DEVICE_SERVICEpermission. Older platforms never bind it.Deliberately absent: device-disappeared events are unhandled. Presence-driven FGS teardown (Phase 3 of the design) waits until field data shows appeared-events are trustworthy across OEMs — a torn-down service that never restarts is strictly worse than today's idle one. If/when soak supports it, teardown returns as a fresh, small change.
🧪 Testing performed
CompanionPresencePolicyTest: appeared matrix — selected-only, case-insensitive MAC, never restarts a live connection.CompanionPresenceCoordinatorTest: reconciliation via a recording repository fake — observe on start, retire on selection change/deselection, pick up late associations (revision bump), ignore non-BLE selections, inert pre-31.CompanionAssociationRepositoryTest: presence-observation forks under Robolectric (the String-overload shadow only exists from sdk 33, hence sdk 34 for that case), feature/SDK guards, association-id ↔ MAC resolution.ForegroundStartPolicyTest:CompanionDevicePresentthrough the trigger × SDK matrix (allowed backgrounded with association, refused without) plus the existing while-in-use invariant.spotlessApply spotlessCheck detekt assembleDebug test allTests(incl. KoinVerify).📲 On-device gate (before merge)
With an associated radio: background (or force-stop) the app, power-cycle the radio → MeshService should start and reconnect on its own. Verify on google + fdroid, ideally on an API 31–32 device and a 33+ device (different callback generations).
🤖 Generated with Claude Code