@@ -24,14 +24,13 @@ func queryAdapter(ctx *app.Context) error {
2424 defer adapter.Close () // releases the JNI global reference
2525
2626 // Check if Bluetooth hardware is enabled.
27- // Internally: env.CallBooleanMethod(obj, mid) -> uint8, then resultRaw != 0
2827 enabled , err := adapter.IsEnabled ()
2928 if err != nil {
3029 return err
3130 }
3231 fmt.Printf (" Bluetooth enabled: %v \n " , enabled)
3332
34- // Adapter name and MAC address (both return string via CallObjectMethod + GoString )
33+ // Adapter name and MAC address (both return string)
3534 name , err := adapter.GetName ()
3635 if err != nil {
3736 return err
@@ -42,12 +41,19 @@ func queryAdapter(ctx *app.Context) error {
4241 }
4342 fmt.Printf (" Adapter: %s (%s )\n " , name, addr)
4443
45- // Scan mode (int32)
44+ // Scan mode (int32) -- compare against named constants
4645 scanMode , err := adapter.GetScanMode ()
4746 if err != nil {
4847 return err
4948 }
50- fmt.Printf (" Scan mode: %d \n " , scanMode)
49+ switch scanMode {
50+ case bluetooth.ScanModeNone :
51+ fmt.Println (" Scan mode: none" )
52+ case bluetooth.ScanModeConnectable :
53+ fmt.Println (" Scan mode: connectable" )
54+ case bluetooth.ScanModeConnectableDiscoverable :
55+ fmt.Println (" Scan mode: connectable + discoverable" )
56+ }
5157
5258 return nil
5359}
@@ -110,6 +116,7 @@ import (
110116 " github.com/AndroidGoLab/jni"
111117 " github.com/AndroidGoLab/jni/app"
112118 " github.com/AndroidGoLab/jni/bluetooth"
119+ " github.com/AndroidGoLab/jni/content"
113120)
114121
115122func runDiscovery (vm *jni .VM , ctx *app .Context ) error {
@@ -136,57 +143,54 @@ func runDiscovery(vm *jni.VM, ctx *app.Context) error {
136143 if methodName != " onReceive" || len (args) < 2 {
137144 return nil , nil
138145 }
139- // args[0] = Context, args[1] = Intent
140- intentObj := args[1 ]
146+ // args[0] = Context, args[1] = Intent (local ref)
141147
142- // Extract the BluetoothDevice from the intent via raw JNI:
143- // BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
144- intentClass , err := env.FindClass (" android/content/Intent" )
145- if err != nil {
146- return nil , err
147- }
148- defer env.DeleteLocalRef (&intentClass.Object )
148+ // Wrap the intent in a typed wrapper. Promote to global ref first
149+ // because Intent methods call vm.Do() internally.
150+ intentGlobal := env.NewGlobalRef (args[1 ])
151+ intent := app.Intent {VM: vm, Obj: intentGlobal}
152+ defer env.DeleteGlobalRef (intentGlobal)
149153
150- getParcelableMid , err := env.GetMethodID (intentClass,
151- " getParcelableExtra" ,
152- " (Ljava/lang/String;)Landroid/os/Parcelable;" )
154+ // Use typed wrapper to read the action.
155+ action , err := intent.GetAction ()
153156 if err != nil {
154157 return nil , err
155158 }
156-
157- extraKey , err := env.NewStringUTF (" android.bluetooth.device.extra.DEVICE" )
158- if err != nil {
159- return nil , err
159+ if action != bluetooth.ActionFound {
160+ return nil , nil
160161 }
161- defer env.DeleteLocalRef (&extraKey.Object )
162162
163- deviceObj , err := env. CallObjectMethod (intentObj, getParcelableMid,
164- jni. ObjectValue (&extraKey. Object ) )
163+ // Extract the BluetoothDevice from the intent extras.
164+ deviceObj , err := intent. GetParcelableExtra (bluetooth. ExtraDevice )
165165 if err != nil || deviceObj == nil {
166166 return nil , err
167167 }
168- defer env.DeleteLocalRef (deviceObj)
169168
170169 // Wrap in the generated Device type to use typed accessors.
171- // We need a global ref for the Device struct.
172170 deviceGlobal := env.NewGlobalRef (deviceObj)
173171 device := bluetooth.Device {VM: vm, Obj: deviceGlobal}
172+ defer env.DeleteGlobalRef (deviceGlobal)
174173
175174 name , _ := device.GetName ()
176175 addr , _ := device.GetAddress ()
177176 devType , _ := device.GetType ()
178177 fmt.Printf (" Found device: %s (%s ) type=%d \n " , name, addr, devType)
179178
180- env.DeleteGlobalRef (deviceGlobal)
181179 return nil , nil
182180 },
183181 )
184182 defer jni.UnregisterProxyHandler (handlerID)
185183
186- // 2. Instantiate GoBroadcastReceiver and IntentFilter via raw JNI.
184+ // 2. Create an IntentFilter for ACTION_FOUND.
185+ filter , err := content.NewIntentFilter (vm, bluetooth.ActionFound )
186+ if err != nil {
187+ return fmt.Errorf (" new IntentFilter: % w" , err)
188+ }
189+ defer filter.Close ()
190+
191+ // 3. Instantiate GoBroadcastReceiver (user-defined Java adapter -- raw JNI required).
187192 var receiverGlobal *jni.GlobalRef
188193 err = vm.Do (func (env *jni.Env ) error {
189- // Create the GoBroadcastReceiver(handlerID)
190194 recvClass , err := env.FindClass (" center/dx/jni/generated/GoBroadcastReceiver" )
191195 if err != nil {
192196 return fmt.Errorf (" find GoBroadcastReceiver: % w" , err)
@@ -203,46 +207,22 @@ func runDiscovery(vm *jni.VM, ctx *app.Context) error {
203207 }
204208 receiverGlobal = env.NewGlobalRef (recvLocal)
205209 env.DeleteLocalRef (recvLocal)
206-
207- // Create IntentFilter("android.bluetooth.device.action.FOUND")
208- ifClass , err := env.FindClass (" android/content/IntentFilter" )
209- if err != nil {
210- return err
211- }
212- defer env.DeleteLocalRef (&ifClass.Object )
213-
214- ifInit , err := env.GetMethodID (ifClass, " <init>" , " (Ljava/lang/String;)V" )
215- if err != nil {
216- return err
217- }
218- actionStr , err := env.NewStringUTF (" android.bluetooth.device.action.FOUND" )
219- if err != nil {
220- return err
221- }
222- defer env.DeleteLocalRef (&actionStr.Object )
223-
224- filterLocal , err := env.NewObject (ifClass, ifInit, jni.ObjectValue (&actionStr.Object ))
225- if err != nil {
226- return err
227- }
228- filterGlobal := env.NewGlobalRef (filterLocal)
229- env.DeleteLocalRef (filterLocal)
230- defer func () { env.DeleteGlobalRef (filterGlobal) }()
231-
232- // Register the receiver with the Context.
233- // ctx.RegisterReceiver2(receiver, filter) -> Intent
234- _, err = ctx.RegisterReceiver2 (
235- (*jni.Object )(unsafe.Pointer (receiverGlobal)),
236- (*jni.Object )(unsafe.Pointer (filterGlobal)),
237- )
238- return err
210+ return nil
239211 })
212+ if err != nil {
213+ return fmt.Errorf (" create receiver: % w" , err)
214+ }
215+
216+ // 4. Register the receiver with the Context.
217+ _, err = ctx.RegisterReceiver2 (
218+ (*jni.Object )(unsafe.Pointer (receiverGlobal)),
219+ filter.Obj ,
220+ )
240221 if err != nil {
241222 return fmt.Errorf (" register receiver: % w" , err)
242223 }
243224
244- // 3. Start discovery.
245- // Internally calls env.CallBooleanMethod with JNI signature "()Z".
225+ // 5. Start discovery.
246226 // Returns (bool, error): true if discovery started successfully.
247227 started , err := adapter.StartDiscovery ()
248228 if err != nil {
@@ -255,7 +235,7 @@ func runDiscovery(vm *jni.VM, ctx *app.Context) error {
255235
256236 // ... wait for results, e.g. time.Sleep or channel ...
257237
258- // 4 . Cleanup: cancel discovery + unregister receiver.
238+ // 6 . Cleanup: cancel discovery + unregister receiver.
259239 _, _ = adapter.CancelDiscovery ()
260240 _ = ctx.UnregisterReceiver ((*jni.Object )(unsafe.Pointer (receiverGlobal)))
261241 _ = vm.Do (func (env *jni.Env ) error {
@@ -304,10 +284,10 @@ type Device struct {
304284}
305285
306286// All accessors follow the same vm.Do + ensureInit + CallXxxMethod pattern.
307- name , err := device.GetName () // string (CallObjectMethod + GoString)
287+ name , err := device.GetName () // string
308288addr , err := device.GetAddress () // string
309- devType , err := device.GetType () // int32 (CallIntMethod)
310- bondState , err := device.GetBondState () // int32 (CallIntMethod)
289+ devType , err := device.GetType () // int32 -- compare with bluetooth.DeviceTypeClassic, etc.
290+ bondState , err := device.GetBondState () // int32 -- compare with bluetooth.BondNone, etc.
311291alias , err := device.GetAlias () // string
312292uuids , err := device.GetUuids () // *jni.Object (raw ParcelUuid[] array)
313293
@@ -417,7 +397,7 @@ public class GoScanCallback extends ScanCallback {
417397 )
418398 defer jni.UnregisterProxyHandler (scanHandlerID)
419399
420- // Instantiate GoScanCallback via raw JNI.
400+ // raw JNI: GoScanCallback is a user-defined Java class with no generated constructor
421401 var callbackObj *jni.Object
422402 err = vm.Do (func (env *jni.Env ) error {
423403 cbClass , err := env.FindClass (" center/dx/jni/generated/GoScanCallback" )
@@ -647,6 +627,15 @@ bluetooth.StateDisconnecting // 3
647627bluetooth.ConnectionPriorityBalanced // 0
648628bluetooth.ConnectionPriorityHigh // 1
649629bluetooth.ConnectionPriorityLowPower // 2
630+
631+ // Action strings (from BluetoothDevice / BluetoothAdapter)
632+ bluetooth.ActionFound // "android.bluetooth.device.action.FOUND"
633+ bluetooth.ActionBondStateChanged // "android.bluetooth.device.action.BOND_STATE_CHANGED"
634+ bluetooth.ActionDiscoveryStarted // "android.bluetooth.adapter.action.DISCOVERY_STARTED"
635+ bluetooth.ActionDiscoveryFinished // "android.bluetooth.adapter.action.DISCOVERY_FINISHED"
636+
637+ // Extra keys (from BluetoothDevice)
638+ bluetooth.ExtraDevice // "android.bluetooth.device.extra.DEVICE"
650639` ` `
651640
652641BLE-specific constants live in ` bluetooth/le` :
0 commit comments