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.

Thanks for all your great work @paulmandal !

I have installed the forwarder, but it looks like it’s signed for ATAK 4.2. Do you have any previous apks signed for older versions of ATAK for those of us using our old, unsupported, phones?

@paulmandal Thank you for your contribution! Got this working with 4.2.2 from your drive. Had a question about messages and groups. As a test I connected each mesh to a phone and had each visible on atak. However, in the group window. I could only see phone 1 show the group listed (I sent a message at that time), but not the other phone #2. Then, sort of out of nowhere, the other phone #2 then showed the group listed including the msg from phone #1, but the first phone #1 stopped showing the group. Also I sent a msg from phone # 2, to see if #1 would receive it. Though it never did. And it also never showed the group listing either.

Have I done something wrong during the setup or maybe issue a reset if I botched something?

Not sure where to go from here. All in all, I understand it’s work in progress and it’s incredible as we can connect now through atak. It’ll get better I’m sure of.

Again thank you for the great work! It’s awesome :grin:

1 Like


There are probably two things at play here. The first is how the plugin maps ATAKs internal UIDs to Meshtastic node IDs, and the second is how messages are transmitted by ATAK and the plugin.

When the plugin starts it sends a broadcast discovery message containing its Meshtastic ID, ATAK UID, and a flag signifying whether the discovery message is an initial broadcast. When another node receives this message with the flag set to true it broadcasts its own discovery message with the flag set to false, this way every node will hopefully discovery each other and hopefully have a mapping of ATAK UIDs to Meshtastic node IDs.

If one of these broadcast messages were missed/received late that might explain phone #2 becoming visible. Not sure about the phone #1 disappearing though.

What modem / mode settings are you using? Chat messages are usually a few segments long so they’re very unreliable at the slower speeds.

Thank you! I don’t have the plugin signed for any older versions but I might be able to get it.

Btw are you using an older version because you can’t use the Play Store version? If so one of the dev builds of ATAK + the forwarder may work for you: dev-builds - Google Drive

That makes sense. We were able to see each other on the map, and when broadcasting, we would receive the others discovery (both units were on the same desk)

For mode, I had it set to the default on short range /fast. Though at one time I believe I bumped it up to medium for testing.

This may sound redundant, what if there was a verification sent with the broadcast and also on the receiving side, if a broadcast hasn’t been received, “call out” again for a repeat of the previously sent packet?

I have tried resetting the psk and unpairing the nodes from the phones. In an effort to get them to forget any data and hopefully start fresh. But that didn’t work. The nodes really seem to hold on to previous data for quite a long time.

I could try reflashing them completely and seeing if that has any positive change.

Thanks @paulmandal. Looking forward to anything new with Forwardwarder.

Oh yeah, what is “connect to svc”, intended for? Probably planned future use I was thinking.

I’d like to make some improvements on how the plugin propagates messages but that’s a while off.

“connect to svc” is a leftover from testing, it should be removed in the next build.

thanks for the interest in the plugin, I’ll post here when I push a new build!


Thanks for your reply! You’re exactly right. I am using the older versions because the play store version doesn’t work. I tried the dev builds, but they both ask for an encryption passphrase. Not sure what that is from

Alrighty! So I got my old pixel loaded up with atak and meshtastic and the plug-in. Did some testing late last night. I found with the mode / speed set to “short range / fast” also “medium range / fast”. Seemed to have better luck with medium, even though both devices were on my desk. During the test, I found receiving the msg sent by either phone, could take anywhere from a few minutes to 10+. Also of which the messengers would disappear from the chat window, oddly enough when you could see a unit on the map, I found you could still enter the chat window through the icon menu from the map and select geochat.

Hope this helps. Still learning as I go, and thought maybe documenting it may help.

Lastly, I noticed (just remembered lol), the @ would change colors, green, red (ofc that’s bad), yellow, brownish, dark orange, gray, there was purple too. Anyhow just curious on what the various colors mean and what significance they represent. When both phone showed a different color than the other, it seemed like that was when they weren’t communicating anymore. But I don’t know how much that holds true, because I did receive a msg during a time when neither were visible on the map or chat to each other. :rofl: I enjoy tinkering.

@paulmandal Thanks again for the awesome plugin.

ATAK should prompt you for an encryption passphrase the first time it starts. If you update to a new version it will request the same passphrase to access your existing data. I ran into an issue with this before and I found a decent workaround is to:

  • Export all your data as a Data Package
  • backup then wipe out /sdcard/atak
  • upgrade ATAK
  • import the Data Package

Quick (kinda incomplete) explanation – icons only live on the map until they hit their “stale time” set by ATAK, so if you didn’t get a position update for ~10 mins the map marker for the other EUD will disappear.

Red - No device connected / no service connection
Purple - No device configured
Green - More than 89% of last 10 sent packets got ACK
Yellow - More than 75% of last 10 sent packets got ACK
Orange - More than 50% of last 10 packets got ACK
Brown - More than 25% of last 10 packets got ACK
Grey - Anything below 25% of last 10 packets got an ACK

Check out the MsgQ Len in the UI, that # tells you how many outbound messages are waiting to send

Also most things the plugin does are logged to logcat tagged either ATAKDBG (signed version) or FWDDBG (later versions)