Templates: Bluetooth Classic peripheral codegen - #4
Merged
Conversation
Companion to mob#5+ (Mob.Bt runtime). Generates the Kotlin BroadcastReceivers, JNI native_* externs, and AndroidManifest permissions for the Mob.Bt + Mob.Bt.Hfp / Spp / Hid API. ## What's generated ### priv/templates/.../AndroidManifest.xml.eex (+15 lines) - BLUETOOTH_CONNECT / SCAN / ADVERTISE permissions - uses-feature bluetooth=true (required) - uses-feature bluetooth_le=false (not required for Classic) ### priv/templates/.../MobBridge.kt.eex (+541 lines) 16 @JvmStatic methods matching the Mob.Bt NIF surface: - bt_list_paired, bt_start_discovery, bt_cancel_discovery - bt_pair, bt_unpair, bt_disconnect - bt_hfp_connect, bt_hfp_subscribe_vendor_at (with companyIdsJson), bt_hfp_send_vendor_at, bt_hfp_start_sco, bt_hfp_stop_sco, bt_hfp_send_audio - bt_spp_connect, bt_spp_write - bt_hid_connect, bt_hid_subscribe_raw 5 BroadcastReceivers handle the Android side: - ACTION_FOUND / ACTION_DISCOVERY_STARTED / _FINISHED (discovery) - ACTION_BOND_STATE_CHANGED (pairing) - BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED (HFP) - ACTION_VENDOR_SPECIFIC_HEADSET_EVENT (vendor AT) - BluetoothDevice.ACTION_ACL_DISCONNECTED (cross-profile disconnect) The vendor AT receiver registers IntentFilter categories ONLY for the BT SIG company IDs the caller specified in companyIdsJson. Empty list is valid — the receiver registers but no events route through. ### priv/templates/.../beam_jni.c.eex (+275 lines) 26 native_* JNI thunks invoking the matching mob_deliver_bt_* C exports. ## Coordination Pair with mob's migrate/bt branch (Mob.Bt runtime). Either order works at build time — the runtime short-circuits to :unsupported when the matching MobBridge methodID isn't present — but the user-visible feature only works end-to-end with both in place.
GenericJam added a commit
that referenced
this pull request
May 16, 2026
Generates the Kotlin BroadcastReceivers, JNI native_* externs, and AndroidManifest permissions for the Mob.Bt + Mob.Bt.Hfp / Spp / Hid runtime API (companion to mob#9). Includes follow-on review fixes: 3 new generator-test cases asserting the BT permissions, JNI thunks, and external fn declarations land correctly in the generated app.
Uh oh!
There was an error while loading. Please reload this page.
GenericJam added a commit
that referenced
this pull request
May 16, 2026
Ships HeroesLament's Mob.Bt template work (#4) to Hex so newly generated apps include the BT runtime wiring out of the box. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
GenericJam added a commit
that referenced
this pull request
May 17, 2026
Two bugs that surfaced in projects generated from the current master. Both were originally fixed in 0.3.2 (see CHANGELOG) and reintroduced when I resolved the import-block conflict during the PR #4 merge by taking the union of both sides' imports — not realising the BT-PR imports were the duplicates the 0.3.2 fix had specifically removed. beam_jni.c.eex: - Restored the closing `}` for nativeDeliverVendorUsbEvent before the BT JNI thunks. Without it, clang sees nested function definitions and rejects every JNIEXPORT that follows ("function definition is not allowed here"). C compilation fails immediately. MobBridge.kt.eex: - Removed three duplicate imports (IntentFilter, ConcurrentHashMap, AtomicInteger). Each now appears exactly once in the alphabetised bottom-of-file import block. kotlinc was rejecting with "Conflicting import" so gradleDebug failed. Generated-output verification: `mix mob.new mob_plugin_fix_test` produced a project whose MobBridge.kt has each import exactly once and whose beam_jni.c has the closing brace before the BT thunks section. Note: generator tests grep rendered output but don't compile, which is exactly why both regressions slipped through. Mentioned this gap in 0.3.2's CHANGELOG — should consider a compile-check step in the generator test suite as a follow-up. Reported by external user on master 2026-05-17. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
GenericJam added a commit
that referenced
this pull request
May 17, 2026
Two cheap generator-output checks for the regression classes that
slipped past every string-match assertion in 0.3.2 AND 0.3.4:
- `beam_jni.c has balanced braces`: counts `{` vs `}` in the
rendered C file. Catches "missing closing brace turns subsequent
function defs into nested-defs syntax error" class. Naive (would
miscount strings containing literal braces, but the JNI template
has no JSON or printf-with-braces in strings, so reliable here).
- `MobBridge.kt has no duplicate imports`: parses `^import ` lines
and asserts uniqueness. Catches "merge resolved by union of both
sides' imports, but one side's imports were duplicates of the
other's already-present-elsewhere block" — the exact shape that
bit us when merging PR #4 (post-0.3.2-dedup) by union-resolving
the import conflict.
Both validated red-then-green: temporarily reverted each fix,
confirmed the corresponding test fails with the right message, then
re-applied the fix and confirmed both go green.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>GenericJam added a commit
that referenced
this pull request
May 17, 2026
Tier-1 structural lints (cheap, no toolchain) + tier-3 compile check (NDK clang, skipped without NDK installed). Caught a real regression during validation — a duplicate 276-line BT JNI block in beam_jni.c.eex (also from the PR #4 union-merge fallout). Removed. lib/mob_new/templates/lint.ex — 8 structural checks: - balanced_braces / balanced_parens / balanced_brackets - no_eex_leaks (detects `<%=`, `<% `, ` %>` survivors) - unique_kotlin_imports / unique_swift_imports - external_fun_jni_consistency (Kotlin externs ↔ C JNI thunks) - check_kotlin / check_c / check_swift aggregate funs test/mob_new/templates/lint_test.exs — 25 unit tests; red-then-green validated each check. test/mob_new/project_generator_test.exs: - Refactored the existing brace-balance + import-uniqueness tests to use Lint (single source of truth, cleaner failure messages). - Added cross-file JNI/Kotlin consistency test. - Added `clang -fsyntax-only` test tagged :requires_android_ndk so it skips cleanly on systems without the NDK. beam_jni.c.eex: dropped lines 533-808 (the duplicate BT block). The first BT block (lines 256-531) is the canonical copy. Caught by the clang test on first run — exactly the kind of bug the test was meant to catch. Tier-3 paid for itself immediately. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
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 freeto 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.
Companion to GenericJam/mob#9 (Mob.Bt runtime).
Generates the Kotlin BroadcastReceivers, JNI native_* externs, and AndroidManifest permissions for the Mob.Bt + Mob.Bt.Hfp / Spp / Hid API.
See the commit message for full details.
cc @GenericJam