ATAK forwardwarder for android

I’m developing a plugin (GitHub - paulmandal/atak-forwarder: Forwards packets to/from ATAK over an off-grid communication layer) for ATAK (Android Team Awareness Kit - a very feature rich mapping software) to allow hikers and other outdoorspeople to coordinate while in the backcountry.

I’ve got a decent integration with the Meshtastic Android API going that works for almost all of my needs. However, I am trying to use the MeshService.setDeviceAddress(String) method from my plugin/application but I cannot. Whenever I call this I get an exception like:

23130-23147/com.geeksville.mesh E/toRemoteExceptions: Uncaught exception, returning to remote client
    java.lang.RuntimeException: Can't create handler inside thread Thread[Binder:23130_1,5,main] that has not called Looper.prepare()
        at android.os.Handler.<init>(
        at android.os.Handler.<init>(
        at com.geeksville.mesh.service.SafeBluetooth.<init>(SafeBluetooth.kt:100)
        at com.geeksville.mesh.service.BluetoothInterface.<init>(BluetoothInterface.kt:210)
        at com.geeksville.mesh.service.RadioInterfaceService.startInterface(RadioInterfaceService.kt:234)
        at com.geeksville.mesh.service.RadioInterfaceService.setBondedDeviceAddress(RadioInterfaceService.kt:304)
        at com.geeksville.mesh.service.RadioInterfaceService.access$setBondedDeviceAddress(RadioInterfaceService.kt:37)
        at com.geeksville.mesh.service.RadioInterfaceService$binder$1$setDeviceAddress$1.invoke(RadioInterfaceService.kt:312)
        at com.geeksville.mesh.service.RadioInterfaceService$binder$1$setDeviceAddress$1.invoke(RadioInterfaceService.kt:309)
        at com.geeksville.util.ExceptionsKt.toRemoteExceptions(Exceptions.kt:56)
        at com.geeksville.mesh.service.RadioInterfaceService$binder$1.setDeviceAddress(RadioInterfaceService.kt:311)
        at com.geeksville.mesh.service.MeshService$binder$1$setDeviceAddress$1.invoke(MeshService.kt:1538)
        at com.geeksville.mesh.service.MeshService$binder$1$setDeviceAddress$1.invoke(MeshService.kt:1533)
        at com.geeksville.util.ExceptionsKt.toRemoteExceptions(Exceptions.kt:56)
        at com.geeksville.mesh.service.MeshService$binder$1.setDeviceAddress(MeshService.kt:1535)
        at com.geeksville.mesh.IMeshService$Stub.onTransact(
        at android.os.Binder.execTransactInternal(
        at android.os.Binder.execTransact(

I know the method documentation states “Users should not call this directly, only used internally by the MeshUtil activity” but I need this method for my use case: assigning a callsign, map marker color/symbol (used in ATAK), and reporting interval to devices that do not have phone + ATAK to control them so that they can be shown on the map in ATAK.

Is there any way to work around this?

Just some quick feedback – integrating with the Meshtastic API has been easy and device performance has been good. Really nice work on the software/hardware!


DId you try to call the method from another thread than the main ?

I’m calling from the main thread, do I need to do this in a background thread?

It has to be run in a coroutines in kotlin.
I guess it is the problem, i need to google from the computer to verify that

Can you try to call it like :

new Handler(Looper.getMainLooper()).post(new Runnable() {
    public void run() {

This didn’t work for me, I am connecting to the MeshService as a service so I don’t know if the callers thread will have any impact here.

I was able to get this working by modifying SafeBluetooth.kt:L101 to read:

private val mHandler: Handler = Handler(Looper.getMainLooper())

Not sure if that is an appropriate solution though.

hi @paulmandal,

Just a heads up because I think you might be using this API. I just changed the action that is broadcast when messages arrive at the android service. I think this won’t break your code because I was careful to keep the old legacy OPAQUE datatype working identically (I do an extra publish in case someone is listing for that).

Also, if you would like to start using a new ‘well defined’ portnum for your app I think you would like it. If you’d like the portnumber to be documented as in-use, I recommend sending in a pull-request to update portnums.proto.

If I did screw up and this breaks your app, I bet the cause is the following:


Thanks for the heads up, @geeksville! I’ll test this out within the next day or two.


oops - wait a few of days. I’ve just checked in the code, no android build out yet with this change. It will be in the next alpha release.