1414import android .content .Intent ;
1515
1616import android .content .SharedPreferences ;
17+ import android .os .Bundle ;
1718import android .os .Environment ;
1819import android .os .RemoteException ;
1920import android .preference .PreferenceManager ;
2324import androidx .core .app .NotificationCompat ;
2425
2526import com .atakmap .android .chat .ChatDatabase ;
27+ import com .atakmap .android .chat .ChatManagerMapComponent ;
28+ import com .atakmap .android .chat .GeoChatConnectorHandler ;
29+ import com .atakmap .android .contact .Contact ;
30+ import com .atakmap .android .contact .Contacts ;
2631import com .atakmap .android .cot .CotMapComponent ;
2732import com .atakmap .android .maps .MapItem ;
2833import com .atakmap .android .maps .MapView ;
2934import com .atakmap .android .meshtastic .plugin .R ;
35+ import com .atakmap .comms .CotServiceRemote ;
3036import com .atakmap .coremap .cot .event .CotDetail ;
3137import com .atakmap .coremap .cot .event .CotEvent ;
3238import com .atakmap .coremap .cot .event .CotPoint ;
5157
5258import java .io .File ;
5359import java .io .IOException ;
60+ import java .io .StringReader ;
5461import java .nio .file .Files ;
62+ import java .util .ArrayList ;
5563import java .util .HashMap ;
64+ import java .util .List ;
5665import java .util .Locale ;
5766import java .util .UUID ;
5867import java .util .concurrent .atomic .AtomicReference ;
5968
6069import com .atakmap .android .meshtastic .plugin .*;
6170
62- public class MeshtasticReceiver extends BroadcastReceiver {
71+ import org .xmlpull .v1 .XmlPullParser ;
72+ import org .xmlpull .v1 .XmlPullParserException ;
73+ import org .xmlpull .v1 .XmlPullParserFactory ;
74+
75+ public class MeshtasticReceiver extends BroadcastReceiver implements CotServiceRemote .CotEventListener {
6376 private final String TAG = "MeshtasticReceiver" ;
6477 private SharedPreferences prefs ;
6578 private SharedPreferences .Editor editor ;
66-
6779 private int oldModemPreset ;
6880 private String sender ;
6981 private static NotificationManager mNotifyManager ;
@@ -447,7 +459,7 @@ public void onReceive(Context context, Intent intent) {
447459
448460 CotDetail takvDetail = new CotDetail ("takv" );
449461 takvDetail .setAttribute ("platform" , "Meshtastic Plugin" );
450- takvDetail .setAttribute ("version" , "1.0.25 " + "\n ----NodeInfo----\n " + ni .toString ());
462+ takvDetail .setAttribute ("version" , "1.0.27 " + "\n ----NodeInfo----\n " + ni .toString ());
451463 takvDetail .setAttribute ("device" , ni .getUser ().getHwModelString ());
452464 takvDetail .setAttribute ("os" , "1" );
453465 cotDetail .addChild (takvDetail );
@@ -461,7 +473,6 @@ public void onReceive(Context context, Intent intent) {
461473 contactDetail .setAttribute ("endpoint" , "0.0.0.0:4242:tcp" );
462474 cotDetail .addChild (contactDetail );
463475
464-
465476 if (cotEvent .isValid ()) {
466477 CotMapComponent .getInternalDispatcher ().dispatch (cotEvent );
467478 if (prefs .getBoolean ("plugin_meshtastic_server" , false )) {
@@ -880,7 +891,7 @@ else if (team.equals("DarkGreen"))
880891 if (cotEvent .isValid ()) {
881892 CotMapComponent .getInternalDispatcher ().dispatch (cotEvent );
882893 if (prefs .getBoolean ("plugin_meshtastic_server" , false )) {
883- // CotMapComponent.getExternalDispatcher().dispatch(cotEvent);
894+ CotMapComponent .getExternalDispatcher ().dispatch (cotEvent );
884895 }
885896 } else
886897 Log .e (TAG , "cotEvent was not valid" );
@@ -980,4 +991,192 @@ else if (team.equals("DarkGreen"))
980991 }
981992 }
982993 }
994+
995+ @ Override
996+ public void onCotEvent (CotEvent cotEvent , Bundle bundle ) {
997+ if (prefs .getBoolean ("plugin_meshtastic_from_server" , false )) {
998+ if (cotEvent .isValid ()) {
999+
1000+ int hopLimit = prefs .getInt ("plugin_meshtastic_hop_limit" , 3 );
1001+ if (hopLimit > 8 ) {
1002+ hopLimit = 8 ;
1003+ }
1004+
1005+ int channel = prefs .getInt ("plugin_meshtastic_channel" , 0 );
1006+
1007+
1008+ DataPacket dp = null ;
1009+ int eventType = -1 ;
1010+ double divisor = 1e-7 ;
1011+ XmlPullParserFactory factory = null ;
1012+ XmlPullParser xpp = null ;
1013+ String callsign = null ;
1014+ String deviceCallsign = null ;
1015+ String message = null ;
1016+
1017+ CotDetail cotDetail = cotEvent .getDetail ();
1018+
1019+ try {
1020+ factory = XmlPullParserFactory .newInstance ();
1021+ factory .setNamespaceAware (true );
1022+ xpp = factory .newPullParser ();
1023+ xpp .setInput (new StringReader (cotDetail .toString ()));
1024+ eventType = xpp .getEventType ();
1025+ } catch (XmlPullParserException e ) {
1026+ e .printStackTrace ();
1027+ return ;
1028+ }
1029+
1030+ // All Chat Rooms
1031+ if (cotEvent .getType ().startsWith ("b-t-f" ) && cotEvent .getUID ().contains ("All Chat Rooms" )) {
1032+
1033+ try {
1034+ while (eventType != XmlPullParser .END_DOCUMENT ) {
1035+ if (eventType == XmlPullParser .START_TAG ) {
1036+ Log .d (TAG , xpp .getName ());
1037+ if (xpp .getName ().equalsIgnoreCase ("remarks" )) {
1038+ if (xpp .next () == XmlPullParser .TEXT )
1039+ message = xpp .getText ();
1040+ } else if (xpp .getName ().equalsIgnoreCase ("__chat" )) {
1041+ int attributeCount = xpp .getAttributeCount ();
1042+ Log .d (TAG , "__chat has " + +attributeCount );
1043+ for (int i = 0 ; i < attributeCount ; i ++) {
1044+ if (xpp .getAttributeName (i ).equalsIgnoreCase ("senderCallsign" ))
1045+ callsign = xpp .getAttributeValue (i );
1046+ }
1047+ } else if (xpp .getName ().equalsIgnoreCase ("link" )) {
1048+ int attributeCount = xpp .getAttributeCount ();
1049+ Log .d (TAG , "link has " + +attributeCount );
1050+ for (int i = 0 ; i < attributeCount ; i ++) {
1051+ if (xpp .getAttributeName (i ).equalsIgnoreCase ("uid" ))
1052+ deviceCallsign = xpp .getAttributeValue (i );
1053+ }
1054+ }
1055+ }
1056+ eventType = xpp .next ();
1057+ }
1058+
1059+ } catch (XmlPullParserException | IOException e ) {
1060+ e .printStackTrace ();
1061+ }
1062+
1063+ ATAKProtos .Contact .Builder contact = ATAKProtos .Contact .newBuilder ();
1064+ contact .setCallsign (callsign );
1065+ contact .setDeviceCallsign (deviceCallsign );
1066+
1067+ ATAKProtos .GeoChat .Builder geochat = ATAKProtos .GeoChat .newBuilder ();
1068+ geochat .setMessage (message );
1069+ geochat .setTo ("All Chat Rooms" );
1070+
1071+ ATAKProtos .TAKPacket .Builder tak_packet = ATAKProtos .TAKPacket .newBuilder ();
1072+ tak_packet .setContact (contact );
1073+ tak_packet .setChat (geochat );
1074+
1075+ Log .d (TAG , "Total wire size for TAKPacket: " + tak_packet .build ().toByteArray ().length );
1076+ Log .d (TAG , "Sending: " + tak_packet .build ().toString ());
1077+
1078+ dp = new DataPacket (DataPacket .ID_BROADCAST , tak_packet .build ().toByteArray (), Portnums .PortNum .ATAK_PLUGIN_VALUE , DataPacket .ID_LOCAL , System .currentTimeMillis (), 0 , MessageStatus .UNKNOWN , hopLimit , channel );
1079+ try {
1080+ if (MeshtasticMapComponent .getMeshService () != null )
1081+ MeshtasticMapComponent .getMeshService ().send (dp );
1082+ } catch (RemoteException e ) {
1083+ throw new RuntimeException (e );
1084+ }
1085+ } else if (cotDetail .getAttribute ("contact" ) != null ) {
1086+ for (Contact c : Contacts .getInstance ().getAllContacts ()) {
1087+ if (cotEvent .getUID ().equals (c .getUid ())) {
1088+
1089+ int battery = 0 , course = 0 , speed = 0 ;
1090+ String role = null , name = null ;
1091+ double lat = 0 , lng = 0 , alt = 0 ;
1092+
1093+ lat = cotEvent .getGeoPoint ().getLatitude ();
1094+ lng = cotEvent .getGeoPoint ().getLongitude ();
1095+ alt = cotEvent .getGeoPoint ().getAltitude ();
1096+
1097+ try {
1098+ while (eventType != XmlPullParser .END_DOCUMENT ) {
1099+ if (eventType == XmlPullParser .START_TAG ) {
1100+ if (xpp .getName ().equalsIgnoreCase ("contact" )) {
1101+ int attributeCount = xpp .getAttributeCount ();
1102+ Log .d (TAG , "Contact has " + attributeCount );
1103+ for (int i = 0 ; i < attributeCount ; i ++) {
1104+ if (xpp .getAttributeName (i ).equalsIgnoreCase ("callsign" ))
1105+ callsign = xpp .getAttributeValue (i );
1106+ }
1107+ } else if (xpp .getName ().equalsIgnoreCase ("__group" )) {
1108+ int attributeCount = xpp .getAttributeCount ();
1109+ Log .d (TAG , "__group has " + attributeCount );
1110+ for (int i = 0 ; i < attributeCount ; i ++) {
1111+ if (xpp .getAttributeName (i ).equalsIgnoreCase ("role" ))
1112+ role = xpp .getAttributeValue (i );
1113+ else if (xpp .getAttributeName (i ).equalsIgnoreCase ("name" ))
1114+ name = xpp .getAttributeValue (i );
1115+ }
1116+ } else if (xpp .getName ().equalsIgnoreCase ("status" )) {
1117+ int attributeCount = xpp .getAttributeCount ();
1118+ Log .d (TAG , "status has " + attributeCount );
1119+ for (int i = 0 ; i < attributeCount ; i ++) {
1120+ if (xpp .getAttributeName (i ).equalsIgnoreCase ("battery" ))
1121+ battery = Integer .parseInt (xpp .getAttributeValue (i ));
1122+ }
1123+ } else if (xpp .getName ().equalsIgnoreCase ("track" )) {
1124+ int attributeCount = xpp .getAttributeCount ();
1125+ Log .d (TAG , "track has " + attributeCount );
1126+ for (int i = 0 ; i < attributeCount ; i ++) {
1127+ if (xpp .getAttributeName (i ).equalsIgnoreCase ("course" ))
1128+ course = Double .valueOf (xpp .getAttributeValue (i )).intValue ();
1129+ else if (xpp .getAttributeName (i ).equalsIgnoreCase ("speed" ))
1130+ speed = Double .valueOf (xpp .getAttributeValue (i )).intValue ();
1131+ }
1132+ }
1133+ }
1134+ eventType = xpp .next ();
1135+ }
1136+ } catch (XmlPullParserException | IOException e ) {
1137+ e .printStackTrace ();
1138+ return ;
1139+ }
1140+
1141+ ATAKProtos .Contact .Builder contact = ATAKProtos .Contact .newBuilder ();
1142+ contact .setCallsign (callsign );
1143+ contact .setDeviceCallsign (cotEvent .getUID ());
1144+
1145+ ATAKProtos .Group .Builder group = ATAKProtos .Group .newBuilder ();
1146+ group .setRole (ATAKProtos .MemberRole .valueOf (role .replace (" " , "" )));
1147+ group .setTeam (ATAKProtos .Team .valueOf (name .replace (" " , "" )));
1148+
1149+ ATAKProtos .Status .Builder status = ATAKProtos .Status .newBuilder ();
1150+ status .setBattery (battery );
1151+
1152+ ATAKProtos .PLI .Builder pli = ATAKProtos .PLI .newBuilder ();
1153+ pli .setAltitude (Double .valueOf (alt ).intValue ());
1154+ pli .setLatitudeI ((int ) (lat / divisor ));
1155+ pli .setLongitudeI ((int ) (lng / divisor ));
1156+ pli .setCourse (course );
1157+ pli .setSpeed (speed );
1158+
1159+ ATAKProtos .TAKPacket .Builder tak_packet = ATAKProtos .TAKPacket .newBuilder ();
1160+ tak_packet .setContact (contact );
1161+ tak_packet .setStatus (status );
1162+ tak_packet .setGroup (group );
1163+ tak_packet .setPli (pli );
1164+
1165+ Log .d (TAG , "Total wire size for TAKPacket: " + tak_packet .build ().toByteArray ().length );
1166+ Log .d (TAG , "Sending: " + tak_packet .build ().toString ());
1167+
1168+ dp = new DataPacket (DataPacket .ID_BROADCAST , tak_packet .build ().toByteArray (), Portnums .PortNum .ATAK_PLUGIN_VALUE , DataPacket .ID_LOCAL , System .currentTimeMillis (), 0 , MessageStatus .UNKNOWN , hopLimit , channel );
1169+ try {
1170+ if (MeshtasticMapComponent .getMeshService () != null )
1171+ MeshtasticMapComponent .getMeshService ().send (dp );
1172+ } catch (RemoteException e ) {
1173+ throw new RuntimeException (e );
1174+ }
1175+ }
1176+ }
1177+ }
1178+ }
1179+ }
1180+ }
1181+
9831182}
0 commit comments